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