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