Scippy

SCIP

Solving Constraint Integer Programs

cutsel_ensemble.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (c) 2002-2024 Zuse Institute Berlin (ZIB) */
7 /* */
8 /* Licensed under the Apache License, Version 2.0 (the "License"); */
9 /* you may not use this file except in compliance with the License. */
10 /* You may obtain a copy of the License at */
11 /* */
12 /* http://www.apache.org/licenses/LICENSE-2.0 */
13 /* */
14 /* Unless required by applicable law or agreed to in writing, software */
15 /* distributed under the License is distributed on an "AS IS" BASIS, */
16 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17 /* See the License for the specific language governing permissions and */
18 /* limitations under the License. */
19 /* */
20 /* You should have received a copy of the Apache-2.0 license */
21 /* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22 /* */
23 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24 
25 /**@file cutsel_ensemble.c
26  * @ingroup DEFPLUGINS_CUTSEL
27  * @brief ensemble cut selector
28  * @author Mark Turner
29  *
30  * @todo separator hard limit on density is inappropriate for MINLP. Need to relax hard limit in case of all cuts dense
31  * @todo penalising via parallelism is overly costly if many cuts. Hash cuts before and find appropriate groups?
32  */
33 
34 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
35 
36 #include <assert.h>
37 
38 #include "scip/scip_cutsel.h"
39 #include "scip/scip_cut.h"
40 #include "scip/scip_lp.h"
41 #include "scip/scip_randnumgen.h"
42 #include "scip/cutsel_ensemble.h"
43 
44 
45 #define CUTSEL_NAME "ensemble"
46 #define CUTSEL_DESC "weighted sum of many terms with optional filtering and penalties"
47 #define CUTSEL_PRIORITY 7000
48 
49 #define RANDSEED 0x5EED
50 
51 #define DEFAULT_MINSCORE 0.0 /**< minimum score s.t. a cut can be selected */
52 #define DEFAULT_EFFICACYWEIGHT 0.75 /**< weight of normed-efficacy in score calculation */
53 #define DEFAULT_DIRCUTOFFDISTWEIGHT 0.0 /**< weight of normed-directed cutoff distance in score calculation */
54 #define DEFAULT_OBJPARALWEIGHT 0.25 /**< weight of objective parallelism in score calculation */
55 #define DEFAULT_INTSUPPORTWEIGHT 0.45 /**< weight of integral support in cut score calculation */
56 #define DEFAULT_EXPIMPROVWEIGHT 0.1 /**< weight of normed-expected improvement in cut score calculation */
57 #define DEFAULT_PSCOSTWEIGHT 0.75 /**< weight of normalised pseudo-costs in cut score calculation */
58 #define DEFAULT_NLOCKSWEIGHT 0.25 /**< weight of normalised number of locks in cut score calculation */
59 #define DEFAULT_MAXSPARSITYBONUS 0.5 /**< score given to a cut with complete sparsity */
60 #define DEFAULT_SPARSITYENDBONUS 0.2 /**< the density at which a cut no longer receives additional score */
61 #define DEFAULT_GOODNUMERICBONUS 0.0 /**< bonus provided for good numerics */
62 #define DEFAULT_MAXCOEFRATIOBONUS 10000 /**< maximum coefficient ratio of cut for which numeric bonus is given */
63 #define DEFAULT_PENALISELOCKS TRUE /**< whether having less locks should be rewarded instead of more */
64 #define DEFAULT_PENALISEOBJPARAL TRUE /**< whether objective parallelism should be penalised not rewarded */
65 #define DEFAULT_FILTERPARALCUTS FALSE /**< should cuts be filtered so no two parallel cuts are added */
66 #define DEFAULT_MAXPARAL 0.95 /**< threshold for when two cuts are considered parallel to each other */
67 #define DEFAULT_PENALISEPARALCUTS TRUE /**< should two parallel cuts be penalised instead of outright filtered */
68 #define DEFAULT_PARALPENALTY 0.25 /**< penalty for weaker of two parallel cuts if penalising parallel cuts */
69 #define DEFAULT_FILTERDENSECUTS TRUE /**< should cuts over a given density threshold be filtered */
70 #define DEFAULT_MAXCUTDENSITY 0.425 /**< max allowed cut density if filtering dense cuts */
71 #define DEFAULT_MAXNONZEROROOTROUND 4.5 /**< max nonzeros per round (root). Gets multiplied by num LP cols */
72 #define DEFAULT_MAXNONZEROTREEROUND 9.5 /**< max nonzeros per round (tree). Gets multiplied by num LP cols */
73 #define DEFAULT_MAXCUTS 200 /**< maximum number of cuts that can be considered by this cut selector */
74 #define DEFAULT_MAXNUMVARS 50000 /**< maximum number of variables that a problem can have while calling this cut selector */
75 
76 /*
77  * Data structures
78  */
79 
80 /** cut selector data */
81 struct SCIP_CutselData
82 {
83  SCIP_RANDNUMGEN* randnumgen; /**< random generator for tie-breaking */
84  SCIP_Real minscore; /**< minimum score for a cut to be added to the LP */
85  SCIP_Real objparalweight; /**< weight of objective parallelism in cut score calculation */
86  SCIP_Real efficacyweight; /**< weight of normed-efficacy in cut score calculation */
87  SCIP_Real dircutoffdistweight;/**< weight of normed-directed cutoff distance in cut score calculation */
88  SCIP_Real expimprovweight; /**< weight of normed-expected improvement in cut score calculation */
89  SCIP_Real intsupportweight; /**< weight of integral support in cut score calculation */
90  SCIP_Real pscostweight; /**< weight of normalised pseudo-costs in cut score calculation */
91  SCIP_Real locksweight; /**< weight of normed-number of active locks in cut score calculation */
92  SCIP_Real maxsparsitybonus; /**< weight of maximum sparsity reward in cut score calculation */
93  SCIP_Real goodnumericsbonus; /**< weight of good numeric bonus in cut score calculation */
94  SCIP_Real endsparsitybonus; /**< max sparsity value for which a bonus is applied */
95  SCIP_Real maxparal; /**< threshold for when two cuts are considered parallel to each other */
96  SCIP_Real paralpenalty; /**< penalty for weaker of two parallel cuts if penalising parallel cuts */
97  SCIP_Real maxcutdensity; /**< max allowed cut density if filtering dense cuts */
98  SCIP_Real maxnonzerorootround;/**< max nonzeros per round (root). Gets multiplied by num LP cols */
99  SCIP_Real maxnonzerotreeround;/**< max nonzeros per round (tree). Gets multiplied by num LP cols */
100  SCIP_Bool filterparalcuts; /**< should cuts be filtered so no two parallel cuts are added */
101  SCIP_Bool penaliseparalcuts; /**< should two parallel cuts be penalised instead of outright filtered */
102  SCIP_Bool filterdensecuts; /**< should cuts over a given density threshold be filtered */
103  SCIP_Bool penaliselocks; /**< whether the number of locks should be penalised instead of rewarded */
104  SCIP_Bool penaliseobjparal; /**< whether objective parallelism should be penalised */
105  int maxcoefratiobonus; /**< maximum coefficient ratio for which numeric bonus is applied */
106  int maxcuts; /**< maximum number of cuts that can be considered by this cut selector */
107  int maxnumvars; /**< maximum number of variables that a problem can have while calling this cut selector */
108 };
109 
110 
111 /*
112  * Local methods
113  */
114 
115 /** returns the maximum score of cuts; if scores is not NULL, then stores the individual score of each cut in scores */
116 static
118  SCIP* scip, /**< SCIP data structure */
119  SCIP_ROW** cuts, /**< array with cuts to score */
120  SCIP_CUTSELDATA* cutseldata, /**< cut selector data */
121  SCIP_Real* scores, /**< array to store the score of cuts or NULL */
122  SCIP_Bool root, /**< whether we are at the root node or not */
123  int ncuts /**< number of cuts in cuts array */
124  )
125 {
126  SCIP_Real* effs;
127  SCIP_Real* dcds;
128  SCIP_Real* exps;
129  SCIP_Real* cutdensities;
130  SCIP_Real* cutlocks;
131  SCIP_Real* pscosts;
132  SCIP_SOL* sol;
133  SCIP_Real maxdcd = 0.0;
134  SCIP_Real maxeff = 0.0;
135  SCIP_Real maxexp = 0.0;
136  SCIP_Real maxpscost = 0.0;
137  SCIP_Real maxlocks = 0.0;
138  SCIP_Real ncols;
139 
140  /* Get the solution that we use for directed cutoff distance calculations. Get the number of columns too */
141  sol = SCIPgetBestSol(scip);
142  ncols = SCIPgetNLPCols(scip);
143 
144  /* Initialise all array information that we're going to use for scoring */
145  SCIP_CALL(SCIPallocBufferArray(scip, &effs, ncuts));
146  SCIP_CALL(SCIPallocBufferArray(scip, &dcds, ncuts));
147  SCIP_CALL(SCIPallocBufferArray(scip, &exps, ncuts));
148  SCIP_CALL(SCIPallocBufferArray(scip, &cutdensities, ncuts));
149  SCIP_CALL(SCIPallocBufferArray(scip, &cutlocks, ncuts));
150  SCIP_CALL(SCIPallocBufferArray(scip, &pscosts, ncuts));
151 
152  /* Populate the number of cut locks, the pseudo-cost scores, and the cut densities */
153  for (int i = 0; i < ncuts; ++i )
154  {
155  SCIP_COL** cols;
156  SCIP_Real* cutvals;
157  SCIP_Real sqrcutnorm;
158  SCIP_Real ncutcols;
159  SCIP_Real cutalpha;
160 
161  cols = SCIProwGetCols(cuts[i]);
162  cutvals = SCIProwGetVals(cuts[i]);
163  sqrcutnorm = MAX(SCIPsumepsilon(scip), SQR(SCIProwGetNorm(cuts[i]))); /*lint !e666*/
164  cutalpha = -SCIPgetRowFeasibility(scip, cuts[i]) / sqrcutnorm;
165  ncutcols = SCIProwGetNNonz(cuts[i]);
166  cutdensities[i] = ncutcols / ncols;
167  cutlocks[i] = 0;
168  pscosts[i] = 0;
169 
170  for ( int j = 0; j < (int) ncutcols; ++j )
171  {
172  SCIP_VAR* colvar;
173  SCIP_Real colval;
174  SCIP_Real l1dist;
175 
176  colval = SCIPcolGetPrimsol(cols[j]);
177  colvar = SCIPcolGetVar(cols[j]);
178  /* Get the number of active locks feature in the cut */
179  if( ! SCIPisInfinity(scip, SCIProwGetRhs(cuts[i])) && cutvals[j] > 0.0 )
180  cutlocks[i] += SCIPvarGetNLocksUp(colvar);
181  if( ! SCIPisInfinity(scip, -SCIProwGetLhs(cuts[i])) && cutvals[j] < 0.0 )
182  cutlocks[i] += SCIPvarGetNLocksUp(colvar);
183  if( ! SCIPisInfinity(scip, SCIProwGetRhs(cuts[i])) && cutvals[j] < 0.0 )
184  cutlocks[i] += SCIPvarGetNLocksDown(colvar);
185  if( ! SCIPisInfinity(scip, -SCIProwGetLhs(cuts[i])) && cutvals[j] > 0.0 )
186  cutlocks[i] += SCIPvarGetNLocksDown(colvar);
187 
188  /* Get the L1 distance from the projection onto the cut and the LP solution in the variable direction */
189  l1dist = ABS(colval - (cutalpha * cutvals[j]));
190  pscosts[i] += SCIPgetVarPseudocostScore(scip, colvar, colval) * l1dist;
191  }
192  cutlocks[i] = cutlocks[i] / ncutcols; /*lint !e414*/
193 
194  if( cutlocks[i] > maxlocks )
195  maxlocks = cutlocks[i];
196 
197  if( pscosts[i] > maxpscost )
198  maxpscost = pscosts[i];
199  }
200 
201  /* account for the case where maxlocks or maxpscost is 0 */
202  maxpscost = MAX(maxpscost, SCIPepsilon(scip)); /*lint !e666*/
203  maxlocks = MAX(maxlocks, 1);
204 
205  for ( int i = 0; i < ncuts; i++ )
206  {
207  cutlocks[i] = cutlocks[i] / maxlocks; /*lint !e414*/
208  /* if locks are penalized, we complement the corresponding score */
209  if( cutseldata->penaliselocks )
210  cutlocks[i] = 1 - cutlocks[i];
211  pscosts[i] = pscosts[i] / maxpscost; /*lint !e414*/
212  }
213 
214  /* Get the arrays / maximums of directed cutoff distance, efficacy, and expected improvement values. */
215  if ( sol != NULL && root )
216  {
217  for ( int i = 0; i < ncuts; i++ )
218  {
219  dcds[i] = SCIPgetCutLPSolCutoffDistance(scip, sol, cuts[i]);
220  maxdcd = MAX(maxdcd, dcds[i]);
221  }
222  }
223 
224  for ( int i = 0; i < ncuts; ++i )
225  {
226  effs[i] = SCIPgetCutEfficacy(scip, NULL, cuts[i]);
227  exps[i] = effs[i] * SCIPgetRowObjParallelism(scip, cuts[i]);
228  maxeff = MAX(maxeff, effs[i]);
229  maxexp = MAX(maxexp, exps[i]);
230  }
231 
232  /* Now score the cuts */
233  for ( int i = 0; i < ncuts; ++i )
234  {
235  SCIP_Real score;
236  SCIP_Real scaleddcd;
237  SCIP_Real scaledeff;
238  SCIP_Real scaledexp;
239  SCIP_Real objparallelism;
240  SCIP_Real intsupport;
242  SCIP_Real dynamism;
243  SCIP_Real mincutval;
244  SCIP_Real maxcutval;
245  SCIP_Real pscost;
246  SCIP_Real cutlock;
247 
248  /* Get the integer support */
249  intsupport = SCIPgetRowNumIntCols(scip, cuts[i]) / (SCIP_Real) SCIProwGetNNonz(cuts[i]);
250  intsupport *= cutseldata->intsupportweight;
251 
252  /* Get the objective parallelism and orthogonality */
253  if( ! cutseldata->penaliseobjparal )
254  objparallelism = cutseldata->objparalweight * SCIPgetRowObjParallelism(scip, cuts[i]);
255  else
256  objparallelism = cutseldata->objparalweight * (1 - SCIPgetRowObjParallelism(scip, cuts[i]));
257 
258  /* Get the density score */
259  density = (cutseldata->maxsparsitybonus / cutseldata->endsparsitybonus) * -1 * cutdensities[i];
260  density += cutseldata->maxsparsitybonus;
261  density = MAX(density, 0.0);
262 
263  /* Get the normalised pseudo-cost and number of locks score */
264  if( root )
265  pscost = 0.0;
266  else
267  pscost = cutseldata->pscostweight * pscosts[i];
268  cutlock = cutseldata->locksweight * cutlocks[i];
269 
270  /* Get the dynamism (good numerics) score */
271  maxcutval = SCIPgetRowMaxCoef(scip, cuts[i]);
272  mincutval = SCIPgetRowMinCoef(scip, cuts[i]);
273  mincutval = mincutval > 0.0 ? mincutval : 1.0;
274  dynamism = cutseldata->maxcoefratiobonus >= maxcutval / mincutval ? cutseldata->goodnumericsbonus : 0.0;
275 
276  /* Get the dcd / eff / exp score */
277  if ( sol != NULL && root )
278  {
279  if ( SCIPisSumLE(scip, dcds[i], 0.0))
280  scaleddcd = 0.0;
281  else
282  scaleddcd = cutseldata->dircutoffdistweight * SQR(LOG1P(dcds[i]) / LOG1P(maxdcd)); /*lint !e666*/
283  }
284  else
285  {
286  scaleddcd = 0.0;
287  }
288 
289  if ( SCIPisSumLE(scip, exps[i], 0.0))
290  scaledexp = 0.0;
291  else
292  scaledexp = cutseldata->expimprovweight * SQR(LOG1P(exps[i]) / LOG1P(maxexp)); /*lint !e666*/
293 
294  if ( SCIPisSumLE(scip, effs[i], 0.0))
295  {
296  scaledeff = 0.0;
297  }
298  else
299  {
300  if ( sol != NULL && root )
301  scaledeff = cutseldata->efficacyweight * SQR(LOG1P(effs[i]) / LOG1P(maxeff)); /*lint !e666*/
302  else
303  scaledeff = (cutseldata->efficacyweight + cutseldata->dircutoffdistweight) * SQR(LOG1P(effs[i]) / LOG1P(maxeff)); /*lint !e666*/
304  }
305 
306  /* Combine all scores and introduce some minor randomness */
307  score = scaledeff + scaleddcd + scaledexp + objparallelism + intsupport + density + dynamism + pscost + cutlock;
308 
309  score += SCIPrandomGetReal(cutseldata->randnumgen, 0.0, 1e-6);
310 
311  scores[i] = score;
312  }
313 
314  SCIPfreeBufferArray(scip, &effs);
315  SCIPfreeBufferArray(scip, &dcds);
316  SCIPfreeBufferArray(scip, &exps);
317  SCIPfreeBufferArray(scip, &cutdensities);
318  SCIPfreeBufferArray(scip, &cutlocks);
319  SCIPfreeBufferArray(scip, &pscosts);
320 
321  return SCIP_OKAY;
322 }
323 
324 
325 /** move the cut with the highest score to the first position in the array; there must be at least one cut */
326 static
328  SCIP_ROW** cuts, /**< array with cuts to perform selection algorithm */
329  SCIP_Real* scores, /**< array with scores of cuts to perform selection algorithm */
330  int ncuts /**< number of cuts in given array */
331  )
332 {
333  int bestpos;
334  SCIP_Real bestscore;
335 
336  assert(ncuts > 0);
337  assert(cuts != NULL);
338  assert(scores != NULL);
339 
340  bestscore = scores[0];
341  bestpos = 0;
342 
343  for( int i = 1; i < ncuts; ++i )
344  {
345  if( scores[i] > bestscore )
346  {
347  bestpos = i;
348  bestscore = scores[i];
349  }
350  }
351 
352  SCIPswapPointers((void**) &cuts[bestpos], (void**) &cuts[0]);
353  SCIPswapReals(&scores[bestpos], &scores[0]);
354 }
355 
356 /** filters the given array of cuts to enforce a maximum parallelism constraint
357  * w.r.t the given cut; moves filtered cuts to the end of the array and returns number of selected cuts */
358 static
360  SCIP_ROW* cut, /**< cut to filter orthogonality with */
361  SCIP_ROW** cuts, /**< array with cuts to perform selection algorithm */
362  SCIP_Real* scores, /**< array with scores of cuts to perform selection algorithm */
363  int ncuts, /**< number of cuts in given array */
364  SCIP_Real maxparallel /**< maximal parallelism for all cuts that are not good */
365  )
366 {
367  assert( cut != NULL );
368  assert( ncuts == 0 || cuts != NULL );
369  assert( ncuts == 0 || scores != NULL );
370 
371  for( int i = ncuts - 1; i >= 0; --i )
372  {
373  SCIP_Real thisparallel;
374 
375  thisparallel = SCIProwGetParallelism(cut, cuts[i], 'e');
376 
377  if( thisparallel > maxparallel )
378  {
379  --ncuts;
380  SCIPswapPointers((void**) &cuts[i], (void**) &cuts[ncuts]);
381  SCIPswapReals(&scores[i], &scores[ncuts]);
382  }
383  }
384 
385  return ncuts;
386 }
387 
388 /** penalises any cut too parallel to cut by reducing the parallel cut's score. */
389 static
391  SCIP* scip, /**< SCIP data structure */
392  SCIP_ROW* cut, /**< cut to filter orthogonality with */
393  SCIP_ROW** cuts, /**< array with cuts to perform selection algorithm */
394  SCIP_Real* scores, /**< array with scores of cuts to perform selection algorithm */
395  int ncuts, /**< number of cuts in given array */
396  SCIP_Real maxparallel, /**< maximal parallelism for all cuts that are not good */
397  SCIP_Real paralpenalty /**< penalty for weaker of two parallel cuts if penalising parallel cuts */
398  )
399 {
400  assert( cut != NULL );
401  assert( ncuts == 0 || cuts != NULL );
402  assert( ncuts == 0 || scores != NULL );
403 
404  for( int i = ncuts - 1; i >= 0; --i )
405  {
406  SCIP_Real thisparallel;
407 
408  thisparallel = SCIProwGetParallelism(cut, cuts[i], 'e');
409 
410  /* Filter cuts that are absolutely parallel still. Otherwise penalise if closely parallel */
411  if( thisparallel > 1 - SCIPsumepsilon(scip) )
412  {
413  --ncuts;
414  SCIPswapPointers((void**) &cuts[i], (void**) &cuts[ncuts]);
415  SCIPswapReals(&scores[i], &scores[ncuts]);
416  }
417  else if( thisparallel > maxparallel )
418  {
419  scores[i] -= paralpenalty;
420  }
421  }
422 
423  return ncuts;
424 }
425 
426 /** filters the given array of cuts to enforce a maximum density constraint,
427  * Moves filtered cuts to the end of the array and returns number of selected cuts */
428 static
430  SCIP* scip, /**< SCIP data structure */
431  SCIP_ROW** cuts, /**< array with cuts to perform selection algorithm */
432  SCIP_Real maxdensity, /**< maximum density s.t. a cut is not filtered */
433  int ncuts /**< number of cuts in given array */
434  )
435 {
436  SCIP_Real ncols;
437 
438  assert( ncuts == 0 || cuts != NULL );
439 
440  ncols = SCIPgetNLPCols(scip);
441 
442  for( int i = ncuts - 1; i >= 0; --i )
443  {
444  SCIP_Real nvals;
445 
446  nvals = SCIProwGetNNonz(cuts[i]);
447 
448  if( maxdensity < nvals / ncols )
449  {
450  --ncuts;
451  SCIPswapPointers((void**) &cuts[i], (void**) &cuts[ncuts]);
452  }
453  }
454 
455  return ncuts;
456 }
457 
458 
459 /*
460  * Callback methods of cut selector
461  */
462 
463 
464 /** copy method for cut selector plugin (called when SCIP copies plugins) */
465 static
466 SCIP_DECL_CUTSELCOPY(cutselCopyEnsemble)
467 { /*lint --e{715}*/
468  assert(scip != NULL);
469  assert(cutsel != NULL);
470  assert(strcmp(SCIPcutselGetName(cutsel), CUTSEL_NAME) == 0);
471 
472  /* call inclusion method of cut selector */
474 
475  return SCIP_OKAY;
476 }
477 
478 /** destructor of cut selector to free user data (called when SCIP is exiting) */
479 /**! [SnippetCutselFreeEnsemble] */
480 static
481 SCIP_DECL_CUTSELFREE(cutselFreeEnsemble)
482 { /*lint --e{715}*/
483  SCIP_CUTSELDATA* cutseldata;
484 
485  cutseldata = SCIPcutselGetData(cutsel);
486 
487  SCIPfreeBlockMemory(scip, &cutseldata);
488 
489  SCIPcutselSetData(cutsel, NULL);
490 
491  return SCIP_OKAY;
492 }
493 /**! [SnippetCutselFreeEnsemble] */
494 
495 /** initialization method of cut selector (called after problem was transformed) */
496 static
497 SCIP_DECL_CUTSELINIT(cutselInitEnsemble)
498 { /*lint --e{715}*/
499  SCIP_CUTSELDATA* cutseldata;
500 
501  cutseldata = SCIPcutselGetData(cutsel);
502  assert(cutseldata != NULL);
503 
504  SCIP_CALL( SCIPcreateRandom(scip, &(cutseldata)->randnumgen, RANDSEED, TRUE) );
505 
506  return SCIP_OKAY;
507 }
508 
509 /** deinitialization method of cut selector (called before transformed problem is freed) */
510 static
511 SCIP_DECL_CUTSELEXIT(cutselExitEnsemble)
512 { /*lint --e{715}*/
513  SCIP_CUTSELDATA* cutseldata;
514 
515  cutseldata = SCIPcutselGetData(cutsel);
516  assert(cutseldata != NULL);
517  assert(cutseldata->randnumgen != NULL);
518 
519  SCIPfreeRandom(scip, &cutseldata->randnumgen);
520 
521  return SCIP_OKAY;
522 }
523 
524 /** cut selection method of cut selector */
525 static
526 SCIP_DECL_CUTSELSELECT(cutselSelectEnsemble)
527 { /*lint --e{715}*/
528  SCIP_CUTSELDATA* cutseldata;
529 
530  assert(cutsel != NULL);
531  assert(result != NULL);
532 
533  cutseldata = SCIPcutselGetData(cutsel);
534  assert(cutseldata != NULL);
535 
536  if( ncuts > cutseldata->maxcuts || SCIPgetNVars(scip) > cutseldata->maxnumvars )
537  {
538  *result = SCIP_DIDNOTFIND;
539  return SCIP_OKAY;
540  }
541 
542  *result = SCIP_SUCCESS;
543 
544  SCIP_CALL( SCIPselectCutsEnsemble(scip, cuts, forcedcuts, cutseldata, root, ncuts, nforcedcuts,
545  maxnselectedcuts, nselectedcuts) );
546 
547  return SCIP_OKAY;
548 }
549 
550 
551 /*
552  * cut selector specific interface methods
553  */
554 
555 /** creates the ensemble cut selector and includes it in SCIP */
557  SCIP* scip /**< SCIP data structure */
558  )
559 {
560  SCIP_CUTSELDATA* cutseldata;
561  SCIP_CUTSEL* cutsel;
562 
563  /* create ensemble cut selector data */
564  SCIP_CALL( SCIPallocBlockMemory(scip, &cutseldata) );
565  BMSclearMemory(cutseldata);
566 
567  SCIP_CALL( SCIPincludeCutselBasic(scip, &cutsel, CUTSEL_NAME, CUTSEL_DESC, CUTSEL_PRIORITY, cutselSelectEnsemble,
568  cutseldata) );
569 
570  assert(cutsel != NULL);
571 
572  /* set non fundamental callbacks via setter functions */
573  SCIP_CALL( SCIPsetCutselCopy(scip, cutsel, cutselCopyEnsemble) );
574 
575  SCIP_CALL( SCIPsetCutselFree(scip, cutsel, cutselFreeEnsemble) );
576  SCIP_CALL( SCIPsetCutselInit(scip, cutsel, cutselInitEnsemble) );
577  SCIP_CALL( SCIPsetCutselExit(scip, cutsel, cutselExitEnsemble) );
578 
579  /* add ensemble cut selector parameters */
580  SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/efficacyweight", "weight of normed-efficacy in cut "
581  "score calculation", &cutseldata->efficacyweight, FALSE, DEFAULT_EFFICACYWEIGHT, 0.0, SCIP_INVALID/10.0, NULL,
582  NULL) );
583 
584  SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/dircutoffdistweight", "weight of normed-directed "
585  "cutoff distance in cut score calculation", &cutseldata->dircutoffdistweight, FALSE,
587 
588  SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/objparalweight", "weight of objective parallelism "
589  "in cut score calculation", &cutseldata->objparalweight, FALSE, DEFAULT_OBJPARALWEIGHT, 0.0, SCIP_INVALID/10.0,
590  NULL, NULL) );
591 
592  SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/intsupportweight", "weight of integral support in "
593  "cut score calculation", &cutseldata->intsupportweight, FALSE, DEFAULT_INTSUPPORTWEIGHT, 0.0,
594  SCIP_INVALID/10.0, NULL, NULL) );
595 
596  SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/expimprovweight", "weight of normed-expected obj "
597  "improvement in cut score calculation", &cutseldata->expimprovweight, FALSE, DEFAULT_EXPIMPROVWEIGHT, 0.0,
598  SCIP_INVALID/10.0, NULL, NULL) );
599 
600  SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/minscore", "minimum score s.t. a cut can be added",
601  &cutseldata->minscore, FALSE, DEFAULT_MINSCORE, -SCIP_INVALID/10.0, SCIP_INVALID/10.0, NULL, NULL) );
602 
603  SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/pscostweight", "weight of normed-pseudo-costs in "
604  "cut score calculation", &cutseldata->pscostweight, FALSE, DEFAULT_PSCOSTWEIGHT, 0.0, SCIP_INVALID/10.0, NULL,
605  NULL) );
606 
607  SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/locksweight", "weight of normed-num-locks in cut "
608  "score calculation", &cutseldata->locksweight, FALSE, DEFAULT_NLOCKSWEIGHT, 0.0, SCIP_INVALID/10.0, NULL,
609  NULL) );
610 
611  SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/maxsparsitybonus", "weight of maximum sparsity "
612  "reward in cut score calculation", &cutseldata->maxsparsitybonus, FALSE, DEFAULT_MAXSPARSITYBONUS, 0.0,
613  SCIP_INVALID/10.0, NULL, NULL) );
614 
615  SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/goodnumericsbonus", "weight of good numerics bonus "
616  "(ratio of coefficients) in cut score calculation", &cutseldata->goodnumericsbonus, FALSE,
618 
619  SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/endsparsitybonus", "max sparsity value for which a "
620  "bonus is applied in cut score calculation", &cutseldata->endsparsitybonus, FALSE, DEFAULT_SPARSITYENDBONUS,
621  0.0, SCIP_INVALID/10.0, NULL, NULL) );
622 
623  SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/maxparal", "threshold for when two cuts are "
624  "considered parallel to each other", &cutseldata->maxparal, FALSE, DEFAULT_MAXPARAL, 0.0, 1.0, NULL, NULL) );
625 
626  SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/paralpenalty", "penalty for weaker of two parallel "
627  "cuts if penalising parallel cuts", &cutseldata->paralpenalty, TRUE, DEFAULT_PARALPENALTY, 0.0,
628  SCIP_INVALID/10.0, NULL, NULL) );
629 
630  SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/maxcutdensity", "max allowed cut density if "
631  "filtering dense cuts", &cutseldata->maxcutdensity, TRUE, DEFAULT_MAXCUTDENSITY, 0.0, 1.0, NULL, NULL) );
632 
633  SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/maxnonzerorootround", "max non-zeros per round "
634  "applied cuts (root). multiple num LP cols.", &cutseldata->maxnonzerorootround, FALSE,
636 
637  SCIP_CALL( SCIPaddRealParam(scip, "cutselection/" CUTSEL_NAME "/maxnonzerotreeround", "max non-zeros per round "
638  "applied cuts (tree). multiple num LP cols.", &cutseldata->maxnonzerotreeround, FALSE,
640 
641  SCIP_CALL( SCIPaddBoolParam(scip, "cutselection/" CUTSEL_NAME "/filterparalcuts", "should cuts be filtered so no "
642  "two parallel cuts are added", &cutseldata->filterparalcuts, FALSE, DEFAULT_FILTERPARALCUTS, NULL, NULL) );
643 
644  SCIP_CALL( SCIPaddBoolParam(scip, "cutselection/" CUTSEL_NAME "/penaliseparalcuts", "should two parallel cuts be "
645  "penalised instead of outright filtered", &cutseldata->penaliseparalcuts, TRUE, DEFAULT_PENALISEPARALCUTS,
646  NULL, NULL) );
647 
648  SCIP_CALL( SCIPaddBoolParam(scip, "cutselection/" CUTSEL_NAME "/filterdensecuts", "should cuts over a given density "
649  "threshold be filtered", &cutseldata->filterdensecuts, TRUE, DEFAULT_FILTERDENSECUTS, NULL, NULL) );
650 
651  SCIP_CALL( SCIPaddBoolParam(scip, "cutselection/" CUTSEL_NAME "/penaliselocks", "should the number of locks be "
652  "penalised instead of rewarded", &cutseldata->penaliselocks, TRUE, DEFAULT_PENALISELOCKS, NULL, NULL) );
653 
654  SCIP_CALL( SCIPaddBoolParam(scip, "cutselection/" CUTSEL_NAME "/penaliseobjparal", "should objective parallelism "
655  "be penalised instead of rewarded", &cutseldata->penaliseobjparal, TRUE, DEFAULT_PENALISEOBJPARAL, NULL, NULL)
656  );
657 
658  SCIP_CALL( SCIPaddIntParam(scip, "cutselection/" CUTSEL_NAME "/maxcoefratiobonus", "max coefficient ratio for "
659  "which numeric bonus is applied.", &cutseldata->maxcoefratiobonus, TRUE, DEFAULT_MAXCOEFRATIOBONUS, 1, 1000000,
660  NULL, NULL) );
661 
662  SCIP_CALL( SCIPaddIntParam(scip, "cutselection/" CUTSEL_NAME "/maxcuts", "max number of cuts such that cut "
663  "selector is applied.", &cutseldata->maxcuts, TRUE, DEFAULT_MAXCUTS, 1, 1000000, NULL, NULL) );
664 
665  SCIP_CALL( SCIPaddIntParam(scip, "cutselection/" CUTSEL_NAME "/maxnumvars", "max number of variables such that cut "
666  "selector is applied.", &cutseldata->maxnumvars, TRUE, DEFAULT_MAXNUMVARS, 1, 1000000, NULL, NULL) );
667 
668  return SCIP_OKAY;
669 }
670 
671 /** perform a cut selection algorithm for the given array of cuts
672  *
673  * This is the selection method of the ensemble cut selector. It uses a weighted sum of normalised efficacy,
674  * normalised directed cutoff distance, normalised expected improvements, objective parallelism,
675  * integer support, sparsity, dynamism, pseudo-costs, and variable locks.
676  * In addition to the weighted sum score, there are optionally parallelism-based filtering and penalties,
677  * and density filtering.
678  * There are also additional budget constraints on the number of cuts that should be added.
679  * The input cuts array gets re-sorted such that the selected cuts come first and the remaining ones are the end.
680  */
682  SCIP* scip, /**< SCIP data structure */
683  SCIP_ROW** cuts, /**< array with cuts to perform selection algorithm */
684  SCIP_ROW** forcedcuts, /**< array with forced cuts */
685  SCIP_CUTSELDATA* cutseldata, /**< cut selector data */
686  SCIP_Bool root, /**< whether we are at the root node or not */
687  int ncuts, /**< number of cuts in cuts array */
688  int nforcedcuts, /**< number of forced cuts */
689  int maxselectedcuts, /**< maximal number of cuts from cuts array to select */
690  int* nselectedcuts /**< pointer to return number of selected cuts from cuts array */
691  )
692 {
693  SCIP_Real* scores;
694  SCIP_Real* origscoresptr;
695  SCIP_Real nonzerobudget;
696  SCIP_Real budgettaken = 0.0;
697  SCIP_Real ncols;
698 
699  assert(cuts != NULL && ncuts > 0);
700  assert(forcedcuts != NULL || nforcedcuts == 0);
701  assert(nselectedcuts != NULL);
702 
703  *nselectedcuts = 0;
704  ncols = SCIPgetNLPCols(scip);
705 
706  /* filter dense cuts */
707  if( cutseldata->filterdensecuts )
708  {
709  ncuts = filterWithDensity(scip, cuts, cutseldata->maxcutdensity, ncuts);
710  if( ncuts == 0 )
711  return SCIP_OKAY;
712  }
713 
714  /* Initialise the score array */
715  SCIP_CALL( SCIPallocBufferArray(scip, &scores, ncuts) );
716  origscoresptr = scores;
717 
718  /* compute scores of cuts */
719  SCIP_CALL( scoring(scip, cuts, cutseldata, scores, root, ncuts) );
720 
721  /* perform cut selection algorithm for the cuts */
722 
723  /* forced cuts are going to be selected so use them to filter cuts */
724  for( int i = 0; i < nforcedcuts && ncuts > 0; ++i )
725  {
726  if( cutseldata->filterparalcuts )
727  ncuts = filterWithParallelism(forcedcuts[i], cuts, scores, ncuts, cutseldata->maxparal);
728  else if( cutseldata->penaliseparalcuts )
729  ncuts = penaliseWithParallelism(scip, forcedcuts[i], cuts, scores, ncuts, cutseldata->maxparal, cutseldata->paralpenalty);
730  }
731 
732  /* Get the budget depending on if we are the root or not */
733  nonzerobudget = root ? cutseldata->maxnonzerorootround : cutseldata->maxnonzerotreeround;
734 
735  /* now greedily select the remaining cuts */
736  while( ncuts > 0 )
737  {
738  SCIP_ROW* selectedcut;
739 
740  selectBestCut(cuts, scores, ncuts);
741  selectedcut = cuts[0];
742 
743  /* if the best cut of the remaining cuts is considered bad, we discard it and all remaining cuts */
744  if( scores[0] < cutseldata->minscore )
745  break;
746 
747  ++(*nselectedcuts);
748 
749  /* if the maximal number of cuts was selected, we can stop here */
750  if( *nselectedcuts == maxselectedcuts )
751  break;
752 
753  /* increase the non-zero budget counter of added cuts */
754  budgettaken += SCIProwGetNNonz(cuts[0]) / ncols;
755 
756  /* move the pointers to the next position and filter the remaining cuts to enforce the maximum parallelism constraint */
757  ++cuts;
758  ++scores;
759  --ncuts;
760 
761  if( cutseldata->filterparalcuts && ncuts > 0)
762  ncuts = filterWithParallelism(selectedcut, cuts, scores, ncuts, cutseldata->maxparal);
763  else if( cutseldata->penaliseparalcuts && ncuts > 0 )
764  ncuts = penaliseWithParallelism(scip, selectedcut, cuts, scores, ncuts, cutseldata->maxparal, cutseldata->paralpenalty);
765 
766  /* Filter out all remaining cuts that would go over the non-zero budget threshold */
767  if( nonzerobudget - budgettaken < 1 && ncuts > 0 )
768  ncuts = filterWithDensity(scip, cuts, nonzerobudget - budgettaken, ncuts);
769  }
770 
771  SCIPfreeBufferArray(scip, &origscoresptr);
772 
773  return SCIP_OKAY;
774 }
SCIP_RETCODE SCIPsetCutselExit(SCIP *scip, SCIP_CUTSEL *cutsel, SCIP_DECL_CUTSELEXIT((*cutselexit)))
Definition: scip_cutsel.c:173
#define DEFAULT_FILTERDENSECUTS
void SCIPfreeRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen)
const char * SCIPcutselGetName(SCIP_CUTSEL *cutsel)
Definition: cutsel.c:159
#define NULL
Definition: def.h:267
#define DEFAULT_EFFICACYWEIGHT
#define CUTSEL_NAME
#define DEFAULT_MAXSPARSITYBONUS
SCIP_CUTSELDATA * SCIPcutselGetData(SCIP_CUTSEL *cutsel)
Definition: cutsel.c:419
#define DEFAULT_NLOCKSWEIGHT
struct SCIP_CutselData SCIP_CUTSELDATA
Definition: type_cutsel.h:53
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:17213
#define SQR(x)
Definition: def.h:214
#define DEFAULT_MAXPARAL
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition: misc.c:10396
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:17292
#define FALSE
Definition: def.h:94
#define TRUE
Definition: def.h:93
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
SCIP_RETCODE SCIPselectCutsEnsemble(SCIP *scip, SCIP_ROW **cuts, SCIP_ROW **forcedcuts, SCIP_CUTSELDATA *cutseldata, SCIP_Bool root, int ncuts, int nforcedcuts, int maxselectedcuts, int *nselectedcuts)
SCIP_Real SCIPgetCutLPSolCutoffDistance(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip_cut.c:72
void SCIPswapReals(SCIP_Real *value1, SCIP_Real *value2)
Definition: misc.c:10383
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define DEFAULT_PENALISELOCKS
void SCIPcutselSetData(SCIP_CUTSEL *cutsel, SCIP_CUTSELDATA *cutseldata)
Definition: cutsel.c:429
#define DEFAULT_MAXNONZEROROOTROUND
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:83
SCIP_Real SCIPgetRowFeasibility(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:2124
SCIP_Real SCIPepsilon(SCIP *scip)
#define DEFAULT_INTSUPPORTWEIGHT
SCIP_Real SCIPgetRowMaxCoef(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1922
SCIP_Real SCIPgetVarPseudocostScore(SCIP *scip, SCIP_VAR *var, SCIP_Real solval)
Definition: scip_var.c:9102
static SCIP_DECL_CUTSELCOPY(cutselCopyEnsemble)
#define DEFAULT_PARALPENALTY
#define DEFAULT_FILTERPARALCUTS
SCIP_Real SCIPcolGetPrimsol(SCIP_COL *col)
Definition: lp.c:16996
#define DEFAULT_PENALISEOBJPARAL
#define DEFAULT_OBJPARALWEIGHT
SCIP_Real SCIPgetRowMinCoef(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1904
static int filterWithDensity(SCIP *scip, SCIP_ROW **cuts, SCIP_Real maxdensity, int ncuts)
#define DEFAULT_MAXCUTDENSITY
SCIP_RETCODE SCIPsetCutselCopy(SCIP *scip, SCIP_CUTSEL *cutsel, SCIP_DECL_CUTSELCOPY((*cutselcopy)))
Definition: scip_cutsel.c:125
static SCIP_DECL_CUTSELSELECT(cutselSelectEnsemble)
#define CUTSEL_DESC
#define DEFAULT_EXPIMPROVWEIGHT
#define SCIP_CALL(x)
Definition: def.h:380
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:17302
#define DEFAULT_SPARSITYENDBONUS
ensemble cut selector
#define DEFAULT_PSCOSTWEIGHT
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:17238
static SCIP_RETCODE scoring(SCIP *scip, SCIP_ROW **cuts, SCIP_CUTSELDATA *cutseldata, SCIP_Real *scores, SCIP_Bool root, int ncuts)
SCIP_RETCODE SCIPcreateRandom(SCIP *scip, SCIP_RANDNUMGEN **randnumgen, unsigned int initialseed, SCIP_Bool useglobalseed)
SCIP_RETCODE SCIPsetCutselInit(SCIP *scip, SCIP_CUTSEL *cutsel, SCIP_DECL_CUTSELINIT((*cutselinit)))
Definition: scip_cutsel.c:157
static int penaliseWithParallelism(SCIP *scip, SCIP_ROW *cut, SCIP_ROW **cuts, SCIP_Real *scores, int ncuts, SCIP_Real maxparallel, SCIP_Real paralpenalty)
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
SCIP_Real SCIPgetRowObjParallelism(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:2190
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition: lp.c:17248
#define SCIP_Bool
Definition: def.h:91
public methods for cut selector plugins
SCIP_RETCODE SCIPincludeCutselEnsemble(SCIP *scip)
SCIP_Bool SCIPisSumLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPgetRowNumIntCols(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1886
#define DEFAULT_GOODNUMERICBONUS
int SCIPvarGetNLocksUp(SCIP_VAR *var)
Definition: var.c:3430
SCIP_Real SCIPgetCutEfficacy(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip_cut.c:94
public methods for cuts and aggregation rows
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
#define BMSclearMemory(ptr)
Definition: memory.h:129
static void selectBestCut(SCIP_ROW **cuts, SCIP_Real *scores, int ncuts)
SCIP_Real SCIPrandomGetReal(SCIP_RANDNUMGEN *randnumgen, SCIP_Real minrandval, SCIP_Real maxrandval)
Definition: misc.c:10130
public methods for the LP relaxation, rows and columns
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1992
#define DEFAULT_DIRCUTOFFDISTWEIGHT
static SCIP_DECL_CUTSELFREE(cutselFreeEnsemble)
static const SCIP_Real density
Definition: gastrans.c:145
SCIP_Real SCIProwGetParallelism(SCIP_ROW *row1, SCIP_ROW *row2, char orthofunc)
Definition: lp.c:7724
#define DEFAULT_MAXNUMVARS
#define MAX(x, y)
Definition: def.h:239
int SCIPvarGetNLocksDown(SCIP_VAR *var)
Definition: var.c:3417
SCIP_SOL * SCIPgetBestSol(SCIP *scip)
Definition: scip_sol.c:2169
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:17042
public methods for random numbers
#define RANDSEED
#define SCIP_Real
Definition: def.h:173
#define LOG1P(x)
Definition: def.h:222
#define SCIP_INVALID
Definition: def.h:193
#define DEFAULT_MAXCUTS
SCIP_RETCODE SCIPsetCutselFree(SCIP *scip, SCIP_CUTSEL *cutsel, SCIP_DECL_CUTSELFREE((*cutselfree)))
Definition: scip_cutsel.c:141
#define DEFAULT_PENALISEPARALCUTS
static int filterWithParallelism(SCIP_ROW *cut, SCIP_ROW **cuts, SCIP_Real *scores, int ncuts, SCIP_Real maxparallel)
#define DEFAULT_MAXNONZEROTREEROUND
#define DEFAULT_MINSCORE
#define CUTSEL_PRIORITY
int SCIPgetNLPCols(SCIP *scip)
Definition: scip_lp.c:527
SCIP_Real SCIPsumepsilon(SCIP *scip)
#define DEFAULT_MAXCOEFRATIOBONUS
static SCIP_DECL_CUTSELINIT(cutselInitEnsemble)
SCIP_Real SCIProwGetNorm(SCIP_ROW *row)
Definition: lp.c:17268
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:139
#define ABS(x)
Definition: def.h:235
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:57
static SCIP_DECL_CUTSELEXIT(cutselExitEnsemble)
SCIP_RETCODE SCIPincludeCutselBasic(SCIP *scip, SCIP_CUTSEL **cutsel, const char *name, const char *desc, int priority, SCIP_DECL_CUTSELSELECT((*cutselselect)), SCIP_CUTSELDATA *cutseldata)
Definition: scip_cutsel.c:92