Scippy

SCIP

Solving Constraint Integer Programs

sepa_aggregation.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-2022 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file sepa_aggregation.c
17  * @ingroup DEFPLUGINS_SEPA
18  * @brief flow cover and complemented mixed integer rounding cuts separator (Marchand's version)
19  * @author Leona Gottwald
20  * @author Kati Wolter
21  * @author Tobias Achterberg
22  *
23  * For an overview see:
24  *
25  * Marchand, H., & Wolsey, L. A. (2001).@n
26  * Aggregation and mixed integer rounding to solve MIPs.@n
27  * Operations research, 49(3), 363-371.
28  *
29  * Some remarks:
30  * - In general, continuous variables are less prefered than integer variables, since their cut
31  * coefficient is worse.
32  * - We seek for aggregations that project out continuous variables that are far away from their bound,
33  * since if it is at its bound then it doesn't contribute to the violation
34  * - These aggregations are also useful for the flowcover separation, so after building an aggregation
35  * we try to generate a MIR cut and a flowcover cut.
36  * - We only keep the best cut.
37  */
38 
39 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
40 
41 #include "blockmemshell/memory.h"
42 #include "scip/cuts.h"
43 #include "scip/pub_lp.h"
44 #include "scip/pub_message.h"
45 #include "scip/pub_misc.h"
46 #include "scip/pub_misc_sort.h"
47 #include "scip/pub_sepa.h"
48 #include "scip/pub_var.h"
49 #include "scip/scip_branch.h"
50 #include "scip/scip_cut.h"
51 #include "scip/scip_general.h"
52 #include "scip/scip_lp.h"
53 #include "scip/scip_mem.h"
54 #include "scip/scip_message.h"
55 #include "scip/scip_numerics.h"
56 #include "scip/scip_param.h"
57 #include "scip/scip_prob.h"
58 #include "scip/scip_sepa.h"
59 #include "scip/scip_sol.h"
60 #include "scip/scip_solvingstats.h"
61 #include "scip/scip_tree.h"
62 #include "scip/scip_var.h"
63 #include "scip/sepa_aggregation.h"
64 #include <string.h>
65 
66 
67 #define SEPA_NAME "aggregation"
68 #define SEPA_DESC "aggregation heuristic for complemented mixed integer rounding cuts and flowcover cuts"
69 #define SEPA_PRIORITY -3000
70 #define SEPA_FREQ 10
71 #define SEPA_MAXBOUNDDIST 1.0
72 #define SEPA_USESSUBSCIP FALSE /**< does the separator use a secondary SCIP instance? */
73 #define SEPA_DELAY FALSE /**< should separation method be delayed, if other separators found cuts? */
74 
75 #define DEFAULT_MAXROUNDS -1 /**< maximal number of cmir separation rounds per node (-1: unlimited) */
76 #define DEFAULT_MAXROUNDSROOT -1 /**< maximal number of cmir separation rounds in the root node (-1: unlimited) */
77 #define DEFAULT_MAXTRIES 200 /**< maximal number of rows to start aggregation with per separation round
78  * (-1: unlimited) */
79 #define DEFAULT_MAXTRIESROOT -1 /**< maximal number of rows to start aggregation with per round in the root node
80  * (-1: unlimited) */
81 #define DEFAULT_MAXFAILS 20 /**< maximal number of consecutive unsuccessful aggregation tries (-1: unlimited) */
82 #define DEFAULT_MAXFAILSROOT 100 /**< maximal number of consecutive unsuccessful aggregation tries in the root node
83  * (-1: unlimited) */
84 #define DEFAULT_MAXAGGRS 3 /**< maximal number of aggregations for each row per separation round */
85 #define DEFAULT_MAXAGGRSROOT 6 /**< maximal number of aggregations for each row per round in the root node */
86 #define DEFAULT_MAXSEPACUTS 100 /**< maximal number of cmir cuts separated per separation round */
87 #define DEFAULT_MAXSEPACUTSROOT 500 /**< maximal number of cmir cuts separated per separation round in root node */
88 #define DEFAULT_MAXSLACK 0.0 /**< maximal slack of rows to be used in aggregation */
89 #define DEFAULT_MAXSLACKROOT 0.1 /**< maximal slack of rows to be used in aggregation in the root node */
90 #define DEFAULT_DENSITYSCORE 1e-4 /**< weight of row density in the aggregation scoring of the rows */
91 #define DEFAULT_SLACKSCORE 1e-3 /**< weight of slack in the aggregation scoring of the rows */
92 #define DEFAULT_MAXAGGDENSITY 0.20 /**< maximal density of aggregated row */
93 #define DEFAULT_MAXROWDENSITY 0.05 /**< maximal density of row to be used in aggregation */
94 #define DEFAULT_DENSITYOFFSET 100 /**< additional number of variables allowed in row on top of density */
95 #define DEFAULT_MAXROWFAC 1e+4 /**< maximal row aggregation factor */
96 #define DEFAULT_MAXTESTDELTA -1 /**< maximal number of different deltas to try (-1: unlimited) */
97 #define DEFAULT_AGGRTOL 1e-2 /**< aggregation heuristic: we try to delete continuous variables from the current
98  * aggregation, whose distance to its tightest bound is >= L - DEFAULT_AGGRTOL,
99  * where L is the largest of the distances between a continuous variable's value
100  * and its tightest bound in the current aggregation */
101 #define DEFAULT_TRYNEGSCALING TRUE /**< should negative values also be tested in scaling? */
102 #define DEFAULT_FIXINTEGRALRHS TRUE /**< should an additional variable be complemented if f0 = 0? */
103 #define DEFAULT_DYNAMICCUTS TRUE /**< should generated cuts be removed from the LP if they are no longer tight? */
104 
105 #define BOUNDSWITCH 0.5
106 #define POSTPROCESS TRUE
107 #define USEVBDS TRUE
108 #define MINFRAC 0.05
109 #define MAXFRAC 0.999
110 #define MAKECONTINTEGRAL FALSE
111 #define IMPLINTSARECONT
114 /*
115  * Data structures
116  */
118 /** separator data */
119 struct SCIP_SepaData
120 {
121  SCIP_Real maxslack; /**< maximal slack of rows to be used in aggregation */
122  SCIP_Real maxslackroot; /**< maximal slack of rows to be used in aggregation in the root node */
123  SCIP_Real densityscore; /**< weight of row density in the aggregation scoring of the rows */
124  SCIP_Real slackscore; /**< weight of slack in the aggregation scoring of the rows */
125  SCIP_Real maxaggdensity; /**< maximal density of aggregated row */
126  SCIP_Real maxrowdensity; /**< maximal density of row to be used in aggregation */
127  SCIP_Real maxrowfac; /**< maximal row aggregation factor */
128  SCIP_Real aggrtol; /**< tolerance for bound distance used in aggregation heuristic */
129  int maxrounds; /**< maximal number of cmir separation rounds per node (-1: unlimited) */
130  int maxroundsroot; /**< maximal number of cmir separation rounds in the root node (-1: unlimited) */
131  int maxtries; /**< maximal number of rows to start aggregation with per separation round
132  * (-1: unlimited) */
133  int maxtriesroot; /**< maximal number of rows to start aggregation with per round in the root node
134  * (-1: unlimited) */
135  int maxfails; /**< maximal number of consecutive unsuccessful aggregation tries
136  * (-1: unlimited) */
137  int maxfailsroot; /**< maximal number of consecutive unsuccessful aggregation tries in the root
138  * node (-1: unlimited) */
139  int maxaggrs; /**< maximal number of aggregations for each row per separation round */
140  int maxaggrsroot; /**< maximal number of aggregations for each row per round in the root node */
141  int maxsepacuts; /**< maximal number of cmir cuts separated per separation round */
142  int maxsepacutsroot; /**< maximal number of cmir cuts separated per separation round in root node */
143  int densityoffset; /**< additional number of variables allowed in row on top of density */
144  int maxtestdelta; /**< maximal number of different deltas to try (-1: unlimited) */
145  SCIP_Bool trynegscaling; /**< should negative values also be tested in scaling? */
146  SCIP_Bool fixintegralrhs; /**< should an additional variable be complemented if f0 = 0? */
147  SCIP_Bool dynamiccuts; /**< should generated cuts be removed from the LP if they are no longer tight? */
148  SCIP_Bool sepflowcover; /**< whether flowcover cuts should be separated in the current call */
149  SCIP_Bool sepknapsackcover; /**< whether knapsack cover cuts should be separated in the current call */
150  SCIP_Bool sepcmir; /**< whether cMIR cuts should be separated in the current call */
151  SCIP_SEPA* cmir; /**< separator for adding cmir cuts */
152  SCIP_SEPA* flowcover; /**< separator for adding flowcover cuts */
153  SCIP_SEPA* knapsackcover; /**< separator for adding knapsack cover cuts */
154 };
155 
156 /** data used for aggregation of row */
157 typedef
158 struct AggregationData {
159  SCIP_Real* bounddist; /**< bound distance of continuous variables */
160  int* bounddistinds; /**< problem indices of the continUous variables corresponding to the bounddistance value */
161  int nbounddistvars; /**< number of continuous variables that are not at their bounds */
162  SCIP_ROW** aggrrows; /**< array of rows suitable for substitution of continuous variable */
163  SCIP_Real* aggrrowscoef; /**< coefficient of continuous variable in row that is suitable for substitution of that variable */
164  int aggrrowssize; /**< size of aggrrows array */
165  int naggrrows; /**< occupied positions in aggrrows array */
166  int* aggrrowsstart; /**< array with start positions of suitable rows for substitution for each
167  * continuous variable with non-zero bound distance */
168  int* ngoodaggrrows; /**< array with number of rows suitable for substitution that only contain
169  * one continuous variable that is not at it's bound */
170  int* nbadvarsinrow; /**< number of continuous variables that are not at their bounds for each row */
171  SCIP_AGGRROW* aggrrow; /**< store aggregation row here so that it can be reused */
173 
174 /*
175  * Local methods
176  */
178 /** adds given cut to LP if violated */
179 static
181  SCIP* scip, /**< SCIP data structure */
182  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
183  SCIP_SEPA* sepa, /**< separator */
184  SCIP_Bool makeintegral, /**< should cut be scaled to integral coefficients if possible? */
185  SCIP_Real* cutcoefs, /**< coefficients of active variables in cut */
186  int* cutinds, /**< problem indices of variables in cut */
187  int cutnnz, /**< number of non-zeros in cut */
188  SCIP_Real cutrhs, /**< right hand side of cut */
189  SCIP_Real cutefficacy, /**< efficacy of cut */
190  SCIP_Bool cutislocal, /**< is the cut only locally valid? */
191  SCIP_Bool cutremovable, /**< should the cut be removed from the LP due to aging or cleanup? */
192  int cutrank, /**< rank of the cut */
193  const char* cutclassname, /**< name of cut class to use for row names */
194  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
195  int* ncuts, /**< pointer to count the number of added cuts */
196  SCIP_ROW** thecut /**< pointer to return cut if it was added */
197  )
198 {
199  assert(scip != NULL);
200  assert(cutcoefs != NULL);
201  assert(cutoff != NULL);
202  assert(ncuts != NULL);
203 
204  *cutoff = FALSE;
205 
206  if( cutnnz > 0 && SCIPisEfficacious(scip, cutefficacy) )
207  {
208  SCIP_VAR** vars;
209  int i;
210  SCIP_ROW* cut;
211  char cutname[SCIP_MAXSTRLEN];
212  SCIP_Bool success;
213 
214  /* get active problem variables */
215  vars = SCIPgetVars(scip);
216 
217  /* create cut name */
218  (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "%s%" SCIP_LONGINT_FORMAT "_%d", cutclassname, SCIPgetNLPs(scip), *ncuts);
219 
220 tryagain:
221  SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &cut, sepa, cutname, -SCIPinfinity(scip), cutrhs, cutislocal, FALSE, cutremovable) );
222 
223  SCIP_CALL( SCIPcacheRowExtensions(scip, cut) );
224 
225  for( i = 0; i < cutnnz; ++i )
226  {
227  SCIP_CALL( SCIPaddVarToRow(scip, cut, vars[cutinds[i]], cutcoefs[i]) );
228  }
229 
230  /* set cut rank */
231  SCIProwChgRank(cut, cutrank);
232 
233  SCIPdebugMsg(scip, " -> found potential %s cut <%s>: rhs=%f, eff=%f\n", cutclassname, cutname, cutrhs, cutefficacy);
234  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, cut, NULL) ) );
235 
236  /* if requested, try to scale the cut to integral values but only if the scaling is small; otherwise keep the fractional cut */
237  if( makeintegral && SCIPgetRowNumIntCols(scip, cut) == SCIProwGetNNonz(cut) )
238  {
239  SCIP_CALL( SCIPmakeRowIntegral(scip, cut, -SCIPepsilon(scip), SCIPsumepsilon(scip),
240  1000LL, 1000.0, MAKECONTINTEGRAL, &success) );
241 
242  if( SCIPisInfinity(scip, SCIProwGetRhs(cut)) )
243  {
244  /* release the row */
245  SCIP_CALL( SCIPreleaseRow(scip, &cut) );
246 
247  /* the scaling destroyed the cut, so try to add it again, but this time do not scale it */
248  makeintegral = FALSE;
249  goto tryagain;
250  }
251  }
252  else
253  {
254  success = FALSE;
255  }
256 
257  if( success && !SCIPisCutEfficacious(scip, sol, cut) )
258  {
259  SCIPdebugMsg(scip, " -> %s cut <%s> no longer efficacious: rhs=%f, eff=%f\n", cutclassname, cutname, cutrhs, cutefficacy);
260  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, cut, NULL) ) );
261 
262  SCIP_CALL( SCIPreleaseRow(scip, &cut) );
263 
264  /* the cut is not efficacious anymore due to the scaling, so do not add it */
265  return SCIP_OKAY;
266  }
267 
268  SCIPdebugMsg(scip, " -> found %s cut <%s>: rhs=%f, eff=%f, rank=%d, min=%f, max=%f (range=%g)\n",
269  cutclassname, cutname, cutrhs, cutefficacy, SCIProwGetRank(cut),
270  SCIPgetRowMinCoef(scip, cut), SCIPgetRowMaxCoef(scip, cut),
271  SCIPgetRowMaxCoef(scip, cut)/SCIPgetRowMinCoef(scip, cut));
272  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, cut, NULL) ) );
273 
274  SCIP_CALL( SCIPflushRowExtensions(scip, cut) );
275 
276  if( SCIPisCutNew(scip, cut) )
277  {
278  (*ncuts)++;
279 
280  if( !cutislocal )
281  {
282  SCIP_CALL( SCIPaddPoolCut(scip, cut) );
283  }
284  else
285  {
286  SCIP_CALL( SCIPaddRow(scip, cut, FALSE, cutoff) );
287  }
288 
289  *thecut = cut;
290  }
291  else
292  {
293  /* release the row */
294  SCIP_CALL( SCIPreleaseRow(scip, &cut) );
295  }
296  }
297 
298  return SCIP_OKAY;
299 }
300 
301 /** setup data for aggregating rows */
302 static
304  SCIP* scip, /**< SCIP data structure */
305  SCIP_SOL* sol, /**< solution to separate, NULL for LP solution */
306  SCIP_Bool allowlocal, /**< should local cuts be allowed */
307  AGGREGATIONDATA* aggrdata /**< pointer to aggregation data to setup */
308  )
309 {
310  SCIP_VAR** vars;
311  int nvars;
312  int nbinvars;
313  int nintvars;
314  int ncontvars;
315  int firstcontvar;
316  int nimplvars;
317  SCIP_ROW** rows;
318  int nrows;
319  int i;
320 
321  SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, &nimplvars, &ncontvars) );
322  SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
323 
324  SCIP_CALL( SCIPallocBufferArray(scip, &aggrdata->bounddist, ncontvars + nimplvars) );
325  SCIP_CALL( SCIPallocBufferArray(scip, &aggrdata->bounddistinds, ncontvars + nimplvars) );
326  SCIP_CALL( SCIPallocBufferArray(scip, &aggrdata->ngoodaggrrows, ncontvars + nimplvars) );
327  SCIP_CALL( SCIPallocBufferArray(scip, &aggrdata->aggrrowsstart, ncontvars + nimplvars + 1) );
328  SCIP_CALL( SCIPallocBufferArray(scip, &aggrdata->nbadvarsinrow, nrows) );
329  SCIP_CALL( SCIPaggrRowCreate(scip, &aggrdata->aggrrow) );
330  assert( aggrdata->aggrrow != NULL );
331  BMSclearMemoryArray(aggrdata->nbadvarsinrow, nrows);
332 
333  aggrdata->nbounddistvars = 0;
334  aggrdata->aggrrows = NULL;
335  aggrdata->aggrrowscoef = NULL;
336  aggrdata->aggrrowssize = 0;
337  aggrdata->naggrrows = 0;
338 
339  firstcontvar = nvars - ncontvars;
340 
341  for( i = nbinvars + nintvars; i < nvars; ++i )
342  {
343  SCIP_Real bounddist;
344  SCIP_Real primsol;
345  SCIP_Real distlb;
346  SCIP_Real distub;
347  SCIP_Real bestlb;
348  SCIP_Real bestub;
349  SCIP_Real bestvlb;
350  SCIP_Real bestvub;
351  int bestvlbidx;
352  int bestvubidx;
353 
354  /* compute the bound distance of the variable */
355  if( allowlocal )
356  {
357  bestlb = SCIPvarGetLbLocal(vars[i]);
358  bestub = SCIPvarGetUbLocal(vars[i]);
359  }
360  else
361  {
362  bestlb = SCIPvarGetLbGlobal(vars[i]);
363  bestub = SCIPvarGetUbGlobal(vars[i]);
364  }
365 
366  SCIP_CALL( SCIPgetVarClosestVlb(scip, vars[i], sol, &bestvlb, &bestvlbidx) );
367  SCIP_CALL( SCIPgetVarClosestVub(scip, vars[i], sol, &bestvub, &bestvubidx) );
368  if( bestvlbidx >= 0 )
369  bestlb = MAX(bestlb, bestvlb);
370  if( bestvubidx >= 0 )
371  bestub = MIN(bestub, bestvub);
372 
373  primsol = SCIPgetSolVal(scip, sol, vars[i]);
374  distlb = primsol - bestlb;
375  distub = bestub - primsol;
376 
377  bounddist = MIN(distlb, distub);
378  bounddist = MAX(bounddist, 0.0);
379 
380  /* prefer continuous variables over implicit integers to be aggregated out */
381  if( i < firstcontvar )
382  bounddist *= 0.1;
383 
384  /* when variable is not at its bound, we want to project it out, so add it to the aggregation data */
385  if( !SCIPisZero(scip, bounddist) )
386  {
387  int k = aggrdata->nbounddistvars++;
388 
389  aggrdata->bounddist[k] = bounddist;
390  aggrdata->bounddistinds[k] = i;
391  aggrdata->aggrrowsstart[k] = aggrdata->naggrrows;
392 
393  /* the current variable is a bad variable (continuous, not at its bound): increase the number of bad variable
394  * count on each row this variables appears in; also each of these rows can be used to project the variable out
395  * so store them.
396  */
397  if( SCIPvarIsInLP(vars[i]) )
398  {
399  SCIP_COL* col = SCIPvarGetCol(vars[i]);
400  SCIP_ROW** colrows = SCIPcolGetRows(col);
401  SCIP_Real* colrowvals = SCIPcolGetVals(col);
402  int ncolnonzeros = SCIPcolGetNLPNonz(col);
403  int aggrrowsminsize = aggrdata->naggrrows + ncolnonzeros;
404 
405  if( aggrrowsminsize > aggrdata->aggrrowssize )
406  {
407  SCIP_CALL( SCIPreallocBufferArray(scip, &aggrdata->aggrrows, aggrrowsminsize) );
408  SCIP_CALL( SCIPreallocBufferArray(scip, &aggrdata->aggrrowscoef, aggrrowsminsize) );
409  aggrdata->aggrrowssize = aggrrowsminsize;
410  }
411  assert(aggrdata->aggrrows != NULL || aggrdata->aggrrowssize == 0);
412  assert(aggrdata->aggrrowscoef != NULL || aggrdata->aggrrowssize == 0);
413  assert(aggrdata->aggrrowssize > 0 || ncolnonzeros == 0);
414 
415  for( k = 0; k < ncolnonzeros; ++k )
416  {
417  /* ignore modifiable rows and local rows if those are not permitted */
418  if( SCIProwIsModifiable(colrows[k]) || (!allowlocal && SCIProwIsLocal(colrows[k])) )
419  continue;
420 
421  ++aggrdata->nbadvarsinrow[SCIProwGetLPPos(colrows[k])];
422  assert(aggrdata->aggrrows != NULL); /* for lint */
423  assert(aggrdata->aggrrowscoef != NULL);
424  /* coverity[var_deref_op] */
425  aggrdata->aggrrows[aggrdata->naggrrows] = colrows[k];
426  aggrdata->aggrrowscoef[aggrdata->naggrrows] = colrowvals[k];
427  ++aggrdata->naggrrows;
428  }
429  }
430  }
431  }
432 
433  /* add sentinel entry at the end */
434  aggrdata->aggrrowsstart[aggrdata->nbounddistvars] = aggrdata->naggrrows;
435 
436  /* for each continous variable that is not at its bounds check if there is a
437  * row where it is the only such variable ("good" rows). In the array with the rows that are
438  * suitable for substituting this variable move the good rows to the beginning
439  * and store the number of good rows for each of the variables.
440  * If a variable has at least one good row, then it is a "better" variable and we make
441  * the value of the bounddistance for this variable negative, to mark it.
442  * Note that better variables are continous variables that are not at their bounds
443  * and can be projected out without introducing bad variables (by using a good row).
444  */
445  {
446  int beg;
447 
448  beg = aggrdata->aggrrowsstart[0];
449  for( i = 0; i < aggrdata->nbounddistvars; ++i )
450  {
451  int k;
452  int ngoodrows;
453  int end;
454 
455  end = aggrdata->aggrrowsstart[i + 1];
456  ngoodrows = 0;
457  for( k = beg; k < end; ++k )
458  {
459  /* coverity[var_deref_op] */
460  int lppos = SCIProwGetLPPos(aggrdata->aggrrows[k]);
461 
462  if( aggrdata->nbadvarsinrow[lppos] == 1 &&
463  SCIPisEQ(scip, SCIProwGetLhs(aggrdata->aggrrows[k]), SCIProwGetRhs(aggrdata->aggrrows[k])) )
464  {
465  int nextgoodrowpos = beg + ngoodrows;
466  if( k > nextgoodrowpos )
467  {
468  SCIPswapPointers((void**) (&aggrdata->aggrrows[k]), (void**) (&aggrdata->aggrrows[nextgoodrowpos]));
469  SCIPswapReals(&aggrdata->aggrrowscoef[k], &aggrdata->aggrrowscoef[nextgoodrowpos]);
470  }
471  ++ngoodrows;
472  }
473  }
474  if( ngoodrows > 0 )
475  {
476  aggrdata->bounddist[i] = -aggrdata->bounddist[i];
477  }
478  aggrdata->ngoodaggrrows[i] = ngoodrows;
479  beg = end;
480  }
481  }
482 
483  return SCIP_OKAY;
484 }
485 
486 /** free resources held in aggregation data */
487 static
489  SCIP* scip, /**< SCIP datastructure */
490  AGGREGATIONDATA* aggrdata /**< pointer to ggregation data */
491  )
492 {
493  SCIPaggrRowFree(scip, &aggrdata->aggrrow);
495  SCIPfreeBufferArrayNull(scip, &aggrdata->aggrrows);
496  SCIPfreeBufferArray(scip, &aggrdata->nbadvarsinrow);
497  SCIPfreeBufferArray(scip, &aggrdata->aggrrowsstart);
498  SCIPfreeBufferArray(scip, &aggrdata->ngoodaggrrows);
499  SCIPfreeBufferArray(scip, &aggrdata->bounddistinds);
500  SCIPfreeBufferArray(scip, &aggrdata->bounddist);
501 }
502 
503 /** retrieves the candidate rows for canceling out the given variable, also returns the number of "good" rows which are the
504  * rows stored at the first ngoodrows positions. A row is good if its continuous variables are all at their bounds, except
505  * maybe the given continuous variable (in probvaridx)
506  */
507 static
509  AGGREGATIONDATA* aggrdata, /**< pointer to ggregation data */
510  int probvaridx, /**< problem index of variables to retrieve candidates for */
511  SCIP_ROW*** rows, /**< pointer to store array to candidate rows */
512  SCIP_Real** rowvarcoefs, /**< pointer to store array of coefficients of given variable in the corresponding rows */
513  int* nrows, /**< pointer to return number of rows in returned arrays */
514  int* ngoodrows /**< pointer to return number of "good" rows in the returned arrays */
515  )
516 {
517  int aggrdataidx;
518 
519  if( !SCIPsortedvecFindInt(aggrdata->bounddistinds, probvaridx, aggrdata->nbounddistvars, &aggrdataidx) )
520  return FALSE;
521 
522  *rows = aggrdata->aggrrows + aggrdata->aggrrowsstart[aggrdataidx];
523  *nrows = aggrdata->aggrrowsstart[aggrdataidx + 1] - aggrdata->aggrrowsstart[aggrdataidx];
524  *rowvarcoefs = aggrdata->aggrrowscoef + aggrdata->aggrrowsstart[aggrdataidx];
525  *ngoodrows = aggrdata->ngoodaggrrows[aggrdataidx];
526 
527  return TRUE;
528 }
529 
530 /** find the bound distance value in the aggregation data struct for the given variable problem index */
531 static
533  AGGREGATIONDATA* aggrdata, /**< SCIP datastructure */
534  int probvaridx /**< problem index of variables to retrieve candidates for */
535  )
536 {
537  int aggrdataidx;
539  if( !SCIPsortedvecFindInt(aggrdata->bounddistinds, probvaridx, aggrdata->nbounddistvars, &aggrdataidx) )
540  return 0.0;
541 
542  return aggrdata->bounddist[aggrdataidx];
543 }
544 
545 /** Aggregates the next row suitable for cancelling out an active continuous variable.
546  *
547  * Equality rows that contain no other active continuous variables are preffered and apart from that
548  * the scores for the rows are used to determine which row is aggregated next
549  */
550 static
552  SCIP* scip, /**< SCIP data structure */
553  SCIP_SEPADATA* sepadata, /**< separator data */
554  SCIP_Real* rowlhsscores, /**< aggregation scores for left hand sides of row */
555  SCIP_Real* rowrhsscores, /**< aggregation scores for right hand sides of row */
556  AGGREGATIONDATA* aggrdata, /**< aggregation data */
557  SCIP_AGGRROW* aggrrow, /**< current aggregation row */
558  int* naggrs, /**< pointer to increase counter if real aggregation took place */
559  SCIP_Bool* success /**< pointer to return whether another row was added to the aggregation row */
560  )
561 {
562  int i;
563  int firstcontvar;
564  int* badvarinds;
565  SCIP_Real* badvarbddist;
566  int nbadvars;
567  SCIP_Real minbddist;
568  SCIP_ROW* bestrow;
569  SCIP_Real bestrowscore;
570  SCIP_Real aggrfac;
571  int bestrowside;
572  int ncontvars;
573  int nnz = SCIPaggrRowGetNNz(aggrrow);
574  int* inds = SCIPaggrRowGetInds(aggrrow);
575 
576  assert( success != NULL );
577  *success = FALSE;
578 
579  firstcontvar = SCIPgetNBinVars(scip) + SCIPgetNIntVars(scip);
580  ncontvars = SCIPgetNImplVars(scip) + SCIPgetNContVars(scip);
581  assert( firstcontvar + ncontvars == SCIPgetNVars(scip) );
582 
583  SCIP_CALL( SCIPallocBufferArray(scip, &badvarinds, MIN(ncontvars, nnz)) );
584  SCIP_CALL( SCIPallocBufferArray(scip, &badvarbddist, MIN(ncontvars, nnz)) );
585 
586  nbadvars = 0;
587 
588  for( i = 0; i < nnz; ++i )
589  {
590  SCIP_Real bounddist;
591 
592  /* only consider continuous variables */
593  if( inds[i] < firstcontvar )
594  continue;
595 
596  bounddist = aggrdataGetBoundDist(aggrdata, inds[i]);
597 
598  if( bounddist == 0.0 )
599  continue;
600 
601  badvarinds[nbadvars] = inds[i];
602  badvarbddist[nbadvars] = bounddist;
603  ++nbadvars;
604  }
605 
606  if( nbadvars == 0 )
607  goto TERMINATE;
608 
609  SCIPsortDownRealInt(badvarbddist, badvarinds, nbadvars);
610 
611  aggrfac = 0.0;
612  bestrowscore = 0.0;
613  bestrowside = 0;
614  minbddist = 0.0;
615  bestrow = NULL;
616 
617  /* because the "good" bad variables have a negative bound distance, they are at the end */
618  for( i = nbadvars - 1; i >= 0; --i )
619  {
620  int probvaridx;
621  SCIP_ROW** candrows;
622  SCIP_Real* candrowcoefs;
623  int nrows;
624  int ngoodrows;
625  int k;
626 
627  /* if the bound distance is not negative, there are no more good variables so stop */
628  if( badvarbddist[i] > 0.0 )
629  break;
630 
631  /* if no best row was found yet, this variable has the currently best bound distance */
632  if( aggrfac == 0.0 )
633  minbddist = -badvarbddist[i] * (1.0 - sepadata->aggrtol);
634 
635  /* if the bound distance of the current variable is smaller than the minimum bound distance stop looping */
636  if( -badvarbddist[i] < minbddist )
637  break;
638 
639  probvaridx = badvarinds[i];
640 
641  if( !getRowAggregationCandidates(aggrdata, probvaridx, &candrows, &candrowcoefs, &nrows, &ngoodrows) )
642  return SCIP_ERROR;
643 
644  assert(ngoodrows > 0); /* bounddistance was negative for this variable, so it should have good rows */
645  assert(ngoodrows <= nrows);
646 
647  for( k = 0; k < ngoodrows; ++k )
648  {
649  SCIP_Real rowaggrfac;
650  SCIP_Real rowscore;
651  int lppos;
652 
653  /* do not add rows twice */
654  if( SCIPaggrRowHasRowBeenAdded(aggrrow, candrows[k]) )
655  continue;
656 
657  rowaggrfac = - SCIPaggrRowGetProbvarValue(aggrrow, probvaridx) / candrowcoefs[k];
658 
659  /* if factor is too extreme skip this row */
660  if( SCIPisFeasZero(scip, rowaggrfac) || REALABS(rowaggrfac) > sepadata->maxrowfac )
661  continue;
662 
663  lppos = SCIProwGetLPPos(candrows[k]);
664 
665  /* row could be used and good rows are equalities, so ignore sidetype */
666  rowscore = MAX(rowlhsscores[lppos], rowrhsscores[lppos]);
667 
668  /* if this rows score is better than the currently best score, remember it */
669  if( aggrfac == 0.0 || rowscore > bestrowscore )
670  {
671  bestrow = candrows[k];
672  aggrfac = rowaggrfac;
673  bestrowscore = rowscore;
674  bestrowside = 0;
675  }
676  }
677  }
678 
679  /* found a row among the good rows, so aggregate it and stop */
680  if( aggrfac != 0.0 )
681  {
682  ++(*naggrs);
683  SCIP_CALL( SCIPaggrRowAddRow(scip, aggrrow, bestrow, aggrfac, bestrowside) );
684  SCIPaggrRowRemoveZeros(scip, aggrrow, FALSE, success);
685  goto TERMINATE;
686  }
687 
688  for( i = 0; i < nbadvars; ++i )
689  {
690  int probvaridx;
691  SCIP_ROW** candrows;
692  SCIP_Real* candrowcoefs;
693  int nrows;
694  int ngoodrows;
695  int k;
696 
697  /* if the bound distance is negative, there are no more variables to be tested, so stop */
698  if( badvarbddist[i] < 0.0 )
699  break;
700 
701  /* if no best row was found yet, this variable has the currently best bound distance */
702  if( aggrfac == 0.0 )
703  minbddist = badvarbddist[i] * (1.0 - sepadata->aggrtol);
704 
705  /* if the bound distance of the current variable is smaller than the minimum bound distance stop looping */
706  if( badvarbddist[i] < minbddist )
707  break;
708 
709  probvaridx = badvarinds[i];
710 
711  if( !getRowAggregationCandidates(aggrdata, probvaridx, &candrows, &candrowcoefs, &nrows, &ngoodrows) )
712  return SCIP_ERROR;
713 
714  /* bounddistance was positive for this variable, so it should not have good rows */
715  assert(ngoodrows == 0);
716 
717  for( k = 0; k < nrows; ++k )
718  {
719  SCIP_Real rowaggrfac;
720  SCIP_Real rowscore;
721  int rowside;
722  int lppos;
723 
724  /* do not add rows twice */
725  if( SCIPaggrRowHasRowBeenAdded(aggrrow, candrows[k]) )
726  continue;
727 
728  rowaggrfac = - SCIPaggrRowGetProbvarValue(aggrrow, probvaridx) / candrowcoefs[k];
729 
730  /* if factor is too extreme skip this row */
731  if( SCIPisFeasZero(scip, rowaggrfac) || REALABS(rowaggrfac) > sepadata->maxrowfac )
732  continue;
733 
734  /* row could be used, decide which side */
735  lppos = SCIProwGetLPPos(candrows[k]);
736 
737  /* either both or none of the rowscores are 0.0 so use the one which gives a positive slack */
738  if( (rowaggrfac < 0.0 && !SCIPisInfinity(scip, -SCIProwGetLhs(candrows[k]))) || SCIPisInfinity(scip, SCIProwGetRhs(candrows[k])) )
739  {
740  rowscore = rowlhsscores[lppos];
741  rowside = -1;
742  }
743  else
744  {
745  rowscore = rowrhsscores[lppos];
746  rowside = 1;
747  }
748 
749  /* if this rows score is better than the currently best score, remember it */
750  if( aggrfac == 0.0 || SCIPisGT(scip, rowscore, bestrowscore) ||
751  (SCIPisEQ(scip, rowscore, bestrowscore) && aggrdata->nbadvarsinrow[lppos] < aggrdata->nbadvarsinrow[SCIProwGetLPPos(bestrow)]) )
752  {
753  bestrow = candrows[k];
754  aggrfac = rowaggrfac;
755  bestrowscore = rowscore;
756  bestrowside = rowside;
757  }
758  }
759  }
760 
761  /* found a row so aggregate it */
762  if( aggrfac != 0.0 )
763  {
764  ++(*naggrs);
765  SCIP_CALL( SCIPaggrRowAddRow(scip, aggrrow, bestrow, aggrfac, bestrowside) );
766  SCIPaggrRowRemoveZeros(scip, aggrrow, FALSE, success);
767  }
768 
769 TERMINATE:
770  SCIPfreeBufferArray(scip, &badvarbddist);
771  SCIPfreeBufferArray(scip, &badvarinds);
772 
773  return SCIP_OKAY;
774 }
775 
776 /** aggregates different single mixed integer constraints by taking linear combinations of the rows of the LP */
777 static
779  SCIP* scip, /**< SCIP data structure */
780  AGGREGATIONDATA* aggrdata, /**< pointer to aggregation data */
781  SCIP_SEPA* sepa, /**< separator */
782  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
783  SCIP_Bool allowlocal, /**< should local cuts be allowed */
784  SCIP_Real* rowlhsscores, /**< aggregation scores for left hand sides of row */
785  SCIP_Real* rowrhsscores, /**< aggregation scores for right hand sides of row */
786  int startrow, /**< index of row to start aggregation; -1 for using the objective cutoff constraint */
787  int maxaggrs, /**< maximal number of aggregations */
788  SCIP_Bool* wastried, /**< pointer to store whether the given startrow was actually tried */
789  SCIP_Bool* cutoff, /**< whether a cutoff has been detected */
790  int* cutinds, /**< buffer array to store temporarily cut */
791  SCIP_Real* cutcoefs, /**< buffer array to store temporarily cut */
792  SCIP_Bool negate, /**< should the start row be multiplied by -1 */
793  int* ncuts /**< pointer to count the number of generated cuts */
794  )
795 {
796  SCIP_SEPADATA* sepadata;
797  SCIP_ROW** rows;
798 
799  SCIP_Real startweight;
800  SCIP_Real startrowact;
801  int maxaggrnonzs;
802  int naggrs;
803  int nrows;
804  int maxtestdelta;
805 
806  assert(scip != NULL);
807  assert(aggrdata != NULL);
808  assert(aggrdata->aggrrow != NULL);
809  assert(sepa != NULL);
810  assert(rowlhsscores != NULL);
811  assert(rowrhsscores != NULL);
812  assert(wastried != NULL);
813  assert(cutoff != NULL);
814  assert(ncuts != NULL);
815 
816  sepadata = SCIPsepaGetData(sepa);
817  assert(sepadata != NULL);
818 
819  *cutoff = FALSE;
820  *wastried = FALSE;
821 
822  SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
823  assert(nrows == 0 || rows != NULL);
824 
825  maxtestdelta = sepadata->maxtestdelta == -1 ? INT_MAX : sepadata->maxtestdelta;
826 
827  /* calculate maximal number of non-zeros in aggregated row */
828  maxaggrnonzs = (int)(sepadata->maxaggdensity * SCIPgetNLPCols(scip)) + sepadata->densityoffset;
829 
830  /* add start row to the initially empty aggregation row (aggrrow) */
831  if( startrow < 0 )
832  {
833  SCIP_Real rhs;
834 
835  /* if the objective is integral we round the right hand side of the cutoff constraint.
836  * Therefore the constraint may not be valid for the problem but it is valid for the set
837  * of all improving solutions. We refrain from adding an epsilon cutoff for the case
838  * of a non-integral objective function to avoid cutting of any improving solution even
839  * if the improvement is below some epsilon value.
840  */
841  if( SCIPisObjIntegral(scip) )
842  rhs = floor(SCIPgetUpperbound(scip) - 0.5);
843  else
844  rhs = SCIPgetUpperbound(scip);
845 
846  SCIP_CALL( SCIPaggrRowAddObjectiveFunction(scip, aggrdata->aggrrow, rhs, 1.0) );
847 
848  if( SCIPaggrRowGetNNz(aggrdata->aggrrow) == 0 )
849  {
850  SCIPaggrRowClear(aggrdata->aggrrow);
851  return SCIP_OKAY;
852  }
853  }
854  else
855  {
856  assert(0 <= startrow && startrow < nrows);
857 
858  SCIPdebugMsg(scip, "start c-MIR aggregation with row <%s> (%d/%d)\n", SCIProwGetName(rows[startrow]), startrow, nrows);
859 
860  startrowact = SCIPgetRowSolActivity(scip, rows[startrow], sol);
861 
862  if( startrowact <= 0.5 * SCIProwGetLhs(rows[startrow]) + 0.5 * SCIProwGetRhs(rows[startrow]) )
863  startweight = -1.0;
864  else
865  startweight = 1.0;
866 
867  SCIP_CALL( SCIPaggrRowAddRow(scip, aggrdata->aggrrow, rows[startrow], negate ? -startweight : startweight, 0) ); /*lint !e644*/
868  }
869 
870  /* try to generate cut from the current aggregated row; add cut if found, otherwise add another row to aggrrow
871  * in order to get rid of a continuous variable
872  */
873  naggrs = 0;
874  while( naggrs <= maxaggrs )
875  {
876  int cutrank = 0;
877  int cutnnz = 0;
878  SCIP_Bool aggrsuccess;
879  SCIP_Bool cmirsuccess;
880  SCIP_Bool cmircutislocal = FALSE;
881  SCIP_Bool flowcoversuccess;
882  SCIP_Real flowcoverefficacy;
883  SCIP_Bool flowcovercutislocal = FALSE;
884  SCIP_Bool knapsackcoversuccess;
885  SCIP_Real knapsackcoverefficacy;
886  SCIP_Bool knapsackcovercutislocal = FALSE;
887  SCIP_ROW* cut = NULL;
888  SCIP_Real cutrhs = SCIP_INVALID;
889  SCIP_Real cutefficacy;
890 
891  *wastried = TRUE;
892 
893  /* Step 1:
894  * try to generate a MIR cut out of the current aggregated row
895  */
896 
897  flowcoverefficacy = -SCIPinfinity(scip);
898 
899  if( sepadata->sepflowcover )
900  {
901  SCIP_CALL( SCIPcalcFlowCover(scip, sol, POSTPROCESS, BOUNDSWITCH, allowlocal, aggrdata->aggrrow, /*lint !e644*/
902  cutcoefs, &cutrhs, cutinds, &cutnnz, &flowcoverefficacy, &cutrank, &flowcovercutislocal, &flowcoversuccess) );
903  }
904  else
905  {
906  flowcoversuccess = FALSE;
907  }
908 
909  /* initialize the knapsack cover cut efficacy variable with the flowcover efficacy so that
910  * only knapsack cover cuts better than that efficacy are returned.
911  */
912  knapsackcoverefficacy = flowcoverefficacy;
913 
914  if( sepadata->sepknapsackcover )
915  {
916  SCIP_CALL( SCIPcalcKnapsackCover(scip, sol, allowlocal, aggrdata->aggrrow, /*lint !e644*/
917  cutcoefs, &cutrhs, cutinds, &cutnnz, &knapsackcoverefficacy, &cutrank, &knapsackcovercutislocal, &knapsackcoversuccess) );
918  }
919  else
920  {
921  knapsackcoversuccess = FALSE;
922  }
923 
924  /* initialize the cutefficacy variable with the knapsackcoverefficacy, so that only CMIR cuts
925  * that have a higher efficacy than that of a flowcover or knapsack cover cut possibly
926  * found in the call above are returned since the previous cut is overwritten in that case.
927  */
928  cutefficacy = knapsackcoverefficacy;
929 
930  if( sepadata->sepcmir )
931  {
932  SCIP_CALL( SCIPcutGenerationHeuristicCMIR(scip, sol, POSTPROCESS, BOUNDSWITCH, USEVBDS, allowlocal, maxtestdelta, NULL, NULL, MINFRAC, MAXFRAC,
933  aggrdata->aggrrow, cutcoefs, &cutrhs, cutinds, &cutnnz, &cutefficacy, &cutrank, &cmircutislocal, &cmirsuccess) );
934  }
935  else
936  {
937  cmirsuccess = FALSE;
938  }
939 
940  if( cmirsuccess )
941  {
942  /* cppcheck-suppress uninitvar */
943  SCIP_CALL( addCut(scip, sol, sepadata->cmir, FALSE, cutcoefs, cutinds, cutnnz, cutrhs, cutefficacy,
944  cmircutislocal, sepadata->dynamiccuts, cutrank, startrow < 0 ? "objcmir" : "cmir", cutoff, ncuts, &cut) ); /*lint !e644*/
945  }
946  else if ( knapsackcoversuccess )
947  {
948  /* cppcheck-suppress uninitvar */
949  SCIP_CALL( addCut(scip, sol, sepadata->knapsackcover, FALSE, cutcoefs, cutinds, cutnnz, cutrhs, cutefficacy,
950  knapsackcovercutislocal, sepadata->dynamiccuts, cutrank, startrow < 0 ? "objlci" : "lci", cutoff, ncuts, &cut) ); /*lint !e644*/
951  }
952  else if ( flowcoversuccess )
953  {
954  /* cppcheck-suppress uninitvar */
955  SCIP_CALL( addCut(scip, sol, sepadata->flowcover, FALSE, cutcoefs, cutinds, cutnnz, cutrhs, cutefficacy,
956  flowcovercutislocal, sepadata->dynamiccuts, cutrank, startrow < 0 ? "objflowcover" : "flowcover", cutoff, ncuts, &cut) ); /*lint !e644*/
957  }
958 
959  if ( *cutoff )
960  {
961  if( cut != NULL )
962  {
963  SCIP_CALL( SCIPreleaseRow(scip, &cut) );
964  }
965  break;
966  }
967 
968  /* if the cut was successfully added, decrease the score of the rows used in the aggregation and clean the aggregation
969  * row (and call this function again with a different start row for aggregation)
970  */
971  if( cut != NULL )
972  {
973  int* rowinds;
974  int i;
975 
976  rowinds = SCIPaggrRowGetRowInds(aggrdata->aggrrow);
977  nrows = SCIPaggrRowGetNRows(aggrdata->aggrrow);
978 
979  /* decrease row score of used rows slightly */
980  for( i = 0; i < nrows; ++i )
981  {
982  SCIP_Real fac = 1.0 - 0.999 * SCIProwGetParallelism(rows[rowinds[i]], cut, 'e');
983 
984  rowlhsscores[rowinds[i]] *= fac;
985  rowrhsscores[rowinds[i]] *= fac;
986  }
987 
988  SCIP_CALL( SCIPreleaseRow(scip, &cut) );
989 
990  SCIPdebugMsg(scip, " -> abort aggregation: cut found\n");
991  break;
992  }
993 
994  /* Step 2:
995  * aggregate an additional row in order to remove a continuous variable
996  */
997 
998  /* abort, if we reached the maximal number of aggregations */
999  if( naggrs == maxaggrs )
1000  {
1001  SCIPdebugMsg(scip, " -> abort aggregation: maximal number of aggregations reached\n");
1002  break;
1003  }
1004 
1005  SCIP_CALL( aggregateNextRow(scip, sepadata, rowlhsscores, rowrhsscores, aggrdata, aggrdata->aggrrow,
1006  &naggrs, &aggrsuccess) );
1007 
1008  /* no suitable aggregation was found or number of non-zeros is now too large so abort */
1009  if( ! aggrsuccess || SCIPaggrRowGetNNz(aggrdata->aggrrow) > maxaggrnonzs || SCIPaggrRowGetNNz(aggrdata->aggrrow) == 0 )
1010  {
1011  break;
1012  }
1013 
1014  SCIPdebugMsg(scip, " -> current aggregation has %d/%d nonzeros and consists of %d/%d rows\n",
1015  SCIPaggrRowGetNNz(aggrdata->aggrrow), maxaggrnonzs, naggrs, maxaggrs);
1016  }
1017 
1018  SCIPaggrRowClear(aggrdata->aggrrow);
1019 
1020  return SCIP_OKAY;
1021 }
1022 
1023 /** gives an estimate of how much the activity of this row is affected by fractionality in the current solution */
1024 static
1026  SCIP_ROW* row, /**< the LP row */
1027  SCIP_Real* fractionalities /**< array of fractionalities for each variable */
1028  )
1029 {
1030  int nlpnonz;
1031  int i;
1032  SCIP_COL** cols;
1033  SCIP_Real* vals;
1034  SCIP_Real fracsum = 0.0;
1035 
1036  cols = SCIProwGetCols(row);
1037  vals = SCIProwGetVals(row);
1038  nlpnonz = SCIProwGetNLPNonz(row);
1039 
1040  for( i = 0; i < nlpnonz; ++i )
1041  {
1042  SCIP_VAR* var = SCIPcolGetVar(cols[i]);
1043  fracsum += REALABS(vals[i] * fractionalities[SCIPvarGetProbindex(var)]);
1044  }
1045 
1046  return fracsum;
1047 }
1048 
1049 /** searches for and adds c-MIR cuts that separate the given primal solution */
1050 static
1052  SCIP* scip, /**< SCIP data structure */
1053  SCIP_SEPA* sepa, /**< the c-MIR separator */
1054  SCIP_SOL* sol, /**< the solution that should be separated, or NULL for LP solution */
1055  SCIP_Bool allowlocal, /**< should local cuts be allowed */
1056  int depth, /**< current depth */
1057  SCIP_RESULT* result /**< pointer to store the result */
1058  )
1059 {
1060  AGGREGATIONDATA aggrdata;
1061  SCIP_SEPADATA* sepadata;
1062  SCIP_VAR** vars;
1063  SCIP_Real* varsolvals;
1064  SCIP_Real* bestcontlbs;
1065  SCIP_Real* bestcontubs;
1066  SCIP_Real* fractionalities;
1067  SCIP_ROW** rows;
1068  SCIP_Real* rowlhsscores;
1069  SCIP_Real* rowrhsscores;
1070  SCIP_Real* rowscores;
1071  int* roworder;
1072  SCIP_Real maxslack;
1073  SCIP_Bool cutoff = FALSE;
1074  SCIP_Bool wastried;
1075  int nvars;
1076  int nintvars;
1077  int ncontvars;
1078  int nrows;
1079  int nnonzrows;
1080  int ntries;
1081  int nfails;
1082  int ncalls;
1083  int maxtries;
1084  int maxfails;
1085  int maxaggrs;
1086  int maxsepacuts;
1087  int ncuts;
1088  int r;
1089  int v;
1090  int oldncuts;
1091 
1092  int* cutinds;
1093  SCIP_Real* cutcoefs;
1094 
1095  assert(result != NULL);
1096  assert(*result == SCIP_DIDNOTRUN);
1097 
1098  sepadata = SCIPsepaGetData(sepa);
1099  assert(sepadata != NULL);
1100 
1101  ncalls = SCIPsepaGetNCallsAtNode(sepa);
1102 
1103  /* only call the cmir cut separator a given number of times at each node */
1104  if( (depth == 0 && sepadata->maxroundsroot >= 0 && ncalls >= sepadata->maxroundsroot)
1105  || (depth > 0 && sepadata->maxrounds >= 0 && ncalls >= sepadata->maxrounds) )
1106  return SCIP_OKAY;
1107 
1108  /* check which cuts should be separated */
1109  {
1110  int cmirfreq;
1111  int flowcoverfreq;
1112  int knapsackcoverfreq;
1113 
1114  cmirfreq = SCIPsepaGetFreq(sepadata->cmir);
1115  flowcoverfreq = SCIPsepaGetFreq(sepadata->flowcover);
1116  knapsackcoverfreq = SCIPsepaGetFreq(sepadata->knapsackcover);
1117 
1118  sepadata->sepcmir = cmirfreq > 0 ? (depth % cmirfreq) == 0 : cmirfreq == depth;
1119  sepadata->sepflowcover = flowcoverfreq > 0 ? (depth % flowcoverfreq) == 0 : flowcoverfreq == depth;
1120  sepadata->sepknapsackcover = knapsackcoverfreq > 0 ? (depth % knapsackcoverfreq) == 0 : knapsackcoverfreq == depth;
1121  }
1122 
1123  if( ! sepadata->sepcmir && ! sepadata->sepflowcover && ! sepadata->sepknapsackcover )
1124  return SCIP_OKAY;
1125 
1126  /* get all rows and number of columns */
1127  SCIP_CALL( SCIPgetLPRowsData(scip, &rows, &nrows) );
1128  assert(nrows == 0 || rows != NULL);
1129 
1130  /* nothing to do, if LP is empty */
1131  if( nrows == 0 )
1132  return SCIP_OKAY;
1133 
1134  /* check whether SCIP was stopped in the meantime */
1135  if( SCIPisStopped(scip) )
1136  return SCIP_OKAY;
1137 
1138  /* get active problem variables */
1139  vars = SCIPgetVars(scip);
1140  nvars = SCIPgetNVars(scip);
1141  ncontvars = SCIPgetNContVars(scip);
1142 #ifdef IMPLINTSARECONT
1143  ncontvars += SCIPgetNImplVars(scip); /* also aggregate out implicit integers */
1144 #endif
1145  nintvars = nvars - ncontvars;
1146  assert(nvars == 0 || vars != NULL);
1147 
1148  /* nothing to do, if problem has no variables */
1149  if( nvars == 0 )
1150  return SCIP_OKAY;
1151 
1152  SCIPdebugMsg(scip, "separating c-MIR cuts\n");
1153 
1154  *result = SCIP_DIDNOTFIND;
1155 
1156  /* get data structure */
1157  SCIP_CALL( SCIPallocBufferArray(scip, &rowlhsscores, nrows) );
1158  SCIP_CALL( SCIPallocBufferArray(scip, &rowrhsscores, nrows) );
1159  SCIP_CALL( SCIPallocBufferArray(scip, &roworder, nrows) );
1160  SCIP_CALL( SCIPallocBufferArray(scip, &varsolvals, nvars) );
1161  SCIP_CALL( SCIPallocBufferArray(scip, &bestcontlbs, ncontvars) );
1162  SCIP_CALL( SCIPallocBufferArray(scip, &bestcontubs, ncontvars) );
1163  SCIP_CALL( SCIPallocBufferArray(scip, &fractionalities, nvars) );
1164  SCIP_CALL( SCIPallocBufferArray(scip, &cutinds, nvars) );
1165  SCIP_CALL( SCIPallocBufferArray(scip, &cutcoefs, nvars) );
1166  SCIP_CALL( SCIPallocBufferArray(scip, &rowscores, nrows) );
1167 
1168  /* get the solution values for all active variables */
1169  SCIP_CALL( SCIPgetSolVals(scip, sol, nvars, vars, varsolvals) );
1170 
1171  /* calculate the fractionality of the integer variables in the current solution */
1172  for( v = 0; v < nintvars; ++v )
1173  {
1174  fractionalities[v] = SCIPfeasFrac(scip, varsolvals[v]);
1175  fractionalities[v] = MIN(fractionalities[v], 1.0 - fractionalities[v]);
1176  }
1177 
1178  /* calculate the fractionality of the continuous variables in the current solution;
1179  * The fractionality of a continuous variable x is defined to be a * f_y,
1180  * if there is a variable bound x <= a * y + c where f_y is the fractionality of y
1181  * and in the current solution the variable bound has no slack.
1182  */
1183  for( ; v < nvars; ++v )
1184  {
1185  SCIP_VAR** vlbvars;
1186  SCIP_VAR** vubvars;
1187  SCIP_Real* vlbcoefs;
1188  SCIP_Real* vubcoefs;
1189  SCIP_Real closestvlb;
1190  SCIP_Real closestvub;
1191  int closestvlbidx;
1192  int closestvubidx;
1193 
1194  SCIP_CALL( SCIPgetVarClosestVlb(scip, vars[v], sol, &closestvlb, &closestvlbidx) );
1195  SCIP_CALL( SCIPgetVarClosestVub(scip, vars[v], sol, &closestvub, &closestvubidx) );
1196 
1197  vlbvars = SCIPvarGetVlbVars(vars[v]);
1198  vubvars = SCIPvarGetVubVars(vars[v]);
1199  vlbcoefs = SCIPvarGetVlbCoefs(vars[v]);
1200  vubcoefs = SCIPvarGetVubCoefs(vars[v]);
1201 
1202  fractionalities[v] = 0.0;
1203  if( closestvlbidx != -1 && SCIPisEQ(scip, varsolvals[v], closestvlb) )
1204  {
1205  int vlbvarprobidx = SCIPvarGetProbindex(vlbvars[closestvlbidx]);
1206  SCIP_Real frac = SCIPfeasFrac(scip, varsolvals[vlbvarprobidx]);
1207 
1208  if( frac < 0.0 )
1209  frac = 0.0;
1210  assert(frac >= 0.0 && frac < 1.0);
1211  frac = MIN(frac, 1.0 - frac) * vlbcoefs[closestvlbidx];
1212  fractionalities[v] += frac;
1213  }
1214 
1215  if( closestvubidx != -1 && SCIPisEQ(scip, varsolvals[v], closestvub) )
1216  {
1217  int vubvarprobidx = SCIPvarGetProbindex(vubvars[closestvubidx]);
1218  SCIP_Real frac = SCIPfeasFrac(scip, varsolvals[vubvarprobidx]);
1219 
1220  if( frac < 0.0 )
1221  frac = 0.0;
1222  assert(frac >= 0.0 && frac < 1.0);
1223  frac = MIN(frac, 1.0 - frac) * vubcoefs[closestvubidx];
1224  fractionalities[v] += frac;
1225  }
1226  }
1227 
1228  /* get the maximal number of cuts allowed in a separation round */
1229  if( depth == 0 )
1230  {
1231  maxtries = sepadata->maxtriesroot;
1232  maxfails = sepadata->maxfailsroot;
1233  maxaggrs = sepadata->maxaggrsroot;
1234  maxsepacuts = sepadata->maxsepacutsroot;
1235  maxslack = sepadata->maxslackroot;
1236  }
1237  else
1238  {
1239  maxtries = sepadata->maxtries;
1240  maxfails = sepadata->maxfails;
1241  maxaggrs = sepadata->maxaggrs;
1242  maxsepacuts = sepadata->maxsepacuts;
1243  maxslack = sepadata->maxslack;
1244  }
1245 
1246  /* calculate aggregation scores for both sides of all rows, and sort rows by decreasing maximal score
1247  * TODO: document score definition */
1248 
1249  /* count the number of non-zero rows and zero rows. these values are used for the sorting of the rowscores.
1250  * only the non-zero rows need to be sorted. */
1251  nnonzrows = 0;
1252  for( r = 0; r < nrows; r++ )
1253  {
1254  int nnonz;
1255 
1256  assert(SCIProwGetLPPos(rows[r]) == r);
1257 
1258  nnonz = SCIProwGetNLPNonz(rows[r]);
1259  if( nnonz == 0 || SCIProwIsModifiable(rows[r]) || (!allowlocal && SCIProwIsLocal(rows[r])) )
1260  {
1261  /* ignore empty rows, modifiable rows, and local rows if they are not allowed */
1262  rowlhsscores[r] = 0.0;
1263  rowrhsscores[r] = 0.0;
1264  }
1265  else
1266  {
1267  SCIP_Real activity;
1268  SCIP_Real lhs;
1269  SCIP_Real rhs;
1270  SCIP_Real dualsol;
1271  SCIP_Real dualscore;
1272  SCIP_Real rowdensity;
1273  SCIP_Real rownorm;
1274  SCIP_Real slack;
1275  SCIP_Real fracact;
1276  SCIP_Real fracscore;
1277  SCIP_Real objnorm;
1278 
1279  objnorm = SCIPgetObjNorm(scip);
1280  objnorm = MAX(objnorm, 1.0);
1281 
1282  fracact = getRowFracActivity(rows[r], fractionalities);
1283  dualsol = (sol == NULL ? SCIProwGetDualsol(rows[r]) : 1.0);
1284  activity = SCIPgetRowSolActivity(scip, rows[r], sol);
1285  lhs = SCIProwGetLhs(rows[r]);
1286  rhs = SCIProwGetRhs(rows[r]);
1287  rownorm = SCIProwGetNorm(rows[r]);
1288  rownorm = MAX(rownorm, 0.1);
1289  rowdensity = (SCIP_Real)(nnonz - sepadata->densityoffset)/(SCIP_Real)nvars;
1290  assert(SCIPisPositive(scip, rownorm));
1291  fracscore = fracact / rownorm;
1292 
1293  slack = (activity - lhs)/rownorm;
1294  dualscore = MAX(fracscore * dualsol/objnorm, 0.0001);
1295  if( !SCIPisInfinity(scip, -lhs) && SCIPisLE(scip, slack, maxslack)
1296  && rowdensity <= sepadata->maxrowdensity
1297  && rowdensity <= sepadata->maxaggdensity ) /*lint !e774*/
1298  {
1299  rowlhsscores[r] = dualscore + sepadata->densityscore * (1.0-rowdensity) + sepadata->slackscore * MAX(1.0 - slack, 0.0);
1300  assert(rowlhsscores[r] > 0.0);
1301  }
1302  else
1303  rowlhsscores[r] = 0.0;
1304 
1305  slack = (rhs - activity)/rownorm;
1306  dualscore = MAX(-fracscore * dualsol/objnorm, 0.0001);
1307  if( !SCIPisInfinity(scip, rhs) && SCIPisLE(scip, slack, maxslack)
1308  && rowdensity <= sepadata->maxrowdensity
1309  && rowdensity <= sepadata->maxaggdensity ) /*lint !e774*/
1310  {
1311  rowrhsscores[r] = dualscore + sepadata->densityscore * (1.0-rowdensity) + sepadata->slackscore * MAX(1.0 - slack, 0.0);
1312  assert(rowrhsscores[r] > 0.0);
1313  }
1314  else
1315  rowrhsscores[r] = 0.0;
1316 
1317  /* for the row order only use the fractionality score since it best indicates how likely it is to find a cut */
1318  if( fracscore != 0.0 )
1319  {
1320  roworder[nnonzrows] = r;
1321  rowscores[nnonzrows] = fracscore;
1322  ++nnonzrows;
1323  }
1324  }
1325 
1326  SCIPdebugMsg(scip, " -> row %d <%s>: lhsscore=%g rhsscore=%g maxscore=%g\n", r, SCIProwGetName(rows[r]),
1327  rowlhsscores[r], rowrhsscores[r], rowscores[r]);
1328  }
1329  assert(nnonzrows <= nrows);
1330 
1331  SCIPsortDownRealInt(rowscores, roworder, nnonzrows);
1332  SCIPfreeBufferArray(scip, &rowscores);
1333 
1334  /* calculate the data required for performing the row aggregation */
1335  SCIP_CALL( setupAggregationData(scip, sol, allowlocal, &aggrdata) );
1336 
1337  ncuts = 0;
1338  if( maxtries < 0 )
1339  maxtries = INT_MAX;
1340  if( maxfails < 0 )
1341  maxfails = INT_MAX;
1342  else if( depth == 0 && 2 * SCIPgetNSepaRounds(scip) < maxfails )
1343  maxfails += maxfails - 2 * SCIPgetNSepaRounds(scip); /* allow up to double as many fails in early separounds of root node */
1344 
1345  /* start aggregation heuristic for each row in the LP and generate resulting cuts */
1346  ntries = 0;
1347  nfails = 0;
1348 
1349  if( !SCIPisInfinity(scip, SCIPgetCutoffbound(scip)) )
1350  {
1351  /* try separating the objective function with the cutoff bound */
1352  SCIP_CALL( aggregation(scip, &aggrdata, sepa, sol, allowlocal, rowlhsscores, rowrhsscores,
1353  -1, 2 * maxaggrs, &wastried, &cutoff, cutinds, cutcoefs, FALSE, &ncuts) );
1354 
1355  if( cutoff )
1356  goto TERMINATE;
1357  }
1358 
1359  for( r = 0; r < nnonzrows && ntries < maxtries && ncuts < maxsepacuts && !SCIPisStopped(scip); r++ )
1360  {
1361  oldncuts = ncuts;
1362  SCIP_CALL( aggregation(scip, &aggrdata, sepa, sol, allowlocal, rowlhsscores, rowrhsscores,
1363  roworder[r], maxaggrs, &wastried, &cutoff, cutinds, cutcoefs, FALSE, &ncuts) );
1364 
1365  /* if trynegscaling is true we start the aggregation heuristic again for this row, but multiply it by -1 first.
1366  * This is done by calling the aggregation function with the parameter negate equal to TRUE
1367  */
1368  if( sepadata->trynegscaling && !cutoff )
1369  {
1370  SCIP_CALL( aggregation(scip, &aggrdata, sepa, sol, allowlocal, rowlhsscores, rowrhsscores,
1371  roworder[r], maxaggrs, &wastried, &cutoff, cutinds, cutcoefs, TRUE, &ncuts) );
1372  }
1373 
1374  if ( cutoff )
1375  break;
1376 
1377  if( !wastried )
1378  {
1379  continue;
1380  }
1381  ntries++;
1382 
1383  if( ncuts == oldncuts )
1384  {
1385  nfails++;
1386  if( nfails >= maxfails )
1387  {
1388  break;
1389  }
1390  }
1391  else
1392  {
1393  nfails = 0;
1394  }
1395  }
1396  TERMINATE:
1397  /* free data structure */
1398  destroyAggregationData(scip, &aggrdata);
1399  SCIPfreeBufferArray(scip, &cutcoefs);
1400  SCIPfreeBufferArray(scip, &cutinds);
1401  SCIPfreeBufferArray(scip, &fractionalities);
1402  SCIPfreeBufferArray(scip, &bestcontubs);
1403  SCIPfreeBufferArray(scip, &bestcontlbs);
1404  SCIPfreeBufferArray(scip, &varsolvals);
1405  SCIPfreeBufferArray(scip, &roworder);
1406  SCIPfreeBufferArray(scip, &rowrhsscores);
1407  SCIPfreeBufferArray(scip, &rowlhsscores);
1408 
1409  if ( cutoff )
1410  *result = SCIP_CUTOFF;
1411  else if ( ncuts > 0 )
1412  *result = SCIP_SEPARATED;
1413 
1414  return SCIP_OKAY;
1415 }
1416 
1417 /*
1418  * Callback methods of separator
1419  */
1420 
1421 /** copy method for separator plugins (called when SCIP copies plugins) */
1422 static
1423 SCIP_DECL_SEPACOPY(sepaCopyAggregation)
1424 { /*lint --e{715}*/
1425  assert(scip != NULL);
1426  assert(sepa != NULL);
1427  assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
1428 
1429  /* call inclusion method of constraint handler */
1431 
1432  return SCIP_OKAY;
1433 }
1434 
1435 /** destructor of separator to free user data (called when SCIP is exiting) */
1436 static
1437 SCIP_DECL_SEPAFREE(sepaFreeAggregation)
1438 { /*lint --e{715}*/
1439  SCIP_SEPADATA* sepadata;
1440 
1441  /* free separator data */
1442  sepadata = SCIPsepaGetData(sepa);
1443  assert(sepadata != NULL);
1444 
1445  SCIPfreeBlockMemory(scip, &sepadata);
1446 
1447  SCIPsepaSetData(sepa, NULL);
1448 
1449  return SCIP_OKAY;
1450 }
1451 
1452 /** LP solution separation method of separator */
1453 static
1454 SCIP_DECL_SEPAEXECLP(sepaExeclpAggregation)
1455 { /*lint --e{715}*/
1456  assert( result != NULL );
1457 
1458  *result = SCIP_DIDNOTRUN;
1459 
1460  /* only call separator, if we are not close to terminating */
1461  if( SCIPisStopped(scip) )
1462  return SCIP_OKAY;
1463 
1464  /* only call separator, if an optimal LP solution is at hand */
1466  return SCIP_OKAY;
1467 
1468  /* only call separator, if there are fractional variables */
1469  if( SCIPgetNLPBranchCands(scip) == 0 )
1470  return SCIP_OKAY;
1471 
1472  SCIP_CALL( separateCuts(scip, sepa, NULL, allowlocal, depth, result) );
1473 
1474  return SCIP_OKAY;
1475 }
1476 
1477 /** arbitrary primal solution separation method of separator */
1478 static
1479 SCIP_DECL_SEPAEXECSOL(sepaExecsolAggregation)
1480 { /*lint --e{715}*/
1481  assert( result != NULL );
1482 
1483  *result = SCIP_DIDNOTRUN;
1484 
1485  SCIP_CALL( separateCuts(scip, sepa, sol, allowlocal, depth, result) );
1486 
1487  return SCIP_OKAY;
1488 }
1489 
1490 /** LP solution separation method of dummy separator */
1491 static
1492 SCIP_DECL_SEPAEXECLP(sepaExeclpDummy)
1493 { /*lint --e{715}*/
1494  assert( result != NULL );
1495 
1496  *result = SCIP_DIDNOTRUN;
1497 
1498  return SCIP_OKAY;
1499 }
1500 
1501 /** arbitrary primal solution separation method of dummy separator */
1502 static
1503 SCIP_DECL_SEPAEXECSOL(sepaExecsolDummy)
1504 { /*lint --e{715}*/
1505  assert( result != NULL );
1506 
1507  *result = SCIP_DIDNOTRUN;
1508 
1509  return SCIP_OKAY;
1510 }
1511 
1512 /*
1513  * separator specific interface methods
1514  */
1515 
1516 /** creates the cmir separator and includes it in SCIP */
1518  SCIP* scip /**< SCIP data structure */
1519  )
1520 {
1521  SCIP_SEPADATA* sepadata;
1522  SCIP_SEPA* sepa;
1524  /* create cmir separator data */
1525  SCIP_CALL( SCIPallocBlockMemory(scip, &sepadata) );
1526 
1527  /* include dummy separators */
1528  SCIP_CALL( SCIPincludeSepaBasic(scip, &sepadata->flowcover, "flowcover", "separator for flowcover cuts", -100000, SEPA_FREQ, 0.0,
1529  SEPA_USESSUBSCIP, FALSE, sepaExeclpDummy, sepaExecsolDummy, NULL) );
1530 
1531  assert(sepadata->flowcover != NULL);
1532 
1533  SCIP_CALL( SCIPincludeSepaBasic(scip, &sepadata->cmir, "cmir", "separator for cmir cuts", -100000, SEPA_FREQ, 0.0,
1534  SEPA_USESSUBSCIP, FALSE, sepaExeclpDummy, sepaExecsolDummy, NULL) );
1535 
1536  assert(sepadata->cmir != NULL);
1537 
1538  SCIP_CALL( SCIPincludeSepaBasic(scip, &sepadata->knapsackcover, "knapsackcover", "separator for knapsack cover cuts", -100000, SEPA_FREQ, 0.0,
1539  SEPA_USESSUBSCIP, FALSE, sepaExeclpDummy, sepaExecsolDummy, NULL) );
1540 
1541  assert(sepadata->knapsackcover != NULL);
1542 
1543  /* include separator */
1546  sepaExeclpAggregation, sepaExecsolAggregation,
1547  sepadata) );
1548 
1549  assert(sepa != NULL);
1550 
1551  /* set non-NULL pointers to callback methods */
1552  SCIP_CALL( SCIPsetSepaCopy(scip, sepa, sepaCopyAggregation) );
1553  SCIP_CALL( SCIPsetSepaFree(scip, sepa, sepaFreeAggregation) );
1554 
1555  /* mark main separator as a parent */
1556  SCIPsetSepaIsParentsepa(scip, sepa);
1557 
1558  /* set pointer from child separators to main separator */
1559  SCIPsetSepaParentsepa(scip, sepadata->flowcover, sepa);
1560  SCIPsetSepaParentsepa(scip, sepadata->cmir, sepa);
1561  SCIPsetSepaParentsepa(scip, sepadata->knapsackcover, sepa);
1562 
1563  /* add cmir separator parameters */
1564  SCIP_CALL( SCIPaddIntParam(scip,
1565  "separating/" SEPA_NAME "/maxrounds",
1566  "maximal number of cmir separation rounds per node (-1: unlimited)",
1567  &sepadata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
1568  SCIP_CALL( SCIPaddIntParam(scip,
1569  "separating/" SEPA_NAME "/maxroundsroot",
1570  "maximal number of cmir separation rounds in the root node (-1: unlimited)",
1571  &sepadata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
1572  SCIP_CALL( SCIPaddIntParam(scip,
1573  "separating/" SEPA_NAME "/maxtries",
1574  "maximal number of rows to start aggregation with per separation round (-1: unlimited)",
1575  &sepadata->maxtries, TRUE, DEFAULT_MAXTRIES, -1, INT_MAX, NULL, NULL) );
1576  SCIP_CALL( SCIPaddIntParam(scip,
1577  "separating/" SEPA_NAME "/maxtriesroot",
1578  "maximal number of rows to start aggregation with per separation round in the root node (-1: unlimited)",
1579  &sepadata->maxtriesroot, TRUE, DEFAULT_MAXTRIESROOT, -1, INT_MAX, NULL, NULL) );
1580  SCIP_CALL( SCIPaddIntParam(scip,
1581  "separating/" SEPA_NAME "/maxfails",
1582  "maximal number of consecutive unsuccessful aggregation tries (-1: unlimited)",
1583  &sepadata->maxfails, TRUE, DEFAULT_MAXFAILS, -1, INT_MAX, NULL, NULL) );
1584  SCIP_CALL( SCIPaddIntParam(scip,
1585  "separating/" SEPA_NAME "/maxfailsroot",
1586  "maximal number of consecutive unsuccessful aggregation tries in the root node (-1: unlimited)",
1587  &sepadata->maxfailsroot, TRUE, DEFAULT_MAXFAILSROOT, -1, INT_MAX, NULL, NULL) );
1588  SCIP_CALL( SCIPaddIntParam(scip,
1589  "separating/" SEPA_NAME "/maxaggrs",
1590  "maximal number of aggregations for each row per separation round",
1591  &sepadata->maxaggrs, TRUE, DEFAULT_MAXAGGRS, 0, INT_MAX, NULL, NULL) );
1592  SCIP_CALL( SCIPaddIntParam(scip,
1593  "separating/" SEPA_NAME "/maxaggrsroot",
1594  "maximal number of aggregations for each row per separation round in the root node",
1595  &sepadata->maxaggrsroot, TRUE, DEFAULT_MAXAGGRSROOT, 0, INT_MAX, NULL, NULL) );
1596  SCIP_CALL( SCIPaddIntParam(scip,
1597  "separating/" SEPA_NAME "/maxsepacuts",
1598  "maximal number of cmir cuts separated per separation round",
1599  &sepadata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
1600  SCIP_CALL( SCIPaddIntParam(scip,
1601  "separating/" SEPA_NAME "/maxsepacutsroot",
1602  "maximal number of cmir cuts separated per separation round in the root node",
1603  &sepadata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
1605  "separating/" SEPA_NAME "/maxslack",
1606  "maximal slack of rows to be used in aggregation",
1607  &sepadata->maxslack, TRUE, DEFAULT_MAXSLACK, 0.0, SCIP_REAL_MAX, NULL, NULL) );
1609  "separating/" SEPA_NAME "/maxslackroot",
1610  "maximal slack of rows to be used in aggregation in the root node",
1611  &sepadata->maxslackroot, TRUE, DEFAULT_MAXSLACKROOT, 0.0, SCIP_REAL_MAX, NULL, NULL) );
1613  "separating/" SEPA_NAME "/densityscore",
1614  "weight of row density in the aggregation scoring of the rows",
1615  &sepadata->densityscore, TRUE, DEFAULT_DENSITYSCORE, 0.0, SCIP_REAL_MAX, NULL, NULL) );
1617  "separating/" SEPA_NAME "/slackscore",
1618  "weight of slack in the aggregation scoring of the rows",
1619  &sepadata->slackscore, TRUE, DEFAULT_SLACKSCORE, 0.0, SCIP_REAL_MAX, NULL, NULL) );
1621  "separating/" SEPA_NAME "/maxaggdensity",
1622  "maximal density of aggregated row",
1623  &sepadata->maxaggdensity, TRUE, DEFAULT_MAXAGGDENSITY, 0.0, 1.0, NULL, NULL) );
1625  "separating/" SEPA_NAME "/maxrowdensity",
1626  "maximal density of row to be used in aggregation",
1627  &sepadata->maxrowdensity, TRUE, DEFAULT_MAXROWDENSITY, 0.0, 1.0, NULL, NULL) );
1628  SCIP_CALL( SCIPaddIntParam(scip,
1629  "separating/" SEPA_NAME "/densityoffset",
1630  "additional number of variables allowed in row on top of density",
1631  &sepadata->densityoffset, TRUE, DEFAULT_DENSITYOFFSET, 0, INT_MAX, NULL, NULL) );
1633  "separating/" SEPA_NAME "/maxrowfac",
1634  "maximal row aggregation factor",
1635  &sepadata->maxrowfac, TRUE, DEFAULT_MAXROWFAC, 0.0, SCIP_REAL_MAX, NULL, NULL) );
1636  SCIP_CALL( SCIPaddIntParam(scip,
1637  "separating/" SEPA_NAME "/maxtestdelta",
1638  "maximal number of different deltas to try (-1: unlimited)",
1639  &sepadata->maxtestdelta, TRUE, DEFAULT_MAXTESTDELTA, -1, INT_MAX, NULL, NULL) );
1641  "separating/" SEPA_NAME "/aggrtol",
1642  "tolerance for bound distances used to select continuous variable in current aggregated constraint to be eliminated",
1643  &sepadata->aggrtol, TRUE, DEFAULT_AGGRTOL, 0.0, SCIP_REAL_MAX, NULL, NULL) );
1645  "separating/" SEPA_NAME "/trynegscaling",
1646  "should negative values also be tested in scaling?",
1647  &sepadata->trynegscaling, TRUE, DEFAULT_TRYNEGSCALING, NULL, NULL) );
1649  "separating/" SEPA_NAME "/fixintegralrhs",
1650  "should an additional variable be complemented if f0 = 0?",
1651  &sepadata->fixintegralrhs, TRUE, DEFAULT_FIXINTEGRALRHS, NULL, NULL) );
1653  "separating/" SEPA_NAME "/dynamiccuts",
1654  "should generated cuts be removed from the LP if they are no longer tight?",
1655  &sepadata->dynamiccuts, FALSE, DEFAULT_DYNAMICCUTS, NULL, NULL) );
1656 
1657  return SCIP_OKAY;
1658 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
#define DEFAULT_MAXAGGRS
static SCIP_RETCODE addCut(SCIP *scip, SCIP_SOL *sol, SCIP_SEPA *sepa, SCIP_Bool makeintegral, SCIP_Real *cutcoefs, int *cutinds, int cutnnz, SCIP_Real cutrhs, SCIP_Real cutefficacy, SCIP_Bool cutislocal, SCIP_Bool cutremovable, int cutrank, const char *cutclassname, SCIP_Bool *cutoff, int *ncuts, SCIP_ROW **thecut)
#define SEPA_MAXBOUNDDIST
int SCIPgetNIntVars(SCIP *scip)
Definition: scip_prob.c:2080
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
#define MAKECONTINTEGRAL
#define DEFAULT_DENSITYSCORE
void SCIPaggrRowFree(SCIP *scip, SCIP_AGGRROW **aggrrow)
Definition: cuts.c:1686
int SCIPaggrRowGetNRows(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2405
#define DEFAULT_MAXFAILSROOT
SCIP_Real * SCIPvarGetVlbCoefs(SCIP_VAR *var)
Definition: var.c:18124
#define DEFAULT_MAXTESTDELTA
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1626
public methods for SCIP parameter handling
SCIP_RETCODE SCIPaggrRowAddRow(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_ROW *row, SCIP_Real weight, int sidetype)
Definition: cuts.c:1790
#define BOUNDSWITCH
public methods for memory management
static SCIP_DECL_SEPACOPY(sepaCopyAggregation)
SCIP_Real SCIPgetCutoffbound(SCIP *scip)
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1649
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17910
#define SCIP_MAXSTRLEN
Definition: def.h:293
void SCIPsetSepaParentsepa(SCIP *scip, SCIP_SEPA *sepa, SCIP_SEPA *parentsepa)
Definition: scip_sepa.c:309
#define DEFAULT_MAXROUNDSROOT
SCIP_Real * SCIPcolGetVals(SCIP_COL *col)
Definition: lp.c:17094
static SCIP_DECL_SEPAEXECSOL(sepaExecsolAggregation)
#define DEFAULT_MAXSLACKROOT
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1686
int SCIProwGetNNonz(SCIP_ROW *row)
Definition: lp.c:17146
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17966
#define DEFAULT_FIXINTEGRALRHS
const char * SCIProwGetName(SCIP_ROW *row)
Definition: lp.c:17284
int SCIProwGetNLPNonz(SCIP_ROW *row)
Definition: lp.c:17160
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition: misc.c:10291
SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
Definition: scip_prob.c:1864
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:17225
#define FALSE
Definition: def.h:87
methods for the aggregation rows
#define DEFAULT_SLACKSCORE
SCIP_Real SCIPinfinity(SCIP *scip)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10755
#define TRUE
Definition: def.h:86
#define SCIPdebug(x)
Definition: pub_message.h:84
const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition: sepa.c:720
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:54
SCIP_RETCODE SCIPcutGenerationHeuristicCMIR(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, SCIP_Bool usevbds, SCIP_Bool allowlocal, int maxtestdelta, int *boundsfortrans, SCIP_BOUNDTYPE *boundtypesfortrans, SCIP_Real minfrac, SCIP_Real maxfrac, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
Definition: cuts.c:4124
SCIP_RETCODE SCIPincludeSepaAggregation(SCIP *scip)
SCIP_Real * bounddist
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17600
SCIP_ROW ** aggrrows
public methods for problem variables
static SCIP_Real negate(SCIP_Real x)
void SCIPswapReals(SCIP_Real *value1, SCIP_Real *value2)
Definition: misc.c:10278
SCIP_RETCODE SCIPcalcKnapsackCover(SCIP *scip, SCIP_SOL *sol, SCIP_Bool allowlocal, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
Definition: cuts.c:7955
int SCIPaggrRowGetNNz(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2470
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:99
SCIP_VAR ** SCIPvarGetVlbVars(SCIP_VAR *var)
Definition: var.c:18114
void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
SCIP_Real SCIPfeasFrac(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:127
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip_branch.c:419
public methods for SCIP variables
SCIP_RETCODE SCIPsetSepaCopy(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPACOPY((*sepacopy)))
Definition: scip_sepa.c:142
SCIP_Real SCIProwGetDualsol(SCIP_ROW *row)
Definition: lp.c:17245
flow cover and complemented mixed integer rounding cuts separator (Marchand&#39;s version) ...
#define SCIPdebugMsg
Definition: scip_message.h:69
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:74
public methods for separator plugins
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2170
SCIP_Real SCIPgetObjNorm(SCIP *scip)
Definition: scip_prob.c:1639
SCIP_Real SCIPepsilon(SCIP *scip)
SCIP_RETCODE SCIPgetVarClosestVlb(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *closestvlb, int *closestvlbidx)
Definition: scip_var.c:6606
SCIP_Real SCIPgetRowMaxCoef(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1907
public methods for numerical tolerances
SCIP_SEPADATA * SCIPsepaGetData(SCIP_SEPA *sepa)
Definition: sepa.c:610
SCIP_Bool SCIPaggrRowHasRowBeenAdded(SCIP_AGGRROW *aggrrow, SCIP_ROW *row)
Definition: cuts.c:2437
public methods for querying solving statistics
SCIP_RETCODE SCIPaggrRowAddObjectiveFunction(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Real rhs, SCIP_Real scale)
Definition: cuts.c:1933
public methods for the branch-and-bound tree
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17920
int SCIPsepaGetFreq(SCIP_SEPA *sepa)
Definition: sepa.c:764
#define DEFAULT_MAXROWFAC
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip_cut.c:108
#define SEPA_FREQ
static SCIP_Real aggrdataGetBoundDist(AGGREGATIONDATA *aggrdata, int probvaridx)
SCIP_Real SCIPgetRowMinCoef(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1889
#define MINFRAC
int * SCIPaggrRowGetRowInds(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2415
static SCIP_RETCODE aggregation(SCIP *scip, AGGREGATIONDATA *aggrdata, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_Bool allowlocal, SCIP_Real *rowlhsscores, SCIP_Real *rowrhsscores, int startrow, int maxaggrs, SCIP_Bool *wastried, SCIP_Bool *cutoff, int *cutinds, SCIP_Real *cutcoefs, SCIP_Bool negate, int *ncuts)
SCIP_ROW ** SCIPcolGetRows(SCIP_COL *col)
Definition: lp.c:17084
SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip_sol.c:1389
#define DEFAULT_MAXAGGRSROOT
SCIP_Bool SCIProwIsLocal(SCIP_ROW *row)
Definition: lp.c:17334
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:128
int SCIPsepaGetNCallsAtNode(SCIP_SEPA *sepa)
Definition: sepa.c:847
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip_cut.c:126
#define DEFAULT_MAXROWDENSITY
#define DEFAULT_MAXFAILS
#define MAXFRAC
void SCIPsepaSetData(SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata)
Definition: sepa.c:620
#define NULL
Definition: lpi_spx1.cpp:155
int * SCIPaggrRowGetInds(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2460
#define REALABS(x)
Definition: def.h:201
static SCIP_DECL_SEPAEXECLP(sepaExeclpAggregation)
void SCIPaggrRowRemoveZeros(SCIP *scip, SCIP_AGGRROW *aggrrow, SCIP_Bool useglbbounds, SCIP_Bool *valid)
Definition: cuts.c:2390
#define SCIP_CALL(x)
Definition: def.h:384
SCIP_RETCODE SCIPgetVarClosestVub(SCIP *scip, SCIP_VAR *var, SCIP_SOL *sol, SCIP_Real *closestvub, int *closestvubidx)
Definition: scip_var.c:6629
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:17235
SCIP_Real * SCIPvarGetVubCoefs(SCIP_VAR *var)
Definition: var.c:18166
void SCIPsetSepaIsParentsepa(SCIP *scip, SCIP_SEPA *sepa)
Definition: scip_sepa.c:294
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:241
SCIP_Bool SCIProwIsModifiable(SCIP_ROW *row)
Definition: lp.c:17344
SCIP_Bool SCIPsortedvecFindInt(int *intarray, int val, int len, int *pos)
SCIP_COL ** SCIProwGetCols(SCIP_ROW *row)
Definition: lp.c:17171
SCIP_RETCODE SCIPincludeSepaBasic(SCIP *scip, SCIP_SEPA **sepa, const char *name, const char *desc, int priority, int freq, SCIP_Real maxbounddist, SCIP_Bool usessubscip, SCIP_Bool delay, SCIP_DECL_SEPAEXECLP((*sepaexeclp)), SCIP_DECL_SEPAEXECSOL((*sepaexecsol)), SCIP_SEPADATA *sepadata)
Definition: scip_sepa.c:100
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:115
SCIP_Real * SCIProwGetVals(SCIP_ROW *row)
Definition: lp.c:17181
public data structures and miscellaneous methods
#define SEPA_USESSUBSCIP
#define SCIP_Bool
Definition: def.h:84
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:159
int SCIPgetNImplVars(SCIP *scip)
Definition: scip_prob.c:2125
static SCIP_RETCODE aggregateNextRow(SCIP *scip, SCIP_SEPADATA *sepadata, SCIP_Real *rowlhsscores, SCIP_Real *rowrhsscores, AGGREGATIONDATA *aggrdata, SCIP_AGGRROW *aggrrow, int *naggrs, SCIP_Bool *success)
static SCIP_Bool getRowAggregationCandidates(AGGREGATIONDATA *aggrdata, int probvaridx, SCIP_ROW ***rows, SCIP_Real **rowvarcoefs, int *nrows, int *ngoodrows)
SCIP_Bool SCIPvarIsInLP(SCIP_VAR *var)
Definition: var.c:17632
SCIP_RETCODE SCIPcalcFlowCover(SCIP *scip, SCIP_SOL *sol, SCIP_Bool postprocess, SCIP_Real boundswitch, SCIP_Bool allowlocal, SCIP_AGGRROW *aggrrow, SCIP_Real *cutcoefs, SCIP_Real *cutrhs, int *cutinds, int *cutnnz, SCIP_Real *cutefficacy, int *cutrank, SCIP_Bool *cutislocal, SCIP_Bool *success)
Definition: cuts.c:7329
int SCIPgetRowNumIntCols(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1871
#define DEFAULT_MAXTRIES
#define MAX(x, y)
Definition: tclique_def.h:83
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip_cut.c:352
public methods for LP management
SCIP_RETCODE SCIPcreateEmptyRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_SEPA *sepa, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1444
public methods for cuts and aggregation rows
#define SEPA_NAME
SCIP_AGGRROW * aggrrow
SCIP_COL * SCIPvarGetCol(SCIP_VAR *var)
Definition: var.c:17621
static void destroyAggregationData(SCIP *scip, AGGREGATIONDATA *aggrdata)
static SCIP_RETCODE setupAggregationData(SCIP *scip, SCIP_SOL *sol, SCIP_Bool allowlocal, AGGREGATIONDATA *aggrdata)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPgetRowSolActivity(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip_lp.c:2129
#define DEFAULT_TRYNEGSCALING
SCIP_Bool SCIPisCutNew(SCIP *scip, SCIP_ROW *row)
Definition: scip_cut.c:334
int SCIPgetNBinVars(SCIP *scip)
Definition: scip_prob.c:2035
public methods for the LP relaxation, rows and columns
int SCIProwGetRank(SCIP_ROW *row)
Definition: lp.c:17314
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1990
#define SEPA_PRIORITY
#define SCIP_REAL_MAX
Definition: def.h:178
#define DEFAULT_MAXSEPACUTS
#define DEFAULT_MAXAGGDENSITY
SCIP_Real SCIProwGetParallelism(SCIP_ROW *row1, SCIP_ROW *row2, char orthofunc)
Definition: lp.c:7717
SCIP_Real * r
Definition: circlepacking.c:50
methods for sorting joint arrays of various types
public methods for branching rule plugins and branching
#define DEFAULT_MAXROUNDS
SCIP_Bool SCIPisObjIntegral(SCIP *scip)
Definition: scip_prob.c:1560
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1553
general public methods
SCIP_RETCODE SCIPsetSepaFree(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPAFREE((*sepafree)))
Definition: scip_sepa.c:158
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define SEPA_DELAY
#define DEFAULT_DENSITYOFFSET
SCIP_VAR * SCIPcolGetVar(SCIP_COL *col)
Definition: lp.c:16975
public methods for solutions
void SCIProwChgRank(SCIP_ROW *row, int rank)
Definition: lp.c:17467
static SCIP_DECL_SEPAFREE(sepaFreeAggregation)
public methods for message output
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1945
int SCIProwGetLPPos(SCIP_ROW *row)
Definition: lp.c:17434
#define SCIP_Real
Definition: def.h:177
static SCIP_RETCODE separateCuts(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_Bool allowlocal, int depth, SCIP_RESULT *result)
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:694
public methods for message handling
#define SCIP_INVALID
Definition: def.h:197
SCIP_RETCODE SCIPaggrRowCreate(SCIP *scip, SCIP_AGGRROW **aggrrow)
Definition: cuts.c:1654
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2197
SCIP_VAR ** SCIPvarGetVubVars(SCIP_VAR *var)
Definition: var.c:18156
#define DEFAULT_DYNAMICCUTS
#define POSTPROCESS
static SCIP_Real getRowFracActivity(SCIP_ROW *row, SCIP_Real *fractionalities)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
static INLINE SCIP_Real SCIPaggrRowGetProbvarValue(SCIP_AGGRROW *aggrrow, int probindex)
Definition: cuts.h:240
int SCIPgetNLPCols(SCIP *scip)
Definition: scip_lp.c:518
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17976
SCIP_Real SCIPsumepsilon(SCIP *scip)
SCIP_Real SCIPgetUpperbound(SCIP *scip)
public methods for separators
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:123
SCIP_RETCODE SCIPgetLPRowsData(SCIP *scip, SCIP_ROW ***rows, int *nrows)
Definition: scip_lp.c:561
SCIPallocBlockMemory(scip, subsol))
#define DEFAULT_MAXTRIESROOT
void SCIPaggrRowClear(SCIP_AGGRROW *aggrrow)
Definition: cuts.c:2054
#define DEFAULT_MAXSEPACUTSROOT
SCIP_Longint SCIPgetNLPs(SCIP *scip)
public methods for global and local (sub)problems
int SCIPcolGetNLPNonz(SCIP_COL *col)
Definition: lp.c:17073
#define USEVBDS
SCIP_RETCODE SCIPmakeRowIntegral(SCIP *scip, SCIP_ROW *row, SCIP_Real mindelta, SCIP_Real maxdelta, SCIP_Longint maxdnom, SCIP_Real maxscale, SCIP_Bool usecontvars, SCIP_Bool *success)
Definition: scip_lp.c:1829
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1352
#define DEFAULT_AGGRTOL
SCIP_Real SCIProwGetNorm(SCIP_ROW *row)
Definition: lp.c:17201
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:130
#define DEFAULT_MAXSLACK
#define SEPA_DESC
struct SCIP_SepaData SCIP_SEPADATA
Definition: type_sepa.h:43
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:48
int SCIPgetNSepaRounds(SCIP *scip)
SCIP_Real * aggrrowscoef
struct AggregationData AGGREGATIONDATA
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:119
memory allocation routines