Scippy

SCIP

Solving Constraint Integer Programs

presol_milp.cpp
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 presol_milp.cpp
26 * @brief MILP presolver
27 * @author Leona Gottwald
28 * @author Alexander Hoen
29 *
30 * Calls the presolve library and communicates (multi-)aggregations, fixings, and bound
31 * changes to SCIP by utilizing the postsolve information. Constraint changes can currently
32 * only be communicated by deleting all constraints and adding new ones.
33 *
34 * @todo add infrastructure to SCIP for handling parallel columns
35 * @todo better communication of constraint changes by adding more information to the postsolve structure
36 * @todo allow to pass additional external locks to the presolve library that are considered when doing reductions
37 *
38 */
39
40/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
41
42#include "scip/presol_milp.h"
43
44#ifndef SCIP_WITH_PAPILO
45
46/** creates the MILP presolver and includes it in SCIP */
48 SCIP* scip /**< SCIP data structure */
49 )
50{
51 assert(scip != NULL);
52 return SCIP_OKAY;
53}
54
55#else
56
57/* disable some warnings that come up in header files of PAPILOs dependencies */
58#ifdef __GNUC__
59#pragma GCC diagnostic ignored "-Wshadow"
60#pragma GCC diagnostic ignored "-Wctor-dtor-privacy"
61#pragma GCC diagnostic ignored "-Wredundant-decls"
62
63/* disable false warning, !3076, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106199 */
64#if __GNUC__ == 12 && __GNUC__MINOR__ <= 2
65#pragma GCC diagnostic ignored "-Wstringop-overflow"
66#endif
67#endif
68
69#include <assert.h>
70#include "scip/cons_linear.h"
71#include "scip/pub_matrix.h"
72#include "scip/pub_presol.h"
73#include "scip/pub_var.h"
74#include "scip/pub_cons.h"
75#include "scip/pub_message.h"
76#include "scip/scip_general.h"
77#include "scip/scip_presol.h"
78#include "scip/scip_var.h"
79#include "scip/scip_mem.h"
80#include "scip/scip_prob.h"
81#include "scip/scip_param.h"
82#include "scip/scip_cons.h"
83#include "scip/scip_numerics.h"
84#include "scip/scip_timing.h"
85#include "scip/scip_message.h"
87#include "papilo/core/Presolve.hpp"
88#include "papilo/core/ProblemBuilder.hpp"
89#include "papilo/Config.hpp"
90
91/* API since PaPILO 2.3.0 */
92#if !defined(PAPILO_API_VERSION)
93#define PAPILO_APIVERSION 0
94#elif !(PAPILO_API_VERSION + 0)
95#define PAPILO_APIVERSION 1
96#else
97#define PAPILO_APIVERSION PAPILO_API_VERSION
98#endif
99
100#define PRESOL_NAME "milp"
101#define PRESOL_DESC "MILP specific presolving methods"
102#define PRESOL_PRIORITY 9999999 /**< priority of the presolver (>= 0: before, < 0: after constraint handlers); combined with propagators */
103#define PRESOL_MAXROUNDS (-1) /**< maximal number of presolving rounds the presolver participates in (-1: no limit) */
104#define PRESOL_TIMING SCIP_PRESOLTIMING_MEDIUM /* timing of the presolver (fast, medium, or exhaustive) */
105
106/** general settings for PaPILO */
107#define DEFAULT_THREADS 1 /**< maximum number of threads presolving may use (0: automatic) */
108#define DEFAULT_ABORTFAC_EXHAUSTIVE 0.0008 /**< the abort factor for exhaustive presolving in PAPILO */
109#define DEFAULT_ABORTFAC_MEDIUM 0.0008 /**< the abort factor for medium presolving in PAPILO */
110#define DEFAULT_ABORTFAC_FAST 0.0008 /**< the abort factor for fast presolving in PAPILO */
111#define DEFAULT_DETECTLINDEP 0 /**< should linear dependent equations and free columns be removed? (0: never, 1: for LPs, 2: always) */
112#define DEFAULT_INTERNAL_MAXROUNDS (-1) /**< internal max rounds in PaPILO (-1: no limit, 0: model cleanup) */
113#define DEFAULT_MODIFYCONSFAC 0.8 /**< modify SCIP constraints when the number of nonzeros or rows is at most this
114 * factor times the number of nonzeros or rows before presolving */
115#define DEFAULT_RANDOMSEED 0 /**< the random seed used for randomization of tie breaking */
116
117/** numerics in PaPILO */
118#define DEFAULT_HUGEBOUND 1e8 /**< absolute bound value that is considered too huge for activitity based calculations */
119
120/** presolvers in PaPILO */
121#define DEFAULT_ENABLEDOMCOL TRUE /**< should the dominated column presolver be enabled within the presolve library? */
122#define DEFAULT_ENABLEDUALINFER TRUE /**< should the dualinfer presolver be enabled within the presolve library? */
123#define DEFAULT_ENABLEMULTIAGGR TRUE /**< should the multi-aggregation/substitution presolver be enabled within the presolve library? */
124#define DEFAULT_ENABLEPARALLELROWS TRUE /**< should the parallel rows presolver be enabled within the presolve library? */
125#define DEFAULT_ENABLEPROBING TRUE /**< should the probing presolver be enabled within the presolve library? */
126#define DEFAULT_ENABLESPARSIFY FALSE /**< should the sparsify presolver be enabled within the presolve library? */
127
128/** parameters tied to a certain presolve technique in PaPILO */
129#define DEFAULT_MAXBADGESIZE_SEQ 15000 /**< the max badge size in Probing if PaPILO is executed in sequential mode */
130#define DEFAULT_MAXBADGESIZE_PAR (-1) /**< the max badge size in Probing if PaPILO is executed in parallel mode */
131#define DEFAULT_MARKOWITZTOLERANCE 0.01 /**< the markowitz tolerance used for substitutions */
132#define DEFAULT_MAXFILLINPERSUBST 3 /**< maximal possible fillin for substitutions to be considered */
133#define DEFAULT_MAXSHIFTPERROW 10 /**< maximal amount of nonzeros allowed to be shifted to make space for substitutions */
134
135/** debug options for PaPILO */
136#define DEFAULT_FILENAME_PROBLEM "-" /**< default filename to store the instance before presolving */
137#define DEFAULT_VERBOSITY 0
138
139/*
140 * Data structures
141 */
142
143/** presolver data */
144struct SCIP_PresolData
145{
146 int lastncols; /**< the number of columns from the last call */
147 int lastnrows; /**< the number of rows from the last call */
148 int threads; /**< maximum number of threads presolving may use (0: automatic) */
149 int maxfillinpersubstitution; /**< maximal possible fillin for substitutions to be considered */
150 int maxbadgesizeseq; /**< the max badge size in Probing if PaPILO is called in sequential mode */
151 int maxbadgesizepar; /**< the max badge size in Probing if PaPILO is called in parallel mode */
152 int internalmaxrounds; /**< internal max rounds in PaPILO (-1: no limit, 0: model cleanup) */
153 int maxshiftperrow; /**< maximal amount of nonzeros allowed to be shifted to make space for substitutions */
154 int detectlineardependency; /**< should linear dependent equations and free columns be removed? (0: never, 1: for LPs, 2: always) */
155 int randomseed; /**< the random seed used for randomization of tie breaking */
156 int verbosity;
157
158 SCIP_Bool enablesparsify; /**< should the sparsify presolver be enabled within the presolve library? */
159 SCIP_Bool enabledomcol; /**< should the dominated column presolver be enabled within the presolve library? */
160 SCIP_Bool enableprobing; /**< should the probing presolver be enabled within the presolve library? */
161 SCIP_Bool enabledualinfer; /**< should the dualinfer presolver be enabled within the presolve library? */
162 SCIP_Bool enablemultiaggr; /**< should the multi-aggregation presolver be enabled within the presolve library? */
163 SCIP_Bool enableparallelrows; /**< should the parallel rows presolver be enabled within the presolve library? */
164 SCIP_Real modifyconsfac; /**< modify SCIP constraints when the number of nonzeros or rows is at most this
165 * factor times the number of nonzeros or rows before presolving */
166 SCIP_Real markowitztolerance; /**< the markowitz tolerance used for substitutions */
167 SCIP_Real hugebound; /**< absolute bound value that is considered too huge for activitity based calculations */
168 SCIP_Real abortfacexhaustive; /**< abort factor for exhaustive presolving in PAPILO */
169 SCIP_Real abortfacmedium; /**< abort factor for medium presolving in PAPILO */
170 SCIP_Real abortfacfast; /**< abort factor for fast presolving in PAPILO */
171
172 char* filename = NULL; /**< filename to store the instance before presolving */
173};
174
175using namespace papilo;
176
177/*
178 * Local methods
179 */
180
181/** builds the presolvelib problem datastructure from the matrix */
182static
183Problem<SCIP_Real> buildProblem(
184 SCIP* scip, /**< SCIP data structure */
185 SCIP_MATRIX* matrix /**< initialized SCIP_MATRIX data structure */
186 )
187{
188 ProblemBuilder<SCIP_Real> builder;
189
190 /* build problem from matrix */
191 int nnz = SCIPmatrixGetNNonzs(matrix);
192 int ncols = SCIPmatrixGetNColumns(matrix);
193 int nrows = SCIPmatrixGetNRows(matrix);
194 builder.reserve(nnz, nrows, ncols);
195
196 /* set up columns */
197 builder.setNumCols(ncols);
198 for(int i = 0; i != ncols; ++i)
199 {
200 SCIP_VAR* var = SCIPmatrixGetVar(matrix, i);
203 builder.setColLb(i, lb);
204 builder.setColUb(i, ub);
205 builder.setColLbInf(i, SCIPisInfinity(scip, -lb));
206 builder.setColUbInf(i, SCIPisInfinity(scip, ub));
207#if PAPILO_VERSION_MAJOR > 2 || (PAPILO_VERSION_MAJOR == 2 && PAPILO_VERSION_MINOR >= 1)
209 builder.setColImplInt(i, TRUE);
210 else
211 builder.setColIntegral(i, SCIPvarIsIntegral(var));
212#else
213 builder.setColIntegral(i, SCIPvarIsIntegral(var));
214#endif
215 builder.setObj(i, SCIPvarGetObj(var));
216 }
217
218 /* set up rows */
219 builder.setNumRows(nrows);
220 for(int i = 0; i != nrows; ++i)
221 {
222 int* rowcols = SCIPmatrixGetRowIdxPtr(matrix, i);
223 SCIP_Real* rowvals = SCIPmatrixGetRowValPtr(matrix, i);
224 int rowlen = SCIPmatrixGetRowNNonzs(matrix, i);
225 builder.addRowEntries(i, rowlen, rowcols, rowvals);
226
227 SCIP_Real lhs = SCIPmatrixGetRowLhs(matrix, i);
228 SCIP_Real rhs = SCIPmatrixGetRowRhs(matrix, i);
229 builder.setRowLhs(i, lhs);
230 builder.setRowRhs(i, rhs);
231 builder.setRowLhsInf(i, SCIPisInfinity(scip, -lhs));
232 builder.setRowRhsInf(i, SCIPisInfinity(scip, rhs));
233 }
234
235 /* init objective offset - the value itself is irrelevant */
236 builder.setObjOffset(0);
237
238#ifdef SCIP_PRESOLLIB_ENABLE_OUTPUT
239 /* show problem name */
240 builder.setProblemName(SCIPgetProbName(scip));
241#endif
242
243 return builder.build();
244}
245
246/** sets up the presolvelib presolve datastructure from the data */
247static
248Presolve<SCIP_Real> setupPresolve(
249 SCIP* scip, /**< SCIP data structure */
250 SCIP_PRESOLDATA* data, /**< presolver data structure */
251 SCIP_Bool allowconsmodification /**< whether constraint modifications are allowed */
252 )
253{
254 Presolve<SCIP_Real> presolve;
255 SCIP_Real timelimit;
256
257 /* important so that SCIP does not throw an error, e.g. when an integer variable is substituted
258 * into a knapsack constraint */
259 presolve.getPresolveOptions().substitutebinarieswithints = false;
260
261 /* currently these changes cannot be communicated to SCIP correctly since a constraint needs
262 * to be modified in the cases where slackvariables are removed from constraints but for the
263 * presolve library those look like normal substitution on the postsolve stack */
264 presolve.getPresolveOptions().removeslackvars = false;
265
266 /* communicate the SCIP parameters to the presolve library */
267 presolve.getPresolveOptions().maxfillinpersubstitution = data->maxfillinpersubstitution;
268 presolve.getPresolveOptions().markowitz_tolerance = data->markowitztolerance;
269 presolve.getPresolveOptions().maxshiftperrow = data->maxshiftperrow;
270 presolve.getPresolveOptions().hugeval = data->hugebound;
271
272 /* removal of linear dependent equations has only an effect when constraint modifications are communicated */
273 presolve.getPresolveOptions().detectlindep = allowconsmodification ? data->detectlineardependency : 0;
274
275 /* communicate the random seed */
276 presolve.getPresolveOptions().randomseed = SCIPinitializeRandomSeed(scip, (unsigned int)data->randomseed);
277
278 /* set number of threads to be used for presolve */
279 presolve.getPresolveOptions().threads = data->threads;
280
281#if PAPILO_VERSION_MAJOR > 2 || (PAPILO_VERSION_MAJOR == 2 && PAPILO_VERSION_MINOR >= 3)
282 presolve.getPresolveOptions().maxrounds = data->internalmaxrounds;
283#endif
284
285 /* disable dual reductions that are not permitted */
287 presolve.getPresolveOptions().dualreds = 2;
288 else if( SCIPallowWeakDualReds(scip) )
289 presolve.getPresolveOptions().dualreds = 1;
290 else
291 presolve.getPresolveOptions().dualreds = 0;
292
293 /* set up the presolvers that shall participate */
294 using uptr = std::unique_ptr<PresolveMethod<SCIP_Real>>;
295
296 /* fast presolvers*/
297 presolve.addPresolveMethod( uptr( new SingletonCols<SCIP_Real>() ) );
298 presolve.addPresolveMethod( uptr( new CoefficientStrengthening<SCIP_Real>() ) );
299 presolve.addPresolveMethod( uptr( new ConstraintPropagation<SCIP_Real>() ) );
300
301 /* medium presolver */
302 presolve.addPresolveMethod( uptr( new SimpleProbing<SCIP_Real>() ) );
303 if( data->enableparallelrows )
304 presolve.addPresolveMethod( uptr( new ParallelRowDetection<SCIP_Real>() ) );
305 /* todo: parallel cols cannot be handled by SCIP currently
306 * addPresolveMethod( uptr( new ParallelColDetection<SCIP_Real>() ) ); */
307 presolve.addPresolveMethod( uptr( new SingletonStuffing<SCIP_Real>() ) );
308#if PAPILO_VERSION_MAJOR > 2 || (PAPILO_VERSION_MAJOR == 2 && PAPILO_VERSION_MINOR >= 1)
309 DualFix<SCIP_Real> *dualfix = new DualFix<SCIP_Real>();
310 dualfix->set_fix_to_infinity_allowed(false);
311 presolve.addPresolveMethod( uptr( dualfix ) );
312#else
313 presolve.addPresolveMethod( uptr( new DualFix<SCIP_Real>() ) );
314#endif
315 presolve.addPresolveMethod( uptr( new FixContinuous<SCIP_Real>() ) );
316 presolve.addPresolveMethod( uptr( new SimplifyInequalities<SCIP_Real>() ) );
317 presolve.addPresolveMethod( uptr( new SimpleSubstitution<SCIP_Real>() ) );
318
319 /* exhaustive presolvers*/
320 presolve.addPresolveMethod( uptr( new ImplIntDetection<SCIP_Real>() ) );
321 if( data->enabledualinfer )
322 presolve.addPresolveMethod( uptr( new DualInfer<SCIP_Real>() ) );
323 if( data->enableprobing )
324 {
325#if PAPILO_VERSION_MAJOR > 2 || (PAPILO_VERSION_MAJOR == 2 && PAPILO_VERSION_MINOR >= 1)
326 Probing<SCIP_Real> *probing = new Probing<SCIP_Real>();
327 if( presolve.getPresolveOptions().runs_sequential() )
328 {
329 probing->set_max_badge_size( data->maxbadgesizeseq );
330 }
331 else
332 {
333 probing->set_max_badge_size( data->maxbadgesizepar );
334 }
335 presolve.addPresolveMethod( uptr( probing ) );
336#else
337 presolve.addPresolveMethod( uptr( new Probing<SCIP_Real>() ) );
338 if( data->maxbadgesizeseq != DEFAULT_MAXBADGESIZE_SEQ )
340 " The parameter 'presolving/milp/maxbadgesizeseq' can only be used with PaPILO 2.1.0 or later versions.\n");
341
342 if( data->maxbadgesizepar != DEFAULT_MAXBADGESIZE_PAR )
344 " The parameter 'presolving/milp/maxbadgesizepar' can only be used with PaPILO 2.1.0 or later versions.\n");
345#endif
346 }
347 if( data->enabledomcol )
348 presolve.addPresolveMethod( uptr( new DominatedCols<SCIP_Real>() ) );
349 if( data->enablemultiaggr )
350 presolve.addPresolveMethod( uptr( new Substitution<SCIP_Real>() ) );
351 if( data->enablesparsify )
352 presolve.addPresolveMethod( uptr( new Sparsify<SCIP_Real>() ) );
353
354 /* set tolerances */
355 presolve.getPresolveOptions().feastol = SCIPfeastol(scip);
356 presolve.getPresolveOptions().epsilon = SCIPepsilon(scip);
357#if PAPILO_APIVERSION >= 3
358 presolve.getPresolveOptions().useabsfeas = false;
359#endif
360
361#ifndef SCIP_PRESOLLIB_ENABLE_OUTPUT
362 /* adjust output settings of presolve library */
363 presolve.setVerbosityLevel((VerbosityLevel) data->verbosity);
364#endif
365
366#if PAPILO_APIVERSION >= 2
367 presolve.getPresolveOptions().abortfac = data->abortfacexhaustive;
368 presolve.getPresolveOptions().abortfacmedium = data->abortfacmedium;
369 presolve.getPresolveOptions().abortfacfast = data->abortfacfast;
370#endif
371
372 /* communicate the time limit */
373 SCIPgetRealParam(scip, "limits/time", &timelimit);
374 if( !SCIPisInfinity(scip, timelimit) )
375 presolve.getPresolveOptions().tlim = timelimit - SCIPgetSolvingTime(scip);
376
377 return presolve;
378}
379
380/*
381 * Callback methods of presolver
382 */
383
384/** copy method for constraint handler plugins (called when SCIP copies plugins) */
385static
386SCIP_DECL_PRESOLCOPY(presolCopyMILP)
387{ /*lint --e{715}*/
389
390 return SCIP_OKAY;
391}
392
393/** destructor of presolver to free user data (called when SCIP is exiting) */
394static
395SCIP_DECL_PRESOLFREE(presolFreeMILP)
396{ /*lint --e{715}*/
397 SCIP_PRESOLDATA* data = SCIPpresolGetData(presol);
398 assert(data != NULL);
399
400 SCIPpresolSetData(presol, NULL);
402 return SCIP_OKAY;
403}
404
405/** initialization method of presolver (called after problem was transformed) */
406static
407SCIP_DECL_PRESOLINIT(presolInitMILP)
408{ /*lint --e{715}*/
409 SCIP_PRESOLDATA* data = SCIPpresolGetData(presol);
410 assert(data != NULL);
411
412 data->lastncols = -1;
413 data->lastnrows = -1;
414
415 return SCIP_OKAY;
416}
417
418/** execution method of presolver */
419static
420SCIP_DECL_PRESOLEXEC(presolExecMILP)
421{ /*lint --e{715}*/
422 SCIP_MATRIX* matrix;
423 SCIP_PRESOLDATA* data;
424 SCIP_Bool initialized;
425 SCIP_Bool complete;
426 SCIP_Bool infeasible;
427
428 *result = SCIP_DIDNOTRUN;
429
430 data = SCIPpresolGetData(presol);
431
432 int nvars = SCIPgetNVars(scip);
433 int nconss = SCIPgetNConss(scip);
434
435 /* run only if the problem size reduced by some amount since the last call or if it is the first call */
436 if( data->lastncols != -1 && data->lastnrows != -1 &&
437 nvars > data->lastncols * 0.85 &&
438 nconss > data->lastnrows * 0.85 )
439 return SCIP_OKAY;
440
441 SCIP_CALL( SCIPmatrixCreate(scip, &matrix, TRUE, &initialized, &complete, &infeasible,
442 naddconss, ndelconss, nchgcoefs, nchgbds, nfixedvars) );
443
444 /* if infeasibility was detected during matrix creation, return here */
445 if( infeasible )
446 {
447 if( initialized )
448 SCIPmatrixFree(scip, &matrix);
449
450 *result = SCIP_CUTOFF;
451 return SCIP_OKAY;
452 }
453
454 /* we only work on pure MIPs, also disable to try building the matrix again if it failed once */
455 if( !initialized || !complete )
456 {
457 data->lastncols = 0;
458 data->lastnrows = 0;
459
460 if( initialized )
461 SCIPmatrixFree(scip, &matrix);
462
463 return SCIP_OKAY;
464 }
465
466 if( 0 != strncmp(data->filename, DEFAULT_FILENAME_PROBLEM, strlen(DEFAULT_FILENAME_PROBLEM)) )
467 {
469 " writing transformed problem to %s (only enforced constraints)\n", data->filename);
470 SCIP_CALL(SCIPwriteTransProblem(scip, data->filename, NULL, FALSE));
471 }
472
473 /* only allow communication of constraint modifications by deleting all constraints when some already have been upgraded */
474 SCIP_CONSHDLR* linconshdlr = SCIPfindConshdlr(scip, "linear");
475 assert(linconshdlr != NULL);
476 SCIP_Bool allowconsmodification = (SCIPconshdlrGetNCheckConss(linconshdlr) == SCIPmatrixGetNRows(matrix));
477
478 /* store current numbers of aggregations, fixings, and changed bounds for statistics */
479 int oldnaggrvars = *naggrvars;
480 int oldnfixedvars = *nfixedvars;
481 int oldnchgbds = *nchgbds;
482
483 /* create presolving objects */
484 Problem<SCIP_Real> problem = buildProblem(scip, matrix);
485 int oldnnz = problem.getConstraintMatrix().getNnz();
486 Presolve<SCIP_Real> presolve = setupPresolve(scip, data, allowconsmodification);
487
488 /* call the presolving */
490 " (%.1fs) running MILP presolver\n", SCIPgetSolvingTime(scip));
491
492 /*call presolving without storing information for dual postsolve*/
493#if (PAPILO_VERSION_MAJOR >= 2)
494 PresolveResult<SCIP_Real> res = presolve.apply(problem, false);
495#else
496 PresolveResult<SCIP_Real> res = presolve.apply(problem);
497#endif
498 data->lastncols = problem.getNCols();
499 data->lastnrows = problem.getNRows();
500
501 /* evaluate the result */
502 switch(res.status)
503 {
504 case PresolveStatus::kInfeasible:
505 *result = SCIP_CUTOFF;
507 " (%.1fs) MILP presolver detected infeasibility\n",
509 SCIPmatrixFree(scip, &matrix);
510 return SCIP_OKAY;
511 case PresolveStatus::kUnbndOrInfeas:
512 case PresolveStatus::kUnbounded:
513 *result = SCIP_UNBOUNDED;
515 " (%.1fs) MILP presolver detected unboundedness\n",
517 SCIPmatrixFree(scip, &matrix);
518 return SCIP_OKAY;
519 case PresolveStatus::kUnchanged:
520 *result = SCIP_DIDNOTFIND;
521 data->lastncols = nvars;
522 data->lastnrows = nconss;
524 " (%.1fs) MILP presolver found nothing\n",
526 SCIPmatrixFree(scip, &matrix);
527 return SCIP_OKAY;
528 case PresolveStatus::kReduced:
529 data->lastncols = problem.getNCols();
530 data->lastnrows = problem.getNRows();
531 *result = SCIP_SUCCESS;
532 }
533
534 /* result indicated success, now populate the changes into the SCIP structures */
535
536 /* tighten bounds of variables that are still present after presolving */
537 VariableDomains<SCIP_Real>& varDomains = problem.getVariableDomains();
538 for( int i = 0; i != problem.getNCols(); ++i )
539 {
540 assert( ! varDomains.flags[i].test(ColFlag::kInactive) );
541 SCIP_VAR* var = SCIPmatrixGetVar(matrix, res.postsolve.origcol_mapping[i]);
542 if( !varDomains.flags[i].test(ColFlag::kLbInf) )
543 {
544 SCIP_Bool infeas;
545 SCIP_Bool tightened;
546 SCIP_CALL( SCIPtightenVarLb(scip, var, varDomains.lower_bounds[i], TRUE, &infeas, &tightened) );
547
548 if( tightened )
549 *nchgbds += 1;
550
551 if( infeas )
552 {
553 *result = SCIP_CUTOFF;
554 break;
555 }
556 }
557
558 if( !varDomains.flags[i].test(ColFlag::kUbInf) )
559 {
560 SCIP_Bool infeas;
561 SCIP_Bool tightened;
562 SCIP_CALL( SCIPtightenVarUb(scip, var, varDomains.upper_bounds[i], TRUE, &infeas, &tightened) );
563
564 if( tightened )
565 *nchgbds += 1;
566
567 if( infeas )
568 {
569 *result = SCIP_CUTOFF;
570 break;
571 }
572 }
573 }
574
575 if( *result == SCIP_CUTOFF )
576 {
578 " (%.1fs) MILP presolver detected infeasibility\n",
580 SCIPmatrixFree(scip, &matrix);
581 return SCIP_OKAY;
582 }
583
584 /* transfer variable fixings and aggregations */
585 std::vector<SCIP_VAR*> tmpvars;
586 std::vector<SCIP_Real> tmpvals;
587
588 /* if the size of the problem decreased by a sufficient factor, create all constraints from scratch if allowed */
589 int newnnz = problem.getConstraintMatrix().getNnz();
590 bool constraintsReplaced = false;
591 if( newnnz == 0 || (allowconsmodification &&
592 (problem.getNCols() <= data->modifyconsfac * SCIPmatrixGetNColumns(matrix) ||
593 problem.getNRows() <= data->modifyconsfac * SCIPmatrixGetNRows(matrix) ||
594 newnnz <= data->modifyconsfac * oldnnz)) )
595 {
596 int oldnrows = SCIPmatrixGetNRows(matrix);
597 int newnrows = problem.getNRows();
598
599 constraintsReplaced = true;
600
601 /* capture constraints that are still present in the problem after presolve */
602 for( int i = 0; i < newnrows; ++i )
603 {
604 SCIP_CONS* c = SCIPmatrixGetCons(matrix, res.postsolve.origrow_mapping[i]);
606 }
607
608 /* delete all constraints */
609 *ndelconss += oldnrows;
610 *naddconss += newnrows;
611
612 for( int i = 0; i < oldnrows; ++i )
613 {
615 }
616
617 /* now loop over rows of presolved problem and create them as new linear constraints,
618 * then release the old constraint after its name was passed to the new constraint */
619 const Vec<RowFlags>& rflags = problem.getRowFlags();
620 const auto& consmatrix = problem.getConstraintMatrix();
621 for( int i = 0; i < newnrows; ++i )
622 {
623 auto rowvec = consmatrix.getRowCoefficients(i);
624 const int* rowcols = rowvec.getIndices();
625 /* SCIPcreateConsBasicLinear() requires a non const pointer */
626 SCIP_Real* rowvals = const_cast<SCIP_Real*>(rowvec.getValues());
627 int rowlen = rowvec.getLength();
628
629 /* retrieve SCIP compatible left and right hand sides */
630 SCIP_Real lhs = rflags[i].test(RowFlag::kLhsInf) ? - SCIPinfinity(scip) : consmatrix.getLeftHandSides()[i];
631 SCIP_Real rhs = rflags[i].test(RowFlag::kRhsInf) ? SCIPinfinity(scip) : consmatrix.getRightHandSides()[i];
632
633 /* create variable array matching the value array */
634 tmpvars.clear();
635 tmpvars.reserve(rowlen);
636 for( int j = 0; j < rowlen; ++j )
637 tmpvars.push_back(SCIPmatrixGetVar(matrix, res.postsolve.origcol_mapping[rowcols[j]]));
638
639 /* create and add new constraint with name of old constraint */
640 SCIP_CONS* oldcons = SCIPmatrixGetCons(matrix, res.postsolve.origrow_mapping[i]);
641 SCIP_CONS* cons;
642 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, SCIPconsGetName(oldcons), rowlen, tmpvars.data(), rowvals, lhs, rhs) );
643 SCIP_CALL( SCIPaddCons(scip, cons) );
644
645 /* release old and new constraint */
646 SCIP_CALL( SCIPreleaseCons(scip, &oldcons) );
647 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
648 }
649 }
650
651 /* PaPILO's aggregations are valid regarding the constraints as they were presolved by PaPILO.
652 * If coefficients were changed, but constraints in SCIP are not replaced by those from PaPILO,
653 * then it can not be guaranteed that the bounds of multiaggregated variables will be enforced,
654 * i.e., will be implied by the constraints in SCIP (see also #3704).
655 * Only for variable aggregations, SCIP will ensure this by tightening the bounds on the aggregation
656 * variable as part of SCIPaggregateVars(). For multiaggregations, we will only accept those
657 * where we can be sure with a simple check that the bounds on the aggregated variable are implied.
658 */
659 bool checkmultaggr =
660#if PAPILO_APIVERSION >= 1
661 presolve.getStatistics().single_matrix_coefficient_changes > 0
662#else
663 presolve.getStatistics().ncoefchgs > 0
664#endif
665 && !constraintsReplaced;
666
667 /* loop over res.postsolve and add all fixed variables and aggregations to scip */
668 for( std::size_t i = 0; i != res.postsolve.types.size(); ++i )
669 {
670 ReductionType type = res.postsolve.types[i];
671 int first = res.postsolve.start[i];
672 int last = res.postsolve.start[i + 1];
673
674 switch( type )
675 {
676 case ReductionType::kFixedCol:
677 {
678 SCIP_Bool infeas;
679 SCIP_Bool fixed;
680 int col = res.postsolve.indices[first];
681
682 SCIP_VAR* var = SCIPmatrixGetVar(matrix, col);
683
684 SCIP_Real value = res.postsolve.values[first];
685
686 SCIP_CALL( SCIPfixVar(scip, var, value, &infeas, &fixed) );
687 *nfixedvars += 1;
688
689 assert(!infeas);
690 /* SCIP has different rules for aggregating variables than PaPILO: therefore the variable PaPILO
691 * tries to fix now may have been aggregated by SCIP before. Additionally, after aggregation SCIP
692 * sometimes performs bound tightening resulting in possible fixings. These cases need to be excluded. */
693 assert(fixed || SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED ||
695 break;
696 }
697/*
698 * Dual-postsolving in PaPILO required introducing a postsolve-type for substitution with additional information.
699 * Further, the different Substitution-postsolving types store the required postsolving data differently (in different order) in the postsolving stack.
700 * Therefore, we need to distinguish how to parse the required data (rowLength, col, side, startRowCoefficients, lastRowCoefficients) from the postsolving stack.
701 * If these values are accessed, the procedure is the same for both.
702 */
703#if (PAPILO_VERSION_MAJOR >= 2)
704 case ReductionType::kSubstitutedColWithDual:
705#endif
706 case ReductionType::kSubstitutedCol:
707 {
708 int col = 0;
709 SCIP_Real side = 0;
710
711 int rowlen = 0;
712 int startRowCoefficients = 0;
713 int lastRowCoefficients = 0;
714
715 if( type == ReductionType::kSubstitutedCol )
716 {
717 rowlen = last - first - 1;
718 col = res.postsolve.indices[first];
719 side = res.postsolve.values[first];
720
721 startRowCoefficients = first + 1;
722 lastRowCoefficients = last;
723 }
724#if (PAPILO_VERSION_MAJOR >= 2)
725 if( type == ReductionType::kSubstitutedColWithDual )
726 {
727 rowlen = (int) res.postsolve.values[first];
728 col = res.postsolve.indices[first + 3 + rowlen];
729 side = res.postsolve.values[first + 1];
730
731 startRowCoefficients = first + 3;
732 lastRowCoefficients = first + 3 + rowlen;
733
734 assert(side == res.postsolve.values[first + 2]);
735 assert(res.postsolve.indices[first + 1] == 0);
736 assert(res.postsolve.indices[first + 2] == 0);
737 }
738 assert( type == ReductionType::kSubstitutedCol || type == ReductionType::kSubstitutedColWithDual );
739#else
740 assert( type == ReductionType::kSubstitutedCol );
741#endif
742 SCIP_Bool infeas;
743 SCIP_Bool aggregated;
744 SCIP_Bool redundant = FALSE;
745 SCIP_Real constant = 0.0;
746 if( rowlen == 2 )
747 {
748 SCIP_Real updatedSide;
749 SCIP_VAR* varx = SCIPmatrixGetVar(matrix, res.postsolve.indices[startRowCoefficients]);
750 SCIP_VAR* vary = SCIPmatrixGetVar(matrix, res.postsolve.indices[startRowCoefficients + 1]);
751 SCIP_Real scalarx = res.postsolve.values[startRowCoefficients];
752 SCIP_Real scalary = res.postsolve.values[startRowCoefficients + 1];
753
754 SCIP_CALL( SCIPgetProbvarSum(scip, &varx, &scalarx, &constant) );
756
757 SCIP_CALL( SCIPgetProbvarSum(scip, &vary, &scalary, &constant) );
759
760 /* If PaPILO tries to aggregate fixed variables then it missed some obvious fixings.
761 * This might happen if another aggregation leads to fixings which are not applied immediately by PaPILO.
762 * With the latest version of PaPILO, this should not occur.
763 */
765 {
766 SCIPdebugMsg(scip, "Aggregation of <%s> and <%s> rejected because they are already fixed.\n",
767 SCIPvarGetName(varx), SCIPvarGetName(vary));
768
769 break;
770 }
771
772 updatedSide = side - constant;
773
774 SCIP_CALL( SCIPaggregateVars(scip, varx, vary, scalarx, scalary, updatedSide, &infeas, &redundant, &aggregated) );
775 }
776 else
777 {
778 SCIP_Real colCoef = 0.0;
779 SCIP_Real updatedSide;
780 SCIP_Bool checklbimplied;
781 SCIP_Bool checkubimplied;
782 SCIP_Real impliedlb;
783 SCIP_Real impliedub;
784 int j;
785
786 for( j = startRowCoefficients; j < lastRowCoefficients; ++j )
787 {
788 if( res.postsolve.indices[j] == col )
789 {
790 colCoef = res.postsolve.values[j];
791 break;
792 }
793 }
794
795 tmpvars.clear();
796 tmpvals.clear();
797 tmpvars.reserve(rowlen);
798 tmpvals.reserve(rowlen);
799
800 assert(colCoef != 0.0);
801 SCIP_VAR* aggrvar = SCIPmatrixGetVar(matrix, col);
802
803 SCIP_CALL( SCIPgetProbvarSum(scip, &aggrvar, &colCoef, &constant) );
804 assert(SCIPvarGetStatus(aggrvar) != SCIP_VARSTATUS_MULTAGGR);
805
806 /* If PaPILO tries to multi-aggregate a fixed variable, then it missed some obvious fixings.
807 * This might happen if another aggregation leads to fixings which are not applied immediately by PaPILO.
808 * With the latest version of PaPILO, this should not occur.
809 */
810 if( SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_FIXED )
811 {
812 SCIPdebugMsg(scip, "Multi-aggregation of <%s> rejected because it is already fixed.\n",
813 SCIPvarGetName(aggrvar));
814
815 break;
816 }
817
818 updatedSide = side - constant;
819
820 /* we need to check whether lb/ub on aggrvar is implied by bounds of other variables in multiaggregation
821 * if checkmultaggr is TRUE and the lb/ub is finite
822 * it should be sufficient to ensure global bounds on aggrvar (and as we are in presolve, local=global anyway)
823 */
824 checklbimplied = checkmultaggr && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(aggrvar));
825 checkubimplied = checkmultaggr && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(aggrvar));
826 impliedlb = impliedub = updatedSide / colCoef;
827
828 for( j = startRowCoefficients; j < lastRowCoefficients; ++j )
829 {
830 SCIP_Real coef;
831 SCIP_VAR* var;
832
833 if( res.postsolve.indices[j] == col )
834 continue;
835
836 coef = - res.postsolve.values[j] / colCoef;
837 var = SCIPmatrixGetVar(matrix, res.postsolve.indices[j]);
838
839 if( checklbimplied )
840 {
841 if( coef > 0.0 )
842 {
843 /* if impliedlb will be -infinity, then we can give up: we cannot use this mutiaggregation */
845 break;
846 else
847 impliedlb += coef * SCIPvarGetLbLocal(var);
848 }
849 else
850 {
852 break;
853 else
854 impliedlb += coef * SCIPvarGetUbLocal(var);
855 }
856 }
857
858 if( checkubimplied )
859 {
860 if( coef > 0.0 )
861 {
863 break;
864 else
865 impliedub += coef * SCIPvarGetUbLocal(var);
866 }
867 else
868 {
870 break;
871 else
872 impliedub += coef * SCIPvarGetLbLocal(var);
873 }
874 }
875
876 tmpvals.push_back(coef);
877 tmpvars.push_back(var);
878 }
879
880 /* if implied bounds are not sufficient to ensure bounds on aggrvar, then we cannot use the multiaggregation */
881 if( j < lastRowCoefficients )
882 break;
883
884 if( checklbimplied && SCIPisGT(scip, SCIPvarGetLbGlobal(aggrvar), impliedlb) )
885 break;
886
887 if( checkubimplied && SCIPisLT(scip, SCIPvarGetUbGlobal(aggrvar), impliedub) )
888 break;
889
890 SCIP_CALL( SCIPmultiaggregateVar(scip, aggrvar, tmpvars.size(),
891 tmpvars.data(), tmpvals.data(), updatedSide / colCoef, &infeas, &aggregated) );
892 }
893
894 if( aggregated )
895 *naggrvars += 1;
896 else if( constraintsReplaced && !redundant )
897 {
898 /* if the constraints where replaced, we need to add the failed substitution as an equality to SCIP */
899 tmpvars.clear();
900 tmpvals.clear();
901 for( int j = startRowCoefficients; j < lastRowCoefficients; ++j )
902 {
903 tmpvars.push_back(SCIPmatrixGetVar(matrix, res.postsolve.indices[j]));
904 tmpvals.push_back(res.postsolve.values[j]);
905 }
906
907 SCIP_CONS* cons;
908 String name = fmt::format("{}_failed_aggregation_equality", SCIPvarGetName(SCIPmatrixGetVar(matrix, col)));
909 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, name.c_str(),
910 tmpvars.size(), tmpvars.data(), tmpvals.data(), side, side ) );
911 SCIP_CALL( SCIPaddCons(scip, cons) );
912 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
913 *naddconss += 1;
914 }
915
916 if( infeas )
917 {
918 *result = SCIP_CUTOFF;
919 break;
920 }
921
922 break;
923 }
924 case ReductionType::kParallelCol:
925 return SCIP_INVALIDRESULT;
926#if PAPILO_VERSION_MAJOR > 1 || (PAPILO_VERSION_MAJOR == 1 && PAPILO_VERSION_MINOR >= 1)
927 case ReductionType::kFixedInfCol: {
928 /* todo: currently SCIP can not handle this kind of reduction (see issue #3391) */
929 assert(false);
930 if(!constraintsReplaced)
931 continue;
932 SCIP_Bool infeas;
933 SCIP_Bool fixed;
934 SCIP_Real value = SCIPinfinity(scip);
935
936 int column = res.postsolve.indices[first];
937 bool is_negative_infinity = res.postsolve.values[first] < 0;
938 SCIP_VAR* column_variable = SCIPmatrixGetVar(matrix, column);
939
940 if( is_negative_infinity )
941 {
942 value = -SCIPinfinity(scip);
943 }
944
945 SCIP_CALL( SCIPfixVar(scip, column_variable, value, &infeas, &fixed) );
946 *nfixedvars += 1;
947
948 assert(!infeas);
949 assert(fixed);
950 break;
951 }
952#endif
953#if (PAPILO_VERSION_MAJOR >= 2)
954 case ReductionType::kVarBoundChange :
955 case ReductionType::kRedundantRow :
956 case ReductionType::kRowBoundChange :
957 case ReductionType::kReasonForRowBoundChangeForcedByRow :
958 case ReductionType::kRowBoundChangeForcedByRow :
959 case ReductionType::kSaveRow :
960 case ReductionType::kReducedBoundsCost :
961 case ReductionType::kColumnDualValue :
962 case ReductionType::kRowDualValue :
963 case ReductionType::kCoefficientChange :
964 // dual ReductionTypes should be only calculated for dual reductions and should not appear for MIP
965 SCIPerrorMessage("PaPILO: PaPILO should not return dual postsolving reductions in SCIP!!\n");
966 SCIPABORT(); /*lint --e{527}*/
967 break;
968#endif
969 default:
970 SCIPdebugMsg(scip, "PaPILO returned unknown data type: \n" );
971 continue;
972 }
973 }
974
975 /* finish with a final verb message and return */
977 " (%.1fs) MILP presolver (%d rounds): %d aggregations, %d fixings, %d bound changes\n",
978 SCIPgetSolvingTime(scip), presolve.getStatistics().nrounds, *naggrvars - oldnaggrvars,
979 *nfixedvars - oldnfixedvars, *nchgbds - oldnchgbds);
980
981 /* free the matrix */
982 assert(initialized);
983 SCIPmatrixFree(scip, &matrix);
984
985 return SCIP_OKAY;
986}
987
988
989/*
990 * presolver specific interface methods
991 */
992
993/** creates the MILP presolver and includes it in SCIP */
995 SCIP* scip /**< SCIP data structure */
996 )
997{
998 SCIP_PRESOLDATA* presoldata;
999 SCIP_PRESOL* presol;
1000
1001#if defined(PAPILO_VERSION_TWEAK) && PAPILO_VERSION_TWEAK != 0
1002 String name = fmt::format("PaPILO {}.{}.{}.{}", PAPILO_VERSION_MAJOR, PAPILO_VERSION_MINOR, PAPILO_VERSION_PATCH, PAPILO_VERSION_TWEAK);
1003#else
1004 String name = fmt::format("PaPILO {}.{}.{}", PAPILO_VERSION_MAJOR, PAPILO_VERSION_MINOR, PAPILO_VERSION_PATCH);
1005#endif
1006
1007#if defined(PAPILO_GITHASH_AVAILABLE) && defined(PAPILO_TBB)
1008 String desc = fmt::format("parallel presolve for integer and linear optimization (github.com/scipopt/papilo) (built with TBB) [GitHash: {}]", PAPILO_GITHASH);
1009#elif !defined(PAPILO_GITHASH_AVAILABLE) && !defined(PAPILO_TBB)
1010 String desc("parallel presolve for integer and linear optimization (github.com/scipopt/papilo)");
1011#elif defined(PAPILO_GITHASH_AVAILABLE) && !defined(PAPILO_TBB)
1012 String desc = fmt::format("parallel presolve for integer and linear optimization (github.com/scipopt/papilo) [GitHash: {}]", PAPILO_GITHASH);
1013#elif !defined(PAPILO_GITHASH_AVAILABLE) && defined(PAPILO_TBB)
1014 String desc = fmt::format("parallel presolve for integer and linear optimization (github.com/scipopt/papilo) (built with TBB)");
1015#endif
1016
1017 /* add external code info for the presolve library */
1018 SCIP_CALL( SCIPincludeExternalCodeInformation(scip, name.c_str(), desc.c_str()) );
1019
1020 /* create MILP presolver data */
1021 presoldata = NULL;
1022 SCIP_CALL( SCIPallocBlockMemory(scip, &presoldata) );
1023 BMSclearMemory(presoldata);
1024
1025 presol = NULL;
1026
1027 /* include presolver */
1029 presolExecMILP,
1030 presoldata) );
1031
1032 assert(presol != NULL);
1033
1034 /* set non fundamental callbacks via setter functions */
1035 SCIP_CALL( SCIPsetPresolCopy(scip, presol, presolCopyMILP) );
1036 SCIP_CALL( SCIPsetPresolFree(scip, presol, presolFreeMILP) );
1037 SCIP_CALL( SCIPsetPresolInit(scip, presol, presolInitMILP) );
1038
1039 /* add MILP presolver parameters */
1040#ifdef PAPILO_TBB
1042 "presolving/" PRESOL_NAME "/threads",
1043 "maximum number of threads presolving may use (0: automatic)",
1044 &presoldata->threads, FALSE, DEFAULT_THREADS, 0, INT_MAX, NULL, NULL) );
1045#else
1046 presoldata->threads = DEFAULT_THREADS;
1047#endif
1048
1050 "presolving/" PRESOL_NAME "/maxfillinpersubstitution",
1051 "maximal possible fillin for substitutions to be considered",
1052 &presoldata->maxfillinpersubstitution, FALSE, DEFAULT_MAXFILLINPERSUBST, INT_MIN, INT_MAX, NULL, NULL) );
1053
1055 "presolving/" PRESOL_NAME "/maxshiftperrow",
1056 "maximal amount of nonzeros allowed to be shifted to make space for substitutions",
1057 &presoldata->maxshiftperrow, TRUE, DEFAULT_MAXSHIFTPERROW, 0, INT_MAX, NULL, NULL) );
1058
1060 "presolving/" PRESOL_NAME "/randomseed",
1061 "the random seed used for randomization of tie breaking",
1062 &presoldata->randomseed, FALSE, DEFAULT_RANDOMSEED, INT_MIN, INT_MAX, NULL, NULL) );
1063
1064 if( DependentRows<double>::Enabled )
1065 {
1067 "presolving/" PRESOL_NAME "/detectlineardependency",
1068 "should linear dependent equations and free columns be removed? (0: never, 1: for LPs, 2: always)",
1069 &presoldata->detectlineardependency, TRUE, DEFAULT_DETECTLINDEP, 0, 2, NULL, NULL) );
1070 }
1071 else
1072 presoldata->detectlineardependency = DEFAULT_DETECTLINDEP;
1073
1075 "presolving/" PRESOL_NAME "/modifyconsfac",
1076 "modify SCIP constraints when the number of nonzeros or rows is at most this factor "
1077 "times the number of nonzeros or rows before presolving",
1078 &presoldata->modifyconsfac, FALSE, DEFAULT_MODIFYCONSFAC, 0.0, 1.0, NULL, NULL) );
1079
1081 "presolving/" PRESOL_NAME "/markowitztolerance",
1082 "the markowitz tolerance used for substitutions",
1083 &presoldata->markowitztolerance, FALSE, DEFAULT_MARKOWITZTOLERANCE, 0.0, 1.0, NULL, NULL) );
1084
1086 "presolving/" PRESOL_NAME "/hugebound",
1087 "absolute bound value that is considered too huge for activity based calculations",
1088 &presoldata->hugebound, FALSE, DEFAULT_HUGEBOUND, 0.0, SCIP_REAL_MAX, NULL, NULL) );
1089
1090#if PAPILO_APIVERSION >= 2
1091 SCIP_CALL( SCIPaddRealParam(scip, "presolving/" PRESOL_NAME "/abortfacexhaustive",
1092 "abort threshold for exhaustive presolving in PAPILO",
1093 &presoldata->abortfacexhaustive, TRUE, DEFAULT_ABORTFAC_EXHAUSTIVE, 0.0, 1.0, NULL, NULL) );
1094 SCIP_CALL( SCIPaddRealParam(scip, "presolving/" PRESOL_NAME "/abortfacmedium",
1095 "abort threshold for medium presolving in PAPILO",
1096 &presoldata->abortfacmedium, TRUE, DEFAULT_ABORTFAC_MEDIUM, 0.0, 1.0, NULL, NULL) );
1097 SCIP_CALL( SCIPaddRealParam(scip, "presolving/" PRESOL_NAME "/abortfacfast",
1098 "abort threshold for fast presolving in PAPILO",
1099 &presoldata->abortfacfast, TRUE, DEFAULT_ABORTFAC_FAST, 0.0, 1.0, NULL, NULL) );
1100#else
1101 presoldata->abortfacexhaustive = DEFAULT_ABORTFAC_EXHAUSTIVE;
1102 presoldata->abortfacmedium = DEFAULT_ABORTFAC_MEDIUM;
1103 presoldata->abortfacfast = DEFAULT_ABORTFAC_FAST;
1104#endif
1105
1106#if PAPILO_VERSION_MAJOR > 2 || (PAPILO_VERSION_MAJOR == 2 && PAPILO_VERSION_MINOR >= 1)
1107 SCIP_CALL(SCIPaddIntParam(scip, "presolving/" PRESOL_NAME "/maxbadgesizeseq",
1108 "maximal badge size in Probing in PaPILO if PaPILO is executed in sequential mode",
1109 &presoldata->maxbadgesizeseq, FALSE, DEFAULT_MAXBADGESIZE_SEQ, -1, INT_MAX, NULL, NULL));
1110
1111 SCIP_CALL(SCIPaddIntParam(scip, "presolving/" PRESOL_NAME "/maxbadgesizepar",
1112 "maximal badge size in Probing in PaPILO if PaPILO is executed in parallel mode",
1113 &presoldata->maxbadgesizepar, FALSE, DEFAULT_MAXBADGESIZE_PAR, -1, INT_MAX, NULL, NULL));
1114#else
1115 presoldata->maxbadgesizeseq = DEFAULT_MAXBADGESIZE_SEQ;
1116 presoldata->maxbadgesizepar = DEFAULT_MAXBADGESIZE_PAR;
1117#endif
1118
1119#if PAPILO_VERSION_MAJOR > 2 || (PAPILO_VERSION_MAJOR == 2 && PAPILO_VERSION_MINOR >= 3)
1120 SCIP_CALL(SCIPaddIntParam(scip, "presolving/" PRESOL_NAME "/internalmaxrounds",
1121 "internal maxrounds for each milp presolving (-1: no limit, 0: model cleanup)",
1122 &presoldata->internalmaxrounds, TRUE, DEFAULT_INTERNAL_MAXROUNDS, -1, INT_MAX, NULL, NULL));
1123#else
1124 presoldata->internalmaxrounds = DEFAULT_INTERNAL_MAXROUNDS;
1125#endif
1126
1128 "presolving/" PRESOL_NAME "/enableparallelrows",
1129 "should the parallel rows presolver be enabled within the presolve library?",
1130 &presoldata->enableparallelrows, TRUE, DEFAULT_ENABLEPARALLELROWS, NULL, NULL) );
1131
1133 "presolving/" PRESOL_NAME "/enabledomcol",
1134 "should the dominated column presolver be enabled within the presolve library?",
1135 &presoldata->enabledomcol, TRUE, DEFAULT_ENABLEDOMCOL, NULL, NULL) );
1136
1138 "presolving/" PRESOL_NAME "/enabledualinfer",
1139 "should the dualinfer presolver be enabled within the presolve library?",
1140 &presoldata->enabledualinfer, TRUE, DEFAULT_ENABLEDUALINFER, NULL, NULL) );
1141
1143 "presolving/" PRESOL_NAME "/enablemultiaggr",
1144 "should the multi-aggregation presolver be enabled within the presolve library?",
1145 &presoldata->enablemultiaggr, TRUE, DEFAULT_ENABLEMULTIAGGR, NULL, NULL) );
1146
1148 "presolving/" PRESOL_NAME "/enableprobing",
1149 "should the probing presolver be enabled within the presolve library?",
1150 &presoldata->enableprobing, TRUE, DEFAULT_ENABLEPROBING, NULL, NULL) );
1151
1153 "presolving/" PRESOL_NAME "/enablesparsify",
1154 "should the sparsify presolver be enabled within the presolve library?",
1155 &presoldata->enablesparsify, TRUE, DEFAULT_ENABLESPARSIFY, NULL, NULL) );
1156
1157 SCIP_CALL( SCIPaddStringParam(scip, "presolving/" PRESOL_NAME "/probfilename",
1158 "filename to store the problem before MILP presolving starts (only enforced constraints)",
1159 &presoldata->filename, TRUE, DEFAULT_FILENAME_PROBLEM, NULL, NULL) );
1160
1161 SCIP_CALL(SCIPaddIntParam(scip, "presolving/" PRESOL_NAME "/verbosity",
1162 "verbosity level of PaPILO (0: quiet, 1: errors, 2: warnings, 3: normal, 4: detailed)",
1163 &presoldata->verbosity, FALSE, DEFAULT_VERBOSITY, 0, 4, NULL, NULL));
1164
1165 return SCIP_OKAY;
1166}
1167
1168#endif
Constraint handler for linear constraints in their most general form, .
#define NULL
Definition: def.h:266
#define SCIP_REAL_MAX
Definition: def.h:173
#define SCIP_Bool
Definition: def.h:91
#define SCIP_Real
Definition: def.h:172
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define SCIPABORT()
Definition: def.h:345
#define SCIP_CALL(x)
Definition: def.h:373
SCIP_RETCODE SCIPcreateConsBasicLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs)
const char * SCIPgetProbName(SCIP *scip)
Definition: scip_prob.c:1067
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1992
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2770
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2843
int SCIPgetNConss(SCIP *scip)
Definition: scip_prob.c:3043
SCIP_RETCODE SCIPwriteTransProblem(SCIP *scip, const char *filename, const char *extension, SCIP_Bool genericnames)
Definition: scip_prob.c:648
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:225
#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 SCIPaddStringParam(SCIP *scip, const char *name, const char *desc, char **valueptr, SCIP_Bool isadvanced, const char *defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:194
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 SCIPgetRealParam(SCIP *scip, const char *name, SCIP_Real *value)
Definition: scip_param.c:307
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
SCIP_RETCODE SCIPincludePresolMILP(SCIP *scip)
Definition: presol_milp.cpp:47
int SCIPconshdlrGetNCheckConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4656
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:941
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8214
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1174
SCIP_RETCODE SCIPcaptureCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1139
SCIP_RETCODE SCIPincludeExternalCodeInformation(SCIP *scip, const char *name, const char *description)
Definition: scip_general.c:744
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
void SCIPpresolSetData(SCIP_PRESOL *presol, SCIP_PRESOLDATA *presoldata)
Definition: presol.c:522
SCIP_PRESOLDATA * SCIPpresolGetData(SCIP_PRESOL *presol)
Definition: presol.c:512
SCIP_RETCODE SCIPsetPresolInit(SCIP *scip, SCIP_PRESOL *presol, SCIP_DECL_PRESOLINIT((*presolinit)))
Definition: scip_presol.c:172
SCIP_RETCODE SCIPsetPresolFree(SCIP *scip, SCIP_PRESOL *presol, SCIP_DECL_PRESOLFREE((*presolfree)))
Definition: scip_presol.c:156
SCIP_RETCODE SCIPsetPresolCopy(SCIP *scip, SCIP_PRESOL *presol, SCIP_DECL_PRESOLCOPY((*presolcopy)))
Definition: scip_presol.c:140
SCIP_RETCODE SCIPincludePresolBasic(SCIP *scip, SCIP_PRESOL **presolptr, const char *name, const char *desc, int priority, int maxrounds, SCIP_PRESOLTIMING timing, SCIP_DECL_PRESOLEXEC((*presolexec)), SCIP_PRESOLDATA *presoldata)
Definition: scip_presol.c:105
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
Definition: scip_timing.c:378
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfeastol(SCIP *scip)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPepsilon(SCIP *scip)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5326
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:17558
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:18164
SCIP_RETCODE SCIPaggregateVars(SCIP *scip, SCIP_VAR *varx, SCIP_VAR *vary, SCIP_Real scalarx, SCIP_Real scalary, SCIP_Real rhs, SCIP_Bool *infeasible, SCIP_Bool *redundant, SCIP_Bool *aggregated)
Definition: scip_var.c:8524
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17946
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5443
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17604
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip_var.c:1794
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:18108
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17439
SCIP_RETCODE SCIPmultiaggregateVar(SCIP *scip, SCIP_VAR *var, int naggvars, SCIP_VAR **aggvars, SCIP_Real *scalars, SCIP_Real constant, SCIP_Bool *infeasible, SCIP_Bool *aggregated)
Definition: scip_var.c:8658
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:17630
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:18154
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:18098
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip_var.c:8399
SCIP_Bool SCIPallowWeakDualReds(SCIP *scip)
Definition: scip_var.c:8779
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition: scip_var.c:8752
unsigned int SCIPinitializeRandomSeed(SCIP *scip, unsigned int initialseedvalue)
int SCIPmatrixGetNNonzs(SCIP_MATRIX *matrix)
Definition: matrix.c:1778
int SCIPmatrixGetRowNNonzs(SCIP_MATRIX *matrix, int row)
Definition: matrix.c:1708
SCIP_Real SCIPmatrixGetRowLhs(SCIP_MATRIX *matrix, int row)
Definition: matrix.c:1742
SCIP_Real * SCIPmatrixGetRowValPtr(SCIP_MATRIX *matrix, int row)
Definition: matrix.c:1684
SCIP_Real SCIPmatrixGetRowRhs(SCIP_MATRIX *matrix, int row)
Definition: matrix.c:1754
SCIP_RETCODE SCIPmatrixCreate(SCIP *scip, SCIP_MATRIX **matrixptr, SCIP_Bool onlyifcomplete, SCIP_Bool *initialized, SCIP_Bool *complete, SCIP_Bool *infeasible, int *naddconss, int *ndelconss, int *nchgcoefs, int *nchgbds, int *nfixedvars)
Definition: matrix.c:454
int SCIPmatrixGetNColumns(SCIP_MATRIX *matrix)
Definition: matrix.c:1604
SCIP_CONS * SCIPmatrixGetCons(SCIP_MATRIX *matrix, int row)
Definition: matrix.c:1860
void SCIPmatrixFree(SCIP *scip, SCIP_MATRIX **matrix)
Definition: matrix.c:1072
SCIP_VAR * SCIPmatrixGetVar(SCIP_MATRIX *matrix, int col)
Definition: matrix.c:1660
int * SCIPmatrixGetRowIdxPtr(SCIP_MATRIX *matrix, int row)
Definition: matrix.c:1696
int SCIPmatrixGetNRows(SCIP_MATRIX *matrix)
Definition: matrix.c:1732
#define BMSclearMemory(ptr)
Definition: memory.h:129
#define PRESOL_NAME
#define PRESOL_PRIORITY
#define PRESOL_MAXROUNDS
#define PRESOL_TIMING
#define PRESOL_DESC
MILP presolver that calls the presolve library on the constraint matrix.
public methods for managing constraints
public methods for matrix
public methods for message output
#define SCIPerrorMessage
Definition: pub_message.h:64
public methods for presolvers
public methods for problem variables
#define DEFAULT_RANDOMSEED
Definition: reader_scflp.c:116
public methods for constraint handler plugins and constraints
general public methods
public methods for memory management
public methods for message handling
public methods for numerical tolerances
public methods for SCIP parameter handling
public methods for presolving plugins
public methods for global and local (sub)problems
public methods for random numbers
static SCIP_RETCODE presolve(SCIP *scip, SCIP_Bool *unbounded, SCIP_Bool *infeasible, SCIP_Bool *vanished)
Definition: scip_solve.c:1114
public methods for timing
public methods for SCIP variables
@ SCIP_VERBLEVEL_HIGH
Definition: type_message.h:56
#define SCIP_DECL_PRESOLCOPY(x)
Definition: type_presol.h:60
struct SCIP_PresolData SCIP_PRESOLDATA
Definition: type_presol.h:51
#define SCIP_DECL_PRESOLFREE(x)
Definition: type_presol.h:68
#define SCIP_DECL_PRESOLINIT(x)
Definition: type_presol.h:76
#define SCIP_DECL_PRESOLEXEC(x)
Definition: type_presol.h:167
@ SCIP_DIDNOTRUN
Definition: type_result.h:42
@ SCIP_CUTOFF
Definition: type_result.h:48
@ SCIP_DIDNOTFIND
Definition: type_result.h:44
@ SCIP_UNBOUNDED
Definition: type_result.h:47
@ SCIP_SUCCESS
Definition: type_result.h:58
@ SCIP_INVALIDRESULT
Definition: type_retcode.h:53
@ SCIP_OKAY
Definition: type_retcode.h:42
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_VARTYPE_IMPLINT
Definition: type_var.h:64
@ SCIP_VARSTATUS_FIXED
Definition: type_var.h:52
@ SCIP_VARSTATUS_MULTAGGR
Definition: type_var.h:54
@ SCIP_VARSTATUS_NEGATED
Definition: type_var.h:55
@ SCIP_VARSTATUS_AGGREGATED
Definition: type_var.h:53