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