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-2024 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
358#ifndef SCIP_PRESOLLIB_ENABLE_OUTPUT
359 /* adjust output settings of presolve library */
360 presolve.setVerbosityLevel((VerbosityLevel) data->verbosity);
361#endif
362
363#if PAPILO_APIVERSION >= 2
364 presolve.getPresolveOptions().abortfac = data->abortfacexhaustive;
365 presolve.getPresolveOptions().abortfacmedium = data->abortfacmedium;
366 presolve.getPresolveOptions().abortfacfast = data->abortfacfast;
367#endif
368
369 /* communicate the time limit */
370 SCIPgetRealParam(scip, "limits/time", &timelimit);
371 if( !SCIPisInfinity(scip, timelimit) )
372 presolve.getPresolveOptions().tlim = timelimit - SCIPgetSolvingTime(scip);
373
374 return presolve;
375}
376
377/*
378 * Callback methods of presolver
379 */
380
381/** copy method for constraint handler plugins (called when SCIP copies plugins) */
382static
383SCIP_DECL_PRESOLCOPY(presolCopyMILP)
384{ /*lint --e{715}*/
386
387 return SCIP_OKAY;
388}
389
390/** destructor of presolver to free user data (called when SCIP is exiting) */
391static
392SCIP_DECL_PRESOLFREE(presolFreeMILP)
393{ /*lint --e{715}*/
394 SCIP_PRESOLDATA* data = SCIPpresolGetData(presol);
395 assert(data != NULL);
396
397 SCIPpresolSetData(presol, NULL);
399 return SCIP_OKAY;
400}
401
402/** initialization method of presolver (called after problem was transformed) */
403static
404SCIP_DECL_PRESOLINIT(presolInitMILP)
405{ /*lint --e{715}*/
406 SCIP_PRESOLDATA* data = SCIPpresolGetData(presol);
407 assert(data != NULL);
408
409 data->lastncols = -1;
410 data->lastnrows = -1;
411
412 return SCIP_OKAY;
413}
414
415/** execution method of presolver */
416static
417SCIP_DECL_PRESOLEXEC(presolExecMILP)
418{ /*lint --e{715}*/
419 SCIP_MATRIX* matrix;
420 SCIP_PRESOLDATA* data;
421 SCIP_Bool initialized;
422 SCIP_Bool complete;
423 SCIP_Bool infeasible;
424
425 *result = SCIP_DIDNOTRUN;
426
427 data = SCIPpresolGetData(presol);
428
429 int nvars = SCIPgetNVars(scip);
430 int nconss = SCIPgetNConss(scip);
431
432 /* run only if the problem size reduced by some amount since the last call or if it is the first call */
433 if( data->lastncols != -1 && data->lastnrows != -1 &&
434 nvars > data->lastncols * 0.85 &&
435 nconss > data->lastnrows * 0.85 )
436 return SCIP_OKAY;
437
438 SCIP_CALL( SCIPmatrixCreate(scip, &matrix, TRUE, &initialized, &complete, &infeasible,
439 naddconss, ndelconss, nchgcoefs, nchgbds, nfixedvars) );
440
441 /* if infeasibility was detected during matrix creation, return here */
442 if( infeasible )
443 {
444 if( initialized )
445 SCIPmatrixFree(scip, &matrix);
446
447 *result = SCIP_CUTOFF;
448 return SCIP_OKAY;
449 }
450
451 /* we only work on pure MIPs, also disable to try building the matrix again if it failed once */
452 if( !initialized || !complete )
453 {
454 data->lastncols = 0;
455 data->lastnrows = 0;
456
457 if( initialized )
458 SCIPmatrixFree(scip, &matrix);
459
460 return SCIP_OKAY;
461 }
462
463 if( 0 != strncmp(data->filename, DEFAULT_FILENAME_PROBLEM, strlen(DEFAULT_FILENAME_PROBLEM)) )
464 {
466 " writing transformed problem to %s (only enforced constraints)\n", data->filename);
467 SCIP_CALL(SCIPwriteTransProblem(scip, data->filename, NULL, FALSE));
468 }
469
470 /* only allow communication of constraint modifications by deleting all constraints when some already have been upgraded */
471 SCIP_CONSHDLR* linconshdlr = SCIPfindConshdlr(scip, "linear");
472 assert(linconshdlr != NULL);
473 SCIP_Bool allowconsmodification = (SCIPconshdlrGetNCheckConss(linconshdlr) == SCIPmatrixGetNRows(matrix));
474
475 /* store current numbers of aggregations, fixings, and changed bounds for statistics */
476 int oldnaggrvars = *naggrvars;
477 int oldnfixedvars = *nfixedvars;
478 int oldnchgbds = *nchgbds;
479
480 /* create presolving objects */
481 Problem<SCIP_Real> problem = buildProblem(scip, matrix);
482 int oldnnz = problem.getConstraintMatrix().getNnz();
483 Presolve<SCIP_Real> presolve = setupPresolve(scip, data, allowconsmodification);
484
485 /* call the presolving */
487 " (%.1fs) running MILP presolver\n", SCIPgetSolvingTime(scip));
488
489 /*call presolving without storing information for dual postsolve*/
490#if (PAPILO_VERSION_MAJOR >= 2)
491 PresolveResult<SCIP_Real> res = presolve.apply(problem, false);
492#else
493 PresolveResult<SCIP_Real> res = presolve.apply(problem);
494#endif
495 data->lastncols = problem.getNCols();
496 data->lastnrows = problem.getNRows();
497
498 /* evaluate the result */
499 switch(res.status)
500 {
501 case PresolveStatus::kInfeasible:
502 *result = SCIP_CUTOFF;
504 " (%.1fs) MILP presolver detected infeasibility\n",
506 SCIPmatrixFree(scip, &matrix);
507 return SCIP_OKAY;
508 case PresolveStatus::kUnbndOrInfeas:
509 case PresolveStatus::kUnbounded:
510 *result = SCIP_UNBOUNDED;
512 " (%.1fs) MILP presolver detected unboundedness\n",
514 SCIPmatrixFree(scip, &matrix);
515 return SCIP_OKAY;
516 case PresolveStatus::kUnchanged:
517 *result = SCIP_DIDNOTFIND;
518 data->lastncols = nvars;
519 data->lastnrows = nconss;
521 " (%.1fs) MILP presolver found nothing\n",
523 SCIPmatrixFree(scip, &matrix);
524 return SCIP_OKAY;
525 case PresolveStatus::kReduced:
526 data->lastncols = problem.getNCols();
527 data->lastnrows = problem.getNRows();
528 *result = SCIP_SUCCESS;
529 }
530
531 /* result indicated success, now populate the changes into the SCIP structures */
532
533 /* tighten bounds of variables that are still present after presolving */
534 VariableDomains<SCIP_Real>& varDomains = problem.getVariableDomains();
535 for( int i = 0; i != problem.getNCols(); ++i )
536 {
537 assert( ! varDomains.flags[i].test(ColFlag::kInactive) );
538 SCIP_VAR* var = SCIPmatrixGetVar(matrix, res.postsolve.origcol_mapping[i]);
539 if( !varDomains.flags[i].test(ColFlag::kLbInf) )
540 {
541 SCIP_Bool infeas;
542 SCIP_Bool tightened;
543 SCIP_CALL( SCIPtightenVarLb(scip, var, varDomains.lower_bounds[i], TRUE, &infeas, &tightened) );
544
545 if( tightened )
546 *nchgbds += 1;
547
548 if( infeas )
549 {
550 *result = SCIP_CUTOFF;
551 break;
552 }
553 }
554
555 if( !varDomains.flags[i].test(ColFlag::kUbInf) )
556 {
557 SCIP_Bool infeas;
558 SCIP_Bool tightened;
559 SCIP_CALL( SCIPtightenVarUb(scip, var, varDomains.upper_bounds[i], TRUE, &infeas, &tightened) );
560
561 if( tightened )
562 *nchgbds += 1;
563
564 if( infeas )
565 {
566 *result = SCIP_CUTOFF;
567 break;
568 }
569 }
570 }
571
572 if( *result == SCIP_CUTOFF )
573 {
575 " (%.1fs) MILP presolver detected infeasibility\n",
577 SCIPmatrixFree(scip, &matrix);
578 return SCIP_OKAY;
579 }
580
581 /* transfer variable fixings and aggregations */
582 std::vector<SCIP_VAR*> tmpvars;
583 std::vector<SCIP_Real> tmpvals;
584
585 /* if the size of the problem decreased by a sufficient factor, create all constraints from scratch if allowed */
586 int newnnz = problem.getConstraintMatrix().getNnz();
587 bool constraintsReplaced = false;
588 if( newnnz == 0 || (allowconsmodification &&
589 (problem.getNCols() <= data->modifyconsfac * SCIPmatrixGetNColumns(matrix) ||
590 problem.getNRows() <= data->modifyconsfac * SCIPmatrixGetNRows(matrix) ||
591 newnnz <= data->modifyconsfac * oldnnz)) )
592 {
593 int oldnrows = SCIPmatrixGetNRows(matrix);
594 int newnrows = problem.getNRows();
595
596 constraintsReplaced = true;
597
598 /* capture constraints that are still present in the problem after presolve */
599 for( int i = 0; i < newnrows; ++i )
600 {
601 SCIP_CONS* c = SCIPmatrixGetCons(matrix, res.postsolve.origrow_mapping[i]);
603 }
604
605 /* delete all constraints */
606 *ndelconss += oldnrows;
607 *naddconss += newnrows;
608
609 for( int i = 0; i < oldnrows; ++i )
610 {
612 }
613
614 /* now loop over rows of presolved problem and create them as new linear constraints,
615 * then release the old constraint after its name was passed to the new constraint */
616 const Vec<RowFlags>& rflags = problem.getRowFlags();
617 const auto& consmatrix = problem.getConstraintMatrix();
618 for( int i = 0; i < newnrows; ++i )
619 {
620 auto rowvec = consmatrix.getRowCoefficients(i);
621 const int* rowcols = rowvec.getIndices();
622 /* SCIPcreateConsBasicLinear() requires a non const pointer */
623 SCIP_Real* rowvals = const_cast<SCIP_Real*>(rowvec.getValues());
624 int rowlen = rowvec.getLength();
625
626 /* retrieve SCIP compatible left and right hand sides */
627 SCIP_Real lhs = rflags[i].test(RowFlag::kLhsInf) ? - SCIPinfinity(scip) : consmatrix.getLeftHandSides()[i];
628 SCIP_Real rhs = rflags[i].test(RowFlag::kRhsInf) ? SCIPinfinity(scip) : consmatrix.getRightHandSides()[i];
629
630 /* create variable array matching the value array */
631 tmpvars.clear();
632 tmpvars.reserve(rowlen);
633 for( int j = 0; j < rowlen; ++j )
634 tmpvars.push_back(SCIPmatrixGetVar(matrix, res.postsolve.origcol_mapping[rowcols[j]]));
635
636 /* create and add new constraint with name of old constraint */
637 SCIP_CONS* oldcons = SCIPmatrixGetCons(matrix, res.postsolve.origrow_mapping[i]);
638 SCIP_CONS* cons;
639 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, SCIPconsGetName(oldcons), rowlen, tmpvars.data(), rowvals, lhs, rhs) );
640 SCIP_CALL( SCIPaddCons(scip, cons) );
641
642 /* release old and new constraint */
643 SCIP_CALL( SCIPreleaseCons(scip, &oldcons) );
644 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
645 }
646 }
647
648 /* PaPILO's aggregations are valid regarding the constraints as they were presolved by PaPILO.
649 * If coefficients were changed, but constraints in SCIP are not replaced by those from PaPILO,
650 * then it can not be guaranteed that the bounds of multiaggregated variables will be enforced,
651 * i.e., will be implied by the constraints in SCIP (see also #3704).
652 * Only for variable aggregations, SCIP will ensure this by tightening the bounds on the aggregation
653 * variable as part of SCIPaggregateVars(). For multiaggregations, we will only accept those
654 * where we can be sure with a simple check that the bounds on the aggregated variable are implied.
655 */
656 bool checkmultaggr =
657#if PAPILO_APIVERSION >= 1
658 presolve.getStatistics().single_matrix_coefficient_changes > 0
659#else
660 presolve.getStatistics().ncoefchgs > 0
661#endif
662 && !constraintsReplaced;
663
664 /* loop over res.postsolve and add all fixed variables and aggregations to scip */
665 for( std::size_t i = 0; i != res.postsolve.types.size(); ++i )
666 {
667 ReductionType type = res.postsolve.types[i];
668 int first = res.postsolve.start[i];
669 int last = res.postsolve.start[i + 1];
670
671 switch( type )
672 {
673 case ReductionType::kFixedCol:
674 {
675 SCIP_Bool infeas;
676 SCIP_Bool fixed;
677 int col = res.postsolve.indices[first];
678
679 SCIP_VAR* var = SCIPmatrixGetVar(matrix, col);
680
681 SCIP_Real value = res.postsolve.values[first];
682
683 SCIP_CALL( SCIPfixVar(scip, var, value, &infeas, &fixed) );
684 *nfixedvars += 1;
685
686 assert(!infeas);
687 /* SCIP has different rules for aggregating variables than PaPILO: therefore the variable PaPILO
688 * tries to fix now may have been aggregated by SCIP before. Additionally, after aggregation SCIP
689 * sometimes performs bound tightening resulting in possible fixings. These cases need to be excluded. */
690 assert(fixed || SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED ||
692 break;
693 }
694/*
695 * Dual-postsolving in PaPILO required introducing a postsolve-type for substitution with additional information.
696 * Further, the different Substitution-postsolving types store the required postsolving data differently (in different order) in the postsolving stack.
697 * Therefore, we need to distinguish how to parse the required data (rowLength, col, side, startRowCoefficients, lastRowCoefficients) from the postsolving stack.
698 * If these values are accessed, the procedure is the same for both.
699 */
700#if (PAPILO_VERSION_MAJOR >= 2)
701 case ReductionType::kSubstitutedColWithDual:
702#endif
703 case ReductionType::kSubstitutedCol:
704 {
705 int col = 0;
706 SCIP_Real side = 0;
707
708 int rowlen = 0;
709 int startRowCoefficients = 0;
710 int lastRowCoefficients = 0;
711
712 if( type == ReductionType::kSubstitutedCol )
713 {
714 rowlen = last - first - 1;
715 col = res.postsolve.indices[first];
716 side = res.postsolve.values[first];
717
718 startRowCoefficients = first + 1;
719 lastRowCoefficients = last;
720 }
721#if (PAPILO_VERSION_MAJOR >= 2)
722 if( type == ReductionType::kSubstitutedColWithDual )
723 {
724 rowlen = (int) res.postsolve.values[first];
725 col = res.postsolve.indices[first + 3 + rowlen];
726 side = res.postsolve.values[first + 1];
727
728 startRowCoefficients = first + 3;
729 lastRowCoefficients = first + 3 + rowlen;
730
731 assert(side == res.postsolve.values[first + 2]);
732 assert(res.postsolve.indices[first + 1] == 0);
733 assert(res.postsolve.indices[first + 2] == 0);
734 }
735 assert( type == ReductionType::kSubstitutedCol || type == ReductionType::kSubstitutedColWithDual );
736#else
737 assert( type == ReductionType::kSubstitutedCol );
738#endif
739 SCIP_Bool infeas;
740 SCIP_Bool aggregated;
741 SCIP_Bool redundant = FALSE;
742 SCIP_Real constant = 0.0;
743 if( rowlen == 2 )
744 {
745 SCIP_Real updatedSide;
746 SCIP_VAR* varx = SCIPmatrixGetVar(matrix, res.postsolve.indices[startRowCoefficients]);
747 SCIP_VAR* vary = SCIPmatrixGetVar(matrix, res.postsolve.indices[startRowCoefficients + 1]);
748 SCIP_Real scalarx = res.postsolve.values[startRowCoefficients];
749 SCIP_Real scalary = res.postsolve.values[startRowCoefficients + 1];
750
751 SCIP_CALL( SCIPgetProbvarSum(scip, &varx, &scalarx, &constant) );
753
754 SCIP_CALL( SCIPgetProbvarSum(scip, &vary, &scalary, &constant) );
756
757 /* If PaPILO tries to aggregate fixed variables then it missed some obvious fixings.
758 * This might happen if another aggregation leads to fixings which are not applied immediately by PaPILO.
759 * With the latest version of PaPILO, this should not occur.
760 */
762 {
763 SCIPdebugMsg(scip, "Aggregation of <%s> and <%s> rejected because they are already fixed.\n",
764 SCIPvarGetName(varx), SCIPvarGetName(vary));
765
766 break;
767 }
768
769 updatedSide = side - constant;
770
771 SCIP_CALL( SCIPaggregateVars(scip, varx, vary, scalarx, scalary, updatedSide, &infeas, &redundant, &aggregated) );
772 }
773 else
774 {
775 SCIP_Real colCoef = 0.0;
776 SCIP_Real updatedSide;
777 SCIP_Bool checklbimplied;
778 SCIP_Bool checkubimplied;
779 SCIP_Real impliedlb;
780 SCIP_Real impliedub;
781 int j;
782
783 for( j = startRowCoefficients; j < lastRowCoefficients; ++j )
784 {
785 if( res.postsolve.indices[j] == col )
786 {
787 colCoef = res.postsolve.values[j];
788 break;
789 }
790 }
791
792 tmpvars.clear();
793 tmpvals.clear();
794 tmpvars.reserve(rowlen);
795 tmpvals.reserve(rowlen);
796
797 assert(colCoef != 0.0);
798 SCIP_VAR* aggrvar = SCIPmatrixGetVar(matrix, col);
799
800 SCIP_CALL( SCIPgetProbvarSum(scip, &aggrvar, &colCoef, &constant) );
801 assert(SCIPvarGetStatus(aggrvar) != SCIP_VARSTATUS_MULTAGGR);
802
803 /* If PaPILO tries to multi-aggregate a fixed variable, then it missed some obvious fixings.
804 * This might happen if another aggregation leads to fixings which are not applied immediately by PaPILO.
805 * With the latest version of PaPILO, this should not occur.
806 */
807 if( SCIPvarGetStatus(aggrvar) == SCIP_VARSTATUS_FIXED )
808 {
809 SCIPdebugMsg(scip, "Multi-aggregation of <%s> rejected because it is already fixed.\n",
810 SCIPvarGetName(aggrvar));
811
812 break;
813 }
814
815 updatedSide = side - constant;
816
817 /* we need to check whether lb/ub on aggrvar is implied by bounds of other variables in multiaggregation
818 * if checkmultaggr is TRUE and the lb/ub is finite
819 * it should be sufficient to ensure global bounds on aggrvar (and as we are in presolve, local=global anyway)
820 */
821 checklbimplied = checkmultaggr && !SCIPisInfinity(scip, -SCIPvarGetLbGlobal(aggrvar));
822 checkubimplied = checkmultaggr && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(aggrvar));
823 impliedlb = impliedub = updatedSide / colCoef;
824
825 for( j = startRowCoefficients; j < lastRowCoefficients; ++j )
826 {
827 SCIP_Real coef;
828 SCIP_VAR* var;
829
830 if( res.postsolve.indices[j] == col )
831 continue;
832
833 coef = - res.postsolve.values[j] / colCoef;
834 var = SCIPmatrixGetVar(matrix, res.postsolve.indices[j]);
835
836 if( checklbimplied )
837 {
838 if( coef > 0.0 )
839 {
840 /* if impliedlb will be -infinity, then we can give up: we cannot use this mutiaggregation */
842 break;
843 else
844 impliedlb += coef * SCIPvarGetLbLocal(var);
845 }
846 else
847 {
849 break;
850 else
851 impliedlb += coef * SCIPvarGetUbLocal(var);
852 }
853 }
854
855 if( checkubimplied )
856 {
857 if( coef > 0.0 )
858 {
860 break;
861 else
862 impliedub += coef * SCIPvarGetUbLocal(var);
863 }
864 else
865 {
867 break;
868 else
869 impliedub += coef * SCIPvarGetLbLocal(var);
870 }
871 }
872
873 tmpvals.push_back(coef);
874 tmpvars.push_back(var);
875 }
876
877 /* if implied bounds are not sufficient to ensure bounds on aggrvar, then we cannot use the multiaggregation */
878 if( j < lastRowCoefficients )
879 break;
880
881 if( checklbimplied && SCIPisGT(scip, SCIPvarGetLbGlobal(aggrvar), impliedlb) )
882 break;
883
884 if( checkubimplied && SCIPisLT(scip, SCIPvarGetUbGlobal(aggrvar), impliedub) )
885 break;
886
887 SCIP_CALL( SCIPmultiaggregateVar(scip, aggrvar, tmpvars.size(),
888 tmpvars.data(), tmpvals.data(), updatedSide / colCoef, &infeas, &aggregated) );
889 }
890
891 if( aggregated )
892 *naggrvars += 1;
893 else if( constraintsReplaced && !redundant )
894 {
895 /* if the constraints where replaced, we need to add the failed substitution as an equality to SCIP */
896 tmpvars.clear();
897 tmpvals.clear();
898 for( int j = startRowCoefficients; j < lastRowCoefficients; ++j )
899 {
900 tmpvars.push_back(SCIPmatrixGetVar(matrix, res.postsolve.indices[j]));
901 tmpvals.push_back(res.postsolve.values[j]);
902 }
903
904 SCIP_CONS* cons;
905 String name = fmt::format("{}_failed_aggregation_equality", SCIPvarGetName(SCIPmatrixGetVar(matrix, col)));
906 SCIP_CALL( SCIPcreateConsBasicLinear(scip, &cons, name.c_str(),
907 tmpvars.size(), tmpvars.data(), tmpvals.data(), side, side ) );
908 SCIP_CALL( SCIPaddCons(scip, cons) );
909 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
910 *naddconss += 1;
911 }
912
913 if( infeas )
914 {
915 *result = SCIP_CUTOFF;
916 break;
917 }
918
919 break;
920 }
921 case ReductionType::kParallelCol:
922 return SCIP_INVALIDRESULT;
923#if PAPILO_VERSION_MAJOR > 1 || (PAPILO_VERSION_MAJOR == 1 && PAPILO_VERSION_MINOR >= 1)
924 case ReductionType::kFixedInfCol: {
925 /* todo: currently SCIP can not handle this kind of reduction (see issue #3391) */
926 assert(false);
927 if(!constraintsReplaced)
928 continue;
929 SCIP_Bool infeas;
930 SCIP_Bool fixed;
931 SCIP_Real value = SCIPinfinity(scip);
932
933 int column = res.postsolve.indices[first];
934 bool is_negative_infinity = res.postsolve.values[first] < 0;
935 SCIP_VAR* column_variable = SCIPmatrixGetVar(matrix, column);
936
937 if( is_negative_infinity )
938 {
939 value = -SCIPinfinity(scip);
940 }
941
942 SCIP_CALL( SCIPfixVar(scip, column_variable, value, &infeas, &fixed) );
943 *nfixedvars += 1;
944
945 assert(!infeas);
946 assert(fixed);
947 break;
948 }
949#endif
950#if (PAPILO_VERSION_MAJOR >= 2)
951 case ReductionType::kVarBoundChange :
952 case ReductionType::kRedundantRow :
953 case ReductionType::kRowBoundChange :
954 case ReductionType::kReasonForRowBoundChangeForcedByRow :
955 case ReductionType::kRowBoundChangeForcedByRow :
956 case ReductionType::kSaveRow :
957 case ReductionType::kReducedBoundsCost :
958 case ReductionType::kColumnDualValue :
959 case ReductionType::kRowDualValue :
960 case ReductionType::kCoefficientChange :
961 // dual ReductionTypes should be only calculated for dual reductions and should not appear for MIP
962 SCIPerrorMessage("PaPILO: PaPILO should not return dual postsolving reductions in SCIP!!\n");
963 SCIPABORT(); /*lint --e{527}*/
964 break;
965#endif
966 default:
967 SCIPdebugMsg(scip, "PaPILO returned unknown data type: \n" );
968 continue;
969 }
970 }
971
972 /* finish with a final verb message and return */
974 " (%.1fs) MILP presolver (%d rounds): %d aggregations, %d fixings, %d bound changes\n",
975 SCIPgetSolvingTime(scip), presolve.getStatistics().nrounds, *naggrvars - oldnaggrvars,
976 *nfixedvars - oldnfixedvars, *nchgbds - oldnchgbds);
977
978 /* free the matrix */
979 assert(initialized);
980 SCIPmatrixFree(scip, &matrix);
981
982 return SCIP_OKAY;
983}
984
985
986/*
987 * presolver specific interface methods
988 */
989
990/** creates the MILP presolver and includes it in SCIP */
992 SCIP* scip /**< SCIP data structure */
993 )
994{
995 SCIP_PRESOLDATA* presoldata;
996 SCIP_PRESOL* presol;
997
998#if defined(PAPILO_VERSION_TWEAK) && PAPILO_VERSION_TWEAK != 0
999 String name = fmt::format("PaPILO {}.{}.{}.{}", PAPILO_VERSION_MAJOR, PAPILO_VERSION_MINOR, PAPILO_VERSION_PATCH, PAPILO_VERSION_TWEAK);
1000#else
1001 String name = fmt::format("PaPILO {}.{}.{}", PAPILO_VERSION_MAJOR, PAPILO_VERSION_MINOR, PAPILO_VERSION_PATCH);
1002#endif
1003
1004#if defined(PAPILO_GITHASH_AVAILABLE) && defined(PAPILO_TBB)
1005 String desc = fmt::format("parallel presolve for integer and linear optimization (github.com/scipopt/papilo) (built with TBB) [GitHash: {}]", PAPILO_GITHASH);
1006#elif !defined(PAPILO_GITHASH_AVAILABLE) && !defined(PAPILO_TBB)
1007 String desc("parallel presolve for integer and linear optimization (github.com/scipopt/papilo)");
1008#elif defined(PAPILO_GITHASH_AVAILABLE) && !defined(PAPILO_TBB)
1009 String desc = fmt::format("parallel presolve for integer and linear optimization (github.com/scipopt/papilo) [GitHash: {}]", PAPILO_GITHASH);
1010#elif !defined(PAPILO_GITHASH_AVAILABLE) && defined(PAPILO_TBB)
1011 String desc = fmt::format("parallel presolve for integer and linear optimization (github.com/scipopt/papilo) (built with TBB)");
1012#endif
1013
1014 /* add external code info for the presolve library */
1015 SCIP_CALL( SCIPincludeExternalCodeInformation(scip, name.c_str(), desc.c_str()) );
1016
1017 /* create MILP presolver data */
1018 presoldata = NULL;
1019 SCIP_CALL( SCIPallocBlockMemory(scip, &presoldata) );
1020 BMSclearMemory(presoldata);
1021
1022 presol = NULL;
1023
1024 /* include presolver */
1026 presolExecMILP,
1027 presoldata) );
1028
1029 assert(presol != NULL);
1030
1031 /* set non fundamental callbacks via setter functions */
1032 SCIP_CALL( SCIPsetPresolCopy(scip, presol, presolCopyMILP) );
1033 SCIP_CALL( SCIPsetPresolFree(scip, presol, presolFreeMILP) );
1034 SCIP_CALL( SCIPsetPresolInit(scip, presol, presolInitMILP) );
1035
1036 /* add MILP presolver parameters */
1037#ifdef PAPILO_TBB
1039 "presolving/" PRESOL_NAME "/threads",
1040 "maximum number of threads presolving may use (0: automatic)",
1041 &presoldata->threads, FALSE, DEFAULT_THREADS, 0, INT_MAX, NULL, NULL) );
1042#else
1043 presoldata->threads = DEFAULT_THREADS;
1044#endif
1045
1047 "presolving/" PRESOL_NAME "/maxfillinpersubstitution",
1048 "maximal possible fillin for substitutions to be considered",
1049 &presoldata->maxfillinpersubstitution, FALSE, DEFAULT_MAXFILLINPERSUBST, INT_MIN, INT_MAX, NULL, NULL) );
1050
1052 "presolving/" PRESOL_NAME "/maxshiftperrow",
1053 "maximal amount of nonzeros allowed to be shifted to make space for substitutions",
1054 &presoldata->maxshiftperrow, TRUE, DEFAULT_MAXSHIFTPERROW, 0, INT_MAX, NULL, NULL) );
1055
1057 "presolving/" PRESOL_NAME "/randomseed",
1058 "the random seed used for randomization of tie breaking",
1059 &presoldata->randomseed, FALSE, DEFAULT_RANDOMSEED, INT_MIN, INT_MAX, NULL, NULL) );
1060
1061 if( DependentRows<double>::Enabled )
1062 {
1064 "presolving/" PRESOL_NAME "/detectlineardependency",
1065 "should linear dependent equations and free columns be removed? (0: never, 1: for LPs, 2: always)",
1066 &presoldata->detectlineardependency, TRUE, DEFAULT_DETECTLINDEP, 0, 2, NULL, NULL) );
1067 }
1068 else
1069 presoldata->detectlineardependency = DEFAULT_DETECTLINDEP;
1070
1072 "presolving/" PRESOL_NAME "/modifyconsfac",
1073 "modify SCIP constraints when the number of nonzeros or rows is at most this factor "
1074 "times the number of nonzeros or rows before presolving",
1075 &presoldata->modifyconsfac, FALSE, DEFAULT_MODIFYCONSFAC, 0.0, 1.0, NULL, NULL) );
1076
1078 "presolving/" PRESOL_NAME "/markowitztolerance",
1079 "the markowitz tolerance used for substitutions",
1080 &presoldata->markowitztolerance, FALSE, DEFAULT_MARKOWITZTOLERANCE, 0.0, 1.0, NULL, NULL) );
1081
1083 "presolving/" PRESOL_NAME "/hugebound",
1084 "absolute bound value that is considered too huge for activity based calculations",
1085 &presoldata->hugebound, FALSE, DEFAULT_HUGEBOUND, 0.0, SCIP_REAL_MAX, NULL, NULL) );
1086
1087#if PAPILO_APIVERSION >= 2
1088 SCIP_CALL( SCIPaddRealParam(scip, "presolving/" PRESOL_NAME "/abortfacexhaustive",
1089 "abort threshold for exhaustive presolving in PAPILO",
1090 &presoldata->abortfacexhaustive, TRUE, DEFAULT_ABORTFAC_EXHAUSTIVE, 0.0, 1.0, NULL, NULL) );
1091 SCIP_CALL( SCIPaddRealParam(scip, "presolving/" PRESOL_NAME "/abortfacmedium",
1092 "abort threshold for medium presolving in PAPILO",
1093 &presoldata->abortfacmedium, TRUE, DEFAULT_ABORTFAC_MEDIUM, 0.0, 1.0, NULL, NULL) );
1094 SCIP_CALL( SCIPaddRealParam(scip, "presolving/" PRESOL_NAME "/abortfacfast",
1095 "abort threshold for fast presolving in PAPILO",
1096 &presoldata->abortfacfast, TRUE, DEFAULT_ABORTFAC_FAST, 0.0, 1.0, NULL, NULL) );
1097#else
1098 presoldata->abortfacexhaustive = DEFAULT_ABORTFAC_EXHAUSTIVE;
1099 presoldata->abortfacmedium = DEFAULT_ABORTFAC_MEDIUM;
1100 presoldata->abortfacfast = DEFAULT_ABORTFAC_FAST;
1101#endif
1102
1103#if PAPILO_VERSION_MAJOR > 2 || (PAPILO_VERSION_MAJOR == 2 && PAPILO_VERSION_MINOR >= 1)
1104 SCIP_CALL(SCIPaddIntParam(scip, "presolving/" PRESOL_NAME "/maxbadgesizeseq",
1105 "maximal badge size in Probing in PaPILO if PaPILO is executed in sequential mode",
1106 &presoldata->maxbadgesizeseq, FALSE, DEFAULT_MAXBADGESIZE_SEQ, -1, INT_MAX, NULL, NULL));
1107
1108 SCIP_CALL(SCIPaddIntParam(scip, "presolving/" PRESOL_NAME "/maxbadgesizepar",
1109 "maximal badge size in Probing in PaPILO if PaPILO is executed in parallel mode",
1110 &presoldata->maxbadgesizepar, FALSE, DEFAULT_MAXBADGESIZE_PAR, -1, INT_MAX, NULL, NULL));
1111#else
1112 presoldata->maxbadgesizeseq = DEFAULT_MAXBADGESIZE_SEQ;
1113 presoldata->maxbadgesizepar = DEFAULT_MAXBADGESIZE_PAR;
1114#endif
1115
1116#if PAPILO_VERSION_MAJOR > 2 || (PAPILO_VERSION_MAJOR == 2 && PAPILO_VERSION_MINOR >= 3)
1117 SCIP_CALL(SCIPaddIntParam(scip, "presolving/" PRESOL_NAME "/internalmaxrounds",
1118 "internal maxrounds for each milp presolving (-1: no limit, 0: model cleanup)",
1119 &presoldata->internalmaxrounds, TRUE, DEFAULT_INTERNAL_MAXROUNDS, -1, INT_MAX, NULL, NULL));
1120#else
1121 presoldata->internalmaxrounds = DEFAULT_INTERNAL_MAXROUNDS;
1122#endif
1123
1125 "presolving/" PRESOL_NAME "/enableparallelrows",
1126 "should the parallel rows presolver be enabled within the presolve library?",
1127 &presoldata->enableparallelrows, TRUE, DEFAULT_ENABLEPARALLELROWS, NULL, NULL) );
1128
1130 "presolving/" PRESOL_NAME "/enabledomcol",
1131 "should the dominated column presolver be enabled within the presolve library?",
1132 &presoldata->enabledomcol, TRUE, DEFAULT_ENABLEDOMCOL, NULL, NULL) );
1133
1135 "presolving/" PRESOL_NAME "/enabledualinfer",
1136 "should the dualinfer presolver be enabled within the presolve library?",
1137 &presoldata->enabledualinfer, TRUE, DEFAULT_ENABLEDUALINFER, NULL, NULL) );
1138
1140 "presolving/" PRESOL_NAME "/enablemultiaggr",
1141 "should the multi-aggregation presolver be enabled within the presolve library?",
1142 &presoldata->enablemultiaggr, TRUE, DEFAULT_ENABLEMULTIAGGR, NULL, NULL) );
1143
1145 "presolving/" PRESOL_NAME "/enableprobing",
1146 "should the probing presolver be enabled within the presolve library?",
1147 &presoldata->enableprobing, TRUE, DEFAULT_ENABLEPROBING, NULL, NULL) );
1148
1150 "presolving/" PRESOL_NAME "/enablesparsify",
1151 "should the sparsify presolver be enabled within the presolve library?",
1152 &presoldata->enablesparsify, TRUE, DEFAULT_ENABLESPARSIFY, NULL, NULL) );
1153
1154 SCIP_CALL( SCIPaddStringParam(scip, "presolving/" PRESOL_NAME "/probfilename",
1155 "filename to store the problem before MILP presolving starts (only enforced constraints)",
1156 &presoldata->filename, TRUE, DEFAULT_FILENAME_PROBLEM, NULL, NULL) );
1157
1158 SCIP_CALL(SCIPaddIntParam(scip, "presolving/" PRESOL_NAME "/verbosity",
1159 "verbosity level of PaPILO (0: quiet, 1: errors, 2: warnings, 3: normal, 4: detailed)",
1160 &presoldata->verbosity, FALSE, DEFAULT_VERBOSITY, 0, 4, NULL, NULL));
1161
1162 return SCIP_OKAY;
1163}
1164
1165#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:17537
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:18143
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:17925
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:17583
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:18087
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17418
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:17609
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:18133
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:18077
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