1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2021 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15
16 /**@file cons_linear.c
17 * @ingroup DEFPLUGINS_CONS
18 * @brief Constraint handler for linear constraints in their most general form, \f$lhs <= a^T x <= rhs\f$.
19 * @author Tobias Achterberg
20 * @author Timo Berthold
21 * @author Marc Pfetsch
22 * @author Kati Wolter
23 * @author Michael Winkler
24 * @author Gerald Gamrath
25 * @author Domenico Salvagnin
26 *
27 * Linear constraints are separated with a high priority, because they are easy
28 * to separate. Instead of using the global cut pool, the same effect can be
29 * implemented by adding linear constraints to the root node, such that they are
30 * separated each time, the linear constraints are separated. A constraint
31 * handler, which generates linear constraints in this way should have a lower
32 * separation priority than the linear constraint handler, and it should have a
33 * separation frequency that is a multiple of the frequency of the linear
34 * constraint handler. In this way, it can be avoided to separate the same cut
35 * twice, because if a separation run of the handler is always preceded by a
36 * separation of the linear constraints, the priorily added constraints are
37 * always satisfied.
38 *
39 * Linear constraints are enforced and checked with a very low priority. Checking
40 * of (many) linear constraints is much more involved than checking the solution
41 * values for integrality. Because we are separating the linear constraints quite
42 * often, it is only necessary to enforce them for integral solutions. A constraint
43 * handler which generates pool cuts in its enforcing method should have an
44 * enforcing priority smaller than that of the linear constraint handler to avoid
45 * regenerating constraints which already exist.
46 */
47
48 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
49
50 #include "blockmemshell/memory.h"
51 #include "scip/cons_knapsack.h"
52 #include "scip/cons_linear.h"
53 #include "scip/cons_nonlinear.h"
54 #include "scip/cons_quadratic.h"
55 #include "scip/debug.h"
56 #include "scip/pub_conflict.h"
57 #include "scip/pub_cons.h"
58 #include "scip/pub_event.h"
59 #include "scip/pub_lp.h"
60 #include "scip/pub_message.h"
61 #include "scip/pub_misc.h"
62 #include "scip/pub_misc_sort.h"
63 #include "scip/pub_var.h"
64 #include "scip/scip_branch.h"
65 #include "scip/scip_conflict.h"
66 #include "scip/scip_cons.h"
67 #include "scip/scip_copy.h"
68 #include "scip/scip_cut.h"
69 #include "scip/scip_event.h"
70 #include "scip/scip_general.h"
71 #include "scip/scip_lp.h"
72 #include "scip/scip_mem.h"
73 #include "scip/scip_message.h"
74 #include "scip/scip_numerics.h"
75 #include "scip/scip_param.h"
76 #include "scip/scip_prob.h"
77 #include "scip/scip_probing.h"
78 #include "scip/scip_sol.h"
79 #include "scip/scip_solvingstats.h"
80 #include "scip/scip_tree.h"
81 #include "scip/scip_var.h"
82 #include <ctype.h>
83 #include <string.h>
84 #if defined(_WIN32) || defined(_WIN64)
85 #else
86 #include <strings.h> /*lint --e{766}*/
87 #endif
88
89
90 #define CONSHDLR_NAME "linear"
91 #define CONSHDLR_DESC "linear constraints of the form lhs <= a^T x <= rhs"
92 #define CONSHDLR_SEPAPRIORITY +100000 /**< priority of the constraint handler for separation */
93 #define CONSHDLR_ENFOPRIORITY -1000000 /**< priority of the constraint handler for constraint enforcing */
94 #define CONSHDLR_CHECKPRIORITY -1000000 /**< priority of the constraint handler for checking feasibility */
95 #define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
96 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
97 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
98 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
99 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
100 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
101 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
102 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
103
104 #define CONSHDLR_PRESOLTIMING (SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_EXHAUSTIVE) /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
105 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
106
107 #define EVENTHDLR_NAME "linear"
108 #define EVENTHDLR_DESC "bound change event handler for linear constraints"
109
110 #define CONFLICTHDLR_NAME "linear"
111 #define CONFLICTHDLR_DESC "conflict handler creating linear constraints"
112 #define CONFLICTHDLR_PRIORITY -1000000
113
114 #define DEFAULT_TIGHTENBOUNDSFREQ 1 /**< multiplier on propagation frequency, how often the bounds are tightened */
115 #define DEFAULT_MAXROUNDS 5 /**< maximal number of separation rounds per node (-1: unlimited) */
116 #define DEFAULT_MAXROUNDSROOT -1 /**< maximal number of separation rounds in the root node (-1: unlimited) */
117 #define DEFAULT_MAXSEPACUTS 50 /**< maximal number of cuts separated per separation round */
118 #define DEFAULT_MAXSEPACUTSROOT 200 /**< maximal number of cuts separated per separation round in root node */
119 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
120 #define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
121 #define DEFAULT_NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */
122 #define DEFAULT_MINGAINPERNMINCOMP 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise
123 * comparison round */
124 #define DEFAULT_SORTVARS TRUE /**< should variables be sorted after presolve w.r.t their coefficient absolute for faster
125 * propagation? */
126 #define DEFAULT_CHECKRELMAXABS FALSE /**< should the violation for a constraint with side 0.0 be checked relative
127 * to 1.0 (FALSE) or to the maximum absolute value in the activity (TRUE)? */
128 #define DEFAULT_MAXAGGRNORMSCALE 0.0 /**< maximal allowed relative gain in maximum norm for constraint aggregation
129 * (0.0: disable constraint aggregation) */
130 #define DEFAULT_MAXEASYACTIVITYDELTA 1e6 /**< maximum activity delta to run easy propagation on linear constraint
131 * (faster, but numerically less stable) */
132 #define DEFAULT_MAXCARDBOUNDDIST 0.0 /**< maximal relative distance from current node's dual bound to primal bound compared
133 * to best node's dual bound for separating knapsack cardinality cuts */
134 #define DEFAULT_SEPARATEALL FALSE /**< should all constraints be subject to cardinality cut generation instead of only
135 * the ones with non-zero dual value? */
136 #define DEFAULT_AGGREGATEVARIABLES TRUE /**< should presolving search for redundant variables in equations */
137 #define DEFAULT_SIMPLIFYINEQUALITIES TRUE /**< should presolving try to simplify inequalities */
138 #define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving steps be performed? */
139 #define DEFAULT_SINGLETONSTUFFING TRUE /**< should stuffing of singleton continuous variables be performed? */
140 #define DEFAULT_SINGLEVARSTUFFING FALSE /**< should single variable stuffing be performed, which tries to fulfill
141 * constraints using the cheapest variable? */
142 #define DEFAULT_DETECTCUTOFFBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
143 * function defining an upper bound and prevent these constraints from
144 * entering the LP */
145 #define DEFAULT_DETECTLOWERBOUND TRUE /**< should presolving try to detect constraints parallel to the objective
146 * function defining a lower bound and prevent these constraints from
147 * entering the LP */
148 #define DEFAULT_DETECTPARTIALOBJECTIVE TRUE/**< should presolving try to detect subsets of constraints parallel to the
149 * objective function */
150 #define DEFAULT_RANGEDROWPROPAGATION TRUE /**< should we perform ranged row propagation */
151 #define DEFAULT_RANGEDROWARTCONS TRUE /**< should presolving and propagation extract sub-constraints from ranged rows and equations? */
152 #define DEFAULT_RANGEDROWMAXDEPTH INT_MAX /**< maximum depth to apply ranged row propagation */
153 #define DEFAULT_RANGEDROWFREQ 1 /**< frequency for applying ranged row propagation */
154
155 #define DEFAULT_MULTAGGRREMOVE FALSE /**< should multi-aggregations only be performed if the constraint can be
156 * removed afterwards? */
157 #define DEFAULT_MAXMULTAGGRQUOT 1e+03 /**< maximum coefficient dynamism (ie. maxabsval / minabsval) for multiaggregation */
158 #define DEFAULT_MAXDUALMULTAGGRQUOT 1e+20 /**< maximum coefficient dynamism (ie. maxabsval / minabsval) for multiaggregation */
159 #define DEFAULT_EXTRACTCLIQUES TRUE /**< should cliques be extracted? */
160
161 #define MAXDNOM 10000LL /**< maximal denominator for simple rational fixed values */
162 #define MAXSCALEDCOEF 0 /**< maximal coefficient value after scaling */
163 #define MAXSCALEDCOEFINTEGER 0 /**< maximal coefficient value after scaling if all variables are of integral
164 * type
165 */
166
167 #define MAXVALRECOMP 1e+06 /**< maximal abolsute value we trust without recomputing the activity */
168 #define MINVALRECOMP 1e-05 /**< minimal abolsute value we trust without recomputing the activity */
169
170
171 #define QUADCONSUPGD_PRIORITY 1000000 /**< priority of the constraint handler for upgrading of quadratic constraints */
172 #define NONLINCONSUPGD_PRIORITY 1000000 /**< priority of the constraint handler for upgrading of nonlinear constraints */
173
174 /* @todo add multi-aggregation of variables that are in exactly two equations (, if not numerically an issue),
175 * maybe in fullDualPresolve(), see convertLongEquality()
176 */
177
178
179 /** constraint data for linear constraints */
180 struct SCIP_ConsData
181 {
182 SCIP_Real lhs; /**< left hand side of row (for ranged rows) */
183 SCIP_Real rhs; /**< right hand side of row */
184 SCIP_Real maxabsval; /**< maximum absolute value of all coefficients */
185 SCIP_Real minabsval; /**< minimal absolute value of all coefficients */
186 SCIP_Real minactivity; /**< minimal value w.r.t. the variable's local bounds for the constraint's
187 * activity, ignoring the coefficients contributing with infinite value */
188 SCIP_Real maxactivity; /**< maximal value w.r.t. the variable's local bounds for the constraint's
189 * activity, ignoring the coefficients contributing with infinite value */
190 SCIP_Real lastminactivity; /**< last minimal activity which was computed by complete summation
191 * over all contributing values */
192 SCIP_Real lastmaxactivity; /**< last maximal activity which was computed by complete summation
193 * over all contributing values */
194 SCIP_Real glbminactivity; /**< minimal value w.r.t. the variable's global bounds for the constraint's
195 * activity, ignoring the coefficients contributing with infinite value */
196 SCIP_Real glbmaxactivity; /**< maximal value w.r.t. the variable's global bounds for the constraint's
197 * activity, ignoring the coefficients contributing with infinite value */
198 SCIP_Real lastglbminactivity; /**< last global minimal activity which was computed by complete summation
199 * over all contributing values */
200 SCIP_Real lastglbmaxactivity; /**< last global maximal activity which was computed by complete summation
201 * over all contributing values */
202 SCIP_Real maxactdelta; /**< maximal activity contribution of a single variable, or SCIP_INVALID if invalid */
203 SCIP_VAR* maxactdeltavar; /**< variable with maximal activity contribution, or NULL if invalid */
204 uint64_t possignature; /**< bit signature of coefficients that may take a positive value */
205 uint64_t negsignature; /**< bit signature of coefficients that may take a negative value */
206 SCIP_ROW* row; /**< LP row, if constraint is already stored in LP row format */
207 SCIP_VAR** vars; /**< variables of constraint entries */
208 SCIP_Real* vals; /**< coefficients of constraint entries */
209 SCIP_EVENTDATA** eventdata; /**< event data for bound change events of the variables */
210 int minactivityneginf; /**< number of coefficients contributing with neg. infinite value to minactivity */
211 int minactivityposinf; /**< number of coefficients contributing with pos. infinite value to minactivity */
212 int maxactivityneginf; /**< number of coefficients contributing with neg. infinite value to maxactivity */
213 int maxactivityposinf; /**< number of coefficients contributing with pos. infinite value to maxactivity */
214 int minactivityneghuge; /**< number of coefficients contributing with huge neg. value to minactivity */
215 int minactivityposhuge; /**< number of coefficients contributing with huge pos. value to minactivity */
216 int maxactivityneghuge; /**< number of coefficients contributing with huge neg. value to maxactivity */
217 int maxactivityposhuge; /**< number of coefficients contributing with huge pos. value to maxactivity */
218 int glbminactivityneginf;/**< number of coefficients contrib. with neg. infinite value to glbminactivity */
219 int glbminactivityposinf;/**< number of coefficients contrib. with pos. infinite value to glbminactivity */
220 int glbmaxactivityneginf;/**< number of coefficients contrib. with neg. infinite value to glbmaxactivity */
221 int glbmaxactivityposinf;/**< number of coefficients contrib. with pos. infinite value to glbmaxactivity */
222 int glbminactivityneghuge;/**< number of coefficients contrib. with huge neg. value to glbminactivity */
223 int glbminactivityposhuge;/**< number of coefficients contrib. with huge pos. value to glbminactivity */
224 int glbmaxactivityneghuge;/**< number of coefficients contrib. with huge neg. value to glbmaxactivity */
225 int glbmaxactivityposhuge;/**< number of coefficients contrib. with huge pos. value to glbmaxactivity */
226 int varssize; /**< size of the vars- and vals-arrays */
227 int nvars; /**< number of nonzeros in constraint */
228 int nbinvars; /**< the number of binary variables in the constraint, only valid after
229 * sorting in stage >= SCIP_STAGE_INITSOLVE
230 */
231 unsigned int boundstightened:2; /**< is constraint already propagated with bound tightening? */
232 unsigned int rangedrowpropagated:2; /**< did we perform ranged row propagation on this constraint?
233 * (0: no, 1: yes, 2: with potentially adding artificial constraint */
234 unsigned int validmaxabsval:1; /**< is the maximum absolute value valid? */
235 unsigned int validminabsval:1; /**< is the minimum absolute value valid? */
236 unsigned int validactivities:1; /**< are the activity bounds (local and global) valid? */
237 unsigned int validminact:1; /**< is the local minactivity valid? */
238 unsigned int validmaxact:1; /**< is the local maxactivity valid? */
239 unsigned int validglbminact:1; /**< is the global minactivity valid? */
240 unsigned int validglbmaxact:1; /**< is the global maxactivity valid? */
241 unsigned int presolved:1; /**< is constraint already presolved? */
242 unsigned int removedfixings:1; /**< are all fixed variables removed from the constraint? */
243 unsigned int validsignature:1; /**< is the bit signature valid? */
244 unsigned int changed:1; /**< was constraint changed since last aggregation round in preprocessing? */
245 unsigned int normalized:1; /**< is the constraint in normalized form? */
246 unsigned int upgradetried:1; /**< was the constraint already tried to be upgraded? */
247 unsigned int upgraded:1; /**< is the constraint upgraded and will it be removed after preprocessing? */
248 unsigned int indexsorted:1; /**< are the constraint's variables sorted by type and index? */
249 unsigned int merged:1; /**< are the constraint's equal variables already merged? */
250 unsigned int cliquesadded:1; /**< were the cliques of the constraint already extracted? */
251 unsigned int implsadded:1; /**< were the implications of the constraint already extracted? */
252 unsigned int coefsorted:1; /**< are variables sorted by type and their absolute activity delta? */
253 unsigned int varsdeleted:1; /**< were variables deleted after last cleanup? */
254 unsigned int hascontvar:1; /**< does the constraint contain at least one continuous variable? */
255 unsigned int hasnonbinvar:1; /**< does the constraint contain at least one non-binary variable? */
256 unsigned int hasnonbinvalid:1; /**< is the information stored in hasnonbinvar and hascontvar valid? */
257 unsigned int checkabsolute:1; /**< should the constraint be checked w.r.t. an absolute feasibilty tolerance? */
258 };
259
260 /** event data for bound change event */
261 struct SCIP_EventData
262 {
263 SCIP_CONS* cons; /**< linear constraint to process the bound change for */
264 int varpos; /**< position of variable in vars array */
265 int filterpos; /**< position of event in variable's event filter */
266 };
267
268 /** constraint handler data */
269 struct SCIP_ConshdlrData
270 {
271 SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
272 SCIP_LINCONSUPGRADE** linconsupgrades; /**< linear constraint upgrade methods for specializing linear constraints */
273 SCIP_Real maxaggrnormscale; /**< maximal allowed relative gain in maximum norm for constraint aggregation
274 * (0.0: disable constraint aggregation) */
275 SCIP_Real maxcardbounddist; /**< maximal relative distance from current node's dual bound to primal bound compared
276 * to best node's dual bound for separating knapsack cardinality cuts */
277 SCIP_Real mingainpernmincomp; /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise comparison round */
278 SCIP_Real maxeasyactivitydelta;/**< maximum activity delta to run easy propagation on linear constraint
279 * (faster, but numerically less stable) */
280 int linconsupgradessize;/**< size of linconsupgrade array */
281 int nlinconsupgrades; /**< number of linear constraint upgrade methods */
282 int tightenboundsfreq; /**< multiplier on propagation frequency, how often the bounds are tightened */
283 int maxrounds; /**< maximal number of separation rounds per node (-1: unlimited) */
284 int maxroundsroot; /**< maximal number of separation rounds in the root node (-1: unlimited) */
285 int maxsepacuts; /**< maximal number of cuts separated per separation round */
286 int maxsepacutsroot; /**< maximal number of cuts separated per separation round in root node */
287 int nmincomparisons; /**< number for minimal pairwise presolving comparisons */
288 int naddconss; /**< number of added constraints */
289 SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
290 SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance */
291 SCIP_Bool separateall; /**< should all constraints be subject to cardinality cut generation instead of only
292 * the ones with non-zero dual value? */
293 SCIP_Bool aggregatevariables; /**< should presolving search for redundant variables in equations */
294 SCIP_Bool simplifyinequalities;/**< should presolving try to cancel down or delete coefficients in inequalities */
295 SCIP_Bool dualpresolving; /**< should dual presolving steps be performed? */
296 SCIP_Bool singletonstuffing; /**< should stuffing of singleton continuous variables be performed? */
297 SCIP_Bool singlevarstuffing; /**< should single variable stuffing be performed, which tries to fulfill
298 * constraints using the cheapest variable? */
299 SCIP_Bool sortvars; /**< should binary variables be sorted for faster propagation? */
300 SCIP_Bool checkrelmaxabs; /**< should the violation for a constraint with side 0.0 be checked relative
301 * to 1.0 (FALSE) or to the maximum absolute value in the activity (TRUE)? */
302 SCIP_Bool detectcutoffbound; /**< should presolving try to detect constraints parallel to the objective
303 * function defining an upper bound and prevent these constraints from
304 * entering the LP */
305 SCIP_Bool detectlowerbound; /**< should presolving try to detect constraints parallel to the objective
306 * function defining a lower bound and prevent these constraints from
307 * entering the LP */
308 SCIP_Bool detectpartialobjective;/**< should presolving try to detect subsets of constraints parallel to
309 * the objective function */
310 SCIP_Bool rangedrowpropagation;/**< should presolving and propagation try to improve bounds, detect
311 * infeasibility, and extract sub-constraints from ranged rows and
312 * equations */
313 SCIP_Bool rangedrowartcons; /**< should presolving and propagation extract sub-constraints from ranged rows and equations?*/
314 int rangedrowmaxdepth; /**< maximum depth to apply ranged row propagation */
315 int rangedrowfreq; /**< frequency for applying ranged row propagation */
316 SCIP_Bool multaggrremove; /**< should multi-aggregations only be performed if the constraint can be
317 * removed afterwards? */
318 SCIP_Real maxmultaggrquot; /**< maximum coefficient dynamism (ie. maxabsval / minabsval) for primal multiaggregation */
319 SCIP_Real maxdualmultaggrquot;/**< maximum coefficient dynamism (ie. maxabsval / minabsval) for dual multiaggregation */
320 SCIP_Bool extractcliques; /**< should cliques be extracted? */
321 };
322
323 /** linear constraint update method */
324 struct SCIP_LinConsUpgrade
325 {
326 SCIP_DECL_LINCONSUPGD((*linconsupgd)); /**< method to call for upgrading linear constraint */
327 int priority; /**< priority of upgrading method */
328 SCIP_Bool active; /**< is upgrading enabled */
329 };
330
331
332 /*
333 * Propagation rules
334 */
335
336 enum Proprule
337 {
338 PROPRULE_1_RHS = 1, /**< activity residuals of all other variables tighten bounds of single
339 * variable due to the right hand side of the inequality */
340 PROPRULE_1_LHS = 2, /**< activity residuals of all other variables tighten bounds of single
341 * variable due to the left hand side of the inequality */
342 PROPRULE_1_RANGEDROW = 3, /**< fixed variables and gcd of all left variables tighten bounds of a
343 * single variable in this reanged row */
344 PROPRULE_INVALID = 0 /**< propagation was applied without a specific propagation rule */
345 };
346 typedef enum Proprule PROPRULE;
347
348 /** inference information */
349 struct InferInfo
350 {
351 union
352 {
353 struct
354 {
355 unsigned int proprule:8; /**< propagation rule that was applied */
356 unsigned int pos:24; /**< variable position, the propagation rule was applied at */
357 } asbits;
358 int asint; /**< inference information as a single int value */
359 } val;
360 };
361 typedef struct InferInfo INFERINFO;
362
363 /** converts an integer into an inference information */
364 static
intToInferInfo(int i)365 INFERINFO intToInferInfo(
366 int i /**< integer to convert */
367 )
368 {
369 INFERINFO inferinfo;
370
371 inferinfo.val.asint = i;
372
373 return inferinfo;
374 }
375
376 /** converts an inference information into an int */
377 static
inferInfoToInt(INFERINFO inferinfo)378 int inferInfoToInt(
379 INFERINFO inferinfo /**< inference information to convert */
380 )
381 {
382 return inferinfo.val.asint;
383 }
384
385 /** returns the propagation rule stored in the inference information */
386 static
inferInfoGetProprule(INFERINFO inferinfo)387 int inferInfoGetProprule(
388 INFERINFO inferinfo /**< inference information to convert */
389 )
390 {
391 return (int) inferinfo.val.asbits.proprule;
392 }
393
394 /** returns the position stored in the inference information */
395 static
inferInfoGetPos(INFERINFO inferinfo)396 int inferInfoGetPos(
397 INFERINFO inferinfo /**< inference information to convert */
398 )
399 {
400 return (int) inferinfo.val.asbits.pos;
401 }
402
403 /** constructs an inference information out of a propagation rule and a position number */
404 static
getInferInfo(PROPRULE proprule,int pos)405 INFERINFO getInferInfo(
406 PROPRULE proprule, /**< propagation rule that deduced the value */
407 int pos /**< variable position, the propagation rule was applied at */
408 )
409 {
410 INFERINFO inferinfo;
411
412 assert(pos >= 0);
413 /* in the inferinfo struct only 24 bits for 'pos' are reserved */
414 assert(pos < (1<<24));
415
416 inferinfo.val.asbits.proprule = (unsigned int) proprule; /*lint !e641*/
417 inferinfo.val.asbits.pos = (unsigned int) pos; /*lint !e732*/
418
419 return inferinfo;
420 }
421
422 /** constructs an inference information out of a propagation rule and a position number, returns info as int */
423 static
getInferInt(PROPRULE proprule,int pos)424 int getInferInt(
425 PROPRULE proprule, /**< propagation rule that deduced the value */
426 int pos /**< variable position, the propagation rule was applied at */
427 )
428 {
429 return inferInfoToInt(getInferInfo(proprule, pos));
430 }
431
432
433 /*
434 * memory growing methods for dynamically allocated arrays
435 */
436
437 /** ensures, that linconsupgrades array can store at least num entries */
438 static
conshdlrdataEnsureLinconsupgradesSize(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,int num)439 SCIP_RETCODE conshdlrdataEnsureLinconsupgradesSize(
440 SCIP* scip, /**< SCIP data structure */
441 SCIP_CONSHDLRDATA* conshdlrdata, /**< linear constraint handler data */
442 int num /**< minimum number of entries to store */
443 )
444 {
445 assert(scip != NULL);
446 assert(conshdlrdata != NULL);
447 assert(conshdlrdata->nlinconsupgrades <= conshdlrdata->linconsupgradessize);
448
449 if( num > conshdlrdata->linconsupgradessize )
450 {
451 int newsize;
452
453 newsize = SCIPcalcMemGrowSize(scip, num);
454 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &conshdlrdata->linconsupgrades, conshdlrdata->linconsupgradessize, newsize) );
455 conshdlrdata->linconsupgradessize = newsize;
456 }
457 assert(num <= conshdlrdata->linconsupgradessize);
458
459 return SCIP_OKAY;
460 }
461
462 /** ensures, that vars and vals arrays can store at least num entries */
463 static
consdataEnsureVarsSize(SCIP * scip,SCIP_CONSDATA * consdata,int num)464 SCIP_RETCODE consdataEnsureVarsSize(
465 SCIP* scip, /**< SCIP data structure */
466 SCIP_CONSDATA* consdata, /**< linear constraint data */
467 int num /**< minimum number of entries to store */
468 )
469 {
470 assert(scip != NULL);
471 assert(consdata != NULL);
472 assert(consdata->nvars <= consdata->varssize);
473
474 if( num > consdata->varssize )
475 {
476 int newsize;
477
478 newsize = SCIPcalcMemGrowSize(scip, num);
479 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
480 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vals, consdata->varssize, newsize) );
481 if( consdata->eventdata != NULL )
482 {
483 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventdata, consdata->varssize, newsize) );
484 }
485 consdata->varssize = newsize;
486 }
487 assert(num <= consdata->varssize);
488
489 return SCIP_OKAY;
490 }
491
492
493 /*
494 * local methods for managing linear constraint update methods
495 */
496
497 /** creates a linear constraint upgrade data object */
498 static
linconsupgradeCreate(SCIP * scip,SCIP_LINCONSUPGRADE ** linconsupgrade,SCIP_DECL_LINCONSUPGD ((* linconsupgd)),int priority)499 SCIP_RETCODE linconsupgradeCreate(
500 SCIP* scip, /**< SCIP data structure */
501 SCIP_LINCONSUPGRADE** linconsupgrade, /**< pointer to store the linear constraint upgrade */
502 SCIP_DECL_LINCONSUPGD((*linconsupgd)), /**< method to call for upgrading linear constraint */
503 int priority /**< priority of upgrading method */
504 )
505 {
506 assert(scip != NULL);
507 assert(linconsupgrade != NULL);
508 assert(linconsupgd != NULL);
509
510 SCIP_CALL( SCIPallocBlockMemory(scip, linconsupgrade) );
511 (*linconsupgrade)->linconsupgd = linconsupgd;
512 (*linconsupgrade)->priority = priority;
513 (*linconsupgrade)->active = TRUE;
514
515 return SCIP_OKAY;
516 }
517
518 /** frees a linear constraint upgrade data object */
519 static
linconsupgradeFree(SCIP * scip,SCIP_LINCONSUPGRADE ** linconsupgrade)520 void linconsupgradeFree(
521 SCIP* scip, /**< SCIP data structure */
522 SCIP_LINCONSUPGRADE** linconsupgrade /**< pointer to the linear constraint upgrade */
523 )
524 {
525 assert(scip != NULL);
526 assert(linconsupgrade != NULL);
527 assert(*linconsupgrade != NULL);
528
529 SCIPfreeBlockMemory(scip, linconsupgrade);
530 }
531
532 /** creates constraint handler data for linear constraint handler */
533 static
conshdlrdataCreate(SCIP * scip,SCIP_CONSHDLRDATA ** conshdlrdata,SCIP_EVENTHDLR * eventhdlr)534 SCIP_RETCODE conshdlrdataCreate(
535 SCIP* scip, /**< SCIP data structure */
536 SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
537 SCIP_EVENTHDLR* eventhdlr /**< event handler */
538 )
539 {
540 assert(scip != NULL);
541 assert(conshdlrdata != NULL);
542 assert(eventhdlr != NULL);
543
544 SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
545 (*conshdlrdata)->linconsupgrades = NULL;
546 (*conshdlrdata)->linconsupgradessize = 0;
547 (*conshdlrdata)->nlinconsupgrades = 0;
548 (*conshdlrdata)->naddconss = 0;
549
550 /* set event handler for updating linear constraint activity bounds */
551 (*conshdlrdata)->eventhdlr = eventhdlr;
552
553 return SCIP_OKAY;
554 }
555
556 /** frees constraint handler data for linear constraint handler */
557 static
conshdlrdataFree(SCIP * scip,SCIP_CONSHDLRDATA ** conshdlrdata)558 void conshdlrdataFree(
559 SCIP* scip, /**< SCIP data structure */
560 SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
561 )
562 {
563 int i;
564
565 assert(scip != NULL);
566 assert(conshdlrdata != NULL);
567 assert(*conshdlrdata != NULL);
568
569 for( i = 0; i < (*conshdlrdata)->nlinconsupgrades; ++i )
570 {
571 linconsupgradeFree(scip, &(*conshdlrdata)->linconsupgrades[i]);
572 }
573 SCIPfreeBlockMemoryArrayNull(scip, &(*conshdlrdata)->linconsupgrades, (*conshdlrdata)->linconsupgradessize);
574
575 SCIPfreeBlockMemory(scip, conshdlrdata);
576 }
577
578 /** creates a linear constraint upgrade data object */
579 static
conshdlrdataHasUpgrade(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_DECL_LINCONSUPGD ((* linconsupgd)),const char * conshdlrname)580 SCIP_Bool conshdlrdataHasUpgrade(
581 SCIP* scip, /**< SCIP data structure */
582 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
583 SCIP_DECL_LINCONSUPGD((*linconsupgd)), /**< method to call for upgrading linear constraint */
584 const char* conshdlrname /**< name of the constraint handler */
585 )
586 {
587 int i;
588
589 assert(scip != NULL);
590 assert(conshdlrdata != NULL);
591 assert(linconsupgd != NULL);
592 assert(conshdlrname != NULL);
593
594 for( i = conshdlrdata->nlinconsupgrades - 1; i >= 0; --i )
595 {
596 if( conshdlrdata->linconsupgrades[i]->linconsupgd == linconsupgd )
597 {
598 #ifdef SCIP_DEBUG
599 SCIPwarningMessage(scip, "Try to add already known upgrade message for constraint handler %s.\n", conshdlrname);
600 #endif
601 return TRUE;
602 }
603 }
604
605 return FALSE;
606 }
607
608 /** adds a linear constraint update method to the constraint handler's data */
609 static
conshdlrdataIncludeUpgrade(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_LINCONSUPGRADE * linconsupgrade)610 SCIP_RETCODE conshdlrdataIncludeUpgrade(
611 SCIP* scip, /**< SCIP data structure */
612 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
613 SCIP_LINCONSUPGRADE* linconsupgrade /**< linear constraint upgrade method */
614 )
615 {
616 int i;
617
618 assert(scip != NULL);
619 assert(conshdlrdata != NULL);
620 assert(linconsupgrade != NULL);
621
622 SCIP_CALL( conshdlrdataEnsureLinconsupgradesSize(scip, conshdlrdata, conshdlrdata->nlinconsupgrades+1) );
623
624 for( i = conshdlrdata->nlinconsupgrades;
625 i > 0 && conshdlrdata->linconsupgrades[i-1]->priority < linconsupgrade->priority; --i )
626 {
627 conshdlrdata->linconsupgrades[i] = conshdlrdata->linconsupgrades[i-1];
628 }
629 assert(0 <= i && i <= conshdlrdata->nlinconsupgrades);
630 conshdlrdata->linconsupgrades[i] = linconsupgrade;
631 conshdlrdata->nlinconsupgrades++;
632
633 return SCIP_OKAY;
634 }
635
636 /*
637 * local methods
638 */
639
640 /** installs rounding locks for the given variable associated to the given coefficient in the linear constraint */
641 static
lockRounding(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * var,SCIP_Real val)642 SCIP_RETCODE lockRounding(
643 SCIP* scip, /**< SCIP data structure */
644 SCIP_CONS* cons, /**< linear constraint */
645 SCIP_VAR* var, /**< variable of constraint entry */
646 SCIP_Real val /**< coefficient of constraint entry */
647 )
648 {
649 SCIP_CONSDATA* consdata;
650
651 assert(scip != NULL);
652 assert(cons != NULL);
653 assert(var != NULL);
654
655 consdata = SCIPconsGetData(cons);
656 assert(consdata != NULL);
657 assert(!SCIPisZero(scip, val));
658
659 if( SCIPisPositive(scip, val) )
660 {
661 SCIP_CALL( SCIPlockVarCons(scip, var, cons,
662 !SCIPisInfinity(scip, -consdata->lhs), !SCIPisInfinity(scip, consdata->rhs)) );
663 }
664 else
665 {
666 SCIP_CALL( SCIPlockVarCons(scip, var, cons,
667 !SCIPisInfinity(scip, consdata->rhs), !SCIPisInfinity(scip, -consdata->lhs)) );
668 }
669
670 return SCIP_OKAY;
671 }
672
673 /** removes rounding locks for the given variable associated to the given coefficient in the linear constraint */
674 static
unlockRounding(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * var,SCIP_Real val)675 SCIP_RETCODE unlockRounding(
676 SCIP* scip, /**< SCIP data structure */
677 SCIP_CONS* cons, /**< linear constraint */
678 SCIP_VAR* var, /**< variable of constraint entry */
679 SCIP_Real val /**< coefficient of constraint entry */
680 )
681 {
682 SCIP_CONSDATA* consdata;
683
684 assert(scip != NULL);
685 assert(cons != NULL);
686 assert(var != NULL);
687
688 consdata = SCIPconsGetData(cons);
689 assert(consdata != NULL);
690 assert(!SCIPisZero(scip, val));
691
692 if( SCIPisPositive(scip, val) )
693 {
694 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, -consdata->lhs),
695 !SCIPisInfinity(scip, consdata->rhs)) );
696 }
697 else
698 {
699 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, !SCIPisInfinity(scip, consdata->rhs),
700 !SCIPisInfinity(scip, -consdata->lhs)) );
701 }
702
703 return SCIP_OKAY;
704 }
705
706 /** creates event data for variable at given position, and catches events */
707 /**! [SnippetDebugAssertions] */
708 static
consCatchEvent(SCIP * scip,SCIP_CONS * cons,SCIP_EVENTHDLR * eventhdlr,int pos)709 SCIP_RETCODE consCatchEvent(
710 SCIP* scip, /**< SCIP data structure */
711 SCIP_CONS* cons, /**< linear constraint */
712 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
713 int pos /**< array position of variable to catch bound change events for */
714 )
715 {
716 SCIP_CONSDATA* consdata;
717 assert(scip != NULL);
718 assert(cons != NULL);
719 assert(eventhdlr != NULL);
720
721 consdata = SCIPconsGetData(cons);
722 assert(consdata != NULL);
723
724 assert(0 <= pos && pos < consdata->nvars);
725 assert(consdata->vars != NULL);
726 assert(consdata->vars[pos] != NULL);
727 assert(SCIPvarIsTransformed(consdata->vars[pos]));
728 assert(consdata->eventdata != NULL);
729 assert(consdata->eventdata[pos] == NULL);
730
731 SCIP_CALL( SCIPallocBlockMemory(scip, &(consdata->eventdata[pos])) ); /*lint !e866*/
732 consdata->eventdata[pos]->cons = cons;
733 consdata->eventdata[pos]->varpos = pos;
734
735 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[pos],
736 SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED | SCIP_EVENTTYPE_VARUNLOCKED
737 | SCIP_EVENTTYPE_GBDCHANGED | SCIP_EVENTTYPE_VARDELETED | SCIP_EVENTTYPE_TYPECHANGED,
738 eventhdlr, consdata->eventdata[pos], &consdata->eventdata[pos]->filterpos) );
739
740 consdata->removedfixings = consdata->removedfixings && SCIPvarIsActive(consdata->vars[pos]);
741
742 return SCIP_OKAY;
743 }
744 /**! [SnippetDebugAssertions] */
745
746 /** deletes event data for variable at given position, and drops events */
747 static
consDropEvent(SCIP * scip,SCIP_CONS * cons,SCIP_EVENTHDLR * eventhdlr,int pos)748 SCIP_RETCODE consDropEvent(
749 SCIP* scip, /**< SCIP data structure */
750 SCIP_CONS* cons, /**< linear constraint */
751 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
752 int pos /**< array position of variable to catch bound change events for */
753 )
754 {
755 SCIP_CONSDATA* consdata;
756 assert(scip != NULL);
757 assert(cons != NULL);
758 assert(eventhdlr != NULL);
759
760 consdata = SCIPconsGetData(cons);
761 assert(consdata != NULL);
762
763 assert(0 <= pos && pos < consdata->nvars);
764 assert(consdata->vars[pos] != NULL);
765 assert(consdata->eventdata != NULL);
766 assert(consdata->eventdata[pos] != NULL);
767 assert(consdata->eventdata[pos]->cons == cons);
768 assert(consdata->eventdata[pos]->varpos == pos);
769
770 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos],
771 SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARFIXED | SCIP_EVENTTYPE_VARUNLOCKED
772 | SCIP_EVENTTYPE_GBDCHANGED | SCIP_EVENTTYPE_VARDELETED | SCIP_EVENTTYPE_TYPECHANGED,
773 eventhdlr, consdata->eventdata[pos], consdata->eventdata[pos]->filterpos) );
774
775 SCIPfreeBlockMemory(scip, &consdata->eventdata[pos]); /*lint !e866*/
776
777 return SCIP_OKAY;
778 }
779
780 /** catches bound change events for all variables in transformed linear constraint */
781 static
consCatchAllEvents(SCIP * scip,SCIP_CONS * cons,SCIP_EVENTHDLR * eventhdlr)782 SCIP_RETCODE consCatchAllEvents(
783 SCIP* scip, /**< SCIP data structure */
784 SCIP_CONS* cons, /**< linear constraint */
785 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
786 )
787 {
788 SCIP_CONSDATA* consdata;
789 int i;
790
791 assert(scip != NULL);
792 assert(cons != NULL);
793
794 consdata = SCIPconsGetData(cons);
795 assert(consdata != NULL);
796 assert(consdata->eventdata == NULL);
797
798 /* allocate eventdata array */
799 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eventdata, consdata->varssize) );
800 assert(consdata->eventdata != NULL);
801 BMSclearMemoryArray(consdata->eventdata, consdata->nvars);
802
803 /* catch event for every single variable */
804 for( i = 0; i < consdata->nvars; ++i )
805 {
806 SCIP_CALL( consCatchEvent(scip, cons, eventhdlr, i) );
807 }
808
809 return SCIP_OKAY;
810 }
811
812 /** drops bound change events for all variables in transformed linear constraint */
813 static
consDropAllEvents(SCIP * scip,SCIP_CONS * cons,SCIP_EVENTHDLR * eventhdlr)814 SCIP_RETCODE consDropAllEvents(
815 SCIP* scip, /**< SCIP data structure */
816 SCIP_CONS* cons, /**< linear constraint */
817 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
818 )
819 {
820 SCIP_CONSDATA* consdata;
821 int i;
822
823 assert(scip != NULL);
824 assert(cons != NULL);
825
826 consdata = SCIPconsGetData(cons);
827 assert(consdata != NULL);
828 assert(consdata->eventdata != NULL);
829
830 /* drop event of every single variable */
831 for( i = consdata->nvars - 1; i >= 0; --i )
832 {
833 SCIP_CALL( consDropEvent(scip, cons, eventhdlr, i) );
834 }
835
836 /* free eventdata array */
837 SCIPfreeBlockMemoryArray(scip, &consdata->eventdata, consdata->varssize);
838 assert(consdata->eventdata == NULL);
839
840 return SCIP_OKAY;
841 }
842
843 /** creates a linear constraint data */
844 static
consdataCreate(SCIP * scip,SCIP_CONSDATA ** consdata,int nvars,SCIP_VAR ** vars,SCIP_Real * vals,SCIP_Real lhs,SCIP_Real rhs)845 SCIP_RETCODE consdataCreate(
846 SCIP* scip, /**< SCIP data structure */
847 SCIP_CONSDATA** consdata, /**< pointer to linear constraint data */
848 int nvars, /**< number of nonzeros in the constraint */
849 SCIP_VAR** vars, /**< array with variables of constraint entries */
850 SCIP_Real* vals, /**< array with coefficients of constraint entries */
851 SCIP_Real lhs, /**< left hand side of row */
852 SCIP_Real rhs /**< right hand side of row */
853 )
854 {
855 int v;
856 SCIP_Real constant;
857
858 assert(scip != NULL);
859 assert(consdata != NULL);
860 assert(nvars == 0 || vars != NULL);
861 assert(nvars == 0 || vals != NULL);
862
863 if( SCIPisInfinity(scip, rhs) )
864 rhs = SCIPinfinity(scip);
865 else if( SCIPisInfinity(scip, -rhs) )
866 rhs = -SCIPinfinity(scip);
867
868 if( SCIPisInfinity(scip, -lhs) )
869 lhs = -SCIPinfinity(scip);
870 else if( SCIPisInfinity(scip, lhs) )
871 lhs = SCIPinfinity(scip);
872
873 if( SCIPisGT(scip, lhs, rhs) )
874 {
875 SCIPwarningMessage(scip, "left hand side of linear constraint greater than right hand side\n");
876 SCIPwarningMessage(scip, " -> lhs=%g, rhs=%g\n", lhs, rhs);
877 }
878
879 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
880
881 (*consdata)->varssize = 0;
882 (*consdata)->nvars = nvars;
883 (*consdata)->hascontvar = FALSE;
884 (*consdata)->hasnonbinvar = FALSE;
885 (*consdata)->hasnonbinvalid = TRUE;
886 (*consdata)->vars = NULL;
887 (*consdata)->vals = NULL;
888
889 constant = 0.0;
890 if( nvars > 0 )
891 {
892 int k;
893
894 SCIP_VAR** varsbuffer;
895 SCIP_Real* valsbuffer;
896
897 /* copy variables into temporary buffer */
898 SCIP_CALL( SCIPallocBufferArray(scip, &varsbuffer, nvars) );
899 SCIP_CALL( SCIPallocBufferArray(scip, &valsbuffer, nvars) );
900 k = 0;
901
902 /* loop over variables and sort out fixed ones */
903 for( v = 0; v < nvars; ++v )
904 {
905 SCIP_VAR* var;
906 SCIP_Real val;
907
908 var = vars[v];
909 val = vals[v];
910
911 assert(var != NULL);
912 if( !SCIPisZero(scip, val) )
913 {
914 /* treat fixed variable as a constant if problem compression is enabled */
915 if( SCIPisConsCompressionEnabled(scip) && SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
916 {
917 constant += SCIPvarGetLbGlobal(var) * val;
918 }
919 else
920 {
921 varsbuffer[k] = var;
922 valsbuffer[k] = val;
923 k++;
924
925 /* update hascontvar and hasnonbinvar flags */
926 if( !(*consdata)->hascontvar )
927 {
928 SCIP_VARTYPE vartype = SCIPvarGetType(var);
929
930 if( vartype != SCIP_VARTYPE_BINARY )
931 {
932 (*consdata)->hasnonbinvar = TRUE;
933
934 if( vartype == SCIP_VARTYPE_CONTINUOUS )
935 (*consdata)->hascontvar = TRUE;
936 }
937 }
938 }
939 }
940 }
941 (*consdata)->nvars = k;
942
943 if( k > 0 )
944 {
945 /* copy the possibly reduced buffer arrays into block */
946 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) );
947 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vals, valsbuffer, k) );
948 (*consdata)->varssize = k;
949 }
950 /* free temporary buffer */
951 SCIPfreeBufferArray(scip, &valsbuffer);
952 SCIPfreeBufferArray(scip, &varsbuffer);
953 }
954
955 (*consdata)->eventdata = NULL;
956
957 /* due to compressed copying, we may have fixed variables contributing to the left and right hand side */
958 if( !SCIPisZero(scip, constant) )
959 {
960 if( !SCIPisInfinity(scip, REALABS(lhs)) )
961 lhs -= constant;
962
963 if( !SCIPisInfinity(scip, REALABS(rhs)) )
964 rhs -= constant;
965 }
966
967 (*consdata)->row = NULL;
968 (*consdata)->lhs = lhs;
969 (*consdata)->rhs = rhs;
970 (*consdata)->maxabsval = SCIP_INVALID;
971 (*consdata)->minabsval = SCIP_INVALID;
972 (*consdata)->minactivity = SCIP_INVALID;
973 (*consdata)->maxactivity = SCIP_INVALID;
974 (*consdata)->lastminactivity = SCIP_INVALID;
975 (*consdata)->lastmaxactivity = SCIP_INVALID;
976 (*consdata)->maxactdelta = SCIP_INVALID;
977 (*consdata)->maxactdeltavar = NULL;
978 (*consdata)->minactivityneginf = -1;
979 (*consdata)->minactivityposinf = -1;
980 (*consdata)->maxactivityneginf = -1;
981 (*consdata)->maxactivityposinf = -1;
982 (*consdata)->minactivityneghuge = -1;
983 (*consdata)->minactivityposhuge = -1;
984 (*consdata)->maxactivityneghuge = -1;
985 (*consdata)->maxactivityposhuge = -1;
986 (*consdata)->glbminactivity = SCIP_INVALID;
987 (*consdata)->glbmaxactivity = SCIP_INVALID;
988 (*consdata)->lastglbminactivity = SCIP_INVALID;
989 (*consdata)->lastglbmaxactivity = SCIP_INVALID;
990 (*consdata)->glbminactivityneginf = -1;
991 (*consdata)->glbminactivityposinf = -1;
992 (*consdata)->glbmaxactivityneginf = -1;
993 (*consdata)->glbmaxactivityposinf = -1;
994 (*consdata)->glbminactivityneghuge = -1;
995 (*consdata)->glbminactivityposhuge = -1;
996 (*consdata)->glbmaxactivityneghuge = -1;
997 (*consdata)->glbmaxactivityposhuge = -1;
998 (*consdata)->possignature = 0;
999 (*consdata)->negsignature = 0;
1000 (*consdata)->validmaxabsval = FALSE;
1001 (*consdata)->validminabsval = FALSE;
1002 (*consdata)->validactivities = FALSE;
1003 (*consdata)->validminact = FALSE;
1004 (*consdata)->validmaxact = FALSE;
1005 (*consdata)->validglbminact = FALSE;
1006 (*consdata)->validglbmaxact = FALSE;
1007 (*consdata)->boundstightened = 0;
1008 (*consdata)->presolved = FALSE;
1009 (*consdata)->removedfixings = FALSE;
1010 (*consdata)->validsignature = FALSE;
1011 (*consdata)->changed = TRUE;
1012 (*consdata)->normalized = FALSE;
1013 (*consdata)->upgradetried = FALSE;
1014 (*consdata)->upgraded = FALSE;
1015 (*consdata)->indexsorted = (nvars <= 1);
1016 (*consdata)->merged = (nvars <= 1);
1017 (*consdata)->cliquesadded = FALSE;
1018 (*consdata)->implsadded = FALSE;
1019 (*consdata)->coefsorted = FALSE;
1020 (*consdata)->nbinvars = -1;
1021 (*consdata)->varsdeleted = FALSE;
1022 (*consdata)->rangedrowpropagated = 0;
1023 (*consdata)->checkabsolute = FALSE;
1024
1025 if( SCIPisTransformed(scip) )
1026 {
1027 /* get transformed variables */
1028 SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
1029 }
1030
1031 /* capture variables */
1032 for( v = 0; v < (*consdata)->nvars; v++ )
1033 {
1034 assert((*consdata)->vars[v] != NULL);
1035 assert(!SCIPisZero(scip, (*consdata)->vals[v]));
1036 SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
1037 }
1038
1039 return SCIP_OKAY;
1040 }
1041
1042 /** frees a linear constraint data */
1043 static
consdataFree(SCIP * scip,SCIP_CONSDATA ** consdata)1044 SCIP_RETCODE consdataFree(
1045 SCIP* scip, /**< SCIP data structure */
1046 SCIP_CONSDATA** consdata /**< pointer to linear constraint data */
1047 )
1048 {
1049 int v;
1050
1051 assert(scip != NULL);
1052 assert(consdata != NULL);
1053 assert(*consdata != NULL);
1054 assert((*consdata)->varssize >= 0);
1055
1056 /* release the row */
1057 if( (*consdata)->row != NULL )
1058 {
1059 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
1060 }
1061
1062 /* release variables */
1063 for( v = 0; v < (*consdata)->nvars; v++ )
1064 {
1065 assert((*consdata)->vars[v] != NULL);
1066 assert(!SCIPisZero(scip, (*consdata)->vals[v]));
1067 SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
1068 }
1069
1070 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->vars, (*consdata)->varssize);
1071 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->vals, (*consdata)->varssize);
1072 SCIPfreeBlockMemory(scip, consdata);
1073
1074 return SCIP_OKAY;
1075 }
1076
1077 /** prints linear constraint in CIP format to file stream */
1078 static
consdataPrint(SCIP * scip,SCIP_CONSDATA * consdata,FILE * file)1079 SCIP_RETCODE consdataPrint(
1080 SCIP* scip, /**< SCIP data structure */
1081 SCIP_CONSDATA* consdata, /**< linear constraint data */
1082 FILE* file /**< output file (or NULL for standard output) */
1083 )
1084 {
1085 assert(scip != NULL);
1086 assert(consdata != NULL);
1087
1088 /* print left hand side for ranged rows */
1089 if( !SCIPisInfinity(scip, -consdata->lhs)
1090 && !SCIPisInfinity(scip, consdata->rhs)
1091 && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
1092 SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
1093
1094 /* print coefficients and variables */
1095 if( consdata->nvars == 0 )
1096 SCIPinfoMessage(scip, file, "0");
1097 else
1098 {
1099 /* post linear sum of the linear constraint */
1100 SCIP_CALL( SCIPwriteVarsLinearsum(scip, file, consdata->vars, consdata->vals, consdata->nvars, TRUE) );
1101 }
1102
1103 /* print right hand side */
1104 if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
1105 SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
1106 else if( !SCIPisInfinity(scip, consdata->rhs) )
1107 SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
1108 else if( !SCIPisInfinity(scip, -consdata->lhs) )
1109 SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
1110 else
1111 SCIPinfoMessage(scip, file, " [free]");
1112
1113 return SCIP_OKAY;
1114 }
1115
1116 /** prints linear constraint and contained solution values of variables to file stream */
1117 static
consPrintConsSol(SCIP * scip,SCIP_CONS * cons,SCIP_SOL * sol,FILE * file)1118 SCIP_RETCODE consPrintConsSol(
1119 SCIP* scip, /**< SCIP data structure */
1120 SCIP_CONS* cons, /**< linear constraint */
1121 SCIP_SOL* sol, /**< solution to print */
1122 FILE* file /**< output file (or NULL for standard output) */
1123 )
1124 {
1125 SCIP_CONSDATA* consdata;
1126
1127 assert(scip != NULL);
1128 assert(cons != NULL);
1129
1130 consdata = SCIPconsGetData(cons);
1131 assert(consdata != NULL);
1132
1133 SCIPmessageFPrintInfo(SCIPgetMessagehdlr(scip), file, " [%s] <%s>: ", SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), SCIPconsGetName(cons));
1134
1135 /* print left hand side for ranged rows */
1136 if( !SCIPisInfinity(scip, -consdata->lhs)
1137 && !SCIPisInfinity(scip, consdata->rhs)
1138 && !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
1139 SCIPinfoMessage(scip, file, "%.15g <= ", consdata->lhs);
1140
1141 /* print coefficients and variables */
1142 if( consdata->nvars == 0 )
1143 SCIPinfoMessage(scip, file, "0");
1144 else
1145 {
1146 int v;
1147
1148 /* post linear sum of the linear constraint */
1149 for( v = 0; v < consdata->nvars; ++v )
1150 {
1151 if( consdata->vals != NULL )
1152 {
1153 if( consdata->vals[v] == 1.0 )
1154 {
1155 if( v > 0 )
1156 SCIPinfoMessage(scip, file, " +");
1157 }
1158 else if( consdata->vals[v] == -1.0 )
1159 SCIPinfoMessage(scip, file, " -");
1160 else
1161 SCIPinfoMessage(scip, file, " %+.9g", consdata->vals[v]);
1162 }
1163 else if( consdata->nvars > 0 )
1164 SCIPinfoMessage(scip, file, " +");
1165
1166 /* print variable name */
1167 SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[v], TRUE) );
1168
1169 SCIPinfoMessage(scip, file, " (%+.9g)", SCIPgetSolVal(scip, sol, consdata->vars[v]));
1170 }
1171 }
1172
1173 /* print right hand side */
1174 if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
1175 SCIPinfoMessage(scip, file, " == %.15g", consdata->rhs);
1176 else if( !SCIPisInfinity(scip, consdata->rhs) )
1177 SCIPinfoMessage(scip, file, " <= %.15g", consdata->rhs);
1178 else if( !SCIPisInfinity(scip, -consdata->lhs) )
1179 SCIPinfoMessage(scip, file, " >= %.15g", consdata->lhs);
1180 else
1181 SCIPinfoMessage(scip, file, " [free]");
1182
1183 SCIPinfoMessage(scip, file, ";\n");
1184
1185 return SCIP_OKAY;
1186 }
1187
1188 /** invalidates activity bounds, such that they are recalculated in next get */
1189 static
consdataInvalidateActivities(SCIP_CONSDATA * consdata)1190 void consdataInvalidateActivities(
1191 SCIP_CONSDATA* consdata /**< linear constraint */
1192 )
1193 {
1194 assert(consdata != NULL);
1195
1196 consdata->validactivities = FALSE;
1197 consdata->validminact = FALSE;
1198 consdata->validmaxact = FALSE;
1199 consdata->validglbminact = FALSE;
1200 consdata->validglbmaxact = FALSE;
1201 consdata->validmaxabsval = FALSE;
1202 consdata->validminabsval = FALSE;
1203 consdata->hasnonbinvalid = FALSE;
1204 consdata->minactivity = SCIP_INVALID;
1205 consdata->maxactivity = SCIP_INVALID;
1206 consdata->lastminactivity = SCIP_INVALID;
1207 consdata->lastmaxactivity = SCIP_INVALID;
1208 consdata->maxabsval = SCIP_INVALID;
1209 consdata->minabsval = SCIP_INVALID;
1210 consdata->maxactdelta = SCIP_INVALID;
1211 consdata->maxactdeltavar = NULL;
1212 consdata->minactivityneginf = -1;
1213 consdata->minactivityposinf = -1;
1214 consdata->maxactivityneginf = -1;
1215 consdata->maxactivityposinf = -1;
1216 consdata->minactivityneghuge = -1;
1217 consdata->minactivityposhuge = -1;
1218 consdata->maxactivityneghuge = -1;
1219 consdata->maxactivityposhuge = -1;
1220 consdata->glbminactivity = SCIP_INVALID;
1221 consdata->glbmaxactivity = SCIP_INVALID;
1222 consdata->lastglbminactivity = SCIP_INVALID;
1223 consdata->lastglbmaxactivity = SCIP_INVALID;
1224 consdata->glbminactivityneginf = -1;
1225 consdata->glbminactivityposinf = -1;
1226 consdata->glbmaxactivityneginf = -1;
1227 consdata->glbmaxactivityposinf = -1;
1228 consdata->glbminactivityneghuge = -1;
1229 consdata->glbminactivityposhuge = -1;
1230 consdata->glbmaxactivityneghuge = -1;
1231 consdata->glbmaxactivityposhuge = -1;
1232 }
1233
1234 /** compute the pseudo activity of a constraint */
1235 static
consdataComputePseudoActivity(SCIP * scip,SCIP_CONSDATA * consdata)1236 SCIP_Real consdataComputePseudoActivity(
1237 SCIP* scip, /**< SCIP data structure */
1238 SCIP_CONSDATA* consdata /**< linear constraint data */
1239 )
1240 {
1241 int i;
1242 int pseudoactivityposinf;
1243 int pseudoactivityneginf;
1244 SCIP_Real pseudoactivity;
1245 SCIP_Real bound;
1246 SCIP_Real val;
1247
1248 pseudoactivity = 0;
1249 pseudoactivityposinf = 0;
1250 pseudoactivityneginf = 0;
1251
1252 for( i = consdata->nvars - 1; i >= 0; --i )
1253 {
1254 val = consdata->vals[i];
1255 bound = (SCIPvarGetBestBoundType(consdata->vars[i]) == SCIP_BOUNDTYPE_LOWER) ? SCIPvarGetLbLocal(consdata->vars[i]) : SCIPvarGetUbLocal(consdata->vars[i]);
1256 if( SCIPisInfinity(scip, bound) )
1257 {
1258 if( val > 0.0 )
1259 pseudoactivityposinf++;
1260 else
1261 pseudoactivityneginf++;
1262 }
1263 else
1264 {
1265 if( SCIPisInfinity(scip, -bound) )
1266 {
1267 if( val > 0.0 )
1268 pseudoactivityneginf++;
1269 else
1270 pseudoactivityposinf++;
1271 }
1272 else
1273 pseudoactivity += val * bound;
1274 }
1275 }
1276
1277 if( pseudoactivityneginf > 0 && pseudoactivityposinf > 0 )
1278 return SCIP_INVALID;
1279 else if( pseudoactivityneginf > 0 )
1280 return -SCIPinfinity(scip);
1281 else if( pseudoactivityposinf > 0 )
1282 return SCIPinfinity(scip);
1283
1284 return pseudoactivity;
1285 }
1286
1287 /** recompute the minactivity of a constraint */
1288 static
consdataRecomputeMinactivity(SCIP * scip,SCIP_CONSDATA * consdata)1289 void consdataRecomputeMinactivity(
1290 SCIP* scip, /**< SCIP data structure */
1291 SCIP_CONSDATA* consdata /**< linear constraint data */
1292 )
1293 {
1294 int i;
1295 SCIP_Real bound;
1296
1297 consdata->minactivity = 0;
1298
1299 for( i = consdata->nvars - 1; i >= 0; --i )
1300 {
1301 bound = (consdata->vals[i] > 0.0 ) ? SCIPvarGetLbLocal(consdata->vars[i]) : SCIPvarGetUbLocal(consdata->vars[i]);
1302 if( !SCIPisInfinity(scip, bound) && !SCIPisInfinity(scip, -bound)
1303 && !SCIPisHugeValue(scip, consdata->vals[i] * bound) && !SCIPisHugeValue(scip, -consdata->vals[i] * bound) )
1304 consdata->minactivity += consdata->vals[i] * bound;
1305 }
1306
1307 /* the activity was just computed from scratch and is valid now */
1308 consdata->validminact = TRUE;
1309
1310 /* the activity was just computed from scratch, mark it to be reliable */
1311 consdata->lastminactivity = consdata->minactivity;
1312 }
1313
1314 /** recompute the maxactivity of a constraint */
1315 static
consdataRecomputeMaxactivity(SCIP * scip,SCIP_CONSDATA * consdata)1316 void consdataRecomputeMaxactivity(
1317 SCIP* scip, /**< SCIP data structure */
1318 SCIP_CONSDATA* consdata /**< linear constraint data */
1319 )
1320 {
1321 int i;
1322 SCIP_Real bound;
1323
1324 consdata->maxactivity = 0;
1325
1326 for( i = consdata->nvars - 1; i >= 0; --i )
1327 {
1328 bound = (consdata->vals[i] > 0.0 ) ? SCIPvarGetUbLocal(consdata->vars[i]) : SCIPvarGetLbLocal(consdata->vars[i]);
1329 if( !SCIPisInfinity(scip, bound) && !SCIPisInfinity(scip, -bound)
1330 && !SCIPisHugeValue(scip, consdata->vals[i] * bound) && !SCIPisHugeValue(scip, -consdata->vals[i] * bound) )
1331 consdata->maxactivity += consdata->vals[i] * bound;
1332 }
1333
1334 /* the activity was just computed from scratch and is valid now */
1335 consdata->validmaxact = TRUE;
1336
1337 /* the activity was just computed from scratch, mark it to be reliable */
1338 consdata->lastmaxactivity = consdata->maxactivity;
1339 }
1340
1341 /** recompute the global minactivity of a constraint */
1342 static
consdataRecomputeGlbMinactivity(SCIP * scip,SCIP_CONSDATA * consdata)1343 void consdataRecomputeGlbMinactivity(
1344 SCIP* scip, /**< SCIP data structure */
1345 SCIP_CONSDATA* consdata /**< linear constraint data */
1346 )
1347 {
1348 int i;
1349 SCIP_Real bound;
1350
1351 consdata->glbminactivity = 0;
1352
1353 for( i = consdata->nvars - 1; i >= 0; --i )
1354 {
1355 bound = (consdata->vals[i] > 0.0 ) ? SCIPvarGetLbGlobal(consdata->vars[i]) : SCIPvarGetUbGlobal(consdata->vars[i]);
1356 if( !SCIPisInfinity(scip, bound) && !SCIPisInfinity(scip, -bound)
1357 && !SCIPisHugeValue(scip, consdata->vals[i] * bound) && !SCIPisHugeValue(scip, -consdata->vals[i] * bound) )
1358 consdata->glbminactivity += consdata->vals[i] * bound;
1359 }
1360
1361 /* the activity was just computed from scratch and is valid now */
1362 consdata->validglbminact = TRUE;
1363
1364 /* the activity was just computed from scratch, mark it to be reliable */
1365 consdata->lastglbminactivity = consdata->glbminactivity;
1366 }
1367
1368 /** recompute the global maxactivity of a constraint */
1369 static
consdataRecomputeGlbMaxactivity(SCIP * scip,SCIP_CONSDATA * consdata)1370 void consdataRecomputeGlbMaxactivity(
1371 SCIP* scip, /**< SCIP data structure */
1372 SCIP_CONSDATA* consdata /**< linear constraint data */
1373 )
1374 {
1375 int i;
1376 SCIP_Real bound;
1377
1378 consdata->glbmaxactivity = 0;
1379
1380 for( i = consdata->nvars - 1; i >= 0; --i )
1381 {
1382 bound = (consdata->vals[i] > 0.0 ) ? SCIPvarGetUbGlobal(consdata->vars[i]) : SCIPvarGetLbGlobal(consdata->vars[i]);
1383 if( !SCIPisInfinity(scip, bound) && !SCIPisInfinity(scip, -bound)
1384 && !SCIPisHugeValue(scip, consdata->vals[i] * bound) && !SCIPisHugeValue(scip, -consdata->vals[i] * bound) )
1385 consdata->glbmaxactivity += consdata->vals[i] * bound;
1386 }
1387
1388 /* the activity was just computed from scratch and is valid now */
1389 consdata->validglbmaxact = TRUE;
1390
1391 /* the activity was just computed from scratch, mark it to be reliable */
1392 consdata->lastglbmaxactivity = consdata->glbmaxactivity;
1393 }
1394
1395 /** calculates maximum absolute value of coefficients */
1396 static
consdataCalcMaxAbsval(SCIP_CONSDATA * consdata)1397 void consdataCalcMaxAbsval(
1398 SCIP_CONSDATA* consdata /**< linear constraint data */
1399 )
1400 {
1401 SCIP_Real absval;
1402 int i;
1403
1404 assert(consdata != NULL);
1405 assert(!consdata->validmaxabsval);
1406 assert(consdata->maxabsval >= SCIP_INVALID);
1407
1408 consdata->validmaxabsval = TRUE;
1409 consdata->maxabsval = 0.0;
1410 for( i = 0; i < consdata->nvars; ++i )
1411 {
1412 absval = consdata->vals[i];
1413 absval = REALABS(absval);
1414 if( absval > consdata->maxabsval )
1415 consdata->maxabsval = absval;
1416 }
1417 }
1418
1419 /** calculates minimum absolute value of coefficients */
1420 static
consdataCalcMinAbsval(SCIP_CONSDATA * consdata)1421 void consdataCalcMinAbsval(
1422 SCIP_CONSDATA* consdata /**< linear constraint data */
1423 )
1424 {
1425 SCIP_Real absval;
1426 int i;
1427
1428 assert(consdata != NULL);
1429 assert(!consdata->validminabsval);
1430 assert(consdata->minabsval >= SCIP_INVALID);
1431
1432 consdata->validminabsval = TRUE;
1433
1434 if( consdata->nvars > 0 )
1435 consdata->minabsval = REALABS(consdata->vals[0]);
1436 else
1437 consdata->minabsval = 0.0;
1438
1439 for( i = 1; i < consdata->nvars; ++i )
1440 {
1441 absval = consdata->vals[i];
1442 absval = REALABS(absval);
1443 if( absval < consdata->minabsval )
1444 consdata->minabsval = absval;
1445 }
1446 }
1447
1448 /** checks the type of all variables of the constraint and sets hasnonbinvar and hascontvar flags accordingly */
1449 static
consdataCheckNonbinvar(SCIP_CONSDATA * consdata)1450 void consdataCheckNonbinvar(
1451 SCIP_CONSDATA* consdata /**< linear constraint data */
1452 )
1453 {
1454 int v;
1455
1456 assert(!consdata->hasnonbinvalid);
1457 consdata->hasnonbinvar = FALSE;
1458 consdata->hascontvar = FALSE;
1459
1460 for( v = consdata->nvars - 1; v >= 0; --v )
1461 {
1462 SCIP_VARTYPE vartype = SCIPvarGetType(consdata->vars[v]);
1463
1464 if( vartype != SCIP_VARTYPE_BINARY )
1465 {
1466 consdata->hasnonbinvar = TRUE;
1467
1468 if( vartype == SCIP_VARTYPE_CONTINUOUS )
1469 {
1470 consdata->hascontvar = TRUE;
1471 break;
1472 }
1473 }
1474 }
1475 assert(consdata->hascontvar || v < 0);
1476
1477 consdata->hasnonbinvalid = TRUE;
1478 }
1479
1480
1481 #ifdef CHECKMAXACTDELTA
1482 /** checks that the stored maximal activity delta (if not invalid) is correct */
1483 static
checkMaxActivityDelta(SCIP * scip,SCIP_CONSDATA * consdata)1484 void checkMaxActivityDelta(
1485 SCIP* scip, /**< SCIP data structure */
1486 SCIP_CONSDATA* consdata /**< linear constraint data */
1487 )
1488 {
1489 if( consdata->maxactdelta != SCIP_INVALID )
1490 {
1491 SCIP_Real maxactdelta = 0.0;
1492 SCIP_Real domain;
1493 SCIP_Real delta;
1494 SCIP_Real lb;
1495 SCIP_Real ub;
1496 int v;
1497
1498 for( v = consdata->nvars - 1; v >= 0; --v )
1499 {
1500 lb = SCIPvarGetLbLocal(consdata->vars[v]);
1501 ub = SCIPvarGetUbLocal(consdata->vars[v]);
1502
1503 if( SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub) )
1504 {
1505 maxactdelta = SCIPinfinity(scip);
1506 break;
1507 }
1508
1509 domain = ub - lb;
1510 delta = REALABS(consdata->vals[v]) * domain;
1511
1512 if( delta > maxactdelta )
1513 {
1514 maxactdelta = delta;
1515 }
1516 }
1517 assert(SCIPisFeasEQ(scip, maxactdelta, consdata->maxactdelta));
1518 }
1519 }
1520 #else
1521 #define checkMaxActivityDelta(scip, consdata) /**/
1522 #endif
1523
1524 /** recompute maximal activity contribution for a single variable */
1525 static
consdataRecomputeMaxActivityDelta(SCIP * scip,SCIP_CONSDATA * consdata)1526 void consdataRecomputeMaxActivityDelta(
1527 SCIP* scip, /**< SCIP data structure */
1528 SCIP_CONSDATA* consdata /**< linear constraint data */
1529 )
1530 {
1531 SCIP_Real delta;
1532 int v;
1533
1534 consdata->maxactdelta = 0.0;
1535
1536 if( !consdata->hasnonbinvalid )
1537 consdataCheckNonbinvar(consdata);
1538
1539 /* easy case, the problem consists only of binary variables */
1540 if( !consdata->hasnonbinvar )
1541 {
1542 for( v = consdata->nvars - 1; v >= 0; --v )
1543 {
1544 if( SCIPvarGetLbLocal(consdata->vars[v]) < 0.5 && SCIPvarGetUbLocal(consdata->vars[v]) > 0.5 )
1545 {
1546 delta = REALABS(consdata->vals[v]);
1547
1548 if( delta > consdata->maxactdelta )
1549 {
1550 consdata->maxactdelta = delta;
1551 consdata->maxactdeltavar = consdata->vars[v];
1552 }
1553 }
1554 }
1555 return;
1556 }
1557
1558 for( v = consdata->nvars - 1; v >= 0; --v )
1559 {
1560 SCIP_Real domain;
1561 SCIP_Real lb;
1562 SCIP_Real ub;
1563
1564 lb = SCIPvarGetLbLocal(consdata->vars[v]);
1565 ub = SCIPvarGetUbLocal(consdata->vars[v]);
1566
1567 if( SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub) )
1568 {
1569 consdata->maxactdelta = SCIPinfinity(scip);
1570 consdata->maxactdeltavar = consdata->vars[v];
1571 break;
1572 }
1573
1574 domain = ub - lb;
1575 delta = REALABS(consdata->vals[v]) * domain;
1576
1577 if( delta > consdata->maxactdelta )
1578 {
1579 consdata->maxactdelta = delta;
1580 consdata->maxactdeltavar = consdata->vars[v];
1581 }
1582 }
1583 }
1584
1585
1586 /** updates activities for a change in a bound */
1587 static
consdataUpdateActivities(SCIP * scip,SCIP_CONSDATA * consdata,SCIP_VAR * var,SCIP_Real oldbound,SCIP_Real newbound,SCIP_Real val,SCIP_BOUNDTYPE boundtype,SCIP_Bool global,SCIP_Bool checkreliability)1588 void consdataUpdateActivities(
1589 SCIP* scip, /**< SCIP data structure */
1590 SCIP_CONSDATA* consdata, /**< linear constraint data */
1591 SCIP_VAR* var, /**< variable that has been changed; can be NULL for global bound changes */
1592 SCIP_Real oldbound, /**< old bound of variable */
1593 SCIP_Real newbound, /**< new bound of variable */
1594 SCIP_Real val, /**< coefficient of constraint entry */
1595 SCIP_BOUNDTYPE boundtype, /**< type of the bound change */
1596 SCIP_Bool global, /**< is it a global or a local bound change? */
1597 SCIP_Bool checkreliability /**< should the reliability of the recalculated activity be checked? */
1598 )
1599 {
1600 SCIP_Real* activity;
1601 SCIP_Real* lastactivity;
1602 int* activityposinf;
1603 int* activityneginf;
1604 int* activityposhuge;
1605 int* activityneghuge;
1606 SCIP_Real oldcontribution;
1607 SCIP_Real newcontribution;
1608 SCIP_Real delta;
1609 SCIP_Bool validact;
1610 SCIP_Bool finitenewbound;
1611 SCIP_Bool hugevalnewcont;
1612
1613 assert(scip != NULL);
1614 assert(consdata != NULL);
1615 assert(global || (var != NULL));
1616 assert(consdata->validactivities);
1617 assert(consdata->minactivity < SCIP_INVALID);
1618 assert(consdata->maxactivity < SCIP_INVALID);
1619 assert(consdata->lastminactivity < SCIP_INVALID);
1620 assert(consdata->lastmaxactivity < SCIP_INVALID);
1621 assert(consdata->minactivityneginf >= 0);
1622 assert(consdata->minactivityposinf >= 0);
1623 assert(consdata->maxactivityneginf >= 0);
1624 assert(consdata->maxactivityposinf >= 0);
1625 assert(consdata->minactivityneghuge >= 0);
1626 assert(consdata->minactivityposhuge >= 0);
1627 assert(consdata->maxactivityneghuge >= 0);
1628 assert(consdata->maxactivityposhuge >= 0);
1629 assert(consdata->glbminactivity < SCIP_INVALID);
1630 assert(consdata->glbmaxactivity < SCIP_INVALID);
1631 assert(consdata->lastglbminactivity < SCIP_INVALID);
1632 assert(consdata->lastglbmaxactivity < SCIP_INVALID);
1633 assert(consdata->glbminactivityneginf >= 0);
1634 assert(consdata->glbminactivityposinf >= 0);
1635 assert(consdata->glbmaxactivityneginf >= 0);
1636 assert(consdata->glbmaxactivityposinf >= 0);
1637 assert(consdata->glbminactivityneghuge >= 0);
1638 assert(consdata->glbminactivityposhuge >= 0);
1639 assert(consdata->glbmaxactivityneghuge >= 0);
1640 assert(consdata->glbmaxactivityposhuge >= 0);
1641
1642 delta = 0.0;
1643
1644 /* we are updating global activities */
1645 if( global )
1646 {
1647 /* depending on the boundtype and the coefficient, we choose the activity to be updated:
1648 * lower bound + pos. coef: update minactivity
1649 * lower bound + neg. coef: update maxactivity, positive and negative infinity counters have to be switched
1650 * upper bound + pos. coef: update maxactivity
1651 * upper bound + neg. coef: update minactivity, positive and negative infinity counters have to be switched
1652 */
1653 if( boundtype == SCIP_BOUNDTYPE_LOWER )
1654 {
1655 if( val > 0.0 )
1656 {
1657 activity = &(consdata->glbminactivity);
1658 lastactivity = &(consdata->lastglbminactivity);
1659 activityposinf = &(consdata->glbminactivityposinf);
1660 activityneginf = &(consdata->glbminactivityneginf);
1661 activityposhuge = &(consdata->glbminactivityposhuge);
1662 activityneghuge = &(consdata->glbminactivityneghuge);
1663 validact = consdata->validglbminact;
1664 }
1665 else
1666 {
1667 activity = &(consdata->glbmaxactivity);
1668 lastactivity = &(consdata->lastglbmaxactivity);
1669 activityposinf = &(consdata->glbmaxactivityneginf);
1670 activityneginf = &(consdata->glbmaxactivityposinf);
1671 activityposhuge = &(consdata->glbmaxactivityposhuge);
1672 activityneghuge = &(consdata->glbmaxactivityneghuge);
1673 validact = consdata->validglbmaxact;
1674 }
1675 }
1676 else
1677 {
1678 if( val > 0.0 )
1679 {
1680 activity = &(consdata->glbmaxactivity);
1681 lastactivity = &(consdata->lastglbmaxactivity);
1682 activityposinf = &(consdata->glbmaxactivityposinf);
1683 activityneginf = &(consdata->glbmaxactivityneginf);
1684 activityposhuge = &(consdata->glbmaxactivityposhuge);
1685 activityneghuge = &(consdata->glbmaxactivityneghuge);
1686 validact = consdata->validglbmaxact;
1687 }
1688 else
1689 {
1690 activity = &(consdata->glbminactivity);
1691 lastactivity = &(consdata->lastglbminactivity);
1692 activityposinf = &(consdata->glbminactivityneginf);
1693 activityneginf = &(consdata->glbminactivityposinf);
1694 activityposhuge = &(consdata->glbminactivityposhuge);
1695 activityneghuge = &(consdata->glbminactivityneghuge);
1696 validact = consdata->validglbminact;
1697 }
1698 }
1699 }
1700 /* we are updating local activities */
1701 else
1702 {
1703 /* depending on the boundtype and the coefficient, we choose the activity to be updated:
1704 * lower bound + pos. coef: update minactivity
1705 * lower bound + neg. coef: update maxactivity, positive and negative infinity counters have to be switched
1706 * upper bound + pos. coef: update maxactivity
1707 * upper bound + neg. coef: update minactivity, positive and negative infinity counters have to be switched
1708 */
1709 if( boundtype == SCIP_BOUNDTYPE_LOWER )
1710 {
1711 if( val > 0.0 )
1712 {
1713 activity = &(consdata->minactivity);
1714 lastactivity = &(consdata->lastminactivity);
1715 activityposinf = &(consdata->minactivityposinf);
1716 activityneginf = &(consdata->minactivityneginf);
1717 activityposhuge = &(consdata->minactivityposhuge);
1718 activityneghuge = &(consdata->minactivityneghuge);
1719 validact = consdata->validminact;
1720 }
1721 else
1722 {
1723 activity = &(consdata->maxactivity);
1724 lastactivity = &(consdata->lastmaxactivity);
1725 activityposinf = &(consdata->maxactivityneginf);
1726 activityneginf = &(consdata->maxactivityposinf);
1727 activityposhuge = &(consdata->maxactivityposhuge);
1728 activityneghuge = &(consdata->maxactivityneghuge);
1729 validact = consdata->validmaxact;
1730 }
1731 }
1732 else
1733 {
1734 if( val > 0.0 )
1735 {
1736 activity = &(consdata->maxactivity);
1737 lastactivity = &(consdata->lastmaxactivity);
1738 activityposinf = &(consdata->maxactivityposinf);
1739 activityneginf = &(consdata->maxactivityneginf);
1740 activityposhuge = &(consdata->maxactivityposhuge);
1741 activityneghuge = &(consdata->maxactivityneghuge);
1742 validact = consdata->validmaxact;
1743 }
1744 else
1745 {
1746 activity = &(consdata->minactivity);
1747 lastactivity = &(consdata->lastminactivity);
1748 activityposinf = &(consdata->minactivityneginf);
1749 activityneginf = &(consdata->minactivityposinf);
1750 activityposhuge = &(consdata->minactivityposhuge);
1751 activityneghuge = &(consdata->minactivityneghuge);
1752 validact = consdata->validminact;
1753 }
1754 }
1755 }
1756
1757 oldcontribution = val * oldbound;
1758 newcontribution = val * newbound;
1759 hugevalnewcont = SCIPisHugeValue(scip, REALABS(newcontribution));
1760 finitenewbound = !SCIPisInfinity(scip, REALABS(newbound));
1761
1762 if( SCIPisInfinity(scip, REALABS(oldbound)) )
1763 {
1764 /* old bound was +infinity */
1765 if( oldbound > 0.0 )
1766 {
1767 assert((*activityposinf) >= 1);
1768
1769 /* we only have to do something if the new bound is not again +infinity */
1770 if( finitenewbound || newbound < 0.0 )
1771 {
1772 /* decrease the counter for positive infinite contributions */
1773 (*activityposinf)--;
1774
1775 /* if the bound changed to -infinity, increase the counter for negative infinite contributions */
1776 if( !finitenewbound && newbound < 0.0 )
1777 (*activityneginf)++;
1778 else if( hugevalnewcont )
1779 {
1780 /* if the contribution of this variable is too large, increase the counter for huge values */
1781 if( newcontribution > 0.0 )
1782 (*activityposhuge)++;
1783 else
1784 (*activityneghuge)++;
1785 }
1786 /* "normal case": just add the contribution to the activity */
1787 else
1788 delta = newcontribution;
1789 }
1790 }
1791 /* old bound was -infinity */
1792 else
1793 {
1794 assert(oldbound < 0.0);
1795 assert((*activityneginf) >= 1);
1796
1797 /* we only have to do something ig the new bound is not again -infinity */
1798 if( finitenewbound || newbound > 0.0 )
1799 {
1800 /* decrease the counter for negative infinite contributions */
1801 (*activityneginf)--;
1802
1803 /* if the bound changed to +infinity, increase the counter for positive infinite contributions */
1804 if( !finitenewbound && newbound > 0.0 )
1805 (*activityposinf)++;
1806 else if( hugevalnewcont )
1807 {
1808 /* if the contribution of this variable is too large, increase the counter for huge values */
1809 if( newcontribution > 0.0 )
1810 (*activityposhuge)++;
1811 else
1812 (*activityneghuge)++;
1813 }
1814 /* "normal case": just add the contribution to the activity */
1815 else
1816 delta = newcontribution;
1817 }
1818 }
1819 }
1820 else if( SCIPisHugeValue(scip, REALABS(oldcontribution)) )
1821 {
1822 /* old contribution was too large and positive */
1823 if( oldcontribution > 0.0 )
1824 {
1825 assert((*activityposhuge) >= 1);
1826
1827 /* decrease the counter for huge positive contributions; it might be increased again later,
1828 * but checking here that the bound is not huge again would not handle a change from a huge to an infinite bound
1829 */
1830 (*activityposhuge)--;
1831
1832 if( !finitenewbound )
1833 {
1834 /* if the bound changed to +infinity, increase the counter for positive infinite contributions */
1835 if( newbound > 0.0 )
1836 (*activityposinf)++;
1837 /* if the bound changed to -infinity, increase the counter for negative infinite contributions */
1838 else
1839 (*activityneginf)++;
1840 }
1841 else if( hugevalnewcont )
1842 {
1843 /* if the contribution of this variable is too large and positive, increase the corresponding counter */
1844 if( newcontribution > 0.0 )
1845 (*activityposhuge)++;
1846 /* if the contribution of this variable is too large and negative, increase the corresponding counter */
1847 else
1848 (*activityneghuge)++;
1849 }
1850 /* "normal case": just add the contribution to the activity */
1851 else
1852 delta = newcontribution;
1853 }
1854 /* old contribution was too large and negative */
1855 else
1856 {
1857 assert(oldcontribution < 0.0);
1858 assert((*activityneghuge) >= 1);
1859
1860 /* decrease the counter for huge negative contributions; it might be increased again later,
1861 * but checking here that the bound is not huge again would not handle a change from a huge to an infinite bound
1862 */
1863 (*activityneghuge)--;
1864
1865 if( !finitenewbound )
1866 {
1867 /* if the bound changed to +infinity, increase the counter for positive infinite contributions */
1868 if( newbound > 0.0 )
1869 (*activityposinf)++;
1870 /* if the bound changed to -infinity, increase the counter for negative infinite contributions */
1871 else
1872 (*activityneginf)++;
1873 }
1874 else if( hugevalnewcont )
1875 {
1876 /* if the contribution of this variable is too large and positive, increase the corresponding counter */
1877 if( newcontribution > 0.0 )
1878 (*activityposhuge)++;
1879 /* if the contribution of this variable is too large and negative, increase the corresponding counter */
1880 else
1881 (*activityneghuge)++;
1882 }
1883 /* "normal case": just add the contribution to the activity */
1884 else
1885 delta = newcontribution;
1886 }
1887 }
1888 /* old bound was finite and not too large */
1889 else
1890 {
1891 if( !finitenewbound )
1892 {
1893 /* if the new bound is +infinity, the old contribution has to be subtracted
1894 * and the counter for positive infinite contributions has to be increased
1895 */
1896 if( newbound > 0.0 )
1897 {
1898 (*activityposinf)++;
1899 delta = -oldcontribution;
1900 }
1901 /* if the new bound is -infinity, the old contribution has to be subtracted
1902 * and the counter for negative infinite contributions has to be increased
1903 */
1904 else
1905 {
1906 assert(newbound < 0.0 );
1907
1908 (*activityneginf)++;
1909 delta = -oldcontribution;
1910 }
1911 }
1912 /* if the contribution of this variable is too large, increase the counter for huge values */
1913 else if( hugevalnewcont )
1914 {
1915 if( newcontribution > 0.0 )
1916 {
1917 (*activityposhuge)++;
1918 delta = -oldcontribution;
1919 }
1920 else
1921 {
1922 (*activityneghuge)++;
1923 delta = -oldcontribution;
1924 }
1925 }
1926 /* "normal case": just update the activity */
1927 else
1928 delta = newcontribution - oldcontribution;
1929 }
1930
1931 /* update the activity, if the current value is valid and there was a change in the finite part */
1932 if( validact && (delta != 0.0) )
1933 {
1934 /* if the absolute value of the activity is increased, this is regarded as reliable,
1935 * otherwise, we check whether we can still trust the updated value
1936 */
1937 (*activity) = (*activity) + delta;
1938 assert(!SCIPisInfinity(scip, -(*activity)) && !SCIPisInfinity(scip, *activity));
1939
1940 if( REALABS((*lastactivity)) < REALABS(*activity) )
1941 {
1942 (*lastactivity) = (*activity);
1943 }
1944 else
1945 {
1946 if( checkreliability && SCIPisUpdateUnreliable(scip, (*activity), (*lastactivity)) )
1947 {
1948 SCIPdebugMsg(scip, "%s activity of linear constraint unreliable after update: %16.9g\n",
1949 (global ? "global " : ""), (*activity));
1950
1951 /* mark the activity that was just changed and is not reliable anymore to be invalid */
1952 if( global )
1953 {
1954 if( (boundtype == SCIP_BOUNDTYPE_LOWER) == (val > 0.0) )
1955 consdata->validglbminact = FALSE;
1956 else
1957 consdata->validglbmaxact = FALSE;
1958 }
1959 else
1960 {
1961 if( (boundtype == SCIP_BOUNDTYPE_LOWER) == (val > 0.0) )
1962 consdata->validminact = FALSE;
1963 else
1964 consdata->validmaxact = FALSE;
1965 }
1966 }
1967 }
1968 }
1969 }
1970
1971 /** updates minimum and maximum activity for a change in lower bound */
1972 static
consdataUpdateActivitiesLb(SCIP * scip,SCIP_CONSDATA * consdata,SCIP_VAR * var,SCIP_Real oldlb,SCIP_Real newlb,SCIP_Real val,SCIP_Bool checkreliability)1973 void consdataUpdateActivitiesLb(
1974 SCIP* scip, /**< SCIP data structure */
1975 SCIP_CONSDATA* consdata, /**< linear constraint data */
1976 SCIP_VAR* var, /**< variable that has been changed */
1977 SCIP_Real oldlb, /**< old lower bound of variable */
1978 SCIP_Real newlb, /**< new lower bound of variable */
1979 SCIP_Real val, /**< coefficient of constraint entry */
1980 SCIP_Bool checkreliability /**< should the reliability of the recalculated activity be checked? */
1981 )
1982 {
1983 assert(scip != NULL);
1984 assert(consdata != NULL);
1985 assert(var != NULL);
1986
1987 if( consdata->validactivities )
1988 {
1989 consdataUpdateActivities(scip, consdata, var, oldlb, newlb, val, SCIP_BOUNDTYPE_LOWER, FALSE, checkreliability);
1990
1991 assert(!SCIPisInfinity(scip, -consdata->minactivity) && !SCIPisInfinity(scip, consdata->minactivity));
1992 assert(!SCIPisInfinity(scip, -consdata->maxactivity) && !SCIPisInfinity(scip, consdata->maxactivity));
1993 }
1994 }
1995
1996 /** updates minimum and maximum activity for a change in upper bound */
1997 static
consdataUpdateActivitiesUb(SCIP * scip,SCIP_CONSDATA * consdata,SCIP_VAR * var,SCIP_Real oldub,SCIP_Real newub,SCIP_Real val,SCIP_Bool checkreliability)1998 void consdataUpdateActivitiesUb(
1999 SCIP* scip, /**< SCIP data structure */
2000 SCIP_CONSDATA* consdata, /**< linear constraint data */
2001 SCIP_VAR* var, /**< variable that has been changed */
2002 SCIP_Real oldub, /**< old upper bound of variable */
2003 SCIP_Real newub, /**< new upper bound of variable */
2004 SCIP_Real val, /**< coefficient of constraint entry */
2005 SCIP_Bool checkreliability /**< should the reliability of the recalculated activity be checked? */
2006 )
2007 {
2008 assert(scip != NULL);
2009 assert(consdata != NULL);
2010 assert(var != NULL);
2011
2012 if( consdata->validactivities )
2013 {
2014 consdataUpdateActivities(scip, consdata, var, oldub, newub, val, SCIP_BOUNDTYPE_UPPER, FALSE, checkreliability);
2015
2016 assert(!SCIPisInfinity(scip, -consdata->minactivity) && !SCIPisInfinity(scip, consdata->minactivity));
2017 assert(!SCIPisInfinity(scip, -consdata->maxactivity) && !SCIPisInfinity(scip, consdata->maxactivity));
2018 }
2019 }
2020
2021 /** updates minimum and maximum global activity for a change in the global lower bound */
2022 static
consdataUpdateActivitiesGlbLb(SCIP * scip,SCIP_CONSDATA * consdata,SCIP_Real oldlb,SCIP_Real newlb,SCIP_Real val,SCIP_Bool checkreliability)2023 void consdataUpdateActivitiesGlbLb(
2024 SCIP* scip, /**< SCIP data structure */
2025 SCIP_CONSDATA* consdata, /**< linear constraint data */
2026 SCIP_Real oldlb, /**< old lower bound of variable */
2027 SCIP_Real newlb, /**< new lower bound of variable */
2028 SCIP_Real val, /**< coefficient of constraint entry */
2029 SCIP_Bool checkreliability /**< should the reliability of the recalculated activity be checked? */
2030 )
2031 {
2032 assert(scip != NULL);
2033 assert(consdata != NULL);
2034
2035 if( consdata->validactivities )
2036 {
2037 consdataUpdateActivities(scip, consdata, NULL, oldlb, newlb, val, SCIP_BOUNDTYPE_LOWER, TRUE, checkreliability);
2038
2039 assert(!SCIPisInfinity(scip, -consdata->glbminactivity) && !SCIPisInfinity(scip, consdata->glbminactivity));
2040 assert(!SCIPisInfinity(scip, -consdata->glbmaxactivity) && !SCIPisInfinity(scip, consdata->glbmaxactivity));
2041 }
2042 }
2043
2044 /** updates minimum and maximum global activity for a change in global upper bound */
2045 static
consdataUpdateActivitiesGlbUb(SCIP * scip,SCIP_CONSDATA * consdata,SCIP_Real oldub,SCIP_Real newub,SCIP_Real val,SCIP_Bool checkreliability)2046 void consdataUpdateActivitiesGlbUb(
2047 SCIP* scip, /**< SCIP data structure */
2048 SCIP_CONSDATA* consdata, /**< linear constraint data */
2049 SCIP_Real oldub, /**< old upper bound of variable */
2050 SCIP_Real newub, /**< new upper bound of variable */
2051 SCIP_Real val, /**< coefficient of constraint entry */
2052 SCIP_Bool checkreliability /**< should the reliability of the recalculated activity be checked? */
2053 )
2054 {
2055 assert(scip != NULL);
2056 assert(consdata != NULL);
2057
2058 if( consdata->validactivities )
2059 {
2060 consdataUpdateActivities(scip, consdata, NULL, oldub, newub, val, SCIP_BOUNDTYPE_UPPER, TRUE, checkreliability);
2061
2062 assert(!SCIPisInfinity(scip, -consdata->glbminactivity) && !SCIPisInfinity(scip, consdata->glbminactivity));
2063 assert(!SCIPisInfinity(scip, -consdata->glbmaxactivity) && !SCIPisInfinity(scip, consdata->glbmaxactivity));
2064 }
2065 }
2066
2067 /** updates minimum and maximum activity and maximum absolute value for coefficient addition */
2068 static
consdataUpdateAddCoef(SCIP * scip,SCIP_CONSDATA * consdata,SCIP_VAR * var,SCIP_Real val,SCIP_Bool checkreliability)2069 void consdataUpdateAddCoef(
2070 SCIP* scip, /**< SCIP data structure */
2071 SCIP_CONSDATA* consdata, /**< linear constraint data */
2072 SCIP_VAR* var, /**< variable of constraint entry */
2073 SCIP_Real val, /**< coefficient of constraint entry */
2074 SCIP_Bool checkreliability /**< should the reliability of the recalculated activity be checked? */
2075 )
2076 {
2077 assert(scip != NULL);
2078 assert(consdata != NULL);
2079 assert(var != NULL);
2080
2081 /* update maximum absolute value */
2082 if( consdata->validmaxabsval )
2083 {
2084 SCIP_Real absval;
2085
2086 assert(consdata->maxabsval < SCIP_INVALID);
2087
2088 absval = REALABS(val);
2089 consdata->maxabsval = MAX(consdata->maxabsval, absval);
2090 }
2091
2092 if( consdata->validminabsval )
2093 {
2094 SCIP_Real absval;
2095
2096 assert(consdata->minabsval < SCIP_INVALID);
2097
2098 absval = REALABS(val);
2099 consdata->minabsval = MIN(consdata->minabsval, absval);
2100 }
2101
2102 /* update minimal and maximal activity */
2103 if( consdata->validactivities )
2104 {
2105 assert(consdata->minactivity < SCIP_INVALID);
2106 assert(consdata->maxactivity < SCIP_INVALID);
2107 assert(consdata->glbminactivity < SCIP_INVALID);
2108 assert(consdata->glbmaxactivity < SCIP_INVALID);
2109
2110 consdataUpdateActivitiesLb(scip, consdata, var, 0.0, SCIPvarGetLbLocal(var), val, checkreliability);
2111 consdataUpdateActivitiesUb(scip, consdata, var, 0.0, SCIPvarGetUbLocal(var), val, checkreliability);
2112 consdataUpdateActivitiesGlbLb(scip, consdata, 0.0, SCIPvarGetLbGlobal(var), val, checkreliability);
2113 consdataUpdateActivitiesGlbUb(scip, consdata, 0.0, SCIPvarGetUbGlobal(var), val, checkreliability);
2114 }
2115 }
2116
2117 /** updates minimum and maximum activity for coefficient deletion, invalidates maximum absolute value if necessary */
2118 static
consdataUpdateDelCoef(SCIP * scip,SCIP_CONSDATA * consdata,SCIP_VAR * var,SCIP_Real val,SCIP_Bool checkreliability)2119 void consdataUpdateDelCoef(
2120 SCIP* scip, /**< SCIP data structure */
2121 SCIP_CONSDATA* consdata, /**< linear constraint data */
2122 SCIP_VAR* var, /**< variable of constraint entry */
2123 SCIP_Real val, /**< coefficient of constraint entry */
2124 SCIP_Bool checkreliability /**< should the reliability of the recalculated activity be checked? */
2125 )
2126 {
2127 assert(scip != NULL);
2128 assert(consdata != NULL);
2129 assert(var != NULL);
2130
2131 /* invalidate maximum absolute value, if this coefficient was the maximum */
2132 if( consdata->validmaxabsval )
2133 {
2134 SCIP_Real absval;
2135
2136 absval = REALABS(val);
2137
2138 if( SCIPisEQ(scip, absval, consdata->maxabsval) )
2139 {
2140 consdata->validmaxabsval = FALSE;
2141 consdata->maxabsval = SCIP_INVALID;
2142 }
2143 }
2144
2145 /* invalidate minimum absolute value, if this coefficient was the minimum */
2146 if( consdata->validminabsval )
2147 {
2148 SCIP_Real absval;
2149
2150 absval = REALABS(val);
2151
2152 if( SCIPisEQ(scip, absval, consdata->minabsval) )
2153 {
2154 consdata->validminabsval = FALSE;
2155 consdata->minabsval = SCIP_INVALID;
2156 }
2157 }
2158
2159 /* update minimal and maximal activity */
2160 if( consdata->validactivities )
2161 {
2162 assert(consdata->minactivity < SCIP_INVALID);
2163 assert(consdata->maxactivity < SCIP_INVALID);
2164 assert(consdata->glbminactivity < SCIP_INVALID);
2165 assert(consdata->glbmaxactivity < SCIP_INVALID);
2166
2167 consdataUpdateActivitiesLb(scip, consdata, var, SCIPvarGetLbLocal(var), 0.0, val, checkreliability);
2168 consdataUpdateActivitiesUb(scip, consdata, var, SCIPvarGetUbLocal(var), 0.0, val, checkreliability);
2169 consdataUpdateActivitiesGlbLb(scip, consdata, SCIPvarGetLbGlobal(var), 0.0, val, checkreliability);
2170 consdataUpdateActivitiesGlbUb(scip, consdata, SCIPvarGetUbGlobal(var), 0.0, val, checkreliability);
2171 }
2172 }
2173
2174 /** updates minimum and maximum activity for coefficient change, invalidates maximum absolute value if necessary */
2175 static
consdataUpdateChgCoef(SCIP * scip,SCIP_CONSDATA * consdata,SCIP_VAR * var,SCIP_Real oldval,SCIP_Real newval,SCIP_Bool checkreliability)2176 void consdataUpdateChgCoef(
2177 SCIP* scip, /**< SCIP data structure */
2178 SCIP_CONSDATA* consdata, /**< linear constraint data */
2179 SCIP_VAR* var, /**< variable of constraint entry */
2180 SCIP_Real oldval, /**< old coefficient of constraint entry */
2181 SCIP_Real newval, /**< new coefficient of constraint entry */
2182 SCIP_Bool checkreliability /**< should the reliability of the recalculated activity be checked? */
2183 )
2184 {
2185 assert(scip != NULL);
2186 assert(consdata != NULL);
2187 assert(var != NULL);
2188
2189 /* old zero coefficients should be handled by consdataUpdateAddCoef() */
2190 assert(!SCIPisZero(scip, oldval));
2191
2192 /* new zero coefficients should be handled by consdataUpdateDelCoef() */
2193 assert(!SCIPisZero(scip, newval));
2194
2195 /* update maximum absolute value */
2196 if( consdata->validmaxabsval )
2197 {
2198 SCIP_Real absval;
2199
2200 absval = REALABS(newval);
2201
2202 if( SCIPisGE(scip, absval, consdata->maxabsval) )
2203 {
2204 consdata->maxabsval = absval;
2205 }
2206 else
2207 {
2208 absval = REALABS(oldval);
2209
2210 /* invalidate maximum absolute value */
2211 if( SCIPisEQ(scip, absval, consdata->maxabsval) )
2212 {
2213 consdata->validmaxabsval = FALSE;
2214 consdata->maxabsval = SCIP_INVALID;
2215 }
2216 }
2217 }
2218
2219 /* update minimum absolute value */
2220 if( consdata->validminabsval )
2221 {
2222 SCIP_Real absval;
2223
2224 absval = REALABS(newval);
2225
2226 if( SCIPisLE(scip, absval, consdata->minabsval) )
2227 {
2228 consdata->minabsval = absval;
2229 }
2230 else
2231 {
2232 absval = REALABS(oldval);
2233
2234 /* invalidate minimum absolute value */
2235 if( SCIPisEQ(scip, absval, consdata->minabsval) )
2236 {
2237 consdata->validminabsval = FALSE;
2238 consdata->minabsval = SCIP_INVALID;
2239 }
2240 }
2241 }
2242
2243 /* update maximum activity delta */
2244 if( !SCIPisInfinity(scip, consdata->maxactdelta ) )
2245 {
2246 SCIP_Real domain;
2247 SCIP_Real delta;
2248
2249 assert(!SCIPisInfinity(scip, SCIPvarGetLbLocal(var)));
2250 assert(!SCIPisInfinity(scip, SCIPvarGetUbLocal(var)));
2251
2252 domain = SCIPvarGetUbLocal(var) - SCIPvarGetLbLocal(var);
2253 delta = REALABS(newval) * domain;
2254
2255 if( delta > consdata->maxactdelta )
2256 {
2257 consdata->maxactdelta = delta;
2258 consdata->maxactdeltavar = var;
2259 }
2260 else
2261 {
2262 /* reset maximal activity delta, so that it will be recalculated on the next real propagation */
2263 if( consdata->maxactdeltavar == var )
2264 consdata->maxactdelta = SCIP_INVALID;
2265 }
2266 }
2267
2268 /* @todo do something more clever here, e.g. if oldval * newval >= 0, do the update directly */
2269 consdataUpdateDelCoef(scip, consdata, var, oldval, checkreliability);
2270 consdataUpdateAddCoef(scip, consdata, var, newval, checkreliability);
2271 }
2272
2273 /** returns the maximum absolute value of all coefficients in the constraint */
2274 static
consdataGetMaxAbsval(SCIP_CONSDATA * consdata)2275 SCIP_Real consdataGetMaxAbsval(
2276 SCIP_CONSDATA* consdata /**< linear constraint data */
2277 )
2278 {
2279 assert(consdata != NULL);
2280
2281 if( !consdata->validmaxabsval )
2282 consdataCalcMaxAbsval(consdata);
2283 assert(consdata->validmaxabsval);
2284 assert(consdata->maxabsval < SCIP_INVALID);
2285
2286 return consdata->maxabsval;
2287 }
2288
2289 /** returns the minimum absolute value of all coefficients in the constraint */
2290 static
consdataGetMinAbsval(SCIP_CONSDATA * consdata)2291 SCIP_Real consdataGetMinAbsval(
2292 SCIP_CONSDATA* consdata /**< linear constraint data */
2293 )
2294 {
2295 assert(consdata != NULL);
2296
2297 if( !consdata->validminabsval )
2298 consdataCalcMinAbsval(consdata);
2299 assert(consdata->validminabsval);
2300 assert(consdata->minabsval < SCIP_INVALID);
2301
2302 return consdata->minabsval;
2303 }
2304
2305 /** calculates minimum and maximum local and global activity for constraint from scratch;
2306 * additionally recalculates maximum absolute value of coefficients
2307 */
2308 static
consdataCalcActivities(SCIP * scip,SCIP_CONSDATA * consdata)2309 void consdataCalcActivities(
2310 SCIP* scip, /**< SCIP data structure */
2311 SCIP_CONSDATA* consdata /**< linear constraint data */
2312 )
2313 {
2314 int i;
2315
2316 assert(scip != NULL);
2317 assert(consdata != NULL);
2318 assert(!consdata->validactivities);
2319 assert(consdata->minactivity >= SCIP_INVALID || consdata->validminact);
2320 assert(consdata->maxactivity >= SCIP_INVALID || consdata->validmaxact);
2321 assert(consdata->glbminactivity >= SCIP_INVALID || consdata->validglbminact);
2322 assert(consdata->glbmaxactivity >= SCIP_INVALID || consdata->validglbmaxact);
2323
2324 consdata->validmaxabsval = TRUE;
2325 consdata->validminabsval = TRUE;
2326 consdata->validactivities = TRUE;
2327 consdata->validminact = TRUE;
2328 consdata->validmaxact = TRUE;
2329 consdata->validglbminact = TRUE;
2330 consdata->validglbmaxact = TRUE;
2331 consdata->maxabsval = 0.0;
2332 consdata->minabsval = (consdata->nvars == 0 ? 0.0 : REALABS(consdata->vals[0]));
2333 consdata->minactivity = 0.0;
2334 consdata->maxactivity = 0.0;
2335 consdata->lastminactivity = 0.0;
2336 consdata->lastmaxactivity = 0.0;
2337 consdata->minactivityneginf = 0;
2338 consdata->minactivityposinf = 0;
2339 consdata->maxactivityneginf = 0;
2340 consdata->maxactivityposinf = 0;
2341 consdata->minactivityneghuge = 0;
2342 consdata->minactivityposhuge = 0;
2343 consdata->maxactivityneghuge = 0;
2344 consdata->maxactivityposhuge = 0;
2345 consdata->glbminactivity = 0.0;
2346 consdata->glbmaxactivity = 0.0;
2347 consdata->lastglbminactivity = 0.0;
2348 consdata->lastglbmaxactivity = 0.0;
2349 consdata->glbminactivityneginf = 0;
2350 consdata->glbminactivityposinf = 0;
2351 consdata->glbmaxactivityneginf = 0;
2352 consdata->glbmaxactivityposinf = 0;
2353 consdata->glbminactivityneghuge = 0;
2354 consdata->glbminactivityposhuge = 0;
2355 consdata->glbmaxactivityneghuge = 0;
2356 consdata->glbmaxactivityposhuge = 0;
2357
2358 for( i = 0; i < consdata->nvars; ++i )
2359 consdataUpdateAddCoef(scip, consdata, consdata->vars[i], consdata->vals[i], FALSE);
2360
2361 consdata->lastminactivity = consdata->minactivity;
2362 consdata->lastmaxactivity = consdata->maxactivity;
2363 consdata->lastglbminactivity = consdata->glbminactivity;
2364 consdata->lastglbmaxactivity = consdata->glbmaxactivity;
2365 }
2366
2367 /** gets minimal activity for constraint and given values of counters for infinite and huge contributions
2368 * and (if needed) delta to subtract from stored finite part of activity in case of a residual activity
2369 */
2370 static
getMinActivity(SCIP * scip,SCIP_CONSDATA * consdata,int posinf,int neginf,int poshuge,int neghuge,SCIP_Real delta,SCIP_Bool global,SCIP_Bool goodrelax,SCIP_Real * minactivity,SCIP_Bool * isrelax,SCIP_Bool * issettoinfinity)2371 void getMinActivity(
2372 SCIP* scip, /**< SCIP data structure */
2373 SCIP_CONSDATA* consdata, /**< linear constraint */
2374 int posinf, /**< number of coefficients contributing pos. infinite value */
2375 int neginf, /**< number of coefficients contributing neg. infinite value */
2376 int poshuge, /**< number of coefficients contributing huge pos. value */
2377 int neghuge, /**< number of coefficients contributing huge neg. value */
2378 SCIP_Real delta, /**< value to subtract from stored minactivity
2379 * (contribution of the variable set to zero when getting residual activity) */
2380 SCIP_Bool global, /**< should the global or local minimal activity be returned? */
2381 SCIP_Bool goodrelax, /**< should a good relaxation be computed or are relaxed acticities ignored, anyway? */
2382 SCIP_Real* minactivity, /**< pointer to store the minimal activity */
2383 SCIP_Bool* isrelax, /**< pointer to store whether the activity is a relaxation,
2384 * i.e. is <= the exact minactivity (in case of huge contributing values) */
2385 SCIP_Bool* issettoinfinity /**< pointer to store whether minactivity was set to infinity or calculated */
2386 )
2387 {
2388 assert(scip != NULL);
2389 assert(consdata != NULL);
2390 assert(posinf >= 0);
2391 assert(neginf >= 0);
2392 assert(poshuge >= 0);
2393 assert(neghuge >= 0);
2394 assert(minactivity != NULL);
2395 assert(isrelax != NULL);
2396 assert(issettoinfinity != NULL);
2397
2398 /* if we have pos. infinite contributions, the minactivity is +infty */
2399 if( posinf > 0 )
2400 {
2401 *minactivity = SCIPinfinity(scip);
2402 *issettoinfinity = TRUE;
2403 *isrelax = FALSE;
2404 }
2405 /* if we have neg. (and no pos.) infinite contributions, the minactivity is -infty */
2406 else if( neginf > 0 )
2407 {
2408 *minactivity = -SCIPinfinity(scip);
2409 *issettoinfinity = TRUE;
2410 *isrelax = FALSE;
2411 }
2412 /* if we have neg. huge contributions, we only know that -infty is a relaxation of the minactivity */
2413 else if( neghuge > 0 )
2414 {
2415 *minactivity = -SCIPinfinity(scip);
2416 *issettoinfinity = TRUE;
2417 *isrelax = TRUE;
2418 }
2419 /* we do not need a good relaxation and we have positive huge contributions, so we just return -infty as activity */
2420 else if( !goodrelax && poshuge > 0 )
2421 {
2422 *minactivity = -SCIPinfinity(scip);
2423 *issettoinfinity = TRUE;
2424 *isrelax = TRUE;
2425 }
2426 else
2427 {
2428 SCIP_Real tmpactivity;
2429
2430 /* recompute minactivity if it is not valid */
2431 if( global )
2432 {
2433 if( !consdata->validglbminact )
2434 consdataRecomputeGlbMinactivity(scip, consdata);
2435 assert(consdata->validglbminact);
2436
2437 tmpactivity = consdata->glbminactivity;
2438 }
2439 else
2440 {
2441 if( !consdata->validminact )
2442 consdataRecomputeMinactivity(scip, consdata);
2443 assert(consdata->validminact);
2444
2445 tmpactivity = consdata->minactivity;
2446 }
2447
2448 /* we have no infinite and no neg. huge contributions, but pos. huge contributions;
2449 * a feasible relaxation of the minactivity is the number of positive huge contributions
2450 * times the minimum value counting as "huge" plus finite (and non-huge) part of minactivity - delta
2451 */
2452 if( poshuge > 0 )
2453 {
2454 *minactivity = 1.0 * poshuge * SCIPgetHugeValue(scip) + (tmpactivity - delta);
2455 *issettoinfinity = FALSE;
2456 *isrelax = TRUE;
2457 }
2458 /* all counters are zero, so the minactivity is just stored and we subtract the delta */
2459 else
2460 {
2461 *minactivity = tmpactivity - delta;
2462 *issettoinfinity = FALSE;
2463 *isrelax = FALSE;
2464 }
2465 }
2466 }
2467
2468 /** gets maximal activity for constraint and given values of counters for infinite and huge contributions
2469 * and (if needed) delta to subtract from stored finite part of activity in case of a residual activity
2470 */
2471 static
getMaxActivity(SCIP * scip,SCIP_CONSDATA * consdata,int posinf,int neginf,int poshuge,int neghuge,SCIP_Real delta,SCIP_Bool global,SCIP_Bool goodrelax,SCIP_Real * maxactivity,SCIP_Bool * isrelax,SCIP_Bool * issettoinfinity)2472 void getMaxActivity(
2473 SCIP* scip, /**< SCIP data structure */
2474 SCIP_CONSDATA* consdata, /**< linear constraint */
2475 int posinf, /**< number of coefficients contributing pos. infinite value */
2476 int neginf, /**< number of coefficients contributing neg. infinite value */
2477 int poshuge, /**< number of coefficients contributing huge pos. value */
2478 int neghuge, /**< number of coefficients contributing huge neg. value */
2479 SCIP_Real delta, /**< value to subtract from stored maxactivity
2480 * (contribution of the variable set to zero when getting residual activity) */
2481 SCIP_Bool global, /**< should the global or local maximal activity be returned? */
2482 SCIP_Bool goodrelax, /**< should a good relaxation be computed or are relaxed acticities ignored, anyway? */
2483 SCIP_Real* maxactivity, /**< pointer to store the maximal activity */
2484 SCIP_Bool* isrelax, /**< pointer to store whether the activity is a relaxation,
2485 * i.e. is >= the exact maxactivity (in case of huge contributing values) */
2486 SCIP_Bool* issettoinfinity /**< pointer to store whether maxactivity was set to infinity or calculated */
2487 )
2488 {
2489 assert(scip != NULL);
2490 assert(consdata != NULL);
2491 assert(posinf >= 0);
2492 assert(neginf >= 0);
2493 assert(poshuge >= 0);
2494 assert(neghuge >= 0);
2495 assert(maxactivity != NULL);
2496 assert(isrelax != NULL);
2497 assert(issettoinfinity != NULL);
2498
2499 /* if we have neg. infinite contributions, the maxactivity is -infty */
2500 if( neginf > 0 )
2501 {
2502 *maxactivity = -SCIPinfinity(scip);
2503 *issettoinfinity = TRUE;
2504 *isrelax = FALSE;
2505 }
2506 /* if we have pos. (and no neg.) infinite contributions, the maxactivity is +infty */
2507 else if( posinf > 0 )
2508 {
2509 *maxactivity = SCIPinfinity(scip);
2510 *issettoinfinity = TRUE;
2511 *isrelax = FALSE;
2512 }
2513 /* if we have pos. huge contributions, we only know that +infty is a relaxation of the maxactivity */
2514 else if( poshuge > 0 )
2515 {
2516 *maxactivity = SCIPinfinity(scip);
2517 *issettoinfinity = TRUE;
2518 *isrelax = TRUE;
2519 }
2520 /* we do not need a good relaxation and we have positve huge contributions, so we just return +infty as activity */
2521 else if( !goodrelax && neghuge > 0 )
2522 {
2523 *maxactivity = SCIPinfinity(scip);
2524 *issettoinfinity = TRUE;
2525 *isrelax = TRUE;
2526 }
2527 else
2528 {
2529 SCIP_Real tmpactivity;
2530
2531 /* recompute maxactivity if it is not valid */
2532 if( global )
2533 {
2534 if( !consdata->validglbmaxact )
2535 consdataRecomputeGlbMaxactivity(scip, consdata);
2536 assert(consdata->validglbmaxact);
2537
2538 tmpactivity = consdata->glbmaxactivity;
2539 }
2540 else
2541 {
2542 if( !consdata->validmaxact )
2543 consdataRecomputeMaxactivity(scip, consdata);
2544 assert(consdata->validmaxact);
2545
2546 tmpactivity = consdata->maxactivity;
2547 }
2548
2549 /* we have no infinite, and no pos. huge contributions, but neg. huge contributions;
2550 * a feasible relaxation of the maxactivity is minus the number of negative huge contributions
2551 * times the minimum value counting as "huge" plus the finite (and non-huge) part of maxactivity minus delta
2552 */
2553 if( neghuge > 0 )
2554 {
2555 *maxactivity = -1.0 * neghuge * SCIPgetHugeValue(scip) + tmpactivity - delta;
2556 *issettoinfinity = FALSE;
2557 *isrelax = TRUE;
2558 }
2559 /* all counters are zero, so the maxactivity is just stored and we subtract the delta */
2560 else
2561 {
2562 *maxactivity = tmpactivity - delta;
2563 *issettoinfinity = FALSE;
2564 *isrelax = FALSE;
2565 }
2566 }
2567 }
2568
2569 /** gets activity bounds for constraint */
2570 static
consdataGetActivityBounds(SCIP * scip,SCIP_CONSDATA * consdata,SCIP_Bool goodrelax,SCIP_Real * minactivity,SCIP_Real * maxactivity,SCIP_Bool * minisrelax,SCIP_Bool * maxisrelax,SCIP_Bool * isminsettoinfinity,SCIP_Bool * ismaxsettoinfinity)2571 void consdataGetActivityBounds(
2572 SCIP* scip, /**< SCIP data structure */
2573 SCIP_CONSDATA* consdata, /**< linear constraint */
2574 SCIP_Bool goodrelax, /**< if we have huge contributions, do we need a good relaxation or are
2575 * relaxed activities ignored, anyway? */
2576 SCIP_Real* minactivity, /**< pointer to store the minimal activity */
2577 SCIP_Real* maxactivity, /**< pointer to store the maximal activity */
2578 SCIP_Bool* minisrelax, /**< pointer to store whether the returned minactivity is just a relaxation,
2579 * i.e. <= the exact minactivity (in case of huge contributions),
2580 * or equal to the exact minimal activity */
2581 SCIP_Bool* maxisrelax, /**< pointer to store whether the returned maxactivity is just a relaxation,
2582 * i.e. >= the exact maxactivity (in case of huge contributions),
2583 * or equal to the exact maximal activity */
2584 SCIP_Bool* isminsettoinfinity, /**< pointer to store whether minactivity was set to infinity or calculated */
2585 SCIP_Bool* ismaxsettoinfinity /**< pointer to store whether maxactivity was set to infinity or calculated */
2586
2587 )
2588 {
2589 assert(scip != NULL);
2590 assert(consdata != NULL);
2591 assert(minactivity != NULL);
2592 assert(maxactivity != NULL);
2593 assert(isminsettoinfinity != NULL);
2594 assert(ismaxsettoinfinity != NULL);
2595
2596 if( !consdata->validactivities )
2597 {
2598 consdataCalcActivities(scip, consdata);
2599 assert(consdata->validminact);
2600 assert(consdata->validmaxact);
2601 }
2602 assert(consdata->minactivity < SCIP_INVALID);
2603 assert(consdata->maxactivity < SCIP_INVALID);
2604 assert(consdata->minactivityneginf >= 0);
2605 assert(consdata->minactivityposinf >= 0);
2606 assert(consdata->maxactivityneginf >= 0);
2607 assert(consdata->maxactivityposinf >= 0);
2608
2609 getMinActivity(scip, consdata, consdata->minactivityposinf, consdata->minactivityneginf,
2610 consdata->minactivityposhuge, consdata->minactivityneghuge, 0.0, FALSE, goodrelax,
2611 minactivity, minisrelax, isminsettoinfinity);
2612
2613 getMaxActivity(scip, consdata, consdata->maxactivityposinf, consdata->maxactivityneginf,
2614 consdata->maxactivityposhuge, consdata->maxactivityneghuge, 0.0, FALSE, goodrelax,
2615 maxactivity, maxisrelax, ismaxsettoinfinity);
2616 }
2617
2618 /** calculates activity bounds for constraint after setting variable to zero */
2619 static
consdataGetReliableResidualActivity(SCIP * scip,SCIP_CONSDATA * consdata,SCIP_VAR * cancelvar,SCIP_Real * resactivity,SCIP_Bool isminresact,SCIP_Bool useglobalbounds)2620 void consdataGetReliableResidualActivity(
2621 SCIP* scip, /**< SCIP data structure */
2622 SCIP_CONSDATA* consdata, /**< linear constraint */
2623 SCIP_VAR* cancelvar, /**< variable to calculate activity residual for */
2624 SCIP_Real* resactivity, /**< pointer to store the residual activity */
2625 SCIP_Bool isminresact, /**< should minimal or maximal residual activity be calculated? */
2626 SCIP_Bool useglobalbounds /**< should global or local bounds be used? */
2627 )
2628 {
2629 SCIP_VAR* var;
2630 SCIP_Real val;
2631 SCIP_Real lb;
2632 SCIP_Real ub;
2633 int v;
2634
2635 assert(scip != NULL);
2636 assert(consdata != NULL);
2637 assert(cancelvar != NULL);
2638 assert(resactivity != NULL);
2639
2640 *resactivity = 0.0;
2641
2642 for( v = 0; v < consdata->nvars; ++v )
2643 {
2644 var = consdata->vars[v];
2645 assert(var != NULL);
2646 if( var == cancelvar )
2647 continue;
2648
2649 val = consdata->vals[v];
2650
2651 if( useglobalbounds )
2652 {
2653 lb = SCIPvarGetLbGlobal(var);
2654 ub = SCIPvarGetUbGlobal(var);
2655 }
2656 else
2657 {
2658 lb = SCIPvarGetLbLocal(var);
2659 ub = SCIPvarGetUbLocal(var);
2660 }
2661
2662 assert(!SCIPisZero(scip, val));
2663 assert(SCIPisLE(scip, lb, ub));
2664
2665 if( val > 0.0 )
2666 {
2667 if( isminresact )
2668 {
2669 assert(!SCIPisInfinity(scip, -lb));
2670 assert(!SCIPisHugeValue(scip, REALABS(val*lb)));
2671 *resactivity += val*lb;
2672 }
2673 else
2674 {
2675 assert(!SCIPisInfinity(scip, ub));
2676 assert(!SCIPisHugeValue(scip, REALABS(val*ub)));
2677 *resactivity += val*ub;
2678 }
2679 }
2680 else
2681 {
2682 if( isminresact)
2683 {
2684 assert(!SCIPisInfinity(scip, ub));
2685 assert(!SCIPisHugeValue(scip, REALABS(val*ub)));
2686 *resactivity += val*ub;
2687 }
2688 else
2689 {
2690 assert(!SCIPisInfinity(scip, -lb));
2691 assert(!SCIPisHugeValue(scip, REALABS(val*lb)));
2692 *resactivity += val*lb;
2693 }
2694 }
2695 }
2696 assert(!SCIPisInfinity(scip, *resactivity) && !SCIPisInfinity(scip, -(*resactivity)));
2697 }
2698
2699 /** gets activity bounds for constraint after setting variable to zero */
2700 static
consdataGetActivityResiduals(SCIP * scip,SCIP_CONSDATA * consdata,SCIP_VAR * var,SCIP_Real val,SCIP_Bool goodrelax,SCIP_Real * minresactivity,SCIP_Real * maxresactivity,SCIP_Bool * minisrelax,SCIP_Bool * maxisrelax,SCIP_Bool * isminsettoinfinity,SCIP_Bool * ismaxsettoinfinity)2701 void consdataGetActivityResiduals(
2702 SCIP* scip, /**< SCIP data structure */
2703 SCIP_CONSDATA* consdata, /**< linear constraint */
2704 SCIP_VAR* var, /**< variable to calculate activity residual for */
2705 SCIP_Real val, /**< coefficient value of variable in linear constraint */
2706 SCIP_Bool goodrelax, /**< if we have huge contributions, do we need a good relaxation or are
2707 * relaxed acticities ignored, anyway? */
2708 SCIP_Real* minresactivity, /**< pointer to store the minimal residual activity */
2709 SCIP_Real* maxresactivity, /**< pointer to store the maximal residual activity */
2710 SCIP_Bool* minisrelax, /**< pointer to store whether the returned residual minactivity is just a
2711 * relaxation, i.e. <= the exact residual minactivity (in case of huge
2712 * contributions), or equal to the exact residual minactivity */
2713 SCIP_Bool* maxisrelax, /**< pointer to store whether the returned residual maxactivity is just a
2714 * relaxation, i.e. <= the exact residual maxactivity (in case of huge
2715 * contributions), or equal to the exact residual minactivity */
2716 SCIP_Bool* isminsettoinfinity, /**< pointer to store whether minresactivity was set to infinity or calculated */
2717 SCIP_Bool* ismaxsettoinfinity /**< pointer to store whether maxresactivity was set to infinity or calculated */
2718 )
2719 {
2720 SCIP_Real minactbound;
2721 SCIP_Real maxactbound;
2722 SCIP_Real absval;
2723
2724 assert(scip != NULL);
2725 assert(consdata != NULL);
2726 assert(var != NULL);
2727 assert(minresactivity != NULL);
2728 assert(maxresactivity != NULL);
2729 assert(minisrelax != NULL);
2730 assert(maxisrelax != NULL);
2731 assert(isminsettoinfinity != NULL);
2732 assert(ismaxsettoinfinity != NULL);
2733
2734 /* get activity bounds of linear constraint */
2735 if( !consdata->validactivities )
2736 {
2737 consdataCalcActivities(scip, consdata);
2738 assert(consdata->validminact);
2739 assert(consdata->validmaxact);
2740 }
2741 assert(consdata->minactivity < SCIP_INVALID);
2742 assert(consdata->maxactivity < SCIP_INVALID);
2743 assert(consdata->minactivityneginf >= 0);
2744 assert(consdata->minactivityposinf >= 0);
2745 assert(consdata->maxactivityneginf >= 0);
2746 assert(consdata->maxactivityposinf >= 0);
2747 assert(consdata->minactivityneghuge >= 0);
2748 assert(consdata->minactivityposhuge >= 0);
2749 assert(consdata->maxactivityneghuge >= 0);
2750 assert(consdata->maxactivityposhuge >= 0);
2751
2752 if( val > 0.0 )
2753 {
2754 minactbound = SCIPvarGetLbLocal(var);
2755 maxactbound = SCIPvarGetUbLocal(var);
2756 absval = val;
2757 }
2758 else
2759 {
2760 minactbound = -SCIPvarGetUbLocal(var);
2761 maxactbound = -SCIPvarGetLbLocal(var);
2762 absval = -val;
2763 }
2764
2765 /* get/compute minactivity by calling getMinActivity() with updated counters for infinite and huge values
2766 * and contribution of variable set to zero that has to be subtracted from finite part of activity
2767 */
2768 if( SCIPisInfinity(scip, minactbound) )
2769 {
2770 assert(consdata->minactivityposinf >= 1);
2771
2772 getMinActivity(scip, consdata, consdata->minactivityposinf - 1, consdata->minactivityneginf,
2773 consdata->minactivityposhuge, consdata->minactivityneghuge, 0.0, FALSE, goodrelax,
2774 minresactivity, minisrelax, isminsettoinfinity);
2775 }
2776 else if( SCIPisInfinity(scip, -minactbound) )
2777 {
2778 assert(consdata->minactivityneginf >= 1);
2779
2780 getMinActivity(scip, consdata, consdata->minactivityposinf, consdata->minactivityneginf - 1,
2781 consdata->minactivityposhuge, consdata->minactivityneghuge, 0.0, FALSE, goodrelax,
2782 minresactivity, minisrelax, isminsettoinfinity);
2783 }
2784 else if( SCIPisHugeValue(scip, minactbound * absval) )
2785 {
2786 assert(consdata->minactivityposhuge >= 1);
2787
2788 getMinActivity(scip, consdata, consdata->minactivityposinf, consdata->minactivityneginf,
2789 consdata->minactivityposhuge - 1, consdata->minactivityneghuge, 0.0, FALSE, goodrelax,
2790 minresactivity, minisrelax, isminsettoinfinity);
2791 }
2792 else if( SCIPisHugeValue(scip, -minactbound * absval) )
2793 {
2794 assert(consdata->minactivityneghuge >= 1);
2795
2796 getMinActivity(scip, consdata, consdata->minactivityposinf, consdata->minactivityneginf,
2797 consdata->minactivityposhuge, consdata->minactivityneghuge - 1, 0.0, FALSE, goodrelax,
2798 minresactivity, minisrelax, isminsettoinfinity);
2799 }
2800 else
2801 {
2802 getMinActivity(scip, consdata, consdata->minactivityposinf, consdata->minactivityneginf,
2803 consdata->minactivityposhuge, consdata->minactivityneghuge, absval * minactbound, FALSE, goodrelax,
2804 minresactivity, minisrelax, isminsettoinfinity);
2805 }
2806
2807 /* get/compute maxactivity by calling getMaxActivity() with updated counters for infinite and huge values
2808 * and contribution of variable set to zero that has to be subtracted from finite part of activity
2809 */
2810 if( SCIPisInfinity(scip, -maxactbound) )
2811 {
2812 assert(consdata->maxactivityneginf >= 1);
2813
2814 getMaxActivity(scip, consdata, consdata->maxactivityposinf, consdata->maxactivityneginf - 1,
2815 consdata->maxactivityposhuge, consdata->maxactivityneghuge, 0.0, FALSE, goodrelax,
2816 maxresactivity, maxisrelax, ismaxsettoinfinity);
2817 }
2818 else if( SCIPisInfinity(scip, maxactbound) )
2819 {
2820 assert(consdata->maxactivityposinf >= 1);
2821
2822 getMaxActivity(scip, consdata, consdata->maxactivityposinf - 1, consdata->maxactivityneginf,
2823 consdata->maxactivityposhuge, consdata->maxactivityneghuge, 0.0, FALSE, goodrelax,
2824 maxresactivity, maxisrelax, ismaxsettoinfinity);
2825 }
2826 else if( SCIPisHugeValue(scip, absval * maxactbound) )
2827 {
2828 assert(consdata->maxactivityposhuge >= 1);
2829
2830 getMaxActivity(scip, consdata, consdata->maxactivityposinf, consdata->maxactivityneginf,
2831 consdata->maxactivityposhuge - 1, consdata->maxactivityneghuge, 0.0, FALSE, goodrelax,
2832 maxresactivity, maxisrelax, ismaxsettoinfinity);
2833 }
2834 else if( SCIPisHugeValue(scip, -absval * maxactbound) )
2835 {
2836 assert(consdata->maxactivityneghuge >= 1);
2837
2838 getMaxActivity(scip, consdata, consdata->maxactivityposinf, consdata->maxactivityneginf,
2839 consdata->maxactivityposhuge, consdata->maxactivityneghuge - 1, 0.0, FALSE, goodrelax,
2840 maxresactivity, maxisrelax, ismaxsettoinfinity);
2841 }
2842 else
2843 {
2844 getMaxActivity(scip, consdata, consdata->maxactivityposinf, consdata->maxactivityneginf,
2845 consdata->maxactivityposhuge, consdata->maxactivityneghuge, absval * maxactbound, FALSE, goodrelax,
2846 maxresactivity, maxisrelax, ismaxsettoinfinity);
2847 }
2848 }
2849
2850 /** gets global activity bounds for constraint */
2851 static
consdataGetGlbActivityBounds(SCIP * scip,SCIP_CONSDATA * consdata,SCIP_Bool goodrelax,SCIP_Real * glbminactivity,SCIP_Real * glbmaxactivity,SCIP_Bool * minisrelax,SCIP_Bool * maxisrelax,SCIP_Bool * isminsettoinfinity,SCIP_Bool * ismaxsettoinfinity)2852 void consdataGetGlbActivityBounds(
2853 SCIP* scip, /**< SCIP data structure */
2854 SCIP_CONSDATA* consdata, /**< linear constraint */
2855 SCIP_Bool goodrelax, /**< if we have huge contributions, do we need a good relaxation or are
2856 * relaxed acticities ignored, anyway? */
2857 SCIP_Real* glbminactivity, /**< pointer to store the minimal activity, or NULL, if not needed */
2858 SCIP_Real* glbmaxactivity, /**< pointer to store the maximal activity, or NULL, if not needed */
2859 SCIP_Bool* minisrelax, /**< pointer to store whether the returned minactivity is just a relaxation,
2860 * i.e. <= the exact minactivity (in case of huge contributions),
2861 * or equal to the exact minimal activity */
2862 SCIP_Bool* maxisrelax, /**< pointer to store whether the returned maxactivity is just a relaxation,
2863 * i.e. >= the exact maxactivity (in case of huge contributions),
2864 * or equal to the exact maximal activity */
2865 SCIP_Bool* isminsettoinfinity, /**< pointer to store whether minresactivity was set to infinity or calculated */
2866 SCIP_Bool* ismaxsettoinfinity /**< pointer to store whether maxresactivity was set to infinity or calculated */
2867 )
2868 {
2869 assert(scip != NULL);
2870 assert(consdata != NULL);
2871 assert((glbminactivity != NULL && minisrelax != NULL && isminsettoinfinity != NULL)
2872 || (glbmaxactivity != NULL && maxisrelax != NULL && ismaxsettoinfinity != NULL));
2873
2874 if( !consdata->validactivities )
2875 {
2876 consdataCalcActivities(scip, consdata);
2877 assert(consdata->validglbminact);
2878 assert(consdata->validglbmaxact);
2879 }
2880 assert(consdata->glbminactivity < SCIP_INVALID);
2881 assert(consdata->glbmaxactivity < SCIP_INVALID);
2882 assert(consdata->glbminactivityneginf >= 0);
2883 assert(consdata->glbminactivityposinf >= 0);
2884 assert(consdata->glbmaxactivityneginf >= 0);
2885 assert(consdata->glbmaxactivityposinf >= 0);
2886 assert(consdata->glbminactivityneghuge >= 0);
2887 assert(consdata->glbminactivityposhuge >= 0);
2888 assert(consdata->glbmaxactivityneghuge >= 0);
2889 assert(consdata->glbmaxactivityposhuge >= 0);
2890
2891 if( glbminactivity != NULL )
2892 {
2893 assert(isminsettoinfinity != NULL);
2894 assert(minisrelax != NULL);
2895
2896 getMinActivity(scip, consdata, consdata->glbminactivityposinf, consdata->glbminactivityneginf,
2897 consdata->glbminactivityposhuge, consdata->glbminactivityneghuge, 0.0, TRUE, goodrelax,
2898 glbminactivity, minisrelax, isminsettoinfinity);
2899 }
2900
2901 if( glbmaxactivity != NULL )
2902 {
2903 assert(ismaxsettoinfinity != NULL);
2904 assert(maxisrelax != NULL);
2905
2906 getMaxActivity(scip, consdata, consdata->glbmaxactivityposinf, consdata->glbmaxactivityneginf,
2907 consdata->glbmaxactivityposhuge, consdata->glbmaxactivityneghuge, 0.0, TRUE, goodrelax,
2908 glbmaxactivity, maxisrelax, ismaxsettoinfinity);
2909 }
2910 }
2911
2912 /** gets global activity bounds for constraint after setting variable to zero */
2913 static
consdataGetGlbActivityResiduals(SCIP * scip,SCIP_CONSDATA * consdata,SCIP_VAR * var,SCIP_Real val,SCIP_Bool goodrelax,SCIP_Real * minresactivity,SCIP_Real * maxresactivity,SCIP_Bool * minisrelax,SCIP_Bool * maxisrelax,SCIP_Bool * isminsettoinfinity,SCIP_Bool * ismaxsettoinfinity)2914 void consdataGetGlbActivityResiduals(
2915 SCIP* scip, /**< SCIP data structure */
2916 SCIP_CONSDATA* consdata, /**< linear constraint */
2917 SCIP_VAR* var, /**< variable to calculate activity residual for */
2918 SCIP_Real val, /**< coefficient value of variable in linear constraint */
2919 SCIP_Bool goodrelax, /**< if we have huge contributions, do we need a good relaxation or are
2920 * relaxed acticities ignored, anyway? */
2921 SCIP_Real* minresactivity, /**< pointer to store the minimal residual activity, or NULL, if not needed */
2922 SCIP_Real* maxresactivity, /**< pointer to store the maximal residual activity, or NULL, if not needed */
2923 SCIP_Bool* minisrelax, /**< pointer to store whether the returned residual minactivity is just a
2924 * relaxation, i.e. <= the exact residual minactivity (in case of huge
2925 * contributions), or equal to the exact residual minactivity */
2926 SCIP_Bool* maxisrelax, /**< pointer to store whether the returned residual maxactivity is just a
2927 * relaxation, i.e. <= the exact residual maxactivity (in case of huge
2928 * contributions), or equal to the exact residual minactivity */
2929 SCIP_Bool* isminsettoinfinity, /**< pointer to store whether minresactivity was set to infinity or calculated */
2930 SCIP_Bool* ismaxsettoinfinity /**< pointer to store whether maxresactivity was set to infinity or calculated */
2931 )
2932 {
2933 SCIP_Real minactbound;
2934 SCIP_Real maxactbound;
2935 SCIP_Real absval;
2936
2937 assert(scip != NULL);
2938 assert(consdata != NULL);
2939 assert(var != NULL);
2940 assert((minresactivity != NULL && minisrelax != NULL && isminsettoinfinity != NULL )
2941 || (maxresactivity != NULL && maxisrelax != NULL && ismaxsettoinfinity != NULL));
2942
2943 /* get activity bounds of linear constraint */
2944 if( !consdata->validactivities )
2945 consdataCalcActivities(scip, consdata);
2946
2947 assert(consdata->glbminactivity < SCIP_INVALID);
2948 assert(consdata->glbmaxactivity < SCIP_INVALID);
2949 assert(consdata->glbminactivityneginf >= 0);
2950 assert(consdata->glbminactivityposinf >= 0);
2951 assert(consdata->glbmaxactivityneginf >= 0);
2952 assert(consdata->glbmaxactivityposinf >= 0);
2953
2954 if( val > 0.0 )
2955 {
2956 minactbound = SCIPvarGetLbGlobal(var);
2957 maxactbound = SCIPvarGetUbGlobal(var);
2958 absval = val;
2959 }
2960 else
2961 {
2962 minactbound = -SCIPvarGetUbGlobal(var);
2963 maxactbound = -SCIPvarGetLbGlobal(var);
2964 absval = -val;
2965 }
2966
2967 if( minresactivity != NULL )
2968 {
2969 assert(isminsettoinfinity != NULL);
2970 assert(minisrelax != NULL);
2971
2972 /* get/compute minactivity by calling getMinActivity() with updated counters for infinite and huge values
2973 * and contribution of variable set to zero that has to be subtracted from finite part of activity
2974 */
2975 if( SCIPisInfinity(scip, minactbound) )
2976 {
2977 assert(consdata->glbminactivityposinf >= 1);
2978
2979 getMinActivity(scip, consdata, consdata->glbminactivityposinf - 1, consdata->glbminactivityneginf,
2980 consdata->glbminactivityposhuge, consdata->glbminactivityneghuge, 0.0, TRUE, goodrelax,
2981 minresactivity, minisrelax, isminsettoinfinity);
2982 }
2983 else if( SCIPisInfinity(scip, -minactbound) )
2984 {
2985 assert(consdata->glbminactivityneginf >= 1);
2986
2987 getMinActivity(scip, consdata, consdata->glbminactivityposinf, consdata->glbminactivityneginf - 1,
2988 consdata->glbminactivityposhuge, consdata->glbminactivityneghuge, 0.0, TRUE, goodrelax,
2989 minresactivity, minisrelax, isminsettoinfinity);
2990 }
2991 else if( SCIPisHugeValue(scip, minactbound * absval) )
2992 {
2993 assert(consdata->glbminactivityposhuge >= 1);
2994
2995 getMinActivity(scip, consdata, consdata->glbminactivityposinf, consdata->glbminactivityneginf,
2996 consdata->glbminactivityposhuge - 1, consdata->glbminactivityneghuge, 0.0, TRUE, goodrelax,
2997 minresactivity, minisrelax, isminsettoinfinity);
2998 }
2999 else if( SCIPisHugeValue(scip, -minactbound * absval) )
3000 {
3001 assert(consdata->glbminactivityneghuge >= 1);
3002
3003 getMinActivity(scip, consdata, consdata->glbminactivityposinf, consdata->glbminactivityneginf,
3004 consdata->glbminactivityposhuge, consdata->glbminactivityneghuge - 1, 0.0, TRUE, goodrelax,
3005 minresactivity, minisrelax, isminsettoinfinity);
3006 }
3007 else
3008 {
3009 getMinActivity(scip, consdata, consdata->glbminactivityposinf, consdata->glbminactivityneginf,
3010 consdata->glbminactivityposhuge, consdata->glbminactivityneghuge, absval * minactbound, TRUE,
3011 goodrelax, minresactivity, minisrelax, isminsettoinfinity);
3012 }
3013 }
3014
3015 if( maxresactivity != NULL )
3016 {
3017 assert(ismaxsettoinfinity != NULL);
3018 assert(maxisrelax != NULL);
3019
3020 /* get/compute maxactivity by calling getMaxActivity() with updated counters for infinite and huge values
3021 * and contribution of variable set to zero that has to be subtracted from finite part of activity
3022 */
3023 if( SCIPisInfinity(scip, -maxactbound) )
3024 {
3025 assert(consdata->glbmaxactivityneginf >= 1);
3026
3027 getMaxActivity(scip, consdata, consdata->glbmaxactivityposinf, consdata->glbmaxactivityneginf - 1,
3028 consdata->glbmaxactivityposhuge, consdata->glbmaxactivityneghuge, 0.0, TRUE, goodrelax,
3029 maxresactivity, maxisrelax, ismaxsettoinfinity);
3030 }
3031 else if( SCIPisInfinity(scip, maxactbound) )
3032 {
3033 assert(consdata->glbmaxactivityposinf >= 1);
3034
3035 getMaxActivity(scip, consdata, consdata->glbmaxactivityposinf - 1, consdata->glbmaxactivityneginf,
3036 consdata->glbmaxactivityposhuge, consdata->glbmaxactivityneghuge, 0.0, TRUE, goodrelax,
3037 maxresactivity, maxisrelax, ismaxsettoinfinity);
3038 }
3039 else if( SCIPisHugeValue(scip, absval * maxactbound) )
3040 {
3041 assert(consdata->glbmaxactivityposhuge >= 1);
3042
3043 getMaxActivity(scip, consdata, consdata->glbmaxactivityposinf, consdata->glbmaxactivityneginf,
3044 consdata->glbmaxactivityposhuge - 1, consdata->glbmaxactivityneghuge, 0.0, TRUE, goodrelax,
3045 maxresactivity, maxisrelax, ismaxsettoinfinity);
3046 }
3047 else if( SCIPisHugeValue(scip, -absval * maxactbound) )
3048 {
3049 assert(consdata->glbmaxactivityneghuge >= 1);
3050
3051 getMaxActivity(scip, consdata, consdata->glbmaxactivityposinf, consdata->glbmaxactivityneginf,
3052 consdata->glbmaxactivityposhuge, consdata->glbmaxactivityneghuge - 1, 0.0, TRUE, goodrelax,
3053 maxresactivity, maxisrelax, ismaxsettoinfinity);
3054 }
3055 else
3056 {
3057 getMaxActivity(scip, consdata, consdata->glbmaxactivityposinf, consdata->glbmaxactivityneginf,
3058 consdata->glbmaxactivityposhuge, consdata->glbmaxactivityneghuge, absval * maxactbound, TRUE,
3059 goodrelax, maxresactivity, maxisrelax, ismaxsettoinfinity);
3060 }
3061 }
3062 }
3063
3064 /** calculates the activity of the linear constraint for given solution */
3065 static
consdataGetActivity(SCIP * scip,SCIP_CONSDATA * consdata,SCIP_SOL * sol)3066 SCIP_Real consdataGetActivity(
3067 SCIP* scip, /**< SCIP data structure */
3068 SCIP_CONSDATA* consdata, /**< linear constraint data */
3069 SCIP_SOL* sol /**< solution to get activity for, NULL to current solution */
3070 )
3071 {
3072 SCIP_Real activity;
3073
3074 assert(scip != NULL);
3075 assert(consdata != NULL);
3076
3077 if( sol == NULL && !SCIPhasCurrentNodeLP(scip) )
3078 activity = consdataComputePseudoActivity(scip, consdata);
3079 else
3080 {
3081 SCIP_Real solval;
3082 int nposinf;
3083 int nneginf;
3084 SCIP_Bool negsign;
3085 int v;
3086
3087 activity = 0.0;
3088 nposinf = 0;
3089 nneginf = 0;
3090
3091 for( v = 0; v < consdata->nvars; ++v )
3092 {
3093 solval = SCIPgetSolVal(scip, sol, consdata->vars[v]);
3094
3095 if( consdata->vals[v] < 0 )
3096 negsign = TRUE;
3097 else
3098 negsign = FALSE;
3099
3100 if( (SCIPisInfinity(scip, solval) && !negsign) || (SCIPisInfinity(scip, -solval) && negsign) )
3101 ++nposinf;
3102 else if( (SCIPisInfinity(scip, solval) && negsign) || (SCIPisInfinity(scip, -solval) && !negsign) )
3103 ++nneginf;
3104 else
3105 activity += consdata->vals[v] * solval;
3106 }
3107 assert(nneginf >= 0 && nposinf >= 0);
3108
3109 SCIPdebugMsg(scip, "activity of linear constraint: %.15g, %d positive infinity values, %d negative infinity values \n", activity, nposinf, nneginf);
3110
3111 /* check for amount of infinity values and correct the activity */
3112 if( nposinf > 0 && nneginf > 0 )
3113 activity = (consdata->rhs + consdata->lhs) / 2;
3114 else if( nposinf > 0 )
3115 activity = SCIPinfinity(scip);
3116 else if( nneginf > 0 )
3117 activity = -SCIPinfinity(scip);
3118
3119 SCIPdebugMsg(scip, "corrected activity of linear constraint: %.15g\n", activity);
3120 }
3121
3122 if( activity == SCIP_INVALID ) /*lint !e777*/
3123 return activity;
3124 else if( activity < 0 )
3125 activity = MAX(activity, -SCIPinfinity(scip)); /*lint !e666*/
3126 else
3127 activity = MIN(activity, SCIPinfinity(scip)); /*lint !e666*/
3128
3129 return activity;
3130 }
3131
3132 /** calculates the feasibility of the linear constraint for given solution */
3133 static
consdataGetFeasibility(SCIP * scip,SCIP_CONSDATA * consdata,SCIP_SOL * sol)3134 SCIP_Real consdataGetFeasibility(
3135 SCIP* scip, /**< SCIP data structure */
3136 SCIP_CONSDATA* consdata, /**< linear constraint data */
3137 SCIP_SOL* sol /**< solution to get feasibility for, NULL to current solution */
3138 )
3139 {
3140 SCIP_Real activity;
3141
3142 assert(scip != NULL);
3143 assert(consdata != NULL);
3144
3145 activity = consdataGetActivity(scip, consdata, sol);
3146
3147 if( activity == SCIP_INVALID ) /*lint !e777*/
3148 return -SCIPinfinity(scip);
3149
3150 return MIN(consdata->rhs - activity, activity - consdata->lhs);
3151 }
3152
3153 /** updates bit signatures after adding a single coefficient */
3154 static
consdataUpdateSignatures(SCIP_CONSDATA * consdata,int pos)3155 void consdataUpdateSignatures(
3156 SCIP_CONSDATA* consdata, /**< linear constraint data */
3157 int pos /**< position of coefficient to update signatures for */
3158 )
3159 {
3160 uint64_t varsignature;
3161 SCIP_Real lb;
3162 SCIP_Real ub;
3163 SCIP_Real val;
3164
3165 assert(consdata != NULL);
3166 assert(consdata->validsignature);
3167
3168 varsignature = SCIPhashSignature64(SCIPvarGetIndex(consdata->vars[pos]));
3169 lb = SCIPvarGetLbGlobal(consdata->vars[pos]);
3170 ub = SCIPvarGetUbGlobal(consdata->vars[pos]);
3171 val = consdata->vals[pos];
3172 if( (val > 0.0 && ub > 0.0) || (val < 0.0 && lb < 0.0) )
3173 consdata->possignature |= varsignature;
3174 if( (val > 0.0 && lb < 0.0) || (val < 0.0 && ub > 0.0) )
3175 consdata->negsignature |= varsignature;
3176 }
3177
3178 /** calculates the bit signatures of the given constraint data */
3179 static
consdataCalcSignatures(SCIP_CONSDATA * consdata)3180 void consdataCalcSignatures(
3181 SCIP_CONSDATA* consdata /**< linear constraint data */
3182 )
3183 {
3184 assert(consdata != NULL);
3185
3186 if( !consdata->validsignature )
3187 {
3188 int i;
3189
3190 consdata->validsignature = TRUE;
3191 consdata->possignature = 0;
3192 consdata->negsignature = 0;
3193 for( i = 0; i < consdata->nvars; ++i )
3194 consdataUpdateSignatures(consdata, i);
3195 }
3196 }
3197
3198 /** index comparison method of linear constraints: compares two indices of the variable set in the linear constraint */
3199 static
SCIP_DECL_SORTINDCOMP(consdataCompVar)3200 SCIP_DECL_SORTINDCOMP(consdataCompVar)
3201 { /*lint --e{715}*/
3202 SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
3203 SCIP_VAR* var1;
3204 SCIP_VAR* var2;
3205
3206 assert(consdata != NULL);
3207 assert(0 <= ind1 && ind1 < consdata->nvars);
3208 assert(0 <= ind2 && ind2 < consdata->nvars);
3209
3210 var1 = consdata->vars[ind1];
3211 var2 = consdata->vars[ind2];
3212
3213 /* exactly one variable is binary */
3214 if( SCIPvarIsBinary(var1) != SCIPvarIsBinary(var2) )
3215 {
3216 return (SCIPvarIsBinary(var1) ? -1 : +1);
3217 }
3218 /* both variables are binary */
3219 else if( SCIPvarIsBinary(var1) )
3220 {
3221 return SCIPvarCompare(var1, var2);
3222 }
3223 else
3224 {
3225 SCIP_VARTYPE vartype1 = SCIPvarGetType(var1);
3226 SCIP_VARTYPE vartype2 = SCIPvarGetType(var2);
3227
3228 if( vartype1 < vartype2 )
3229 return -1;
3230 else if( vartype1 > vartype2 )
3231 return +1;
3232 else
3233 return SCIPvarCompare(var1, var2);
3234 }
3235 }
3236
3237 /** index comparison method of linear constraints: compares two indices of the variable set in the linear constraint */
3238 static
SCIP_DECL_SORTINDCOMP(consdataCompVarProp)3239 SCIP_DECL_SORTINDCOMP(consdataCompVarProp)
3240 { /*lint --e{715}*/
3241 SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
3242 SCIP_VAR* var1;
3243 SCIP_VAR* var2;
3244
3245 assert(consdata != NULL);
3246 assert(0 <= ind1 && ind1 < consdata->nvars);
3247 assert(0 <= ind2 && ind2 < consdata->nvars);
3248
3249 var1 = consdata->vars[ind1];
3250 var2 = consdata->vars[ind2];
3251
3252 /* exactly one variable is binary */
3253 if( SCIPvarIsBinary(var1) != SCIPvarIsBinary(var2) )
3254 {
3255 return (SCIPvarIsBinary(var1) ? -1 : +1);
3256 }
3257 /* both variables are binary */
3258 else if( SCIPvarIsBinary(var1) )
3259 {
3260 SCIP_Real abscoef1 = REALABS(consdata->vals[ind1]);
3261 SCIP_Real abscoef2 = REALABS(consdata->vals[ind2]);
3262
3263 if( EPSGT(abscoef1, abscoef2, 1e-9) )
3264 return -1;
3265 else if( EPSGT(abscoef2, abscoef1, 1e-9) )
3266 return +1;
3267 else
3268 return (SCIPvarGetProbindex(var1) - SCIPvarGetProbindex(var2));
3269 }
3270 else
3271 {
3272 SCIP_VARTYPE vartype1 = SCIPvarGetType(var1);
3273 SCIP_VARTYPE vartype2 = SCIPvarGetType(var2);
3274
3275 if( vartype1 < vartype2 )
3276 {
3277 return -1;
3278 }
3279 else if( vartype1 > vartype2 )
3280 {
3281 return +1;
3282 }
3283 else
3284 {
3285 /* both variables are continuous */
3286 if( !SCIPvarIsIntegral(var1) )
3287 {
3288 assert(!SCIPvarIsIntegral(var2));
3289 return (SCIPvarGetProbindex(var1) - SCIPvarGetProbindex(var2));
3290 }
3291 else
3292 {
3293 SCIP_Real abscont1 = REALABS(consdata->vals[ind1] * (SCIPvarGetUbGlobal(var1) - SCIPvarGetLbGlobal(var1)));
3294 SCIP_Real abscont2 = REALABS(consdata->vals[ind2] * (SCIPvarGetUbGlobal(var2) - SCIPvarGetLbGlobal(var2)));
3295
3296 if( EPSGT(abscont1, abscont2, 1e-9) )
3297 return -1;
3298 else if( EPSGT(abscont2, abscont1, 1e-9) )
3299 return +1;
3300 else
3301 return (SCIPvarGetProbindex(var1) - SCIPvarGetProbindex(var2));
3302 }
3303 }
3304 }
3305 }
3306
3307 /** permutes the constraint's variables according to a given permutation. */
3308 static
permSortConsdata(SCIP_CONSDATA * consdata,int * perm,int nvars)3309 void permSortConsdata(
3310 SCIP_CONSDATA* consdata, /**< the constraint data */
3311 int* perm, /**< the target permutation */
3312 int nvars /**< the number of variables */
3313 )
3314 { /*lint --e{715}*/
3315 SCIP_VAR* varv;
3316 SCIP_EVENTDATA* eventdatav;
3317 SCIP_Real valv;
3318 int v;
3319 int i;
3320 int nexti;
3321
3322 assert(perm != NULL);
3323 assert(consdata != NULL);
3324
3325 /* permute the variables in the linear constraint according to the target permutation */
3326 eventdatav = NULL;
3327 for( v = 0; v < nvars; ++v )
3328 {
3329 if( perm[v] != v )
3330 {
3331 varv = consdata->vars[v];
3332 valv = consdata->vals[v];
3333 if( consdata->eventdata != NULL )
3334 eventdatav = consdata->eventdata[v];
3335 i = v;
3336 do
3337 {
3338 assert(0 <= perm[i] && perm[i] < nvars);
3339 assert(perm[i] != i);
3340 consdata->vars[i] = consdata->vars[perm[i]];
3341 consdata->vals[i] = consdata->vals[perm[i]];
3342 if( consdata->eventdata != NULL )
3343 {
3344 consdata->eventdata[i] = consdata->eventdata[perm[i]];
3345 consdata->eventdata[i]->varpos = i;
3346 }
3347 nexti = perm[i];
3348 perm[i] = i;
3349 i = nexti;
3350 }
3351 while( perm[i] != v );
3352 consdata->vars[i] = varv;
3353 consdata->vals[i] = valv;
3354 if( consdata->eventdata != NULL )
3355 {
3356 consdata->eventdata[i] = eventdatav;
3357 consdata->eventdata[i]->varpos = i;
3358 }
3359 perm[i] = i;
3360 }
3361 }
3362 #ifdef SCIP_DEBUG
3363 /* check sorting */
3364 for( v = 0; v < nvars; ++v )
3365 {
3366 assert(perm[v] == v);
3367 assert(consdata->eventdata == NULL || consdata->eventdata[v]->varpos == v);
3368 }
3369 #endif
3370 }
3371
3372 /** sorts linear constraint's variables depending on the stage of the solving process:
3373 * - during PRESOLVING
3374 * sorts variables by binaries, integers, implicit integers, and continuous variables,
3375 * and the variables of the same type by non-decreasing variable index
3376 *
3377 * - during SOLVING
3378 * sorts variables of the remaining problem by binaries, integers, implicit integers, and continuous variables,
3379 * and binary and integer variables by their global max activity delta (within each group),
3380 * ties within a group are broken by problem index of the variable.
3381 *
3382 * This fastens the propagation time of the constraint handler.
3383 */
3384 static
consdataSort(SCIP * scip,SCIP_CONSDATA * consdata)3385 SCIP_RETCODE consdataSort(
3386 SCIP* scip, /**< SCIP data structure */
3387 SCIP_CONSDATA* consdata /**< linear constraint data */
3388 )
3389 {
3390 assert(scip != NULL);
3391 assert(consdata != NULL);
3392
3393 /* check if there are variables for sorting */
3394 if( consdata->nvars <= 1 )
3395 {
3396 consdata->indexsorted = TRUE;
3397 consdata->coefsorted = TRUE;
3398 consdata->nbinvars = (consdata->nvars == 1 ? (int)SCIPvarIsBinary(consdata->vars[0]) : 0);
3399 }
3400 else if( (!consdata->indexsorted && SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE)
3401 || (!consdata->coefsorted && SCIPgetStage(scip) >= SCIP_STAGE_INITSOLVE) )
3402 {
3403 int* perm;
3404 int v;
3405
3406 /* get temporary memory to store the sorted permutation */
3407 SCIP_CALL( SCIPallocBufferArray(scip, &perm, consdata->nvars) );
3408
3409 /* call sorting method */
3410 if( SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE )
3411 SCIPsort(perm, consdataCompVar, (void*)consdata, consdata->nvars);
3412 else
3413 SCIPsort(perm, consdataCompVarProp, (void*)consdata, consdata->nvars);
3414
3415 permSortConsdata(consdata, perm, consdata->nvars);
3416
3417 /* free temporary memory */
3418 SCIPfreeBufferArray(scip, &perm);
3419
3420 if( SCIPgetStage(scip) >= SCIP_STAGE_INITSOLVE )
3421 {
3422 consdata->indexsorted = FALSE;
3423 consdata->coefsorted = TRUE;
3424
3425 /* count binary variables in the sorted vars array */
3426 consdata->nbinvars = 0;
3427 for( v = 0; v < consdata->nvars; ++v )
3428 {
3429 if( SCIPvarIsBinary(consdata->vars[v]) )
3430 ++consdata->nbinvars;
3431 else
3432 break;
3433 }
3434 }
3435 else
3436 {
3437 consdata->indexsorted = TRUE;
3438 consdata->coefsorted = FALSE;
3439 }
3440 }
3441
3442 return SCIP_OKAY;
3443 }
3444
3445
3446 /*
3447 * local linear constraint handler methods
3448 */
3449
3450 /** sets left hand side of linear constraint */
3451 static
chgLhs(SCIP * scip,SCIP_CONS * cons,SCIP_Real lhs)3452 SCIP_RETCODE chgLhs(
3453 SCIP* scip, /**< SCIP data structure */
3454 SCIP_CONS* cons, /**< linear constraint */
3455 SCIP_Real lhs /**< new left hand side */
3456 )
3457 {
3458 SCIP_CONSDATA* consdata;
3459 SCIP_Bool locked;
3460 int i;
3461
3462 assert(scip != NULL);
3463 assert(cons != NULL);
3464 assert(!SCIPisInfinity(scip, lhs));
3465
3466 /* adjust value to not be smaller than -inf */
3467 if ( SCIPisInfinity(scip, -lhs) )
3468 lhs = -SCIPinfinity(scip);
3469
3470 consdata = SCIPconsGetData(cons);
3471 assert(consdata != NULL);
3472 assert(consdata->nvars == 0 || (consdata->vars != NULL && consdata->vals != NULL));
3473 assert(!SCIPisInfinity(scip, consdata->lhs));
3474
3475 /* check whether the side is not changed */
3476 if( SCIPisEQ(scip, consdata->lhs, lhs) )
3477 return SCIP_OKAY;
3478
3479 /* ensure that rhs >= lhs is satisfied without numerical tolerance */
3480 if( SCIPisEQ(scip, lhs, consdata->rhs) )
3481 {
3482 consdata->rhs = lhs;
3483 assert(consdata->row == NULL);
3484 }
3485
3486 locked = FALSE;
3487 for( i = 0; i < NLOCKTYPES && !locked; i++ )
3488 locked = SCIPconsIsLockedType(cons, (SCIP_LOCKTYPE) i);
3489
3490 /* if necessary, update the rounding locks of variables */
3491 if( locked )
3492 {
3493 if( SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, -lhs) )
3494 {
3495 SCIP_VAR** vars;
3496 SCIP_Real* vals;
3497 int v;
3498
3499 /* the left hand side switched from -infinity to a non-infinite value -> install rounding locks */
3500 vars = consdata->vars;
3501 vals = consdata->vals;
3502
3503 for( v = 0; v < consdata->nvars; ++v )
3504 {
3505 assert(vars[v] != NULL);
3506 assert(!SCIPisZero(scip, vals[v]));
3507
3508 if( SCIPisPositive(scip, vals[v]) )
3509 {
3510 SCIP_CALL( SCIPlockVarCons(scip, vars[v], cons, TRUE, FALSE) );
3511 }
3512 else
3513 {
3514 SCIP_CALL( SCIPlockVarCons(scip, vars[v], cons, FALSE, TRUE) );
3515 }
3516 }
3517 }
3518 else if( !SCIPisInfinity(scip, -consdata->lhs) && SCIPisInfinity(scip, -lhs) )
3519 {
3520 SCIP_VAR** vars;
3521 SCIP_Real* vals;
3522 int v;
3523
3524 /* the left hand side switched from a non-infinite value to -infinity -> remove rounding locks */
3525 vars = consdata->vars;
3526 vals = consdata->vals;
3527
3528 for( v = 0; v < consdata->nvars; ++v )
3529 {
3530 assert(vars[v] != NULL);
3531 assert(!SCIPisZero(scip, vals[v]));
3532
3533 if( SCIPisPositive(scip, vals[v]) )
3534 {
3535 SCIP_CALL( SCIPunlockVarCons(scip, vars[v], cons, TRUE, FALSE) );
3536 }
3537 else
3538 {
3539 SCIP_CALL( SCIPunlockVarCons(scip, vars[v], cons, FALSE, TRUE) );
3540 }
3541 }
3542 }
3543 }
3544
3545 /* check whether the left hand side is increased, if and only if that's the case we maybe can propagate, tighten and add more cliques */
3546 if( !SCIPisInfinity(scip, -lhs) && SCIPisGT(scip, lhs, consdata->lhs) )
3547 {
3548 consdata->boundstightened = 0;
3549 consdata->presolved = FALSE;
3550 consdata->cliquesadded = FALSE;
3551 consdata->implsadded = FALSE;
3552
3553 /* mark the constraint for propagation */
3554 if( SCIPconsIsTransformed(cons) )
3555 {
3556 SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
3557 }
3558 }
3559
3560 /* set new left hand side and update constraint data */
3561 consdata->lhs = lhs;
3562 consdata->changed = TRUE;
3563 consdata->normalized = FALSE;
3564 consdata->upgradetried = FALSE;
3565 consdata->rangedrowpropagated = 0;
3566
3567 /* update the lhs of the LP row */
3568 if( consdata->row != NULL )
3569 {
3570 SCIP_CALL( SCIPchgRowLhs(scip, consdata->row, lhs) );
3571 }
3572
3573 return SCIP_OKAY;
3574 }
3575
3576 /** sets right hand side of linear constraint */
3577 static
chgRhs(SCIP * scip,SCIP_CONS * cons,SCIP_Real rhs)3578 SCIP_RETCODE chgRhs(
3579 SCIP* scip, /**< SCIP data structure */
3580 SCIP_CONS* cons, /**< linear constraint */
3581 SCIP_Real rhs /**< new right hand side */
3582 )
3583 {
3584 SCIP_CONSDATA* consdata;
3585 SCIP_Bool locked;
3586 int i;
3587
3588 assert(scip != NULL);
3589 assert(cons != NULL);
3590 assert(!SCIPisInfinity(scip, -rhs));
3591
3592 /* adjust value to not be larger than inf */
3593 if ( SCIPisInfinity(scip, rhs) )
3594 rhs = SCIPinfinity(scip);
3595
3596 consdata = SCIPconsGetData(cons);
3597 assert(consdata != NULL);
3598 assert(consdata->nvars == 0 || (consdata->vars != NULL && consdata->vals != NULL));
3599 assert(!SCIPisInfinity(scip, -consdata->rhs));
3600
3601 /* check whether the side is not changed */
3602 if( SCIPisEQ(scip, consdata->rhs, rhs) )
3603 return SCIP_OKAY;
3604
3605 /* ensure that rhs >= lhs is satisfied without numerical tolerance */
3606 if( SCIPisEQ(scip, rhs, consdata->lhs) )
3607 {
3608 consdata->lhs = rhs;
3609 assert(consdata->row == NULL);
3610 }
3611
3612 locked = FALSE;
3613 for( i = 0; i < NLOCKTYPES && !locked; i++ )
3614 locked = SCIPconsIsLockedType(cons, (SCIP_LOCKTYPE) i);
3615
3616 /* if necessary, update the rounding locks of variables */
3617 if( locked )
3618 {
3619 assert(SCIPconsIsTransformed(cons));
3620
3621 if( SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, rhs) )
3622 {
3623 SCIP_VAR** vars;
3624 SCIP_Real* vals;
3625 int v;
3626
3627 /* the right hand side switched from infinity to a non-infinite value -> install rounding locks */
3628 vars = consdata->vars;
3629 vals = consdata->vals;
3630
3631 for( v = 0; v < consdata->nvars; ++v )
3632 {
3633 assert(vars[v] != NULL);
3634 assert(!SCIPisZero(scip, vals[v]));
3635
3636 if( SCIPisPositive(scip, vals[v]) )
3637 {
3638 SCIP_CALL( SCIPlockVarCons(scip, vars[v], cons, FALSE, TRUE) );
3639 }
3640 else
3641 {
3642 SCIP_CALL( SCIPlockVarCons(scip, vars[v], cons, TRUE, FALSE) );
3643 }
3644 }
3645 }
3646 else if( !SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, rhs) )
3647 {
3648 SCIP_VAR** vars;
3649 SCIP_Real* vals;
3650 int v;
3651
3652 /* the right hand side switched from a non-infinite value to infinity -> remove rounding locks */
3653 vars = consdata->vars;
3654 vals = consdata->vals;
3655
3656 for( v = 0; v < consdata->nvars; ++v )
3657 {
3658 assert(vars[v] != NULL);
3659 assert(!SCIPisZero(scip, vals[v]));
3660
3661 if( SCIPisPositive(scip, vals[v]) )
3662 {
3663 SCIP_CALL( SCIPunlockVarCons(scip, vars[v], cons, FALSE, TRUE) );
3664 }
3665 else
3666 {
3667 SCIP_CALL( SCIPunlockVarCons(scip, vars[v], cons, TRUE, FALSE) );
3668 }
3669 }
3670 }
3671 }
3672
3673 /* check whether the right hand side is decreased, if and only if that's the case we maybe can propagate, tighten and add more cliques */
3674 if( !SCIPisInfinity(scip, rhs) && SCIPisLT(scip, rhs, consdata->rhs) )
3675 {
3676 consdata->boundstightened = 0;
3677 consdata->presolved = FALSE;
3678 consdata->cliquesadded = FALSE;
3679 consdata->implsadded = FALSE;
3680
3681 /* mark the constraint for propagation */
3682 if( SCIPconsIsTransformed(cons) )
3683 {
3684 SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
3685 }
3686 }
3687
3688 /* set new right hand side and update constraint data */
3689 consdata->rhs = rhs;
3690 consdata->changed = TRUE;
3691 consdata->normalized = FALSE;
3692 consdata->upgradetried = FALSE;
3693 consdata->rangedrowpropagated = 0;
3694
3695 /* update the rhs of the LP row */
3696 if( consdata->row != NULL )
3697 {
3698 SCIP_CALL( SCIPchgRowRhs(scip, consdata->row, rhs) );
3699 }
3700
3701 return SCIP_OKAY;
3702 }
3703
3704 /** adds coefficient in linear constraint */
3705 static
addCoef(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * var,SCIP_Real val)3706 SCIP_RETCODE addCoef(
3707 SCIP* scip, /**< SCIP data structure */
3708 SCIP_CONS* cons, /**< linear constraint */
3709 SCIP_VAR* var, /**< variable of constraint entry */
3710 SCIP_Real val /**< coefficient of constraint entry */
3711 )
3712 {
3713 SCIP_CONSDATA* consdata;
3714 SCIP_Bool transformed;
3715
3716 assert(scip != NULL);
3717 assert(cons != NULL);
3718 assert(var != NULL);
3719
3720 /* relaxation-only variables must not be used in checked or enforced constraints */
3721 assert(!SCIPvarIsRelaxationOnly(var) || (!SCIPconsIsChecked(cons) && !SCIPconsIsEnforced(cons)));
3722
3723 /* ignore coefficient if it is nearly zero */
3724 if( SCIPisZero(scip, val) )
3725 return SCIP_OKAY;
3726
3727 consdata = SCIPconsGetData(cons);
3728 assert(consdata != NULL);
3729
3730 /* are we in the transformed problem? */
3731 transformed = SCIPconsIsTransformed(cons);
3732
3733 /* always use transformed variables in transformed constraints */
3734 if( transformed )
3735 {
3736 SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
3737 }
3738 assert(var != NULL);
3739 assert(transformed == SCIPvarIsTransformed(var));
3740
3741 SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1) );
3742 consdata->vars[consdata->nvars] = var;
3743 consdata->vals[consdata->nvars] = val;
3744 consdata->nvars++;
3745
3746 /* capture variable */
3747 SCIP_CALL( SCIPcaptureVar(scip, var) );
3748
3749 /* if we are in transformed problem, the variable needs an additional event data */
3750 if( transformed )
3751 {
3752 if( consdata->eventdata != NULL )
3753 {
3754 SCIP_CONSHDLR* conshdlr;
3755 SCIP_CONSHDLRDATA* conshdlrdata;
3756
3757 /* check for event handler */
3758 conshdlr = SCIPconsGetHdlr(cons);
3759 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3760 assert(conshdlrdata != NULL);
3761 assert(conshdlrdata->eventhdlr != NULL);
3762
3763 /* initialize eventdata array */
3764 consdata->eventdata[consdata->nvars-1] = NULL;
3765
3766 /* catch bound change events of variable */
3767 SCIP_CALL( consCatchEvent(scip, cons, conshdlrdata->eventhdlr, consdata->nvars-1) );
3768 }
3769
3770 /* update minimum and maximum activities */
3771 consdataUpdateAddCoef(scip, consdata, var, val, FALSE);
3772
3773 /* update maximum activity delta */
3774 if( !SCIPisInfinity(scip, consdata->maxactdelta ) )
3775 {
3776 SCIP_Real lb;
3777 SCIP_Real ub;
3778
3779 lb = SCIPvarGetLbLocal(var);
3780 ub = SCIPvarGetUbLocal(var);
3781
3782 if( SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub) )
3783 {
3784 consdata->maxactdelta = SCIPinfinity(scip);
3785 consdata->maxactdeltavar = var;
3786 }
3787 else
3788 {
3789 SCIP_Real domain = ub - lb;
3790 SCIP_Real delta = REALABS(val) * domain;
3791
3792 if( delta > consdata->maxactdelta )
3793 {
3794 consdata->maxactdelta = delta;
3795 consdata->maxactdeltavar = var;
3796 }
3797 }
3798 }
3799 }
3800
3801 /* install rounding locks for new variable */
3802 SCIP_CALL( lockRounding(scip, cons, var, val) );
3803
3804 /* mark the constraint for propagation */
3805 if( transformed )
3806 {
3807 SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
3808 }
3809
3810 consdata->boundstightened = 0;
3811 consdata->presolved = FALSE;
3812 consdata->removedfixings = consdata->removedfixings && SCIPvarIsActive(var);
3813
3814 if( consdata->validsignature )
3815 consdataUpdateSignatures(consdata, consdata->nvars-1);
3816
3817 consdata->changed = TRUE;
3818 consdata->normalized = FALSE;
3819 consdata->upgradetried = FALSE;
3820 consdata->cliquesadded = FALSE;
3821 consdata->implsadded = FALSE;
3822 consdata->rangedrowpropagated = 0;
3823
3824 if( consdata->nvars == 1 )
3825 {
3826 consdata->indexsorted = TRUE;
3827 consdata->coefsorted = TRUE;
3828 consdata->merged = TRUE;
3829 }
3830 else
3831 {
3832 consdata->merged = FALSE;
3833
3834 if( SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE )
3835 {
3836 consdata->indexsorted = consdata->indexsorted && (consdataCompVar((void*)consdata, consdata->nvars-2, consdata->nvars-1) <= 0);
3837 consdata->coefsorted = FALSE;
3838 }
3839 else
3840 {
3841 consdata->indexsorted = FALSE;
3842 consdata->coefsorted = consdata->coefsorted && (consdataCompVarProp((void*)consdata, consdata->nvars-2, consdata->nvars-1) <= 0);
3843 }
3844 }
3845
3846 /* update hascontvar and hasnonbinvar flags */
3847 if( consdata->hasnonbinvalid && !consdata->hascontvar )
3848 {
3849 SCIP_VARTYPE vartype = SCIPvarGetType(var);
3850
3851 if( vartype != SCIP_VARTYPE_BINARY )
3852 {
3853 consdata->hasnonbinvar = TRUE;
3854
3855 if( vartype == SCIP_VARTYPE_CONTINUOUS )
3856 consdata->hascontvar = TRUE;
3857 }
3858 }
3859
3860 /* add the new coefficient to the LP row */
3861 if( consdata->row != NULL )
3862 {
3863 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, val) );
3864 }
3865
3866 return SCIP_OKAY;
3867 }
3868
3869 /** deletes coefficient at given position from linear constraint data */
3870 static
delCoefPos(SCIP * scip,SCIP_CONS * cons,int pos)3871 SCIP_RETCODE delCoefPos(
3872 SCIP* scip, /**< SCIP data structure */
3873 SCIP_CONS* cons, /**< linear constraint */
3874 int pos /**< position of coefficient to delete */
3875 )
3876 {
3877 SCIP_CONSDATA* consdata;
3878 SCIP_VAR* var;
3879 SCIP_Real val;
3880
3881 assert(scip != NULL);
3882 assert(cons != NULL);
3883
3884 consdata = SCIPconsGetData(cons);
3885 assert(consdata != NULL);
3886 assert(0 <= pos && pos < consdata->nvars);
3887
3888 var = consdata->vars[pos];
3889 val = consdata->vals[pos];
3890 assert(var != NULL);
3891
3892 /* remove rounding locks for deleted variable */
3893 SCIP_CALL( unlockRounding(scip, cons, var, val) );
3894
3895 /* if we are in transformed problem, delete the event data of the variable */
3896 if( SCIPconsIsTransformed(cons) )
3897 {
3898 SCIP_CONSHDLR* conshdlr;
3899 SCIP_CONSHDLRDATA* conshdlrdata;
3900
3901 /* check for event handler */
3902 conshdlr = SCIPconsGetHdlr(cons);
3903 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3904 assert(conshdlrdata != NULL);
3905 assert(conshdlrdata->eventhdlr != NULL);
3906
3907 /* drop bound change events of variable */
3908 if( consdata->eventdata != NULL )
3909 {
3910 SCIP_CALL( consDropEvent(scip, cons, conshdlrdata->eventhdlr, pos) );
3911 assert(consdata->eventdata[pos] == NULL);
3912 }
3913 }
3914
3915 /* move the last variable to the free slot */
3916 if( pos != consdata->nvars - 1 )
3917 {
3918 consdata->vars[pos] = consdata->vars[consdata->nvars-1];
3919 consdata->vals[pos] = consdata->vals[consdata->nvars-1];
3920
3921 if( consdata->eventdata != NULL )
3922 {
3923 consdata->eventdata[pos] = consdata->eventdata[consdata->nvars-1];
3924 assert(consdata->eventdata[pos] != NULL);
3925 consdata->eventdata[pos]->varpos = pos;
3926 }
3927
3928 consdata->indexsorted = consdata->indexsorted && (pos + 2 >= consdata->nvars);
3929 consdata->coefsorted = consdata->coefsorted && (pos + 2 >= consdata->nvars);
3930 }
3931 consdata->nvars--;
3932
3933 /* if at most one variable is left, the activities should be recalculated (to correspond exactly to the bounds
3934 * of the remaining variable, or give exactly 0.0)
3935 */
3936 if( consdata->nvars <= 1 )
3937 consdataInvalidateActivities(consdata);
3938 else
3939 {
3940 if( SCIPconsIsTransformed(cons) )
3941 {
3942 /* if we are in transformed problem, update minimum and maximum activities */
3943 consdataUpdateDelCoef(scip, consdata, var, val, TRUE);
3944
3945 /* if the variable defining the maximal activity delta was removed from the constraint, the maximal activity
3946 * delta needs to be recalculated on the next real propagation
3947 */
3948 if( consdata->maxactdeltavar == var )
3949 {
3950 consdata->maxactdelta = SCIP_INVALID;
3951 consdata->maxactdeltavar = NULL;
3952 }
3953 }
3954 }
3955
3956 /* mark the constraint for propagation */
3957 if( SCIPconsIsTransformed(cons) )
3958 {
3959 SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
3960 }
3961
3962 consdata->boundstightened = 0;
3963 consdata->presolved = FALSE;
3964 consdata->validsignature = FALSE;
3965 consdata->changed = TRUE;
3966 consdata->normalized = FALSE;
3967 consdata->upgradetried = FALSE;
3968 consdata->cliquesadded = FALSE;
3969 consdata->implsadded = FALSE;
3970 consdata->rangedrowpropagated = 0;
3971
3972 /* check if hasnonbinvar flag might be incorrect now */
3973 if( consdata->hasnonbinvar && SCIPvarGetType(var) != SCIP_VARTYPE_BINARY )
3974 {
3975 consdata->hasnonbinvalid = FALSE;
3976 }
3977
3978 /* delete coefficient from the LP row */
3979 if( consdata->row != NULL )
3980 {
3981 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -val) );
3982 }
3983
3984 /* release variable */
3985 SCIP_CALL( SCIPreleaseVar(scip, &var) );
3986
3987 return SCIP_OKAY;
3988 }
3989
3990 /** changes coefficient value at given position of linear constraint data */
3991 static
chgCoefPos(SCIP * scip,SCIP_CONS * cons,int pos,SCIP_Real newval)3992 SCIP_RETCODE chgCoefPos(
3993 SCIP* scip, /**< SCIP data structure */
3994 SCIP_CONS* cons, /**< linear constraint */
3995 int pos, /**< position of coefficient to delete */
3996 SCIP_Real newval /**< new value of coefficient */
3997 )
3998 {
3999 SCIP_CONSDATA* consdata;
4000 SCIP_VAR* var;
4001 SCIP_Real val;
4002 SCIP_Bool locked;
4003 int i;
4004
4005 assert(scip != NULL);
4006 assert(cons != NULL);
4007 assert(!SCIPisZero(scip, newval));
4008
4009 consdata = SCIPconsGetData(cons);
4010 assert(consdata != NULL);
4011 assert(0 <= pos && pos < consdata->nvars);
4012 assert(!SCIPisZero(scip, newval));
4013
4014 var = consdata->vars[pos];
4015 val = consdata->vals[pos];
4016 assert(var != NULL);
4017 assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
4018
4019 locked = FALSE;
4020 for( i = 0; i < NLOCKTYPES && !locked; i++ )
4021 locked = SCIPconsIsLockedType(cons, (SCIP_LOCKTYPE) i);
4022
4023 /* if necessary, update the rounding locks of the variable */
4024 if( locked && newval * val < 0.0 )
4025 {
4026 assert(SCIPconsIsTransformed(cons));
4027
4028 /* remove rounding locks for variable with old coefficient */
4029 SCIP_CALL( unlockRounding(scip, cons, var, val) );
4030
4031 /* install rounding locks for variable with new coefficient */
4032 SCIP_CALL( lockRounding(scip, cons, var, newval) );
4033 }
4034
4035 /* change the value */
4036 consdata->vals[pos] = newval;
4037
4038 if( consdata->coefsorted )
4039 {
4040 if( pos > 0 )
4041 consdata->coefsorted = (consdataCompVarProp((void*)consdata, pos - 1, pos) <= 0);
4042 if( consdata->coefsorted && pos < consdata->nvars - 1 )
4043 consdata->coefsorted = (consdataCompVarProp((void*)consdata, pos, pos + 1) <= 0);
4044 }
4045
4046 /* update minimum and maximum activities */
4047 if( SCIPconsIsTransformed(cons) )
4048 consdataUpdateChgCoef(scip, consdata, var, val, newval, TRUE);
4049
4050 /* mark the constraint for propagation */
4051 if( SCIPconsIsTransformed(cons) )
4052 {
4053 SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
4054 }
4055
4056 consdata->boundstightened = 0;
4057 consdata->presolved = FALSE;
4058 consdata->validsignature = consdata->validsignature && (newval * val > 0.0);
4059 consdata->changed = TRUE;
4060 consdata->normalized = FALSE;
4061 consdata->upgradetried = FALSE;
4062 consdata->cliquesadded = FALSE;
4063 consdata->implsadded = FALSE;
4064 consdata->rangedrowpropagated = 0;
4065
4066 return SCIP_OKAY;
4067 }
4068
4069 /** scales a linear constraint with a constant scalar */
4070 static
scaleCons(SCIP * scip,SCIP_CONS * cons,SCIP_Real scalar)4071 SCIP_RETCODE scaleCons(
4072 SCIP* scip, /**< SCIP data structure */
4073 SCIP_CONS* cons, /**< linear constraint to scale */
4074 SCIP_Real scalar /**< value to scale constraint with */
4075 )
4076 {
4077 SCIP_CONSDATA* consdata;
4078 SCIP_Real newval;
4079 SCIP_Real absscalar;
4080 int i;
4081
4082 assert(scip != NULL);
4083 assert(cons != NULL);
4084
4085 consdata = SCIPconsGetData(cons);
4086 assert(consdata != NULL);
4087 assert(consdata->row == NULL);
4088 assert(!SCIPisEQ(scip, scalar, 1.0));
4089
4090 if( (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisInfinity(scip, -consdata->lhs * scalar))
4091 || (!SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, consdata->rhs * scalar)) )
4092 {
4093 SCIPwarningMessage(scip, "skipped scaling for linear constraint <%s> to avoid numerical troubles (scalar: %.15g)\n",
4094 SCIPconsGetName(cons), scalar);
4095
4096 return SCIP_OKAY;
4097 }
4098
4099 /* scale the coefficients */
4100 for( i = consdata->nvars - 1; i >= 0; --i )
4101 {
4102 newval = scalar * consdata->vals[i];
4103
4104 /* because SCIPisScalingIntegral uses another integrality check as SCIPfeasFloor, we add an additional 0.5 before
4105 * flooring down our new value
4106 */
4107 if( SCIPisScalingIntegral(scip, consdata->vals[i], scalar) )
4108 newval = SCIPfeasFloor(scip, newval + 0.5);
4109
4110 if( SCIPisZero(scip, newval) )
4111 {
4112 SCIPwarningMessage(scip, "coefficient %.15g of variable <%s> in linear constraint <%s> scaled to zero (scalar: %.15g)\n",
4113 consdata->vals[i], SCIPvarGetName(consdata->vars[i]), SCIPconsGetName(cons), scalar);
4114 SCIP_CALL( delCoefPos(scip, cons, i) );
4115 }
4116 else
4117 consdata->vals[i] = newval;
4118 }
4119
4120 /* scale the sides */
4121 if( scalar < 0.0 )
4122 {
4123 SCIP_Real lhs;
4124
4125 lhs = consdata->lhs;
4126 consdata->lhs = -consdata->rhs;
4127 consdata->rhs = -lhs;
4128 }
4129 absscalar = REALABS(scalar);
4130 if( !SCIPisInfinity(scip, -consdata->lhs) )
4131 {
4132 newval = absscalar * consdata->lhs;
4133
4134 /* because SCIPisScalingIntegral uses another integrality check as SCIPfeasFloor, we add an additional 0.5 before
4135 * flooring down our new value
4136 */
4137 if( SCIPisScalingIntegral(scip, consdata->lhs, absscalar) )
4138 consdata->lhs = SCIPfeasFloor(scip, newval + 0.5);
4139 else
4140 consdata->lhs = newval;
4141 }
4142 if( !SCIPisInfinity(scip, consdata->rhs) )
4143 {
4144 newval = absscalar * consdata->rhs;
4145
4146 /* because SCIPisScalingIntegral uses another integrality check as SCIPfeasCeil, we subtract 0.5 before ceiling up
4147 * our new value
4148 */
4149 if( SCIPisScalingIntegral(scip, consdata->rhs, absscalar) )
4150 consdata->rhs = SCIPfeasCeil(scip, newval - 0.5);
4151 else
4152 consdata->rhs = newval;
4153 }
4154
4155 consdataInvalidateActivities(consdata);
4156 consdata->cliquesadded = FALSE;
4157 consdata->implsadded = FALSE;
4158
4159 return SCIP_OKAY;
4160 }
4161
4162 /** perform deletion of variables in all constraints of the constraint handler */
4163 static
performVarDeletions(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_CONS ** conss,int nconss)4164 SCIP_RETCODE performVarDeletions(
4165 SCIP* scip, /**< SCIP data structure */
4166 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
4167 SCIP_CONS** conss, /**< array of constraints */
4168 int nconss /**< number of constraints */
4169 )
4170 {
4171 SCIP_CONSDATA* consdata;
4172 int i;
4173 int v;
4174
4175 assert(scip != NULL);
4176 assert(conshdlr != NULL);
4177 assert(conss != NULL);
4178 assert(nconss >= 0);
4179 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
4180
4181 /* iterate over all constraints */
4182 for( i = 0; i < nconss; i++ )
4183 {
4184 consdata = SCIPconsGetData(conss[i]);
4185
4186 /* constraint is marked, that some of its variables were deleted */
4187 if( consdata->varsdeleted )
4188 {
4189 /* iterate over all variables of the constraint and delete them from the constraint */
4190 for( v = consdata->nvars - 1; v >= 0; --v )
4191 {
4192 if( SCIPvarIsDeleted(consdata->vars[v]) )
4193 {
4194 SCIP_CALL( delCoefPos(scip, conss[i], v) );
4195 }
4196 }
4197 consdata->varsdeleted = FALSE;
4198 }
4199 }
4200
4201 return SCIP_OKAY;
4202 }
4203
4204
4205 /** normalizes a linear constraint with the following rules:
4206 * - if all coefficients have them same absolute value, change them to (-)1.0
4207 * - multiplication with +1 or -1:
4208 * Apply the following rules in the given order, until the sign of the factor is determined. Later rules only apply,
4209 * if the current rule doesn't determine the sign):
4210 * 1. the right hand side must not be negative
4211 * 2. the right hand side must not be infinite
4212 * 3. the absolute value of the right hand side must be greater than that of the left hand side
4213 * 4. the number of positive coefficients must not be smaller than the number of negative coefficients
4214 * 5. multiply with +1
4215 * - rationals to integrals
4216 * Try to identify a rational representation of the fractional coefficients, and multiply all coefficients
4217 * by the smallest common multiple of all denominators to get integral coefficients.
4218 * Forbid large denominators due to numerical stability.
4219 * - division by greatest common divisor
4220 * If all coefficients are integral, divide them by the greatest common divisor.
4221 */
4222 static
normalizeCons(SCIP * scip,SCIP_CONS * cons,SCIP_Bool * infeasible)4223 SCIP_RETCODE normalizeCons(
4224 SCIP* scip, /**< SCIP data structure */
4225 SCIP_CONS* cons, /**< linear constraint to normalize */
4226 SCIP_Bool* infeasible /**< pointer to store whether infeasibility was detected */
4227 )
4228 {
4229 SCIP_CONSDATA* consdata;
4230 SCIP_Real* vals;
4231 SCIP_Longint scm;
4232 SCIP_Longint nominator;
4233 SCIP_Longint denominator;
4234 SCIP_Longint gcd;
4235 SCIP_Longint maxmult;
4236 SCIP_Real epsilon;
4237 SCIP_Real feastol;
4238 SCIP_Real maxabsval;
4239 SCIP_Real minabsval;
4240 SCIP_Bool success;
4241 SCIP_Bool onlyintegral;
4242 int nvars;
4243 int mult;
4244 int nposcoeffs;
4245 int nnegcoeffs;
4246 int i;
4247 int v;
4248
4249 assert(scip != NULL);
4250 assert(cons != NULL);
4251 assert(infeasible != NULL);
4252
4253 *infeasible = FALSE;
4254
4255 /* we must not change a modifiable constraint in any way */
4256 if( SCIPconsIsModifiable(cons) )
4257 return SCIP_OKAY;
4258
4259 /* get constraint data */
4260 consdata = SCIPconsGetData(cons);
4261 assert(consdata != NULL);
4262
4263 /* check, if the constraint is already normalized */
4264 if( consdata->normalized )
4265 return SCIP_OKAY;
4266
4267 /* get coefficient arrays */
4268 vals = consdata->vals;
4269 nvars = consdata->nvars;
4270 assert(nvars == 0 || vals != NULL);
4271
4272 if( nvars == 0 )
4273 {
4274 consdata->normalized = TRUE;
4275 return SCIP_OKAY;
4276 }
4277
4278 assert(vals != NULL);
4279
4280 /* get maximal and minimal absolute coefficient */
4281 maxabsval = consdataGetMaxAbsval(consdata);
4282 minabsval = consdataGetMinAbsval(consdata);
4283
4284 /* return if scaling by maxval will eliminate coefficients */
4285 if( SCIPisZero(scip, minabsval/maxabsval) )
4286 return SCIP_OKAY;
4287
4288 /* check if all coefficients are in absolute value equal, and not 1.0 */
4289 if( !SCIPisEQ(scip, maxabsval, 1.0) )
4290 {
4291 SCIP_Bool abscoefsequ;
4292
4293 abscoefsequ = TRUE;
4294
4295 for( v = nvars - 1; v >= 0; --v )
4296 {
4297 if( !SCIPisEQ(scip, REALABS(vals[v]), maxabsval) )
4298 {
4299 abscoefsequ = FALSE;
4300 break;
4301 }
4302 }
4303
4304 /* all coefficients are in absolute value equal, so change them to (-)1.0 */
4305 if( abscoefsequ )
4306 {
4307 SCIPdebugMsg(scip, "divide linear constraint with %g, because all coefficients are in absolute value the same\n", maxabsval);
4308 SCIPdebugPrintCons(scip, cons, NULL);
4309 SCIP_CALL( scaleCons(scip, cons, 1/maxabsval) );
4310
4311 if( consdata->validmaxabsval )
4312 {
4313 if( !SCIPisEQ(scip, consdata->maxabsval, 1.0) )
4314 consdata->maxabsval = 1.0;
4315 if( !SCIPisEQ(scip, consdata->minabsval, 1.0) )
4316 consdata->minabsval = 1.0;
4317
4318 maxabsval = 1.0;
4319 }
4320 else
4321 {
4322 /* get maximal absolute coefficient */
4323 maxabsval = consdataGetMaxAbsval(consdata);
4324 }
4325
4326 /* get new consdata information, because scaleCons() might have deleted variables */
4327 vals = consdata->vals;
4328 nvars = consdata->nvars;
4329
4330 assert(nvars == 0 || vals != NULL);
4331 }
4332 }
4333
4334 /* nvars might have changed */
4335 if( nvars == 0 )
4336 {
4337 consdata->normalized = TRUE;
4338 return SCIP_OKAY;
4339 }
4340
4341 assert(vals != NULL);
4342
4343 /* calculate the maximal multiplier for common divisor calculation:
4344 * |p/q - val| < epsilon and q < feastol/epsilon => |p - q*val| < feastol
4345 * which means, a value of feastol/epsilon should be used as maximal multiplier;
4346 * additionally, we don't want to scale the constraint if this would lead to too
4347 * large coefficients
4348 */
4349 epsilon = SCIPepsilon(scip) * 0.9; /* slightly decrease epsilon to be safe in rational conversion below */
4350 feastol = SCIPfeastol(scip);
4351 maxmult = (SCIP_Longint)(feastol/epsilon + feastol);
4352
4353 if( !consdata->hasnonbinvalid )
4354 consdataCheckNonbinvar(consdata);
4355
4356 /* if all variables are of integral type we will allow a greater multiplier */
4357 if( !consdata->hascontvar )
4358 maxmult = MIN(maxmult, (SCIP_Longint) (MAXSCALEDCOEFINTEGER / MAX(maxabsval, 1.0))); /*lint !e835*/
4359 else
4360 maxmult = MIN(maxmult, (SCIP_Longint) (MAXSCALEDCOEF / MAX(maxabsval, 1.0))); /*lint !e835*/
4361
4362 /*
4363 * multiplication with +1 or -1
4364 */
4365 mult = 0;
4366
4367 /* 1. the right hand side must not be negative */
4368 if( SCIPisPositive(scip, consdata->lhs) )
4369 mult = +1;
4370 else if( SCIPisNegative(scip, consdata->rhs) )
4371 mult = -1;
4372
4373 if( mult == 0 )
4374 {
4375 /* 2. the right hand side must not be infinite */
4376 if( SCIPisInfinity(scip, -consdata->lhs) )
4377 mult = +1;
4378 else if( SCIPisInfinity(scip, consdata->rhs) )
4379 mult = -1;
4380 }
4381
4382 if( mult == 0 )
4383 {
4384 /* 3. the absolute value of the right hand side must be greater than that of the left hand side */
4385 if( SCIPisGT(scip, REALABS(consdata->rhs), REALABS(consdata->lhs)) )
4386 mult = +1;
4387 else if( SCIPisLT(scip, REALABS(consdata->rhs), REALABS(consdata->lhs)) )
4388 mult = -1;
4389 }
4390
4391 if( mult == 0 )
4392 {
4393 /* 4. the number of positive coefficients must not be smaller than the number of negative coefficients */
4394 nposcoeffs = 0;
4395 nnegcoeffs = 0;
4396 for( i = 0; i < nvars; ++i )
4397 {
4398 if( vals[i] > 0.0 )
4399 nposcoeffs++;
4400 else
4401 nnegcoeffs++;
4402 }
4403 if( nposcoeffs > nnegcoeffs )
4404 mult = +1;
4405 else if( nposcoeffs < nnegcoeffs )
4406 mult = -1;
4407 }
4408
4409 if( mult == 0 )
4410 {
4411 /* 5. multiply with +1 */
4412 mult = +1;
4413 }
4414
4415 assert(mult == +1 || mult == -1);
4416 if( mult == -1 )
4417 {
4418 /* scale the constraint with -1 */
4419 SCIPdebugMsg(scip, "multiply linear constraint with -1.0\n");
4420 SCIPdebugPrintCons(scip, cons, NULL);
4421 SCIP_CALL( scaleCons(scip, cons, -1.0) );
4422
4423 /* scalecons() can delete variables, but scaling with -1 should not do that */
4424 assert(nvars == consdata->nvars);
4425 }
4426
4427 /*
4428 * rationals to integrals
4429 *
4430 * @todo try scaling only on behalf of non-continuous variables
4431 */
4432 success = TRUE;
4433 scm = 1;
4434 for( i = 0; i < nvars && success && scm <= maxmult; ++i )
4435 {
4436 if( !SCIPisIntegral(scip, vals[i]) )
4437 {
4438 /* epsilon has been slightly decreased above - to be on the safe side */
4439 success = SCIPrealToRational(vals[i], -epsilon, epsilon , maxmult, &nominator, &denominator);
4440 if( success )
4441 scm = SCIPcalcSmaComMul(scm, denominator);
4442 }
4443 }
4444 assert(scm >= 1);
4445
4446 /* it might be that we have really big coefficients, but all are integral, in that case we want to divide them by
4447 * their greatest common divisor
4448 */
4449 onlyintegral = TRUE;
4450 if( scm == 1 )
4451 {
4452 for( i = nvars - 1; i >= 0; --i )
4453 {
4454 if( !SCIPisIntegral(scip, vals[i]) )
4455 {
4456 onlyintegral = FALSE;
4457 break;
4458 }
4459 }
4460 }
4461
4462 success = success && (scm <= maxmult || (scm == 1 && onlyintegral));
4463 if( success && scm != 1 )
4464 {
4465 /* scale the constraint with the smallest common multiple of all denominators */
4466 SCIPdebugMsg(scip, "scale linear constraint with %" SCIP_LONGINT_FORMAT " to make coefficients integral\n", scm);
4467 SCIPdebugPrintCons(scip, cons, NULL);
4468 SCIP_CALL( scaleCons(scip, cons, (SCIP_Real)scm) );
4469
4470 if( consdata->validmaxabsval )
4471 {
4472 consdata->maxabsval *= REALABS((SCIP_Real)scm);
4473 if( !SCIPisIntegral(scip, consdata->maxabsval) )
4474 {
4475 consdata->validmaxabsval = FALSE;
4476 consdata->maxabsval = SCIP_INVALID;
4477 consdataCalcMaxAbsval(consdata);
4478 }
4479 }
4480
4481 if( consdata->validminabsval )
4482 {
4483 consdata->minabsval *= REALABS((SCIP_Real)scm);
4484 if( !SCIPisIntegral(scip, consdata->minabsval) )
4485 {
4486 consdata->validminabsval = FALSE;
4487 consdata->minabsval = SCIP_INVALID;
4488 consdataCalcMinAbsval(consdata);
4489 }
4490 }
4491
4492 /* get new consdata information, because scalecons() might have deleted variables */
4493 vals = consdata->vals;
4494 nvars = consdata->nvars;
4495 assert(nvars == 0 || vals != NULL);
4496 }
4497
4498 /*
4499 * division by greatest common divisor
4500 */
4501 if( success && nvars >= 1 )
4502 {
4503 /* all coefficients are integral: divide them by their greatest common divisor */
4504 assert(SCIPisIntegral(scip, vals[0]));
4505
4506 gcd = (SCIP_Longint)(REALABS(vals[0]) + feastol);
4507 for( i = 1; i < nvars && gcd > 1; ++i )
4508 {
4509 assert(SCIPisIntegral(scip, vals[i]));
4510 gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)(REALABS(vals[i]) + feastol));
4511 }
4512
4513 if( gcd > 1 )
4514 {
4515 /* since the lhs/rhs is not respected for gcd calculation it can happen that we detect infeasibility */
4516 if( !consdata->hascontvar && onlyintegral )
4517 {
4518 if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) && !SCIPisFeasIntegral(scip, consdata->rhs / gcd) )
4519 {
4520 *infeasible = TRUE;
4521
4522 SCIPdebugMsg(scip, "detected infeasibility of constraint after scaling with gcd=%" SCIP_LONGINT_FORMAT ":\n", gcd);
4523 SCIPdebugPrintCons(scip, cons, NULL);
4524
4525 return SCIP_OKAY;
4526 }
4527 }
4528
4529 /* divide the constraint by the greatest common divisor of the coefficients */
4530 SCIPdebugMsg(scip, "divide linear constraint by greatest common divisor %" SCIP_LONGINT_FORMAT "\n", gcd);
4531 SCIPdebugPrintCons(scip, cons, NULL);
4532 SCIP_CALL( scaleCons(scip, cons, 1.0/(SCIP_Real)gcd) );
4533
4534 if( consdata->validmaxabsval )
4535 {
4536 consdata->maxabsval /= REALABS((SCIP_Real)gcd);
4537 }
4538 if( consdata->validminabsval )
4539 {
4540 consdata->minabsval /= REALABS((SCIP_Real)gcd);
4541 }
4542 }
4543 }
4544
4545 /* mark constraint to be normalized */
4546 consdata->normalized = TRUE;
4547
4548 SCIPdebugMsg(scip, "normalized constraint:\n");
4549 SCIPdebugPrintCons(scip, cons, NULL);
4550
4551 return SCIP_OKAY;
4552 }
4553
4554 /** replaces multiple occurrences of a variable by a single coefficient */
4555 static
mergeMultiples(SCIP * scip,SCIP_CONS * cons)4556 SCIP_RETCODE mergeMultiples(
4557 SCIP* scip, /**< SCIP data structure */
4558 SCIP_CONS* cons /**< linear constraint */
4559 )
4560 {
4561 SCIP_CONSDATA* consdata;
4562 SCIP_VAR* var;
4563 SCIP_Real valsum;
4564 int v;
4565
4566 assert(scip != NULL);
4567 assert(cons != NULL);
4568
4569 consdata = SCIPconsGetData(cons);
4570 assert(consdata != NULL);
4571
4572 if( consdata->merged )
4573 return SCIP_OKAY;
4574
4575 /* sort the constraint */
4576 SCIP_CALL( consdataSort(scip, consdata) );
4577
4578 /* go backwards through the constraint looking for multiple occurrences of the same variable;
4579 * backward direction is necessary, since delCoefPos() modifies the given position and
4580 * the subsequent ones
4581 */
4582 v = consdata->nvars-1;
4583 while( v >= 1 )
4584 {
4585 var = consdata->vars[v];
4586 if( consdata->vars[v-1] == var )
4587 {
4588 valsum = consdata->vals[v];
4589 do
4590 {
4591 SCIP_CALL( delCoefPos(scip, cons, v) );
4592 --v;
4593 valsum += consdata->vals[v];
4594 }
4595 while( v >= 1 && consdata->vars[v-1] == var );
4596
4597 /* modify the last existing occurrence of the variable */
4598 assert(consdata->vars[v] == var);
4599 if( SCIPisZero(scip, valsum) )
4600 {
4601 SCIP_CALL( delCoefPos(scip, cons, v) );
4602
4603 /* if the variable defining the maximal activity delta was removed from the constraint, the maximal activity
4604 * delta needs to be recalculated on the next real propagation
4605 */
4606 if( consdata->maxactdeltavar == var )
4607 {
4608 consdata->maxactdelta = SCIP_INVALID;
4609 consdata->maxactdeltavar = NULL;
4610 }
4611 }
4612 else
4613 {
4614 SCIP_CALL( chgCoefPos(scip, cons, v, valsum) );
4615 }
4616 }
4617 --v;
4618 }
4619
4620 consdata->merged = TRUE;
4621
4622 return SCIP_OKAY;
4623 }
4624
4625 /** replaces all fixed and aggregated variables by their non-fixed counterparts */
4626 static
applyFixings(SCIP * scip,SCIP_CONS * cons,SCIP_Bool * infeasible)4627 SCIP_RETCODE applyFixings(
4628 SCIP* scip, /**< SCIP data structure */
4629 SCIP_CONS* cons, /**< linear constraint */
4630 SCIP_Bool* infeasible /**< pointer to store if infeasibility is detected; or NULL if this
4631 * information is not needed; in this case, we apply all fixings
4632 * instead of stopping after the first infeasible one */
4633 )
4634 {
4635 SCIP_CONSDATA* consdata;
4636 SCIP_VAR* var;
4637 SCIP_VAR** aggrvars;
4638 SCIP_Real val;
4639 SCIP_Real* aggrscalars;
4640 SCIP_Real fixedval;
4641 SCIP_Real aggrconst;
4642 int v;
4643 int naggrvars;
4644 int i;
4645
4646 assert(scip != NULL);
4647 assert(cons != NULL);
4648
4649 if( infeasible != NULL )
4650 *infeasible = FALSE;
4651
4652 consdata = SCIPconsGetData(cons);
4653 assert(consdata != NULL);
4654
4655 if( consdata->eventdata == NULL )
4656 {
4657 SCIP_CONSHDLR* conshdlr;
4658 SCIP_CONSHDLRDATA* conshdlrdata;
4659
4660 conshdlr = SCIPconsGetHdlr(cons);
4661 assert(conshdlr != NULL);
4662
4663 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4664 assert(conshdlrdata != NULL);
4665
4666 /* catch bound change events of variables */
4667 SCIP_CALL( consCatchAllEvents(scip, cons, conshdlrdata->eventhdlr) );
4668 assert(consdata->eventdata != NULL);
4669 }
4670
4671 if( !consdata->removedfixings )
4672 {
4673 SCIP_Real lhssubtrahend;
4674 SCIP_Real rhssubtrahend;
4675
4676 /* if an unmodifiable row has been added to the LP, then we cannot apply fixing anymore (cannot change a row)
4677 * this should not happen, as applyFixings is called in addRelaxation() before creating and adding a row
4678 */
4679 assert(consdata->row == NULL || !SCIProwIsInLP(consdata->row) || SCIProwIsModifiable(consdata->row));
4680
4681 lhssubtrahend = 0.0;
4682 rhssubtrahend = 0.0;
4683
4684 SCIPdebugMsg(scip, "applying fixings:\n");
4685 SCIPdebugPrintCons(scip, cons, NULL);
4686
4687 v = 0;
4688 while( v < consdata->nvars )
4689 {
4690 var = consdata->vars[v];
4691 val = consdata->vals[v];
4692 assert(SCIPvarIsTransformed(var));
4693
4694 switch( SCIPvarGetStatus(var) )
4695 {
4696 case SCIP_VARSTATUS_ORIGINAL:
4697 SCIPerrorMessage("original variable in transformed linear constraint\n");
4698 return SCIP_INVALIDDATA;
4699
4700 case SCIP_VARSTATUS_LOOSE:
4701 case SCIP_VARSTATUS_COLUMN:
4702 ++v;
4703 break;
4704
4705 case SCIP_VARSTATUS_FIXED:
4706 assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)));
4707 fixedval = SCIPvarGetLbGlobal(var);
4708 if( !SCIPisInfinity(scip, -consdata->lhs) )
4709 {
4710 if( SCIPisInfinity(scip, ABS(fixedval)) )
4711 {
4712 if( val * fixedval > 0.0 )
4713 {
4714 SCIP_CALL( chgLhs(scip, cons, -SCIPinfinity(scip)) );
4715 }
4716 else
4717 {
4718 if( infeasible != NULL )
4719 {
4720 /* if lhs gets infinity it means that the problem is infeasible */
4721 *infeasible = TRUE;
4722 return SCIP_OKAY;
4723 }
4724 else
4725 {
4726 SCIP_CALL( chgLhs(scip, cons, SCIPinfinity(scip)) );
4727 }
4728 }
4729 }
4730 else
4731 lhssubtrahend += val * fixedval;
4732 }
4733 if( !SCIPisInfinity(scip, consdata->rhs) )
4734 {
4735 if( SCIPisInfinity(scip, ABS(fixedval)) )
4736 {
4737 if( val * fixedval > 0.0 )
4738 {
4739 if( infeasible != NULL )
4740 {
4741 /* if rhs gets -infinity it means that the problem is infeasible */
4742 *infeasible = TRUE;
4743 return SCIP_OKAY;
4744 }
4745 else
4746 {
4747 SCIP_CALL( chgRhs(scip, cons, -SCIPinfinity(scip)) );
4748 }
4749 }
4750 else
4751 {
4752 SCIP_CALL( chgRhs(scip, cons, SCIPinfinity(scip)) );
4753 }
4754 }
4755 else
4756 rhssubtrahend += val * fixedval;
4757 }
4758 SCIP_CALL( delCoefPos(scip, cons, v) );
4759 break;
4760
4761 case SCIP_VARSTATUS_AGGREGATED:
4762 {
4763 SCIP_VAR* activevar = SCIPvarGetAggrVar(var);
4764 SCIP_Real activescalar = val * SCIPvarGetAggrScalar(var);
4765 SCIP_Real activeconstant = val * SCIPvarGetAggrConstant(var);
4766
4767 assert(activevar != NULL);
4768 SCIP_CALL( SCIPgetProbvarSum(scip, &activevar, &activescalar, &activeconstant) );
4769 assert(activevar != NULL);
4770
4771 if( !SCIPisZero(scip, activescalar) )
4772 {
4773 SCIP_CALL( addCoef(scip, cons, activevar, activescalar) );
4774 }
4775
4776 if( !SCIPisZero(scip, activeconstant) )
4777 {
4778 if( !SCIPisInfinity(scip, -consdata->lhs) )
4779 lhssubtrahend += activeconstant;
4780 if( !SCIPisInfinity(scip, consdata->rhs) )
4781 rhssubtrahend += activeconstant;
4782 }
4783
4784 SCIP_CALL( delCoefPos(scip, cons, v) );
4785 break;
4786 }
4787 case SCIP_VARSTATUS_MULTAGGR:
4788 SCIP_CALL( SCIPflattenVarAggregationGraph(scip, var) );
4789 naggrvars = SCIPvarGetMultaggrNVars(var);
4790 aggrvars = SCIPvarGetMultaggrVars(var);
4791 aggrscalars = SCIPvarGetMultaggrScalars(var);
4792 for( i = 0; i < naggrvars; ++i )
4793 {
4794 SCIP_CALL( addCoef(scip, cons, aggrvars[i], val * aggrscalars[i]) );
4795 }
4796 aggrconst = SCIPvarGetMultaggrConstant(var);
4797
4798 if( !SCIPisInfinity(scip, -consdata->lhs) )
4799 lhssubtrahend += val * aggrconst;
4800 if( !SCIPisInfinity(scip, consdata->rhs) )
4801 rhssubtrahend += val * aggrconst;
4802
4803 SCIP_CALL( delCoefPos(scip, cons, v) );
4804 break;
4805
4806 case SCIP_VARSTATUS_NEGATED:
4807 SCIP_CALL( addCoef(scip, cons, SCIPvarGetNegationVar(var), -val) );
4808 aggrconst = SCIPvarGetNegationConstant(var);
4809
4810 if( !SCIPisInfinity(scip, -consdata->lhs) )
4811 lhssubtrahend += val * aggrconst;
4812 if( !SCIPisInfinity(scip, consdata->rhs) )
4813 rhssubtrahend += val * aggrconst;
4814
4815 SCIP_CALL( delCoefPos(scip, cons, v) );
4816 break;
4817
4818 default:
4819 SCIPerrorMessage("unknown variable status\n");
4820 SCIPABORT();
4821 return SCIP_INVALIDDATA; /*lint !e527*/
4822 }
4823 }
4824
4825 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->lhs) )
4826 {
4827 /* for large numbers that are relatively equal, substraction can lead to cancellation,
4828 * causing wrong fixings of other variables --> better use a real zero here;
4829 * for small numbers, polishing the difference might lead to wrong results -->
4830 * better use the exact difference in this case
4831 */
4832 if( SCIPisEQ(scip, lhssubtrahend, consdata->lhs) && SCIPisFeasGE(scip, REALABS(lhssubtrahend), 1.0) )
4833 {
4834 SCIP_CALL( chgLhs(scip, cons, 0.0) );
4835 }
4836 else
4837 {
4838 SCIP_CALL( chgLhs(scip, cons, consdata->lhs - lhssubtrahend) );
4839 }
4840 }
4841 if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, -consdata->rhs))
4842 {
4843 /* for large numbers that are relatively equal, substraction can lead to cancellation,
4844 * causing wrong fixings of other variables --> better use a real zero here;
4845 * for small numbers, polishing the difference might lead to wrong results -->
4846 * better use the exact difference in this case
4847 */
4848 if( SCIPisEQ(scip, rhssubtrahend, consdata->rhs ) && SCIPisFeasGE(scip, REALABS(rhssubtrahend), 1.0) )
4849 {
4850 SCIP_CALL( chgRhs(scip, cons, 0.0) );
4851 }
4852 else
4853 {
4854 SCIP_CALL( chgRhs(scip, cons, consdata->rhs - rhssubtrahend) );
4855 }
4856 }
4857 consdata->removedfixings = TRUE;
4858
4859 SCIPdebugMsg(scip, "after fixings:\n");
4860 SCIPdebugPrintCons(scip, cons, NULL);
4861
4862 /* if aggregated variables have been replaced, multiple entries of the same variable are possible and we have
4863 * to clean up the constraint
4864 */
4865 SCIP_CALL( mergeMultiples(scip, cons) );
4866
4867 SCIPdebugMsg(scip, "after merging:\n");
4868 SCIPdebugPrintCons(scip, cons, NULL);
4869 }
4870 assert(consdata->removedfixings);
4871
4872 #ifndef NDEBUG
4873 /* check, if all fixings are applied */
4874 for( v = 0; v < consdata->nvars; ++v )
4875 assert(SCIPvarIsActive(consdata->vars[v]));
4876 #endif
4877
4878 return SCIP_OKAY;
4879 }
4880
4881 /** for each variable in the linear constraint, except the inferred variable, adds one bound to the conflict analysis'
4882 * candidate store (bound depends on sign of coefficient and whether the left or right hand side was the reason for the
4883 * inference variable's bound change); the conflict analysis can be initialized with the linear constraint being the
4884 * conflict detecting constraint by using NULL as inferred variable
4885 */
4886 static
addConflictBounds(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * infervar,SCIP_BDCHGIDX * bdchgidx,int inferpos,SCIP_Bool reasonisrhs)4887 SCIP_RETCODE addConflictBounds(
4888 SCIP* scip, /**< SCIP data structure */
4889 SCIP_CONS* cons, /**< constraint that inferred the bound change */
4890 SCIP_VAR* infervar, /**< variable that was deduced, or NULL */
4891 SCIP_BDCHGIDX* bdchgidx, /**< bound change index (time stamp of bound change), or NULL for current time */
4892 int inferpos, /**< position of the inferred variable in the vars array */
4893 SCIP_Bool reasonisrhs /**< is the right hand side responsible for the bound change? */
4894 )
4895 {
4896 SCIP_CONSDATA* consdata;
4897 SCIP_VAR** vars;
4898 SCIP_Real* vals;
4899 int nvars;
4900 int i;
4901
4902 assert(scip != NULL);
4903 assert(cons != NULL);
4904
4905 consdata = SCIPconsGetData(cons);
4906
4907 assert(consdata != NULL);
4908
4909 vars = consdata->vars;
4910 vals = consdata->vals;
4911 nvars = consdata->nvars;
4912
4913 assert(vars != NULL || nvars == 0);
4914 assert(vals != NULL || nvars == 0);
4915
4916 assert(-1 <= inferpos && inferpos < nvars);
4917 assert((infervar == NULL) == (inferpos == -1));
4918 assert(inferpos == -1 || vars[inferpos] == infervar); /*lint !e613*/
4919
4920 /* for each variable, add the bound to the conflict queue, that is responsible for the minimal or maximal
4921 * residual value, depending on whether the left or right hand side is responsible for the bound change:
4922 * - if the right hand side is the reason, the minimal residual activity is responsible
4923 * - if the left hand side is the reason, the maximal residual activity is responsible
4924 */
4925
4926 /* if the variable is integral we only need to add reason bounds until the propagation could be applied */
4927 if( infervar == NULL || SCIPvarIsIntegral(infervar) )
4928 {
4929 SCIP_Real minresactivity;
4930 SCIP_Real maxresactivity;
4931 SCIP_Bool minisrelax;
4932 SCIP_Bool maxisrelax;
4933 SCIP_Bool isminsettoinfinity;
4934 SCIP_Bool ismaxsettoinfinity;
4935
4936 minresactivity = -SCIPinfinity(scip);
4937 maxresactivity = SCIPinfinity(scip);
4938
4939 /* calculate the minimal and maximal global activity of all other variables involved in the constraint */
4940 if( infervar != NULL )
4941 {
4942 assert(vals != NULL); /* for flexelint */
4943 if( reasonisrhs )
4944 consdataGetGlbActivityResiduals(scip, consdata, infervar, vals[inferpos], FALSE, &minresactivity, NULL,
4945 &minisrelax, NULL, &isminsettoinfinity, NULL);
4946 else
4947 consdataGetGlbActivityResiduals(scip, consdata, infervar, vals[inferpos], FALSE, NULL, &maxresactivity,
4948 NULL, &maxisrelax, NULL, &ismaxsettoinfinity);
4949 }
4950 else
4951 {
4952 if( reasonisrhs )
4953 consdataGetGlbActivityBounds(scip, consdata, FALSE, &minresactivity, NULL,
4954 &minisrelax, NULL, &isminsettoinfinity, NULL);
4955 else
4956 consdataGetGlbActivityBounds(scip, consdata, FALSE, NULL, &maxresactivity,
4957 NULL, &maxisrelax, NULL, &ismaxsettoinfinity);
4958 }
4959
4960 /* we can only do something clever, if the residual activity is finite and not relaxed */
4961 if( (reasonisrhs && !isminsettoinfinity && !minisrelax) || (!reasonisrhs && !ismaxsettoinfinity && !maxisrelax) ) /*lint !e644*/
4962 {
4963 SCIP_Real rescap;
4964 SCIP_Bool resactisinf;
4965
4966 resactisinf = FALSE;
4967
4968 /* calculate the residual capacity that would be left, if the variable would be set to one more / one less
4969 * than its inferred bound
4970 */
4971 if( infervar != NULL )
4972 {
4973 assert(vals != NULL); /* for flexelint */
4974
4975 if( reasonisrhs )
4976 {
4977 if( SCIPisUpdateUnreliable(scip, minresactivity, consdata->lastglbminactivity) )
4978 {
4979 consdataGetReliableResidualActivity(scip, consdata, infervar, &minresactivity, TRUE, TRUE);
4980 if( SCIPisInfinity(scip, -minresactivity) )
4981 resactisinf = TRUE;
4982 }
4983 rescap = consdata->rhs - minresactivity;
4984 }
4985 else
4986 {
4987 if( SCIPisUpdateUnreliable(scip, maxresactivity, consdata->lastglbmaxactivity) )
4988 {
4989 consdataGetReliableResidualActivity(scip, consdata, infervar, &maxresactivity, FALSE, TRUE);
4990 if( SCIPisInfinity(scip, maxresactivity) )
4991 resactisinf = TRUE;
4992 }
4993 rescap = consdata->lhs - maxresactivity;
4994 }
4995
4996 if( reasonisrhs == (vals[inferpos] > 0.0) )
4997 rescap -= vals[inferpos] * (SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE) + 1.0);
4998 else
4999 rescap -= vals[inferpos] * (SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE) - 1.0);
5000 }
5001 else
5002 rescap = (reasonisrhs ? consdata->rhs - minresactivity : consdata->lhs - maxresactivity);
5003
5004 if( !resactisinf )
5005 {
5006 /* now add bounds as reasons until the residual capacity is exceeded */
5007 for( i = 0; i < nvars; ++i )
5008 {
5009 assert( vars != NULL && vals != NULL ); /* for lint */
5010
5011 /* zero coefficients and the infered variable can be ignored */
5012 if( vars[i] == infervar || SCIPisZero(scip, vals[i]) )
5013 continue;
5014
5015 /* check if the residual capacity is exceeded */
5016 if( (reasonisrhs && SCIPisFeasNegative(scip, rescap))
5017 || (!reasonisrhs && SCIPisFeasPositive(scip, rescap)) )
5018 break;
5019
5020 /* update the residual capacity due to the local bound of this variable */
5021 if( reasonisrhs == (vals[i] > 0.0) )
5022 {
5023 /* rhs is reason and coeff is positive, or lhs is reason and coeff is negative -> lower bound */
5024 SCIP_CALL( SCIPaddConflictLb(scip, vars[i], bdchgidx) );
5025 rescap -= vals[i] * (SCIPgetVarLbAtIndex(scip, vars[i], bdchgidx, FALSE) - SCIPvarGetLbGlobal(vars[i]));
5026 }
5027 else
5028 {
5029 /* lhs is reason and coeff is positive, or rhs is reason and coeff is negative -> upper bound */
5030 SCIP_CALL( SCIPaddConflictUb(scip, vars[i], bdchgidx) );
5031 rescap -= vals[i] * (SCIPgetVarUbAtIndex(scip, vars[i], bdchgidx, FALSE) - SCIPvarGetUbGlobal(vars[i]));
5032 }
5033 }
5034 return SCIP_OKAY;
5035 }
5036 }
5037 }
5038
5039 /* for a bound change on a continuous variable, all locally changed bounds are responsible */
5040 for( i = 0; i < nvars; ++i )
5041 {
5042 assert(vars != NULL); /* for flexelint */
5043 assert(vals != NULL); /* for flexelint */
5044
5045 /* zero coefficients and the infered variable can be ignored */
5046 if( vars[i] == infervar || SCIPisZero(scip, vals[i]) )
5047 continue;
5048
5049 if( reasonisrhs == (vals[i] > 0.0) )
5050 {
5051 /* rhs is reason and coeff is positive, or lhs is reason and coeff is negative -> lower bound is responsible */
5052 SCIP_CALL( SCIPaddConflictLb(scip, vars[i], bdchgidx) );
5053 }
5054 else
5055 {
5056 /* lhs is reason and coeff is positive, or rhs is reason and coeff is negative -> upper bound is responsible */
5057 SCIP_CALL( SCIPaddConflictUb(scip, vars[i], bdchgidx) );
5058 }
5059 }
5060
5061 return SCIP_OKAY;
5062 }
5063
5064 /** for each variable in the linear ranged row constraint, except the inferred variable, adds the bounds of all fixed
5065 * variables to the conflict analysis' candidate store; the conflict analysis can be initialized
5066 * with the linear constraint being the conflict detecting constraint by using NULL as inferred variable
5067 */
5068 static
addConflictFixedVars(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * infervar,SCIP_BDCHGIDX * bdchgidx,int inferpos)5069 SCIP_RETCODE addConflictFixedVars(
5070 SCIP* scip, /**< SCIP data structure */
5071 SCIP_CONS* cons, /**< constraint that inferred the bound change */
5072 SCIP_VAR* infervar, /**< variable that was deduced, or NULL */
5073 SCIP_BDCHGIDX* bdchgidx, /**< bound change index (time stamp of bound change), or NULL for current time */
5074 int inferpos /**< position of the inferred variable in the vars array, or -1 */
5075 )
5076 {
5077 SCIP_CONSDATA* consdata;
5078 SCIP_VAR** vars;
5079 int nvars;
5080 int v;
5081
5082 assert(scip != NULL);
5083 assert(cons != NULL);
5084
5085 consdata = SCIPconsGetData(cons);
5086 assert(consdata != NULL);
5087 vars = consdata->vars;
5088 nvars = consdata->nvars;
5089 assert(vars != NULL || nvars == 0);
5090 assert(-1 <= inferpos && inferpos < nvars);
5091 assert((infervar == NULL) == (inferpos == -1));
5092 assert(inferpos == -1 || vars != NULL);
5093 assert(inferpos == -1 || vars[inferpos] == infervar); /*lint !e613*/
5094
5095 /* collect all fixed variables */
5096 for( v = nvars - 1; v >= 0; --v )
5097 {
5098 assert(vars != NULL); /* for flexelint */
5099
5100 /* need to add old bounds before propagation of inferrence variable */
5101 if( vars[v] == infervar )
5102 {
5103 assert(vars[v] != NULL);
5104
5105 if( !SCIPisEQ(scip, SCIPgetVarLbAtIndex(scip, vars[v], bdchgidx, FALSE), SCIPvarGetLbGlobal(vars[v])) )
5106 {
5107 /* @todo get boundchange index before this last boundchange and correct the index */
5108 SCIP_CALL( SCIPaddConflictLb(scip, vars[v], bdchgidx) );
5109 }
5110
5111 if( !SCIPisEQ(scip, SCIPgetVarUbAtIndex(scip, vars[v], bdchgidx, FALSE), SCIPvarGetUbGlobal(vars[v])) )
5112 {
5113 /* @todo get boundchange index before this last boundchange and correct the index */
5114 SCIP_CALL( SCIPaddConflictUb(scip, vars[v], bdchgidx) );
5115 }
5116
5117 continue;
5118 }
5119
5120 /* check for fixed variables */
5121 if( SCIPisEQ(scip, SCIPgetVarLbAtIndex(scip, vars[v], bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, vars[v], bdchgidx, FALSE)) )
5122 {
5123 /* add all bounds of fixed variables which lead to the boundchange of the given inference variable */
5124 SCIP_CALL( SCIPaddConflictLb(scip, vars[v], bdchgidx) );
5125 SCIP_CALL( SCIPaddConflictUb(scip, vars[v], bdchgidx) );
5126 }
5127 }
5128
5129 return SCIP_OKAY;
5130 }
5131
5132 /** add reasoning variables to conflict candidate queue which led to the conflict */
5133 static
addConflictReasonVars(SCIP * scip,SCIP_VAR ** vars,int nvars,SCIP_VAR * var,SCIP_Real bound)5134 SCIP_RETCODE addConflictReasonVars(
5135 SCIP* scip, /**< SCIP data structure */
5136 SCIP_VAR** vars, /**< variables reasoning the infeasibility */
5137 int nvars, /**< number of variables reasoning the infeasibility */
5138 SCIP_VAR* var, /**< variable which was tried to fix/tighten, or NULL */
5139 SCIP_Real bound /**< bound of variable which was tried to apply, or SCIP_INVALID */
5140 )
5141 {
5142 int v;
5143
5144 assert(scip != NULL);
5145
5146 /* collect all variables for which the local bounds differ from their global bounds */
5147 for( v = nvars - 1; v >= 0; --v )
5148 {
5149 assert(vars != NULL);
5150
5151 /* check for local bound changes variables */
5152 if( !SCIPisEQ(scip, SCIPvarGetLbLocal(vars[v]), SCIPvarGetLbGlobal(vars[v])) )
5153 {
5154 /* add conflict bound */
5155 SCIP_CALL( SCIPaddConflictLb(scip, vars[v], 0) );
5156 }
5157
5158 if( !SCIPisEQ(scip, SCIPvarGetUbLocal(vars[v]), SCIPvarGetUbGlobal(vars[v])) )
5159 {
5160 SCIP_CALL( SCIPaddConflictUb(scip, vars[v], 0) );
5161 }
5162 }
5163
5164 if( var != NULL )
5165 {
5166 if( bound < SCIPvarGetLbLocal(var) )
5167 {
5168 SCIP_CALL( SCIPaddConflictLb(scip, var, 0) );
5169 }
5170
5171 if( bound > SCIPvarGetUbLocal(var) )
5172 {
5173 SCIP_CALL( SCIPaddConflictUb(scip, var, 0) );
5174 }
5175 }
5176
5177 return SCIP_OKAY;
5178 }
5179
5180 /** resolves a propagation on the given variable by supplying the variables needed for applying the corresponding
5181 * propagation rule (see propagateCons()):
5182 * (1) activity residuals of all other variables tighten bounds of single variable
5183 */
5184 static
resolvePropagation(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * infervar,INFERINFO inferinfo,SCIP_BOUNDTYPE boundtype,SCIP_BDCHGIDX * bdchgidx,SCIP_RESULT * result)5185 SCIP_RETCODE resolvePropagation(
5186 SCIP* scip, /**< SCIP data structure */
5187 SCIP_CONS* cons, /**< constraint that inferred the bound change */
5188 SCIP_VAR* infervar, /**< variable that was deduced */
5189 INFERINFO inferinfo, /**< inference information */
5190 SCIP_BOUNDTYPE boundtype, /**< the type of the changed bound (lower or upper bound) */
5191 SCIP_BDCHGIDX* bdchgidx, /**< bound change index (time stamp of bound change), or NULL for current time */
5192 SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
5193 )
5194 {
5195 SCIP_CONSDATA* consdata;
5196 SCIP_VAR** vars;
5197 #ifndef NDEBUG
5198 SCIP_Real* vals;
5199 #endif
5200 int nvars;
5201 int inferpos;
5202
5203 assert(scip != NULL);
5204 assert(cons != NULL);
5205 assert(result != NULL);
5206
5207 consdata = SCIPconsGetData(cons);
5208 assert(consdata != NULL);
5209 vars = consdata->vars;
5210 nvars = consdata->nvars;
5211 #ifndef NDEBUG
5212 vals = consdata->vals;
5213 assert(vars != NULL);
5214 assert(vals != NULL);
5215 #endif
5216
5217 /* get the position of the inferred variable in the vars array */
5218 inferpos = inferInfoGetPos(inferinfo);
5219 if( inferpos >= nvars || vars[inferpos] != infervar )
5220 {
5221 /* find inference variable in constraint */
5222 /**@todo use a binary search here; the variables can be sorted by variable index */
5223 for( inferpos = 0; inferpos < nvars && vars[inferpos] != infervar; ++inferpos )
5224 {}
5225 }
5226 assert(inferpos < nvars);
5227 assert(vars[inferpos] == infervar);
5228 assert(!SCIPisZero(scip, vals[inferpos]));
5229
5230 switch( inferInfoGetProprule(inferinfo) )
5231 {
5232 case PROPRULE_1_RHS:
5233 /* the bound of the variable was tightened, because the minimal or maximal residual activity of the linear
5234 * constraint (only taking the other variables into account) didn't leave enough space for a larger
5235 * domain in order to not exceed the right hand side of the inequality
5236 */
5237 assert((vals[inferpos] > 0.0) == (boundtype == SCIP_BOUNDTYPE_UPPER));
5238 SCIP_CALL( addConflictBounds(scip, cons, infervar, bdchgidx, inferpos, TRUE) );
5239 *result = SCIP_SUCCESS;
5240 break;
5241
5242 case PROPRULE_1_LHS:
5243 /* the bound of the variable was tightened, because the minimal or maximal residual activity of the linear
5244 * constraint (only taking the other variables into account) didn't leave enough space for a larger
5245 * domain in order to not fall below the left hand side of the inequality
5246 */
5247 assert((vals[inferpos] > 0.0) == (boundtype == SCIP_BOUNDTYPE_LOWER));
5248 SCIP_CALL( addConflictBounds(scip, cons, infervar, bdchgidx, inferpos, FALSE) );
5249 *result = SCIP_SUCCESS;
5250 break;
5251
5252 case PROPRULE_1_RANGEDROW:
5253 /* the bound of the variable was tightened, because some variables were already fixed and the leftover only allow
5254 * the given inference variable to their bounds in this given ranged row
5255 */
5256
5257 /* check that we really have a ranged row here */
5258 assert(!SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs));
5259 SCIP_CALL( addConflictFixedVars(scip, cons, infervar, bdchgidx, inferpos) );
5260 *result = SCIP_SUCCESS;
5261 break;
5262
5263 case PROPRULE_INVALID:
5264 default:
5265 SCIPerrorMessage("invalid inference information %d in linear constraint <%s> at position %d for %s bound of variable <%s>\n",
5266 inferInfoGetProprule(inferinfo), SCIPconsGetName(cons), inferInfoGetPos(inferinfo),
5267 boundtype == SCIP_BOUNDTYPE_LOWER ? "lower" : "upper", SCIPvarGetName(infervar));
5268 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
5269 SCIPinfoMessage(scip, NULL, ";\n");
5270 return SCIP_INVALIDDATA;
5271 }
5272
5273 return SCIP_OKAY;
5274 }
5275
5276 /** analyzes conflicting bounds on given constraint, and adds conflict constraint to problem */
5277 static
analyzeConflict(SCIP * scip,SCIP_CONS * cons,SCIP_Bool reasonisrhs)5278 SCIP_RETCODE analyzeConflict(
5279 SCIP* scip, /**< SCIP data structure */
5280 SCIP_CONS* cons, /**< conflict detecting constraint */
5281 SCIP_Bool reasonisrhs /**< is the right hand side responsible for the conflict? */
5282 )
5283 {
5284 /* conflict analysis can only be applied in solving stage and if it is turned on */
5285 if( (SCIPgetStage(scip) != SCIP_STAGE_SOLVING && !SCIPinProbing(scip)) || !SCIPisConflictAnalysisApplicable(scip) )
5286 return SCIP_OKAY;
5287
5288 /* initialize conflict analysis */
5289 SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) );
5290
5291 /* add the conflicting bound for each variable of infeasible constraint to conflict candidate queue */
5292 SCIP_CALL( addConflictBounds(scip, cons, NULL, NULL, -1, reasonisrhs) );
5293
5294 /* analyze the conflict */
5295 SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
5296
5297 return SCIP_OKAY;
5298 }
5299
5300 /** check if there is any hope of tightening some bounds */
5301 static
canTightenBounds(SCIP_CONS * cons)5302 SCIP_Bool canTightenBounds(
5303 SCIP_CONS* cons /**< linear constraint */
5304 )
5305 {
5306 SCIP_CONSDATA* consdata;
5307 int infcountmin;
5308 int infcountmax;
5309
5310 consdata = SCIPconsGetData(cons);
5311 assert(consdata != NULL);
5312
5313 infcountmin = consdata->minactivityneginf
5314 + consdata->minactivityposinf
5315 + consdata->minactivityneghuge
5316 + consdata->minactivityposhuge;
5317 infcountmax = consdata->maxactivityneginf
5318 + consdata->maxactivityposinf
5319 + consdata->maxactivityneghuge
5320 + consdata->maxactivityposhuge;
5321
5322 if( infcountmin > 1 && infcountmax > 1 )
5323 return FALSE;
5324
5325 return TRUE;
5326 }
5327
5328 /** tighten upper bound */
5329 static
tightenVarUb(SCIP * scip,SCIP_CONS * cons,int pos,PROPRULE proprule,SCIP_Real newub,SCIP_Real oldub,SCIP_Bool * cutoff,int * nchgbds,SCIP_Bool force)5330 SCIP_RETCODE tightenVarUb(
5331 SCIP* scip, /**< SCIP data structure */
5332 SCIP_CONS* cons, /**< linear constraint */
5333 int pos, /**< variable position */
5334 PROPRULE proprule, /**< propagation rule that deduced the value */
5335 SCIP_Real newub, /**< new upper bound */
5336 SCIP_Real oldub, /**< old upper bound */
5337 SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
5338 int* nchgbds, /**< pointer to count the total number of tightened bounds */
5339 SCIP_Bool force /**< should a possible bound change be forced even if below bound strengthening tolerance */
5340 )
5341 {
5342 SCIP_CONSDATA* consdata;
5343 SCIP_VAR* var;
5344 SCIP_Real lb;
5345 SCIP_Bool infeasible;
5346 SCIP_Bool tightened;
5347
5348 assert(cons != NULL);
5349 assert(!SCIPisInfinity(scip, newub));
5350
5351 consdata = SCIPconsGetData(cons);
5352 assert(consdata != NULL);
5353 var = consdata->vars[pos];
5354 assert(var != NULL);
5355
5356 lb = SCIPvarGetLbLocal(var);
5357 newub = SCIPadjustedVarUb(scip, var, newub);
5358
5359 if( force || SCIPisUbBetter(scip, newub, lb, oldub) )
5360 {
5361 SCIP_VARTYPE vartype;
5362
5363 SCIPdebugMsg(scip, "linear constraint <%s>: tighten <%s>, old bds=[%.15g,%.15g], val=%.15g, activity=[%.15g,%.15g], sides=[%.15g,%.15g] -> newub=%.15g\n",
5364 SCIPconsGetName(cons), SCIPvarGetName(var), lb, oldub, consdata->vals[pos], consdata->minactivity, consdata->maxactivity, consdata->lhs, consdata->rhs, newub);
5365
5366 vartype = SCIPvarGetType(var);
5367
5368 /* tighten upper bound */
5369 SCIP_CALL( SCIPinferVarUbCons(scip, var, newub, cons, getInferInt(proprule, pos), force, &infeasible, &tightened) );
5370
5371 if( infeasible )
5372 {
5373 SCIPdebugMsg(scip, "linear constraint <%s>: cutoff <%s>, new bds=[%.15g,%.15g]\n",
5374 SCIPconsGetName(cons), SCIPvarGetName(var), lb, newub);
5375
5376 /* analyze conflict */
5377 SCIP_CALL( analyzeConflict(scip, cons, TRUE) );
5378
5379 *cutoff = TRUE;
5380 }
5381 else if( tightened )
5382 {
5383 assert(SCIPisFeasLE(scip, SCIPvarGetUbLocal(var), oldub));
5384 SCIPdebugMsg(scip, "linear constraint <%s>: tighten <%s>, new bds=[%.15g,%.15g]\n",
5385 SCIPconsGetName(cons), SCIPvarGetName(var), lb, SCIPvarGetUbLocal(var));
5386
5387 (*nchgbds)++;
5388
5389 /* if variable type was changed we might be able to upgrade the constraint */
5390 if( vartype != SCIPvarGetType(var) )
5391 consdata->upgradetried = FALSE;
5392 }
5393 }
5394 return SCIP_OKAY;
5395 }
5396
5397 /** tighten lower bound */
5398 static
tightenVarLb(SCIP * scip,SCIP_CONS * cons,int pos,PROPRULE proprule,SCIP_Real newlb,SCIP_Real oldlb,SCIP_Bool * cutoff,int * nchgbds,SCIP_Bool force)5399 SCIP_RETCODE tightenVarLb(
5400 SCIP* scip, /**< SCIP data structure */
5401 SCIP_CONS* cons, /**< linear constraint */
5402 int pos, /**< variable position */
5403 PROPRULE proprule, /**< propagation rule that deduced the value */
5404 SCIP_Real newlb, /**< new lower bound */
5405 SCIP_Real oldlb, /**< old lower bound */
5406 SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
5407 int* nchgbds, /**< pointer to count the total number of tightened bounds */
5408 SCIP_Bool force /**< should a possible bound change be forced even if below bound strengthening tolerance */
5409 )
5410 {
5411 SCIP_CONSDATA* consdata;
5412 SCIP_VAR* var;
5413 SCIP_Real ub;
5414 SCIP_Bool infeasible;
5415 SCIP_Bool tightened;
5416
5417 assert(cons != NULL);
5418 assert(!SCIPisInfinity(scip, newlb));
5419
5420 consdata = SCIPconsGetData(cons);
5421 assert(consdata != NULL);
5422 var = consdata->vars[pos];
5423 assert(var != NULL);
5424
5425 ub = SCIPvarGetUbLocal(var);
5426 newlb = SCIPadjustedVarLb(scip, var, newlb);
5427
5428 if( force || SCIPisLbBetter(scip, newlb, oldlb, ub) )
5429 {
5430 SCIP_VARTYPE vartype;
5431
5432 SCIPdebugMsg(scip, "linear constraint <%s>: tighten <%s>, old bds=[%.15g,%.15g], val=%.15g, activity=[%.15g,%.15g], sides=[%.15g,%.15g] -> newlb=%.15g\n",
5433 SCIPconsGetName(cons), SCIPvarGetName(var), oldlb, ub, consdata->vals[pos], consdata->minactivity, consdata->maxactivity, consdata->lhs, consdata->rhs, newlb);
5434
5435 vartype = SCIPvarGetType(var);
5436
5437 /* tighten lower bound */
5438 SCIP_CALL( SCIPinferVarLbCons(scip, var, newlb, cons, getInferInt(proprule, pos), force, &infeasible, &tightened) );
5439
5440 if( infeasible )
5441 {
5442 SCIPdebugMsg(scip, "linear constraint <%s>: cutoff <%s>, new bds=[%.15g,%.15g]\n",
5443 SCIPconsGetName(cons), SCIPvarGetName(var), newlb, ub);
5444
5445 /* analyze conflict */
5446 SCIP_CALL( analyzeConflict(scip, cons, FALSE) );
5447
5448 *cutoff = TRUE;
5449 }
5450 else if( tightened )
5451 {
5452 assert(SCIPisFeasGE(scip, SCIPvarGetLbLocal(var), oldlb));
5453 SCIPdebugMsg(scip, "linear constraint <%s>: tighten <%s>, new bds=[%.15g,%.15g]\n",
5454 SCIPconsGetName(cons), SCIPvarGetName(var), SCIPvarGetLbLocal(var), ub);
5455
5456 (*nchgbds)++;
5457
5458 /* if variable type was changed we might be able to upgrade the constraint */
5459 if( vartype != SCIPvarGetType(var) )
5460 consdata->upgradetried = FALSE;
5461 }
5462 }
5463 return SCIP_OKAY;
5464 }
5465
5466 /** tightens bounds of a single variable due to activity bounds (easy case) */
5467 static
tightenVarBoundsEasy(SCIP * scip,SCIP_CONS * cons,int pos,SCIP_Bool * cutoff,int * nchgbds,SCIP_Bool force)5468 SCIP_RETCODE tightenVarBoundsEasy(
5469 SCIP* scip, /**< SCIP data structure */
5470 SCIP_CONS* cons, /**< linear constraint */
5471 int pos, /**< position of the variable in the vars array */
5472 SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
5473 int* nchgbds, /**< pointer to count the total number of tightened bounds */
5474 SCIP_Bool force /**< should a possible bound change be forced even if below bound strengthening tolerance */
5475 )
5476 {
5477 SCIP_CONSDATA* consdata;
5478 SCIP_VAR* var;
5479 SCIP_Real val;
5480 SCIP_Real lb;
5481 SCIP_Real ub;
5482 SCIP_Real lhs;
5483 SCIP_Real rhs;
5484
5485 assert(scip != NULL);
5486 assert(cons != NULL);
5487 assert(cutoff != NULL);
5488 assert(nchgbds != NULL);
5489
5490 /* we cannot tighten variables' bounds, if the constraint may be not complete */
5491 if( SCIPconsIsModifiable(cons) )
5492 return SCIP_OKAY;
5493
5494 consdata = SCIPconsGetData(cons);
5495 assert(consdata != NULL);
5496 assert(0 <= pos && pos < consdata->nvars);
5497
5498 *cutoff = FALSE;
5499
5500 var = consdata->vars[pos];
5501 assert(var != NULL);
5502
5503 /* we cannot tighten bounds of multi-aggregated variables */
5504 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR )
5505 return SCIP_OKAY;
5506
5507 val = consdata->vals[pos];
5508 lhs = consdata->lhs;
5509 rhs = consdata->rhs;
5510 assert(!SCIPisZero(scip, val));
5511 assert(!SCIPisInfinity(scip, lhs));
5512 assert(!SCIPisInfinity(scip, -rhs));
5513
5514 lb = SCIPvarGetLbLocal(var);
5515 ub = SCIPvarGetUbLocal(var);
5516 assert(SCIPisLE(scip, lb, ub));
5517
5518 /* recompute activities if needed */
5519 if( !consdata->validactivities )
5520 consdataCalcActivities(scip, consdata);
5521 assert(consdata->validactivities);
5522 if( !consdata->validminact )
5523 consdataRecomputeMinactivity(scip, consdata);
5524 assert(consdata->validminact);
5525
5526 if( val > 0.0 )
5527 {
5528 /* check, if we can tighten the variable's upper bound */
5529 if( !SCIPisInfinity(scip, rhs) )
5530 {
5531 SCIP_Real slack;
5532 SCIP_Real alpha;
5533
5534 /* min activity should be valid at this point (if this is not true, then some decisions might be wrong!) */
5535 assert(consdata->validminact);
5536
5537 /* if the minactivity is larger than the right hand side by feasibility epsilon, the constraint is infeasible */
5538 if( SCIPisFeasLT(scip, rhs, consdata->minactivity) )
5539 {
5540 SCIPdebugMsg(scip, "linear constraint <%s>: cutoff <%s>, minactivity=%.15g > rhs=%.15g\n",
5541 SCIPconsGetName(cons), SCIPvarGetName(var), consdata->minactivity, rhs);
5542
5543 *cutoff = TRUE;
5544 return SCIP_OKAY;
5545 }
5546
5547 slack = rhs - consdata->minactivity;
5548
5549 /* if the slack is zero in tolerances (or negative, but not enough to make the constraint infeasible), we set
5550 * it to zero
5551 */
5552 if( !SCIPisPositive(scip, slack) )
5553 slack = 0.0;
5554
5555 alpha = val * (ub - lb);
5556 assert(!SCIPisNegative(scip, alpha));
5557
5558 if( SCIPisSumGT(scip, alpha, slack) || (force && SCIPisGT(scip, alpha, slack)) )
5559 {
5560 SCIP_Real newub;
5561
5562 /* compute new upper bound */
5563 newub = lb + (slack / val);
5564
5565 SCIP_CALL( tightenVarUb(scip, cons, pos, PROPRULE_1_RHS, newub, ub, cutoff, nchgbds, force) );
5566
5567 if( *cutoff )
5568 {
5569 SCIPdebugMsg(scip, "linear constraint <%s>: cutoff <%s>, new bds=[%.15g,%.15g]\n",
5570 SCIPconsGetName(cons), SCIPvarGetName(var), lb, newub);
5571
5572 return SCIP_OKAY;
5573 }
5574
5575 /* collect the new upper bound which is needed for the lower bound computation */
5576 ub = SCIPvarGetUbLocal(var);
5577 }
5578 }
5579
5580 /* check, if we can tighten the variable's lower bound */
5581 if( !SCIPisInfinity(scip, -lhs) )
5582 {
5583 SCIP_Real slack;
5584 SCIP_Real alpha;
5585
5586 /* make sure the max activity is reliable */
5587 if( !consdata->validmaxact )
5588 {
5589 consdataRecomputeMaxactivity(scip, consdata);
5590 }
5591 assert(consdata->validmaxact);
5592
5593
5594 /* if the maxactivity is smaller than the left hand side by feasibility epsilon, the constraint is infeasible */
5595 if( SCIPisFeasLT(scip, consdata->maxactivity, lhs) )
5596 {
5597 SCIPdebugMsg(scip, "linear constraint <%s>: cutoff <%s>, maxactivity=%.15g < lhs=%.15g\n",
5598 SCIPconsGetName(cons), SCIPvarGetName(var), consdata->maxactivity, lhs);
5599 *cutoff = TRUE;
5600 return SCIP_OKAY;
5601 }
5602
5603 slack = consdata->maxactivity - lhs;
5604
5605 /* if the slack is zero in tolerances (or negative, but not enough to make the constraint infeasible), we set
5606 * it to zero
5607 */
5608 if( !SCIPisPositive(scip, slack) )
5609 slack = 0.0;
5610
5611 alpha = val * (ub - lb);
5612 assert(!SCIPisNegative(scip, alpha));
5613
5614 if( SCIPisSumGT(scip, alpha, slack) || (force && SCIPisGT(scip, alpha, slack)) )
5615 {
5616 SCIP_Real newlb;
5617
5618 /* compute new lower bound */
5619 newlb = ub - (slack / val);
5620
5621 SCIP_CALL( tightenVarLb(scip, cons, pos, PROPRULE_1_LHS, newlb, lb, cutoff, nchgbds, force) );
5622
5623 if( *cutoff )
5624 {
5625 SCIPdebugMsg(scip, "linear constraint <%s>: cutoff <%s>, new bds=[%.15g,%.15g]\n",
5626 SCIPconsGetName(cons), SCIPvarGetName(var), newlb, ub);
5627
5628 return SCIP_OKAY;
5629 }
5630 }
5631 }
5632 }
5633 else
5634 {
5635 /* check, if we can tighten the variable's lower bound */
5636 if( !SCIPisInfinity(scip, rhs) )
5637 {
5638 SCIP_Real slack;
5639 SCIP_Real alpha;
5640
5641 /* min activity should be valid at this point (if this is not true, then some decisions might be wrong!) */
5642 assert(consdata->validminact);
5643
5644 /* if the minactivity is larger than the right hand side by feasibility epsilon, the constraint is infeasible */
5645 if( SCIPisFeasLT(scip, rhs, consdata->minactivity) )
5646 {
5647 SCIPdebugMsg(scip, "linear constraint <%s>: cutoff <%s>, minactivity=%.15g > rhs=%.15g\n",
5648 SCIPconsGetName(cons), SCIPvarGetName(var), consdata->minactivity, rhs);
5649
5650 *cutoff = TRUE;
5651 return SCIP_OKAY;
5652 }
5653
5654 slack = rhs - consdata->minactivity;
5655
5656 /* if the slack is zero in tolerances (or negative, but not enough to make the constraint infeasible), we set
5657 * it to zero
5658 */
5659 if( !SCIPisPositive(scip, slack) )
5660 slack = 0.0;
5661
5662 alpha = val * (lb - ub);
5663 assert(!SCIPisNegative(scip, alpha));
5664
5665 if( SCIPisSumGT(scip, alpha, slack) || (force && SCIPisGT(scip, alpha, slack)) )
5666 {
5667 SCIP_Real newlb;
5668
5669 /* compute new lower bound */
5670 newlb = ub + slack / val;
5671
5672 SCIP_CALL( tightenVarLb(scip, cons, pos, PROPRULE_1_RHS, newlb, lb, cutoff, nchgbds, force) );
5673
5674 if( *cutoff )
5675 {
5676 SCIPdebugMsg(scip, "linear constraint <%s>: cutoff <%s>, new bds=[%.15g,%.15g]\n",
5677 SCIPconsGetName(cons), SCIPvarGetName(var), newlb, ub);
5678
5679 return SCIP_OKAY;
5680 }
5681 /* collect the new lower bound which is needed for the upper bound computation */
5682 lb = SCIPvarGetLbLocal(var);
5683 }
5684 }
5685
5686 /* check, if we can tighten the variable's upper bound */
5687 if( !SCIPisInfinity(scip, -lhs) )
5688 {
5689 SCIP_Real slack;
5690 SCIP_Real alpha;
5691
5692 /* make sure the max activity is reliable */
5693 if( !consdata->validmaxact )
5694 {
5695 consdataRecomputeMaxactivity(scip, consdata);
5696 }
5697 assert(consdata->validmaxact);
5698
5699 /* if the maxactivity is smaller than the left hand side by feasibility epsilon, the constraint is infeasible */
5700 if( SCIPisFeasLT(scip, consdata->maxactivity, lhs) )
5701 {
5702 SCIPdebugMsg(scip, "linear constraint <%s>: cutoff <%s>, maxactivity=%.15g < lhs=%.15g\n",
5703 SCIPconsGetName(cons), SCIPvarGetName(var), consdata->maxactivity, lhs);
5704
5705 *cutoff = TRUE;
5706 return SCIP_OKAY;
5707 }
5708
5709 slack = consdata->maxactivity - lhs;
5710
5711 /* if the slack is zero in tolerances (or negative, but not enough to make the constraint infeasible), we set
5712 * it to zero
5713 */
5714 if( !SCIPisPositive(scip, slack) )
5715 slack = 0.0;
5716
5717 alpha = val * (lb - ub);
5718 assert(!SCIPisNegative(scip, alpha));
5719
5720 if( SCIPisSumGT(scip, alpha, slack) || (force && SCIPisGT(scip, alpha, slack)) )
5721 {
5722 SCIP_Real newub;
5723
5724 /* compute new upper bound */
5725 newub = lb - (slack / val);
5726
5727 SCIP_CALL( tightenVarUb(scip, cons, pos, PROPRULE_1_LHS, newub, ub, cutoff, nchgbds, force) );
5728
5729 if( *cutoff )
5730 {
5731 SCIPdebugMsg(scip, "linear constraint <%s>: cutoff <%s>, new bds=[%.15g,%.15g]\n",
5732 SCIPconsGetName(cons), SCIPvarGetName(var), lb, newub);
5733
5734 return SCIP_OKAY;
5735 }
5736 }
5737 }
5738 }
5739
5740 return SCIP_OKAY;
5741 }
5742
5743 /** analyzes conflicting bounds on given ranged row constraint, and adds conflict constraint to problem */
5744 static
analyzeConflictRangedRow(SCIP * scip,SCIP_CONS * cons,SCIP_VAR ** vars,int nvars,SCIP_VAR * var,SCIP_Real bound)5745 SCIP_RETCODE analyzeConflictRangedRow(
5746 SCIP* scip, /**< SCIP data structure */
5747 SCIP_CONS* cons, /**< conflict detecting constraint */
5748 SCIP_VAR** vars, /**< variables reasoning the infeasibility */
5749 int nvars, /**< number of variables reasoning the infeasibility */
5750 SCIP_VAR* var, /**< variable which was tried to fix/tighten, or NULL */
5751 SCIP_Real bound /**< bound of variable which was tried to apply, or SCIP_INVALID */
5752 )
5753 {
5754 #ifndef NDEBUG
5755 SCIP_CONSDATA* consdata;
5756
5757 assert(scip != NULL);
5758 assert(cons != NULL);
5759
5760 consdata = SCIPconsGetData(cons);
5761 assert(consdata != NULL);
5762 assert(!SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, consdata->rhs));
5763 #endif
5764
5765 /* conflict analysis can only be applied in solving stage and if it is turned on */
5766 if( (SCIPgetStage(scip) != SCIP_STAGE_SOLVING && !SCIPinProbing(scip)) || !SCIPisConflictAnalysisApplicable(scip) )
5767 return SCIP_OKAY;
5768
5769 /* initialize conflict analysis */
5770 SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) );
5771
5772 /* add the conflicting fixed variables of this ranged row constraint to conflict candidate queue */
5773 SCIP_CALL( addConflictFixedVars(scip, cons, NULL, NULL, -1) );
5774
5775 /* add reasoning variables to conflict candidate queue which led to the conflict */
5776 SCIP_CALL( addConflictReasonVars(scip, vars, nvars, var, bound) );
5777
5778 /* analyze the conflict */
5779 SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
5780
5781 return SCIP_OKAY;
5782 }
5783
5784 /** propagate ranged rows
5785 *
5786 * Check ranged rows for possible solutions, possibly detect infeasibility, fix variables due to having only one possible
5787 * solution, tighten bounds if having only two possible solutions or add constraints which propagate a subset of
5788 * variables better.
5789 *
5790 * Example:
5791 * c1: 12 x1 + 9 x2 - x3 = 0 with x1, x2 free and 1 <= x3 <= 2
5792 *
5793 * x3 needs to be a multiple of 3, so the instance is infeasible.
5794 *
5795 * Example:
5796 * c1: 12 x1 + 9 x2 - x3 = 1 with x1, x2 free and 1 <= x3 <= 2
5797 *
5798 * The only possible value for x3 is 2, so the variable will be fixed.
5799 *
5800 * @todo add holes if possible
5801 */
5802 static
rangedRowPropagation(SCIP * scip,SCIP_CONS * cons,SCIP_Bool * cutoff,int * nfixedvars,int * nchgbds,int * naddconss)5803 SCIP_RETCODE rangedRowPropagation(
5804 SCIP* scip, /**< SCIP data structure */
5805 SCIP_CONS* cons, /**< linear constraint */
5806 SCIP_Bool* cutoff, /**< pointer to store TRUE, if a cutoff was found */
5807 int* nfixedvars, /**< pointer to count number of fixed variables */
5808 int* nchgbds, /**< pointer to count the number of bound changes */
5809 int* naddconss /**< pointer to count number of added constraints */
5810 )
5811 {
5812 SCIP_CONSHDLRDATA* conshdlrdata;
5813 SCIP_CONSHDLR* conshdlr;
5814 SCIP_CONSDATA* consdata;
5815 SCIP_VAR** infcheckvars;
5816 SCIP_Real* infcheckvals;
5817 SCIP_Real minactinfvars;
5818 SCIP_Real maxactinfvars;
5819 SCIP_Real lb;
5820 SCIP_Real ub;
5821 SCIP_Real feastol;
5822 SCIP_Real fixedact;
5823 SCIP_Real lhs;
5824 SCIP_Real rhs;
5825 SCIP_Real absminbincoef;
5826 SCIP_Longint gcd;
5827 SCIP_Longint gcdtmp;
5828 SCIP_Bool minactinfvarsinvalid;
5829 SCIP_Bool maxactinfvarsinvalid;
5830 SCIP_Bool possiblegcd;
5831 SCIP_Bool gcdisone;
5832 SCIP_Bool addartconss;
5833 int ninfcheckvars;
5834 int nunfixedvars;
5835 int nfixedconsvars;
5836 int ncontvars;
5837 int pos;
5838 int v;
5839
5840 assert(scip != NULL);
5841 assert(cons != NULL);
5842 assert(cutoff != NULL);
5843 assert(nfixedvars != NULL);
5844 assert(nchgbds != NULL);
5845 assert(naddconss != NULL);
5846
5847 /* modifiable constraint can be changed so we do not have all necessary information */
5848 if( SCIPconsIsModifiable(cons) )
5849 return SCIP_OKAY;
5850
5851 consdata = SCIPconsGetData(cons);
5852 assert(consdata != NULL);
5853
5854 /* we already did full ranged row propagation */
5855 if( consdata->rangedrowpropagated == 2 )
5856 return SCIP_OKAY;
5857
5858 /* at least three variables are needed */
5859 if( consdata->nvars < 3 )
5860 return SCIP_OKAY;
5861
5862 /* do nothing on normal inequalities */
5863 if( SCIPisInfinity(scip, -consdata->lhs) || SCIPisInfinity(scip, consdata->rhs) )
5864 return SCIP_OKAY;
5865
5866 /* get constraint handler data */
5867 conshdlr = SCIPconsGetHdlr(cons);
5868 assert(conshdlr != NULL);
5869 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5870 assert(conshdlrdata != NULL);
5871
5872 addartconss = conshdlrdata->rangedrowartcons && SCIPgetDepth(scip) < 1 && !SCIPinProbing(scip) && !SCIPinRepropagation(scip);
5873
5874 /* we may add artificial constraints */
5875 if( addartconss )
5876 consdata->rangedrowpropagated = 2;
5877 /* we are not allowed to add artificial constraints during propagation; if nothing changed on this constraint since
5878 * the last rangedrowpropagation, we can stop; otherwise, we mark this constraint to be rangedrowpropagated without
5879 * artificial constraints
5880 */
5881 else
5882 {
5883 if( consdata->rangedrowpropagated > 0 )
5884 return SCIP_OKAY;
5885
5886 consdata->rangedrowpropagated = 1;
5887 }
5888 fixedact = 0;
5889 nfixedconsvars = 0;
5890 /* calculate fixed activity and number of fixed variables */
5891 for( v = consdata->nvars - 1; v >= 0; --v )
5892 {
5893 /* all zero coefficients should be eliminated */
5894 assert(!SCIPisZero(scip, consdata->vals[v]));
5895
5896 if( SCIPisEQ(scip, SCIPvarGetLbLocal(consdata->vars[v]), SCIPvarGetUbLocal(consdata->vars[v])) )
5897 {
5898 fixedact += SCIPvarGetLbLocal(consdata->vars[v]) * consdata->vals[v];
5899 ++nfixedconsvars;
5900 }
5901 }
5902
5903 /* do not work with huge fixed activities */
5904 if( SCIPisHugeValue(scip, REALABS(fixedact)) )
5905 return SCIP_OKAY;
5906
5907 /* compute lhs and rhs for unfixed variables only and get number of unfixed variables */
5908 assert(!SCIPisInfinity(scip, -fixedact) && !SCIPisInfinity(scip, fixedact));
5909 lhs = consdata->lhs - fixedact;
5910 rhs = consdata->rhs - fixedact;
5911 nunfixedvars = consdata->nvars - nfixedconsvars;
5912
5913 /* allocate temporary memory for variables and coefficients which may lead to infeasibility */
5914 SCIP_CALL( SCIPallocBufferArray(scip, &infcheckvars, nunfixedvars) );
5915 SCIP_CALL( SCIPallocBufferArray(scip, &infcheckvals, nunfixedvars) );
5916
5917 absminbincoef = SCIP_REAL_MAX;
5918 ncontvars = 0;
5919 gcdisone = TRUE;
5920 possiblegcd = TRUE;
5921
5922 /* we now partition all unfixed variables in two groups:
5923 *
5924 * the first one contains all integral variable with integral
5925 * coefficient so that all variables in this group will have a gcd greater than 1, this group will be implicitly
5926 * given
5927 *
5928 * the second group will contain all left unfixed variables and will be saved as infcheckvars with corresponding
5929 * coefficients as infcheckvals, the order of these variables should be the same as in the consdata object
5930 */
5931
5932 /* find first integral variables with integral coefficient greater than 1, thereby collecting all other unfixed
5933 * variables
5934 */
5935 ninfcheckvars = 0;
5936 v = -1;
5937 pos = -1;
5938 do
5939 {
5940 ++v;
5941
5942 /* partition the variables, do not change the order of collection, because it might be used later on */
5943 while( v < consdata->nvars && (SCIPvarGetType(consdata->vars[v]) == SCIP_VARTYPE_CONTINUOUS ||
5944 !SCIPisIntegral(scip, consdata->vals[v]) || SCIPisEQ(scip, REALABS(consdata->vals[v]), 1.0)) )
5945 {
5946 if( !SCIPisEQ(scip, SCIPvarGetLbLocal(consdata->vars[v]), SCIPvarGetUbLocal(consdata->vars[v])) )
5947 {
5948 if( SCIPvarGetType(consdata->vars[v]) == SCIP_VARTYPE_CONTINUOUS )
5949 {
5950 ++ncontvars;
5951 }
5952 else if( SCIPvarIsBinary(consdata->vars[v]) )
5953 {
5954 SCIP_Real absval;
5955
5956 absval = REALABS(consdata->vals[v]);
5957
5958 if( absminbincoef > absval )
5959 absminbincoef = absval;
5960 }
5961
5962 gcdisone = gcdisone && SCIPisEQ(scip, REALABS(consdata->vals[v]), 1.0);
5963 possiblegcd = FALSE;
5964 infcheckvars[ninfcheckvars] = consdata->vars[v];
5965 infcheckvals[ninfcheckvars] = consdata->vals[v];
5966 ++ninfcheckvars;
5967
5968 if( pos == -1 )
5969 pos = v;
5970 }
5971 ++v;
5972 }
5973 }
5974 while( v < consdata->nvars && SCIPisEQ(scip, SCIPvarGetLbLocal(consdata->vars[v]), SCIPvarGetUbLocal(consdata->vars[v])) );
5975
5976 /* if the first group of variables is empty, we stop */
5977 /* @todo try to propagate/split up a constraint of the form:
5978 * x_1 + ... + x_m + a_1*y_1 + ... + a_n*y_n = k + c,
5979 * with k \in Z, c \in (d,d + 1], d \in Z, (a_1*y_1 + ... + a_n*y_n) \in (c-1 + d,d + 1]
5980 */
5981 if( v == consdata->nvars )
5982 goto TERMINATE;
5983
5984 /* we need at least two non-continuous variables */
5985 if( ncontvars + 2 > nunfixedvars )
5986 goto TERMINATE;
5987
5988 assert(!SCIPisEQ(scip, SCIPvarGetLbLocal(consdata->vars[v]), SCIPvarGetUbLocal(consdata->vars[v])));
5989 assert(SCIPisIntegral(scip, consdata->vals[v]) && SCIPvarGetType(consdata->vars[v]) != SCIP_VARTYPE_CONTINUOUS && REALABS(consdata->vals[v]) > 1.5);
5990
5991 feastol = SCIPfeastol(scip);
5992
5993 gcd = (SCIP_Longint)(REALABS(consdata->vals[v]) + feastol);
5994 assert(gcd >= 2);
5995
5996 /* go on to partition the variables, do not change the order of collection, because it might be used later on;
5997 * calculate gcd over the first part of variables */
5998 for( ; v < consdata->nvars; ++v )
5999 {
6000 if( SCIPisEQ(scip, SCIPvarGetLbLocal(consdata->vars[v]), SCIPvarGetUbLocal(consdata->vars[v])) )
6001 continue;
6002
6003 if( SCIPvarIsBinary(consdata->vars[v]) )
6004 {
6005 SCIP_Real absval;
6006
6007 absval = REALABS(consdata->vals[v]);
6008
6009 if( absminbincoef > absval )
6010 absminbincoef = absval;
6011 }
6012
6013 if( !SCIPisIntegral(scip, consdata->vals[v]) || SCIPvarGetType(consdata->vars[v]) == SCIP_VARTYPE_CONTINUOUS ||
6014 SCIPisEQ(scip, REALABS(consdata->vals[v]), 1.0) )
6015 {
6016 if( SCIPvarGetType(consdata->vars[v]) == SCIP_VARTYPE_CONTINUOUS )
6017 ++ncontvars;
6018
6019 gcdisone = gcdisone && SCIPisEQ(scip, REALABS(consdata->vals[v]), 1.0);
6020 possiblegcd = FALSE;
6021 infcheckvars[ninfcheckvars] = consdata->vars[v];
6022 infcheckvals[ninfcheckvars] = consdata->vals[v];
6023
6024 ++ninfcheckvars;
6025
6026 if( pos == -1 )
6027 pos = v;
6028 }
6029 else
6030 {
6031 assert(REALABS(consdata->vals[v]) > 1.5);
6032
6033 gcdtmp = SCIPcalcGreComDiv(gcd, (SCIP_Longint)(REALABS(consdata->vals[v]) + feastol));
6034 assert(gcdtmp >= 1);
6035
6036 if( gcdtmp == 1 )
6037 {
6038 infcheckvars[ninfcheckvars] = consdata->vars[v];
6039 infcheckvals[ninfcheckvars] = consdata->vals[v];
6040
6041 ++ninfcheckvars;
6042
6043 if( pos == -1 )
6044 pos = v;
6045 }
6046 else
6047 gcd = gcdtmp;
6048 }
6049 }
6050 assert(gcd >= 2);
6051
6052 /* it should not happen that all variables are of integral type and have a gcd >= 2, this should be done by
6053 * normalizeCons() */
6054 if( ninfcheckvars == 0 )
6055 goto TERMINATE;
6056
6057 assert(pos >= 0);
6058
6059 minactinfvarsinvalid = FALSE;
6060 maxactinfvarsinvalid = FALSE;
6061 maxactinfvars = 0.0;
6062 minactinfvars = 0.0;
6063
6064 /* calculate activities over all infcheckvars */
6065 for( v = ninfcheckvars - 1; v >= 0; --v )
6066 {
6067 lb = SCIPvarGetLbLocal(infcheckvars[v]);
6068 ub = SCIPvarGetUbLocal(infcheckvars[v]);
6069
6070 if( SCIPisInfinity(scip, -lb) )
6071 {
6072 if( infcheckvals[v] < 0.0 )
6073 maxactinfvarsinvalid = TRUE;
6074 else
6075 minactinfvarsinvalid = TRUE;
6076 }
6077 else
6078 {
6079 if( infcheckvals[v] < 0.0 )
6080 maxactinfvars += infcheckvals[v] * lb;
6081 else
6082 minactinfvars += infcheckvals[v] * lb;
6083 }
6084
6085 if( SCIPisInfinity(scip, ub) )
6086 {
6087 if( infcheckvals[v] > 0.0 )
6088 maxactinfvarsinvalid = TRUE;
6089 else
6090 minactinfvarsinvalid = TRUE;
6091 }
6092 else
6093 {
6094 if( infcheckvals[v] > 0.0 )
6095 maxactinfvars += infcheckvals[v] * ub;
6096 else
6097 minactinfvars += infcheckvals[v] * ub;
6098 }
6099
6100 /* better abort on to big values */
6101 if( SCIPisHugeValue(scip, -minactinfvars) )
6102 minactinfvarsinvalid = TRUE;
6103 if( SCIPisHugeValue(scip, maxactinfvars) )
6104 maxactinfvarsinvalid = TRUE;
6105
6106 if( minactinfvarsinvalid || maxactinfvarsinvalid )
6107 goto TERMINATE;
6108 }
6109 assert(!minactinfvarsinvalid && !maxactinfvarsinvalid);
6110
6111 SCIPdebugMsg(scip, "minactinfvarsinvalid = %u, minactinfvars = %g, maxactinfvarsinvalid = %u, maxactinfvars = %g, gcd = %lld, ninfcheckvars = %d, ncontvars = %d\n",
6112 minactinfvarsinvalid, minactinfvars, maxactinfvarsinvalid, maxactinfvars, gcd, ninfcheckvars, ncontvars);
6113
6114 /* @todo maybe we took the wrong variables as infcheckvars we could try to exchange integer variables */
6115 /* @todo if minactinfvarsinvalid or maxactinfvarsinvalid are true, try to exchange both partitions to maybe get valid
6116 * activities */
6117 /* @todo calculate minactivity and maxactivity for all non-intcheckvars, and use this for better bounding,
6118 * !!!note!!!
6119 * that therefore the conflict variables in addConflictFixedVars() need to be extended by all variables which
6120 * are not at their global bound
6121 */
6122
6123 /* check if between left hand side and right hand side exist a feasible point, if not the constraint leads to
6124 * infeasibility */
6125 if( !SCIPisIntegral(scip, (lhs - maxactinfvars) / gcd) &&
6126 SCIPisGT(scip, SCIPceil(scip, (lhs - maxactinfvars) / gcd) * gcd, rhs - minactinfvars) )
6127 {
6128 SCIPdebugMsg(scip, "no feasible value exist, constraint <%s> lead to infeasibility", SCIPconsGetName(cons));
6129 SCIPdebugPrintCons(scip, cons, NULL);
6130
6131 /* start conflict analysis */
6132 /* @todo improve conflict analysis by adding relaxed bounds */
6133 SCIP_CALL( analyzeConflictRangedRow(scip, cons, infcheckvars, ninfcheckvars, NULL, SCIP_INVALID) );
6134
6135 *cutoff = TRUE;
6136 }
6137 else if( ncontvars == 0 )
6138 {
6139 SCIP_Longint gcdinfvars = -1;
6140
6141 /* check for gcd over all infcheckvars */
6142 if( possiblegcd )
6143 {
6144 v = ninfcheckvars - 1;
6145 gcdinfvars = (SCIP_Longint)(REALABS(infcheckvals[v]) + feastol);
6146 assert(gcdinfvars >= 2);
6147
6148 for( ; v >= 0 && gcdinfvars >= 2; --v )
6149 {
6150 gcdinfvars = SCIPcalcGreComDiv(gcdinfvars, (SCIP_Longint)(REALABS(infcheckvals[v]) + feastol));
6151 }
6152 }
6153 else if( gcdisone )
6154 gcdinfvars = 1;
6155
6156 SCIPdebugMsg(scip, "gcdinfvars =%lld, possiblegcd = %u\n", gcdinfvars, possiblegcd);
6157
6158 /* compute solutions for this ranged row, if all variables are of integral type with integral coefficients */
6159 if( gcdinfvars >= 1 )
6160 {
6161 SCIP_Real value;
6162 SCIP_Real value2;
6163 SCIP_Real minvalue = SCIP_INVALID;
6164 SCIP_Real maxvalue = SCIP_INVALID;
6165 int nsols = 0;
6166
6167 value = SCIPceil(scip, minactinfvars - SCIPfeastol(scip));
6168
6169 /* check how many possible solutions exist */
6170 while( SCIPisLE(scip, value, maxactinfvars) )
6171 {
6172 value2 = value + gcd * (SCIPceil(scip, (lhs - value) / gcd));
6173
6174 /* value2 might violate lhs due to numerics, in this case take the next divisible number */
6175 if( !SCIPisGE(scip, value2, lhs) )
6176 {
6177 value2 += gcd;
6178 }
6179
6180 if( SCIPisLE(scip, value2, rhs) )
6181 {
6182 ++nsols;
6183
6184 /* early termination if we found more than two solutions */
6185 if( nsols == 3 )
6186 break;
6187
6188 if( minvalue == SCIP_INVALID ) /*lint !e777*/
6189 minvalue = value;
6190
6191 maxvalue = value;
6192 }
6193 value += gcdinfvars;
6194 }
6195 assert(nsols < 2 || minvalue <= maxvalue);
6196
6197 /* determine last possible solution for better bounding */
6198 if( nsols == 3 )
6199 {
6200 #ifndef NDEBUG
6201 SCIP_Real secondsolval = maxvalue;
6202 #endif
6203 value = SCIPfloor(scip, maxactinfvars + SCIPfeastol(scip));
6204
6205 /* check how many possible solutions exist */
6206 while( SCIPisGE(scip, value, minactinfvars) )
6207 {
6208 value2 = value + gcd * (SCIPfloor(scip, (rhs - value) / gcd));
6209
6210 /* value2 might violate rhs due to numerics, in this case take the next divisible number */
6211 if( !SCIPisLE(scip, value2, rhs) )
6212 {
6213 value2 -= gcd;
6214 }
6215
6216 if( SCIPisGE(scip, value2, lhs) )
6217 {
6218 maxvalue = value;
6219 assert(maxvalue > minvalue);
6220 break;
6221 }
6222 value -= gcdinfvars;
6223 }
6224 assert(maxvalue > secondsolval);
6225 }
6226
6227 SCIPdebugMsg(scip, "here nsols %s %d, minsolvalue = %g, maxsolvalue = %g, ninfcheckvars = %d, nunfixedvars = %d\n",
6228 nsols > 2 ? ">=" : "=", nsols, minvalue, maxvalue, ninfcheckvars, nunfixedvars);
6229
6230 /* no possible solution found */
6231 if( nsols == 0 )
6232 {
6233 SCIPdebugMsg(scip, "gcdinfvars = %lld, gcd = %lld, correctedlhs = %g, correctedrhs = %g\n",
6234 gcdinfvars, gcd, lhs, rhs);
6235 SCIPdebugMsg(scip, "no solution found; constraint <%s> lead to infeasibility\n", SCIPconsGetName(cons));
6236 SCIPdebugPrintCons(scip, cons, NULL);
6237
6238 /* start conflict analysis */
6239 /* @todo improve conflict analysis by adding relaxed bounds */
6240 SCIP_CALL( analyzeConflictRangedRow(scip, cons, infcheckvars, ninfcheckvars, NULL, SCIP_INVALID) );
6241
6242 *cutoff = TRUE;
6243 }
6244 /* if only one solution exist we can extract a new constraint or fix variables */
6245 else if( nsols == 1 )
6246 {
6247 assert(minvalue == maxvalue); /*lint !e777*/
6248
6249 /* we can fix the only variable in our second set of variables */
6250 if( ninfcheckvars == 1 )
6251 {
6252 SCIP_Bool fixed;
6253
6254 assert(SCIPisEQ(scip, (SCIP_Real)gcdinfvars, REALABS(infcheckvals[0])));
6255
6256 SCIPdebugMsg(scip, "fixing single variable <%s> with bounds [%.15g,%.15g] to %.15g\n",
6257 SCIPvarGetName(infcheckvars[0]), SCIPvarGetLbLocal(infcheckvars[0]),
6258 SCIPvarGetUbLocal(infcheckvars[0]), maxvalue/infcheckvals[0]);
6259
6260 /* fix variable to only possible value */
6261 SCIP_CALL( SCIPinferVarFixCons(scip, infcheckvars[0], maxvalue/infcheckvals[0], cons,
6262 getInferInt(PROPRULE_1_RANGEDROW, pos), TRUE, cutoff, &fixed) );
6263
6264 if( *cutoff )
6265 {
6266 /* start conflict analysis */
6267 /* @todo improve conflict analysis by adding relaxed bounds */
6268 SCIP_CALL( analyzeConflictRangedRow(scip, cons, infcheckvars, ninfcheckvars, NULL, SCIP_INVALID) );
6269 }
6270
6271 if( fixed )
6272 ++(*nfixedvars);
6273 }
6274 else
6275 {
6276 /* check for exactly one unfixed variable which is not part of the infcheckvars */
6277 if( ninfcheckvars == nunfixedvars - 1 )
6278 {
6279 SCIP_Real bound;
6280 SCIP_Bool foundvar = FALSE;
6281 SCIP_Bool fixed;
6282 int w = 0;
6283
6284 assert(ninfcheckvars > 0);
6285
6286 /* find variable which is not an infcheckvar and fix it */
6287 for( v = 0; v < consdata->nvars - 1; ++v )
6288 {
6289 if( !SCIPisEQ(scip, SCIPvarGetLbLocal(consdata->vars[v]), SCIPvarGetUbLocal(consdata->vars[v])) )
6290 {
6291 if( w >= ninfcheckvars || consdata->vars[v] != infcheckvars[w] )
6292 {
6293 #ifndef NDEBUG
6294 int v2 = v + 1;
6295 int w2 = w;
6296
6297 assert((nfixedconsvars == 0) ? (consdata->nvars - v - 1 == ninfcheckvars - w) : TRUE);
6298
6299 for( ; v2 < consdata->nvars && w2 < ninfcheckvars; ++v2 )
6300 {
6301 if( SCIPisEQ(scip, SCIPvarGetLbLocal(consdata->vars[v2]), SCIPvarGetUbLocal(consdata->vars[v2])) )
6302 continue;
6303
6304 assert(consdata->vars[v2] == infcheckvars[w2]);
6305 ++w2;
6306 }
6307 assert(w2 == ninfcheckvars);
6308 #endif
6309 assert(SCIPisEQ(scip, (SCIP_Real)gcd, REALABS(consdata->vals[v])));
6310
6311 foundvar = TRUE;
6312
6313 if( consdata->vals[v] < 0 )
6314 {
6315 bound = SCIPfloor(scip, (lhs - maxvalue) / consdata->vals[v]);
6316 }
6317 else
6318 {
6319 bound = SCIPceil(scip, (lhs - maxvalue) / consdata->vals[v]);
6320 }
6321
6322 SCIPdebugMsg(scip, "fixing variable <%s> with bounds [%.15g,%.15g] to %.15g\n",
6323 SCIPvarGetName(consdata->vars[v]), SCIPvarGetLbLocal(consdata->vars[v]),
6324 SCIPvarGetUbLocal(consdata->vars[v]), bound);
6325
6326 /* fix variable to only possible value */
6327 SCIP_CALL( SCIPinferVarFixCons(scip, consdata->vars[v], bound, cons,
6328 getInferInt(PROPRULE_1_RANGEDROW, v), TRUE, cutoff, &fixed) );
6329
6330 if( *cutoff )
6331 {
6332 /* start conflict analysis */
6333 /* @todo improve conflict analysis by adding relaxed bounds */
6334 SCIP_CALL( analyzeConflictRangedRow(scip, cons, infcheckvars, ninfcheckvars,
6335 consdata->vars[v], bound) );
6336 }
6337
6338 if( fixed )
6339 ++(*nfixedvars);
6340
6341 break;
6342 }
6343
6344 ++w;
6345 }
6346 }
6347
6348 /* maybe last variable was the not infcheckvar */
6349 if( !foundvar )
6350 {
6351 assert(v == consdata->nvars - 1);
6352 assert(SCIPisEQ(scip, (SCIP_Real)gcd, REALABS(consdata->vals[v])));
6353
6354 if( consdata->vals[v] < 0 )
6355 {
6356 bound = SCIPfloor(scip, (lhs - maxvalue) / consdata->vals[v]);
6357 }
6358 else
6359 {
6360 bound = SCIPceil(scip, (lhs - maxvalue) / consdata->vals[v]);
6361 }
6362
6363 SCIPdebugMsg(scip, "fixing variable <%s> with bounds [%.15g,%.15g] to %.15g\n",
6364 SCIPvarGetName(consdata->vars[v]), SCIPvarGetLbLocal(consdata->vars[v]),
6365 SCIPvarGetUbLocal(consdata->vars[v]), bound);
6366
6367 /* fix variable to only possible value */
6368 SCIP_CALL( SCIPinferVarFixCons(scip, consdata->vars[v], bound, cons,
6369 getInferInt(PROPRULE_1_RANGEDROW, v), TRUE, cutoff, &fixed) );
6370
6371 if( *cutoff )
6372 {
6373 /* start conflict analysis */
6374 /* @todo improve conflict analysis by adding relaxed bounds */
6375 SCIP_CALL( analyzeConflictRangedRow(scip, cons, infcheckvars, ninfcheckvars,
6376 consdata->vars[v], bound) );
6377 }
6378
6379 if( fixed )
6380 ++(*nfixedvars);
6381 }
6382 }
6383 else if( addartconss && (SCIPisGT(scip, minvalue, minactinfvars) || SCIPisLT(scip, maxvalue, maxactinfvars)) )
6384 {
6385 /* aggregation possible if we have two variables, but this will be done later on */
6386 SCIP_CONS* newcons;
6387 char name[SCIP_MAXSTRLEN];
6388
6389 /* create, add, and release new artificial constraint */
6390 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_artcons_%d", SCIPconsGetName(cons), conshdlrdata->naddconss);
6391 ++conshdlrdata->naddconss;
6392
6393 SCIPdebugMsg(scip, "adding artificial constraint %s\n", name);
6394
6395 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, ninfcheckvars, infcheckvars, infcheckvals,
6396 maxvalue, maxvalue, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE) );
6397 SCIP_CALL( SCIPaddConsLocal(scip, newcons, NULL) );
6398
6399 SCIPdebugPrintCons(scip, newcons, NULL);
6400
6401 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
6402
6403 ++(*naddconss);
6404 }
6405 }
6406 }
6407 /* at least two solutions */
6408 else
6409 {
6410 /* @todo if we found more then one solution, we may reduced domains due to dualpresolving? */
6411
6412 /* only one variable in the second set, so we can bound this variables */
6413 if( ninfcheckvars == 1 )
6414 {
6415 SCIP_Bool tightened;
6416 SCIP_Real newlb;
6417 SCIP_Real newub;
6418
6419 assert(SCIPisEQ(scip, (SCIP_Real)gcdinfvars, REALABS(infcheckvals[0])));
6420
6421 if( infcheckvals[0] < 0 )
6422 {
6423 newlb = maxvalue/infcheckvals[0];
6424 newub = minvalue/infcheckvals[0];
6425 }
6426 else
6427 {
6428 newlb = minvalue/infcheckvals[0];
6429 newub = maxvalue/infcheckvals[0];
6430 }
6431 assert(newlb < newub);
6432
6433 if( newlb > SCIPvarGetLbLocal(infcheckvars[0]) )
6434 {
6435 /* update lower bound of variable */
6436 SCIPdebugMsg(scip, "tightening lower bound of variable <%s> from %g to %g\n",
6437 SCIPvarGetName(infcheckvars[0]), SCIPvarGetLbLocal(infcheckvars[0]), newlb);
6438
6439 /* tighten variable lower bound to minimal possible value */
6440 SCIP_CALL( SCIPinferVarLbCons(scip, infcheckvars[0], newlb, cons,
6441 getInferInt(PROPRULE_1_RANGEDROW, pos), TRUE, cutoff, &tightened) );
6442
6443 if( *cutoff )
6444 {
6445 /* start conflict analysis */
6446 /* @todo improve conflict analysis by adding relaxed bounds */
6447 SCIP_CALL( analyzeConflictRangedRow(scip, cons, infcheckvars, ninfcheckvars, NULL, SCIP_INVALID) );
6448 }
6449
6450 if( tightened )
6451 ++(*nchgbds);
6452 }
6453
6454 if( newub < SCIPvarGetUbLocal(infcheckvars[0]) )
6455 {
6456 /* update upper bound of variable */
6457 SCIPdebugMsg(scip, "tightening upper bound of variable <%s> from %g to %g\n",
6458 SCIPvarGetName(infcheckvars[0]), SCIPvarGetUbLocal(infcheckvars[0]), newub);
6459
6460 /* tighten variable upper bound to maximal possible value */
6461 SCIP_CALL( SCIPinferVarUbCons(scip, infcheckvars[0], newub, cons,
6462 getInferInt(PROPRULE_1_RANGEDROW, pos), TRUE, cutoff, &tightened) );
6463
6464 if( *cutoff )
6465 {
6466 /* start conflict analysis */
6467 /* @todo improve conflict analysis by adding relaxed bounds */
6468 SCIP_CALL( analyzeConflictRangedRow(scip, cons, infcheckvars, ninfcheckvars, NULL, SCIP_INVALID) );
6469 }
6470
6471 if( tightened )
6472 ++(*nchgbds);
6473 }
6474 }
6475 /* check if we have only one not infcheckvars, if so we can tighten this variable */
6476 else if( ninfcheckvars == nunfixedvars - 1 )
6477 {
6478 SCIP_Bool foundvar = FALSE;
6479 SCIP_Bool tightened;
6480 SCIP_Real newlb;
6481 SCIP_Real newub;
6482 int w = 0;
6483
6484 assert(ninfcheckvars > 0);
6485 assert(minvalue < maxvalue);
6486
6487 /* find variable which is not an infcheckvar and fix it */
6488 for( v = 0; v < consdata->nvars - 1; ++v )
6489 {
6490 if( !SCIPisEQ(scip, SCIPvarGetLbLocal(consdata->vars[v]), SCIPvarGetUbLocal(consdata->vars[v])) )
6491 {
6492 if( w >= ninfcheckvars || consdata->vars[v] != infcheckvars[w] )
6493 {
6494 #ifndef NDEBUG
6495 int v2 = v + 1;
6496 int w2 = w;
6497
6498 assert((nfixedconsvars == 0) ? (consdata->nvars - v - 1 == ninfcheckvars - w) : TRUE);
6499
6500 for( ; v2 < consdata->nvars && w2 < ninfcheckvars; ++v2 )
6501 {
6502 if( SCIPisEQ(scip, SCIPvarGetLbLocal(consdata->vars[v2]), SCIPvarGetUbLocal(consdata->vars[v2])) )
6503 continue;
6504
6505 assert(consdata->vars[v2] == infcheckvars[w2]);
6506 ++w2;
6507 }
6508 assert(w2 == ninfcheckvars);
6509 #endif
6510
6511 assert(SCIPisEQ(scip, (SCIP_Real)gcd, REALABS(consdata->vals[v])));
6512 foundvar = TRUE;
6513
6514 if( consdata->vals[v] < 0 )
6515 {
6516 newlb = SCIPfloor(scip, (rhs - minvalue) / consdata->vals[v]);
6517 newub = SCIPfloor(scip, (lhs - maxvalue) / consdata->vals[v]);
6518 }
6519 else
6520 {
6521 newlb = SCIPceil(scip, (lhs - maxvalue) / consdata->vals[v]);
6522 newub = SCIPceil(scip, (rhs - minvalue) / consdata->vals[v]);
6523 }
6524 assert(SCIPisLE(scip, newlb, newub));
6525
6526 if( newlb > SCIPvarGetLbLocal(consdata->vars[v]) )
6527 {
6528 /* update lower bound of variable */
6529 SCIPdebugMsg(scip, "tightening lower bound of variable <%s> from %g to %g\n",
6530 SCIPvarGetName(consdata->vars[v]), SCIPvarGetLbLocal(consdata->vars[v]), newlb);
6531
6532 /* tighten variable lower bound to minimal possible value */
6533 SCIP_CALL( SCIPinferVarLbCons(scip, consdata->vars[v], newlb, cons,
6534 getInferInt(PROPRULE_1_RANGEDROW, v), TRUE, cutoff, &tightened) );
6535
6536 if( *cutoff )
6537 {
6538 /* start conflict analysis */
6539 /* @todo improve conflict analysis by adding relaxed bounds */
6540 SCIP_CALL( analyzeConflictRangedRow(scip, cons, infcheckvars, ninfcheckvars,
6541 consdata->vars[v], newlb) );
6542 }
6543
6544 if( tightened )
6545 ++(*nchgbds);
6546 }
6547
6548 if( newub < SCIPvarGetUbLocal(consdata->vars[v]) )
6549 {
6550 /* update upper bound of variable */
6551 SCIPdebugMsg(scip, "tightening upper bound of variable <%s> from %g to %g\n",
6552 SCIPvarGetName(consdata->vars[v]), SCIPvarGetUbLocal(consdata->vars[v]), newub);
6553
6554 /* tighten variable upper bound to maximal possible value */
6555 SCIP_CALL( SCIPinferVarUbCons(scip, consdata->vars[v], newub, cons,
6556 getInferInt(PROPRULE_1_RANGEDROW, v), TRUE, cutoff, &tightened) );
6557
6558 if( *cutoff )
6559 {
6560 /* start conflict analysis */
6561 /* @todo improve conflict analysis by adding relaxed bounds */
6562 SCIP_CALL( analyzeConflictRangedRow(scip, cons, infcheckvars, ninfcheckvars,
6563 consdata->vars[v], newub) );
6564 }
6565
6566 if( tightened )
6567 ++(*nchgbds);
6568 }
6569
6570 break;
6571 }
6572
6573 ++w;
6574 }
6575 }
6576
6577 /* maybe last variable was the not infcheckvar */
6578 if( !foundvar )
6579 {
6580 assert(v == consdata->nvars - 1);
6581 assert(SCIPisEQ(scip, (SCIP_Real)gcd, REALABS(consdata->vals[v])));
6582
6583 if( consdata->vals[v] < 0 )
6584 {
6585 newlb = SCIPfloor(scip, (rhs - minvalue) / consdata->vals[v]);
6586 newub = SCIPfloor(scip, (lhs - maxvalue) / consdata->vals[v]);
6587 }
6588 else
6589 {
6590 newlb = SCIPceil(scip, (lhs - maxvalue) / consdata->vals[v]);
6591 newub = SCIPceil(scip, (rhs - minvalue) / consdata->vals[v]);
6592 }
6593 assert(SCIPisLE(scip, newlb, newub));
6594
6595 if( newlb > SCIPvarGetLbLocal(consdata->vars[v]) )
6596 {
6597 /* update lower bound of variable */
6598 SCIPdebugMsg(scip, "tightening lower bound of variable <%s> from %g to %g\n",
6599 SCIPvarGetName(consdata->vars[v]), SCIPvarGetLbLocal(consdata->vars[v]), newlb);
6600
6601 /* tighten variable lower bound to minimal possible value */
6602 SCIP_CALL( SCIPinferVarLbCons(scip, consdata->vars[v], newlb, cons,
6603 getInferInt(PROPRULE_1_RANGEDROW, v), TRUE, cutoff, &tightened) );
6604
6605 if( *cutoff )
6606 {
6607 /* start conflict analysis */
6608 /* @todo improve conflict analysis by adding relaxed bounds */
6609 SCIP_CALL( analyzeConflictRangedRow(scip, cons, infcheckvars, ninfcheckvars, consdata->vars[v], newlb) );
6610 }
6611
6612 if( tightened )
6613 ++(*nchgbds);
6614 }
6615
6616 if( newub < SCIPvarGetUbLocal(consdata->vars[v]) )
6617 {
6618 /* update upper bound of variable */
6619 SCIPdebugMsg(scip, "tightening upper bound of variable <%s> from %g to %g\n",
6620 SCIPvarGetName(consdata->vars[v]), SCIPvarGetUbLocal(consdata->vars[v]), newub);
6621
6622 /* tighten variable upper bound to maximal possible value */
6623 SCIP_CALL( SCIPinferVarUbCons(scip, consdata->vars[v], newub, cons,
6624 getInferInt(PROPRULE_1_RANGEDROW, v), TRUE, cutoff, &tightened) );
6625
6626 if( *cutoff )
6627 {
6628 /* start conflict analysis */
6629 /* @todo improve conflict analysis by adding relaxed bounds */
6630 SCIP_CALL( analyzeConflictRangedRow(scip, cons, infcheckvars, ninfcheckvars, consdata->vars[v], newub) );
6631 }
6632
6633 if( tightened )
6634 ++(*nchgbds);
6635 }
6636 }
6637 }
6638 /* at least two solutions and more than one variable, so we add a new constraint which bounds the feasible
6639 * region for our infcheckvars, if possible
6640 */
6641 else if( addartconss && (SCIPisGT(scip, minvalue, minactinfvars) || SCIPisLT(scip, maxvalue, maxactinfvars)) )
6642 {
6643 SCIP_CONS* newcons;
6644 char name[SCIP_MAXSTRLEN];
6645 SCIP_Real newlhs;
6646 SCIP_Real newrhs;
6647
6648 assert(maxvalue > minvalue);
6649
6650 if( SCIPisGT(scip, minvalue, minactinfvars) )
6651 newlhs = minvalue;
6652 else
6653 newlhs = -SCIPinfinity(scip);
6654
6655 if( SCIPisLT(scip, maxvalue, maxactinfvars) )
6656 newrhs = maxvalue;
6657 else
6658 newrhs = SCIPinfinity(scip);
6659
6660 if( !SCIPisInfinity(scip, -newlhs) || !SCIPisInfinity(scip, newrhs) )
6661 {
6662 /* create, add, and release new artificial constraint */
6663 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_artcons1_%d", SCIPconsGetName(cons), conshdlrdata->naddconss);
6664 ++conshdlrdata->naddconss;
6665
6666 SCIPdebugMsg(scip, "adding artificial constraint %s\n", name);
6667
6668 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, ninfcheckvars, infcheckvars, infcheckvals, newlhs, newrhs,
6669 TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE) );
6670 SCIP_CALL( SCIPaddConsLocal(scip, newcons, NULL) );
6671
6672 SCIPdebugPrintCons(scip, newcons, NULL);
6673 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
6674
6675 ++(*naddconss);
6676 }
6677 /* @todo maybe add constraint for all variables which are not infcheckvars, lhs should be minvalue, rhs
6678 * should be maxvalue */
6679 }
6680 }
6681 }
6682 }
6683 else if( addartconss && ncontvars < ninfcheckvars )
6684 {
6685 SCIP_Real maxact = 0.0;
6686 SCIP_Real minact = 0.0;
6687 int w = 0;
6688
6689 /* compute activities of non-infcheckvars */
6690 for( v = 0; v < consdata->nvars; ++v )
6691 {
6692 if( w < ninfcheckvars && consdata->vars[v] == infcheckvars[w] )
6693 {
6694 ++w;
6695 continue;
6696 }
6697
6698 if( !SCIPisEQ(scip, SCIPvarGetLbLocal(consdata->vars[v]), SCIPvarGetUbLocal(consdata->vars[v])) )
6699 {
6700 if( SCIPvarIsBinary(consdata->vars[v]) )
6701 {
6702 if( consdata->vals[v] > 0.0 )
6703 maxact += consdata->vals[v];
6704 else
6705 minact += consdata->vals[v];
6706 }
6707 else
6708 {
6709 SCIP_Real tmpval;
6710
6711 assert(SCIPvarIsIntegral(consdata->vars[v]));
6712
6713 if( consdata->vals[v] > 0.0 )
6714 {
6715 tmpval = consdata->vals[v] * SCIPvarGetLbLocal(consdata->vars[v]);
6716
6717 if( SCIPisHugeValue(scip, -tmpval) )
6718 break;
6719
6720 minact += tmpval;
6721
6722 tmpval = consdata->vals[v] * SCIPvarGetUbLocal(consdata->vars[v]);
6723
6724 if( SCIPisHugeValue(scip, tmpval) )
6725 break;
6726
6727 maxact += tmpval;
6728 }
6729 else
6730 {
6731 tmpval = consdata->vals[v] * SCIPvarGetUbLocal(consdata->vars[v]);
6732
6733 if( SCIPisHugeValue(scip, -tmpval) )
6734 break;
6735
6736 minact += tmpval;
6737
6738 tmpval = consdata->vals[v] * SCIPvarGetLbLocal(consdata->vars[v]);
6739
6740 if( SCIPisHugeValue(scip, tmpval) )
6741 break;
6742
6743 maxact += tmpval;
6744 }
6745 }
6746 }
6747 }
6748 if( v == consdata->nvars && !SCIPisHugeValue(scip, -minact) && !SCIPisHugeValue(scip, maxact) )
6749 {
6750 SCIP_CONS* newcons;
6751 char name[SCIP_MAXSTRLEN];
6752 SCIP_Real newlhs;
6753 SCIP_Real newrhs;
6754
6755 assert(maxact > minact);
6756 assert(w == ninfcheckvars);
6757
6758 newlhs = lhs - maxact;
6759 newrhs = rhs - minact;
6760 assert(newlhs < newrhs);
6761
6762 /* create, add, and release new artificial constraint */
6763 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_artcons2_%d", SCIPconsGetName(cons), conshdlrdata->naddconss);
6764 ++conshdlrdata->naddconss;
6765
6766 SCIPdebugMsg(scip, "adding artificial constraint %s\n", name);
6767
6768 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, ninfcheckvars, infcheckvars, infcheckvals, newlhs, newrhs,
6769 TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE) );
6770 SCIP_CALL( SCIPaddConsLocal(scip, newcons, NULL) );
6771
6772 SCIPdebugPrintCons(scip, newcons, NULL);
6773 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
6774
6775 ++(*naddconss);
6776 }
6777 }
6778
6779 TERMINATE:
6780 SCIPfreeBufferArray(scip, &infcheckvals);
6781 SCIPfreeBufferArray(scip, &infcheckvars);
6782
6783 return SCIP_OKAY;
6784 }
6785
6786 /** tightens bounds of a single variable due to activity bounds */
6787 static
tightenVarBounds(SCIP * scip,SCIP_CONS * cons,int pos,SCIP_Bool * cutoff,int * nchgbds,SCIP_Bool force)6788 SCIP_RETCODE tightenVarBounds(
6789 SCIP* scip, /**< SCIP data structure */
6790 SCIP_CONS* cons, /**< linear constraint */
6791 int pos, /**< position of the variable in the vars array */
6792 SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
6793 int* nchgbds, /**< pointer to count the total number of tightened bounds */
6794 SCIP_Bool force /**< should a possible bound change be forced even if below bound strengthening tolerance */
6795 )
6796 {
6797 SCIP_CONSDATA* consdata;
6798 SCIP_VAR* var;
6799 SCIP_Real val;
6800 SCIP_Real lb;
6801 SCIP_Real ub;
6802 SCIP_Real minresactivity;
6803 SCIP_Real maxresactivity;
6804 SCIP_Real lhs;
6805 SCIP_Real rhs;
6806 SCIP_Bool infeasible;
6807 SCIP_Bool tightened;
6808 SCIP_Bool minisrelax;
6809 SCIP_Bool maxisrelax;
6810 SCIP_Bool isminsettoinfinity;
6811 SCIP_Bool ismaxsettoinfinity;
6812
6813 assert(scip != NULL);
6814 assert(cons != NULL);
6815 assert(cutoff != NULL);
6816 assert(nchgbds != NULL);
6817
6818 /* we cannot tighten variables' bounds, if the constraint may be not complete */
6819 if( SCIPconsIsModifiable(cons) )
6820 return SCIP_OKAY;
6821
6822 consdata = SCIPconsGetData(cons);
6823 assert(consdata != NULL);
6824 assert(0 <= pos && pos < consdata->nvars);
6825
6826 *cutoff = FALSE;
6827
6828 var = consdata->vars[pos];
6829
6830 /* we cannot tighten bounds of multi-aggregated variables */
6831 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR )
6832 return SCIP_OKAY;
6833
6834 val = consdata->vals[pos];
6835 lhs = consdata->lhs;
6836 rhs = consdata->rhs;
6837 consdataGetActivityResiduals(scip, consdata, var, val, FALSE, &minresactivity, &maxresactivity,
6838 &minisrelax, &maxisrelax, &isminsettoinfinity, &ismaxsettoinfinity);
6839 assert(var != NULL);
6840 assert(!SCIPisZero(scip, val));
6841 assert(!SCIPisInfinity(scip, lhs));
6842 assert(!SCIPisInfinity(scip, -rhs));
6843
6844 lb = SCIPvarGetLbLocal(var);
6845 ub = SCIPvarGetUbLocal(var);
6846 assert(SCIPisLE(scip, lb, ub));
6847
6848 if( val > 0.0 )
6849 {
6850 /* check, if we can tighten the variable's bounds */
6851 if( !isminsettoinfinity && !SCIPisInfinity(scip, rhs) && !minisrelax )
6852 {
6853 SCIP_Real newub;
6854
6855 newub = (rhs - minresactivity)/val;
6856
6857 if( !SCIPisInfinity(scip, newub) &&
6858 ((force && SCIPisLT(scip, newub, ub)) || (SCIPvarIsIntegral(var) && SCIPisFeasLT(scip, newub, ub)) || SCIPisUbBetter(scip, newub, lb, ub)) )
6859 {
6860 SCIP_Bool activityunreliable;
6861 activityunreliable = SCIPisUpdateUnreliable(scip, minresactivity, consdata->lastminactivity);
6862
6863 /* check minresactivities for reliability */
6864 if( activityunreliable )
6865 {
6866 consdataGetReliableResidualActivity(scip, consdata, var, &minresactivity, TRUE, FALSE);
6867 newub = (rhs - minresactivity)/val;
6868 activityunreliable = SCIPisInfinity(scip, -minresactivity) ||
6869 (!SCIPisUbBetter(scip, newub, lb, ub) && (!SCIPisFeasLT(scip, newub, ub) || !SCIPvarIsIntegral(var))
6870 && (!force || !SCIPisLT(scip, newub, ub)));
6871 }
6872
6873 if( !activityunreliable )
6874 {
6875 /* tighten upper bound */
6876 SCIPdebugMsg(scip, "linear constraint <%s>: tighten <%s>, old bds=[%.15g,%.15g], val=%.15g, resactivity=[%.15g,%.15g], sides=[%.15g,%.15g] -> newub=%.15g\n",
6877 SCIPconsGetName(cons), SCIPvarGetName(var), lb, ub, val, minresactivity, maxresactivity, lhs, rhs, newub);
6878 SCIP_CALL( SCIPinferVarUbCons(scip, var, newub, cons, getInferInt(PROPRULE_1_RHS, pos), force,
6879 &infeasible, &tightened) );
6880 if( infeasible )
6881 {
6882 SCIPdebugMsg(scip, "linear constraint <%s>: cutoff <%s>, new bds=[%.15g,%.15g]\n",
6883 SCIPconsGetName(cons), SCIPvarGetName(var), lb, newub);
6884
6885 /* analyze conflict */
6886 SCIP_CALL( analyzeConflict(scip, cons, TRUE) );
6887
6888 *cutoff = TRUE;
6889 return SCIP_OKAY;
6890 }
6891 if( tightened )
6892 {
6893 ub = SCIPvarGetUbLocal(var); /* get bound again: it may be additionally modified due to integrality */
6894 assert(SCIPisFeasLE(scip, ub, newub));
6895 (*nchgbds)++;
6896
6897 SCIPdebugMsg(scip, "linear constraint <%s>: tighten <%s>, new bds=[%.15g,%.15g]\n",
6898 SCIPconsGetName(cons), SCIPvarGetName(var), lb, ub);
6899 }
6900 }
6901 }
6902 }
6903
6904 if( !ismaxsettoinfinity && !SCIPisInfinity(scip, -lhs) && !maxisrelax )
6905 {
6906 SCIP_Real newlb;
6907
6908 newlb = (lhs - maxresactivity)/val;
6909 if( !SCIPisInfinity(scip, -newlb) &&
6910 ((force && SCIPisGT(scip, newlb, lb)) || (SCIPvarIsIntegral(var) && SCIPisFeasGT(scip, newlb, lb)) || SCIPisLbBetter(scip, newlb, lb, ub)) )
6911 {
6912 /* check maxresactivities for reliability */
6913 if( SCIPisUpdateUnreliable(scip, maxresactivity, consdata->lastmaxactivity) )
6914 {
6915 consdataGetReliableResidualActivity(scip, consdata, var, &maxresactivity, FALSE, FALSE);
6916 newlb = (lhs - maxresactivity)/val;
6917
6918 if( SCIPisInfinity(scip, maxresactivity) || (!SCIPisLbBetter(scip, newlb, lb, ub)
6919 && (!SCIPisFeasGT(scip, newlb, lb) || !SCIPvarIsIntegral(var))
6920 && (!force || !SCIPisGT(scip, newlb, lb))) )
6921 return SCIP_OKAY;
6922 }
6923
6924 /* tighten lower bound */
6925 SCIPdebugMsg(scip, "linear constraint <%s>: tighten <%s>, old bds=[%.15g,%.15g], val=%.15g, resactivity=[%.15g,%.15g], sides=[%.15g,%.15g] -> newlb=%.15g\n",
6926 SCIPconsGetName(cons), SCIPvarGetName(var), lb, ub, val, minresactivity, maxresactivity, lhs, rhs, newlb);
6927 SCIP_CALL( SCIPinferVarLbCons(scip, var, newlb, cons, getInferInt(PROPRULE_1_LHS, pos), force,
6928 &infeasible, &tightened) );
6929 if( infeasible )
6930 {
6931 SCIPdebugMsg(scip, "linear constraint <%s>: cutoff <%s>, new bds=[%.15g,%.15g]\n",
6932 SCIPconsGetName(cons), SCIPvarGetName(var), newlb, ub);
6933
6934 /* analyze conflict */
6935 SCIP_CALL( analyzeConflict(scip, cons, FALSE) );
6936
6937 *cutoff = TRUE;
6938 return SCIP_OKAY;
6939 }
6940 if( tightened )
6941 {
6942 lb = SCIPvarGetLbLocal(var); /* get bound again: it may be additionally modified due to integrality */
6943 assert(SCIPisFeasGE(scip, lb, newlb));
6944 (*nchgbds)++;
6945 SCIPdebugMsg(scip, "linear constraint <%s>: tighten <%s>, new bds=[%.15g,%.15g]\n",
6946 SCIPconsGetName(cons), SCIPvarGetName(var), lb, ub);
6947 }
6948 }
6949 }
6950 }
6951 else
6952 {
6953 /* check, if we can tighten the variable's bounds */
6954 if( !isminsettoinfinity && !SCIPisInfinity(scip, rhs) && !minisrelax )
6955 {
6956 SCIP_Real newlb;
6957
6958 newlb = (rhs - minresactivity)/val;
6959 if( !SCIPisInfinity(scip, -newlb) &&
6960 ((force && SCIPisGT(scip, newlb, lb)) || (SCIPvarIsIntegral(var) && SCIPisFeasGT(scip, newlb, lb)) || SCIPisLbBetter(scip, newlb, lb, ub)) )
6961 {
6962 SCIP_Bool activityunreliable;
6963 activityunreliable = SCIPisUpdateUnreliable(scip, minresactivity, consdata->lastminactivity);
6964 /* check minresactivities for reliability */
6965 if( activityunreliable )
6966 {
6967 consdataGetReliableResidualActivity(scip, consdata, var, &minresactivity, TRUE, FALSE);
6968 newlb = (rhs - minresactivity)/val;
6969
6970 activityunreliable = SCIPisInfinity(scip, -minresactivity)
6971 || (!SCIPisLbBetter(scip, newlb, lb, ub) && (!SCIPisFeasGT(scip, newlb, lb) || !SCIPvarIsIntegral(var))
6972 && (!force || !SCIPisGT(scip, newlb, lb)));
6973 }
6974
6975 if( !activityunreliable )
6976 {
6977 /* tighten lower bound */
6978 SCIPdebugMsg(scip, "linear constraint <%s>: tighten <%s>, old bds=[%.15g,%.15g], val=%.15g, resactivity=[%.15g,%.15g], sides=[%.15g,%.15g] -> newlb=%.15g\n",
6979 SCIPconsGetName(cons), SCIPvarGetName(var), lb, ub, val, minresactivity, maxresactivity, lhs, rhs, newlb);
6980 SCIP_CALL( SCIPinferVarLbCons(scip, var, newlb, cons, getInferInt(PROPRULE_1_RHS, pos), force,
6981 &infeasible, &tightened) );
6982 if( infeasible )
6983 {
6984 SCIPdebugMsg(scip, "linear constraint <%s>: cutoff <%s>, new bds=[%.15g,%.15g]\n",
6985 SCIPconsGetName(cons), SCIPvarGetName(var), newlb, ub);
6986
6987 /* analyze conflict */
6988 SCIP_CALL( analyzeConflict(scip, cons, TRUE) );
6989
6990 *cutoff = TRUE;
6991 return SCIP_OKAY;
6992 }
6993 if( tightened )
6994 {
6995 lb = SCIPvarGetLbLocal(var); /* get bound again: it may be additionally modified due to integrality */
6996 assert(SCIPisFeasGE(scip, lb, newlb));
6997 (*nchgbds)++;
6998 SCIPdebugMsg(scip, "linear constraint <%s>: tighten <%s>, new bds=[%.15g,%.15g]\n",
6999 SCIPconsGetName(cons), SCIPvarGetName(var), lb, ub);
7000 }
7001 }
7002 }
7003 }
7004
7005 if( !ismaxsettoinfinity && !SCIPisInfinity(scip, -lhs) && !maxisrelax )
7006 {
7007 SCIP_Real newub;
7008
7009 newub = (lhs - maxresactivity)/val;
7010 if( !SCIPisInfinity(scip, newub) &&
7011 ((force && SCIPisLT(scip, newub, ub)) || (SCIPvarIsIntegral(var) && SCIPisFeasLT(scip, newub, ub)) || SCIPisUbBetter(scip, newub, lb, ub)) )
7012 {
7013 /* check maxresactivities for reliability */
7014 if( SCIPisUpdateUnreliable(scip, maxresactivity, consdata->lastmaxactivity) )
7015 {
7016 consdataGetReliableResidualActivity(scip, consdata, var, &maxresactivity, FALSE, FALSE);
7017 newub = (lhs - maxresactivity)/val;
7018
7019 if( SCIPisInfinity(scip, maxresactivity) || (!SCIPisUbBetter(scip, newub, lb, ub)
7020 && (!SCIPisFeasLT(scip, newub, ub) && !SCIPvarIsIntegral(var))
7021 && (!force || !SCIPisLT(scip, newub, ub))) )
7022 return SCIP_OKAY;
7023 }
7024
7025 /* tighten upper bound */
7026 SCIPdebugMsg(scip, "linear constraint <%s>: tighten <%s>, old bds=[%.15g,%.15g], val=%.15g, resactivity=[%.15g,%.15g], sides=[%.15g,%.15g], newub=%.15g\n",
7027 SCIPconsGetName(cons), SCIPvarGetName(var), lb, ub, val, minresactivity, maxresactivity, lhs, rhs, newub);
7028 SCIP_CALL( SCIPinferVarUbCons(scip, var, newub, cons, getInferInt(PROPRULE_1_LHS, pos), force,
7029 &infeasible, &tightened) );
7030 if( infeasible )
7031 {
7032 SCIPdebugMsg(scip, "linear constraint <%s>: cutoff <%s>, new bds=[%.15g,%.15g]\n",
7033 SCIPconsGetName(cons), SCIPvarGetName(var), lb, newub);
7034
7035 /* analyze conflict */
7036 SCIP_CALL( analyzeConflict(scip, cons, FALSE) );
7037
7038 *cutoff = TRUE;
7039 return SCIP_OKAY;
7040 }
7041 if( tightened )
7042 {
7043 ub = SCIPvarGetUbLocal(var); /* get bound again: it may be additionally modified due to integrality */
7044 assert(SCIPisFeasLE(scip, ub, newub));
7045 (*nchgbds)++;
7046 SCIPdebugMsg(scip, "linear constraint <%s>: tighten <%s>, new bds=[%.15g,%.15g]\n",
7047 SCIPconsGetName(cons), SCIPvarGetName(var), lb, ub);
7048 }
7049 }
7050 }
7051 }
7052
7053 return SCIP_OKAY;
7054 }
7055
7056 #define MAXTIGHTENROUNDS 10
7057
7058 /** tightens bounds of variables in constraint due to activity bounds */
7059 static
tightenBounds(SCIP * scip,SCIP_CONS * cons,SCIP_Real maxeasyactivitydelta,SCIP_Bool sortvars,SCIP_Bool * cutoff,int * nchgbds)7060 SCIP_RETCODE tightenBounds(
7061 SCIP* scip, /**< SCIP data structure */
7062 SCIP_CONS* cons, /**< linear constraint */
7063 SCIP_Real maxeasyactivitydelta,/**< maximum activity delta to run easy propagation on linear constraint */
7064 SCIP_Bool sortvars, /**< should variables be used in sorted order? */
7065 SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
7066 int* nchgbds /**< pointer to count the total number of tightened bounds */
7067 )
7068 {
7069 SCIP_CONSDATA* consdata;
7070 unsigned int tightenmode;
7071 int nvars;
7072 int nrounds;
7073 int lastchange;
7074 int oldnchgbds;
7075 #ifndef SCIP_DEBUG
7076 int oldnchgbdstotal;
7077 #endif
7078 int v;
7079 SCIP_Bool force;
7080 SCIP_Bool easycase;
7081
7082 assert(scip != NULL);
7083 assert(cons != NULL);
7084 assert(nchgbds != NULL);
7085 assert(cutoff != NULL);
7086
7087 *cutoff = FALSE;
7088
7089 /* we cannot tighten variables' bounds, if the constraint may be not complete */
7090 if( SCIPconsIsModifiable(cons) )
7091 return SCIP_OKAY;
7092
7093 /* if a constraint was created after presolve, then it may hold fixed variables
7094 * if there are even multi-aggregated variables, then we cannot do bound tightening on these
7095 * thus, ensure here again that variable fixings have been applied
7096 */
7097 SCIP_CALL( applyFixings(scip, cons, cutoff) );
7098 if( *cutoff )
7099 return SCIP_OKAY;
7100
7101 /* check if constraint has any chances of tightening bounds */
7102 if( !canTightenBounds(cons) )
7103 return SCIP_OKAY;
7104
7105 consdata = SCIPconsGetData(cons);
7106 assert(consdata != NULL);
7107
7108 nvars = consdata->nvars;
7109 force = (nvars == 1) && !SCIPconsIsModifiable(cons);
7110
7111 /* we are at the root node or during presolving */
7112 if( SCIPgetDepth(scip) < 1 )
7113 tightenmode = 2;
7114 else
7115 tightenmode = 1;
7116
7117 /* stop if we already tightened the constraint and the tightening is not forced */
7118 if( !force && (consdata->boundstightened >= tightenmode) ) /*lint !e574*/
7119 return SCIP_OKAY;
7120
7121 /* ensure that the variables are properly sorted */
7122 if( sortvars && SCIPgetStage(scip) >= SCIP_STAGE_INITSOLVE && !consdata->coefsorted )
7123 {
7124 SCIP_CALL( consdataSort(scip, consdata) );
7125 assert(consdata->coefsorted);
7126 }
7127
7128 /* update maximal activity delta if necessary */
7129 if( consdata->maxactdelta == SCIP_INVALID ) /*lint !e777*/
7130 consdataRecomputeMaxActivityDelta(scip, consdata);
7131
7132 assert(consdata->maxactdelta != SCIP_INVALID); /*lint !e777*/
7133 assert(!SCIPisFeasNegative(scip, consdata->maxactdelta));
7134 checkMaxActivityDelta(scip, consdata);
7135
7136 /* this may happen if all variables are fixed */
7137 if( SCIPisFeasZero(scip, consdata->maxactdelta) )
7138 return SCIP_OKAY;
7139
7140 if( !SCIPisInfinity(scip, consdata->maxactdelta) )
7141 {
7142 SCIP_Real slack;
7143 SCIP_Real surplus;
7144 SCIP_Real minactivity;
7145 SCIP_Real maxactivity;
7146 SCIP_Bool minisrelax;
7147 SCIP_Bool maxisrelax;
7148 SCIP_Bool isminsettoinfinity;
7149 SCIP_Bool ismaxsettoinfinity;
7150
7151 /* use maximal activity delta to skip propagation (cannot deduce anything) */
7152 consdataGetActivityBounds(scip, consdata, FALSE, &minactivity, &maxactivity, &minisrelax, &maxisrelax,
7153 &isminsettoinfinity, &ismaxsettoinfinity);
7154 assert(!SCIPisInfinity(scip, minactivity));
7155 assert(!SCIPisInfinity(scip, -maxactivity));
7156
7157 slack = (SCIPisInfinity(scip, consdata->rhs) || isminsettoinfinity) ? SCIPinfinity(scip) : (consdata->rhs - minactivity);
7158 surplus = (SCIPisInfinity(scip, -consdata->lhs) || ismaxsettoinfinity) ? SCIPinfinity(scip) : (maxactivity - consdata->lhs);
7159
7160 /* check if the constraint will propagate */
7161 if( SCIPisLE(scip, consdata->maxactdelta, MIN(slack, surplus)) )
7162 return SCIP_OKAY;
7163 }
7164
7165 /* check if we can use fast implementation for easy and numerically well behaved cases */
7166 easycase = SCIPisLT(scip, consdata->maxactdelta, maxeasyactivitydelta);
7167
7168 /* as long as the bounds might be tightened again, try to tighten them; abort after a maximal number of rounds */
7169 lastchange = -1;
7170 oldnchgbds = 0;
7171
7172 #ifndef SCIP_DEBUG
7173 oldnchgbdstotal = *nchgbds;
7174 #endif
7175
7176 for( nrounds = 0; (force || consdata->boundstightened < tightenmode) && nrounds < MAXTIGHTENROUNDS; ++nrounds ) /*lint !e574*/
7177 {
7178 /* ensure that the variables are properly sorted
7179 *
7180 * note: it might happen that integer variables become binary during bound tightening at the root node
7181 */
7182 if( sortvars && SCIPgetStage(scip) >= SCIP_STAGE_INITSOLVE && !consdata->coefsorted )
7183 {
7184 SCIP_CALL( consdataSort(scip, consdata) );
7185 assert(consdata->coefsorted);
7186 }
7187
7188 /* mark the constraint to have the variables' bounds tightened */
7189 consdata->boundstightened = (unsigned int)tightenmode;
7190
7191 /* try to tighten the bounds of each variable in the constraint. During solving process, the binary variable
7192 * sorting enables skipping variables
7193 */
7194 v = 0;
7195 while( v < nvars && v != lastchange && !(*cutoff) )
7196 {
7197 oldnchgbds = *nchgbds;
7198
7199 if( easycase )
7200 {
7201 SCIP_CALL( tightenVarBoundsEasy(scip, cons, v, cutoff, nchgbds, force) );
7202 }
7203 else
7204 {
7205 SCIP_CALL( tightenVarBounds(scip, cons, v, cutoff, nchgbds, force) );
7206 }
7207
7208 /* if there was no progress, skip the rest of the binary variables */
7209 if( *nchgbds > oldnchgbds )
7210 {
7211 lastchange = v;
7212 ++v;
7213 }
7214 else if( consdata->coefsorted && v < consdata->nbinvars - 1
7215 && !SCIPisFeasEQ(scip, SCIPvarGetUbLocal(consdata->vars[v]), SCIPvarGetLbLocal(consdata->vars[v])) )
7216 v = consdata->nbinvars;
7217 else
7218 ++v;
7219 }
7220
7221 #ifndef SCIP_DEBUG
7222 SCIPdebugMessage("linear constraint <%s> found %d bound changes in round %d\n", SCIPconsGetName(cons),
7223 *nchgbds - oldnchgbdstotal, nrounds);
7224 oldnchgbdstotal += oldnchgbds;
7225 #endif
7226 }
7227
7228 #ifndef NDEBUG
7229 if( force && SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
7230 assert(*cutoff || SCIPisFeasEQ(scip, SCIPvarGetLbLocal(consdata->vars[0]), SCIPvarGetUbLocal(consdata->vars[0])));
7231 #endif
7232
7233 return SCIP_OKAY;
7234 }
7235
7236 /** checks linear constraint for feasibility of given solution or current solution */
7237 static
checkCons(SCIP * scip,SCIP_CONS * cons,SCIP_SOL * sol,SCIP_Bool checklprows,SCIP_Bool checkrelmaxabs,SCIP_Bool * violated)7238 SCIP_RETCODE checkCons(
7239 SCIP* scip, /**< SCIP data structure */
7240 SCIP_CONS* cons, /**< linear constraint */
7241 SCIP_SOL* sol, /**< solution to be checked, or NULL for current solution */
7242 SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */
7243 SCIP_Bool checkrelmaxabs, /**< Should the violation for a constraint with side 0.0 be checked relative
7244 * to 1.0 (FALSE) or to the maximum absolute value in the activity (TRUE)? */
7245 SCIP_Bool* violated /**< pointer to store whether the constraint is violated */
7246 )
7247 {
7248 SCIP_CONSDATA* consdata;
7249 SCIP_Real activity;
7250 SCIP_Real absviol;
7251 SCIP_Real relviol;
7252 SCIP_Real lhsviol;
7253 SCIP_Real rhsviol;
7254
7255 assert(scip != NULL);
7256 assert(cons != NULL);
7257 assert(violated != NULL);
7258
7259 SCIPdebugMsg(scip, "checking linear constraint <%s>\n", SCIPconsGetName(cons));
7260 SCIPdebugPrintCons(scip, cons, NULL);
7261
7262 consdata = SCIPconsGetData(cons);
7263 assert(consdata != NULL);
7264
7265 *violated = FALSE;
7266
7267 if( consdata->row != NULL )
7268 {
7269 if( !checklprows && SCIProwIsInLP(consdata->row) )
7270 return SCIP_OKAY;
7271 else if( sol == NULL && !SCIPhasCurrentNodeLP(scip) )
7272 activity = consdataComputePseudoActivity(scip, consdata);
7273 else
7274 activity = SCIPgetRowSolActivity(scip, consdata->row, sol);
7275 }
7276 else
7277 activity = consdataGetActivity(scip, consdata, sol);
7278
7279 SCIPdebugMsg(scip, " consdata activity=%.15g (lhs=%.15g, rhs=%.15g, row=%p, checklprows=%u, rowinlp=%u, sol=%p, hascurrentnodelp=%u)\n",
7280 activity, consdata->lhs, consdata->rhs, (void*)consdata->row, checklprows,
7281 consdata->row == NULL ? 0 : SCIProwIsInLP(consdata->row), (void*)sol,
7282 consdata->row == NULL ? FALSE : SCIPhasCurrentNodeLP(scip));
7283
7284 /* calculate absolute and relative bound violations */
7285 lhsviol = consdata->lhs - activity;
7286 rhsviol = activity - consdata->rhs;
7287
7288 absviol = 0.0;
7289 relviol = 0.0;
7290 if( (lhsviol > 0) && (lhsviol > rhsviol) )
7291 {
7292 absviol = lhsviol;
7293 relviol = SCIPrelDiff(consdata->lhs, activity);
7294 }
7295 else if( rhsviol > 0 )
7296 {
7297 absviol = rhsviol;
7298 relviol = SCIPrelDiff(activity, consdata->rhs);
7299 }
7300
7301 /* the activity of pseudo solutions may be invalid if it comprises positive and negative infinity contributions; we
7302 * return infeasible for safety
7303 */
7304 if( activity == SCIP_INVALID ) /*lint !e777*/
7305 {
7306 assert(sol == NULL);
7307 *violated = TRUE;
7308
7309 /* set violation of invalid pseudo solutions */
7310 absviol = SCIP_INVALID;
7311 relviol = SCIP_INVALID;
7312
7313 /* reset constraint age since we are in enforcement */
7314 SCIP_CALL( SCIPresetConsAge(scip, cons) );
7315 }
7316 /* check with relative tolerances (the default) */
7317 else if( !consdata->checkabsolute && (SCIPisFeasLT(scip, activity, consdata->lhs) || SCIPisFeasGT(scip, activity, consdata->rhs)) )
7318 {
7319 /* the "normal" check: one of the two sides is violated */
7320 if( !checkrelmaxabs )
7321 {
7322 *violated = TRUE;
7323
7324 /* only reset constraint age if we are in enforcement */
7325 if( sol == NULL )
7326 {
7327 SCIP_CALL( SCIPresetConsAge(scip, cons) );
7328 }
7329 }
7330 /* the (much) more complicated check: we try to disregard random noise and violations of a 0.0 side which are
7331 * small compared to the absolute values occurring in the activity
7332 */
7333 else
7334 {
7335 SCIP_Real maxabs;
7336 SCIP_Real coef;
7337 SCIP_Real absval;
7338 SCIP_Real solval;
7339 int v;
7340
7341 maxabs = 1.0;
7342
7343 /* compute maximum absolute value */
7344 for( v = 0; v < consdata->nvars; ++v )
7345 {
7346 if( consdata->vals != NULL )
7347 {
7348 coef = consdata->vals[v];
7349 }
7350 else
7351 coef = 1.0;
7352
7353 solval = SCIPgetSolVal(scip, sol, consdata->vars[v]);
7354 absval = REALABS( coef * solval );
7355 maxabs = MAX( maxabs, absval );
7356 }
7357
7358 /* regard left hand side, first */
7359 if( SCIPisFeasLT(scip, activity, consdata->lhs) )
7360 {
7361 /* check whether violation is random noise */
7362 if( (consdata->lhs - activity) <= (1e-15 * maxabs) )
7363 {
7364 SCIPdebugMsg(scip, " lhs violated due to random noise: violation=%16.9g, maxabs=%16.9g\n",
7365 consdata->lhs - activity, maxabs);
7366 SCIPdebug( SCIP_CALL( consPrintConsSol(scip, cons, sol, NULL) ) );
7367
7368 /* only increase constraint age if we are in enforcement */
7369 if( sol == NULL )
7370 {
7371 SCIP_CALL( SCIPincConsAge(scip, cons) );
7372 }
7373 }
7374 /* lhs is violated and lhs is 0.0: use relative tolerance w.r.t. largest absolute value */
7375 else if( SCIPisZero(scip, consdata->lhs) )
7376 {
7377 if( (consdata->lhs - activity) <= (SCIPfeastol(scip) * maxabs) )
7378 {
7379 SCIPdebugMsg(scip, " lhs violated absolutely (violation=%16.9g), but feasible when using relative tolerance w.r.t. maximum absolute value (%16.9g)\n",
7380 consdata->lhs - activity, maxabs);
7381 SCIPdebug( SCIP_CALL( consPrintConsSol(scip, cons, sol, NULL) ) );
7382
7383 /* only increase constraint age if we are in enforcement */
7384 if( sol == NULL )
7385 {
7386 SCIP_CALL( SCIPincConsAge(scip, cons) );
7387 }
7388 }
7389 else
7390 {
7391 *violated = TRUE;
7392
7393 /* only reset constraint age if we are in enforcement */
7394 if( sol == NULL )
7395 {
7396 SCIP_CALL( SCIPresetConsAge(scip, cons) );
7397 }
7398 }
7399 }
7400 else
7401 {
7402 *violated = TRUE;
7403
7404 /* only reset constraint age if we are in enforcement */
7405 if( sol == NULL )
7406 {
7407 SCIP_CALL( SCIPresetConsAge(scip, cons) );
7408 }
7409 }
7410 }
7411
7412 /* now regard right hand side */
7413 if( SCIPisFeasGT(scip, activity, consdata->rhs) )
7414 {
7415 /* check whether violation is random noise */
7416 if( (activity - consdata->rhs) <= (1e-15 * maxabs) )
7417 {
7418 SCIPdebugMsg(scip, " rhs violated due to random noise: violation=%16.9g, maxabs=%16.9g\n",
7419 activity - consdata->rhs, maxabs);
7420 SCIPdebug( SCIP_CALL( consPrintConsSol(scip, cons, sol, NULL) ) );
7421
7422 /* only increase constraint age if we are in enforcement */
7423 if( sol == NULL )
7424 {
7425 SCIP_CALL( SCIPincConsAge(scip, cons) );
7426 }
7427 }
7428 /* rhs is violated and rhs is 0.0, use relative tolerance w.r.t. largest absolute value */
7429 else if( SCIPisZero(scip, consdata->rhs) )
7430 {
7431 if( (activity - consdata->rhs) <= (SCIPfeastol(scip) * maxabs) )
7432 {
7433 SCIPdebugMsg(scip, " rhs violated absolutely (violation=%16.9g), but feasible when using relative tolerance w.r.t. maximum absolute value (%16.9g)\n",
7434 activity - consdata->rhs, maxabs);
7435 SCIPdebug( SCIP_CALL( consPrintConsSol(scip, cons, sol, NULL) ) );
7436
7437 /* only increase constraint age if we are in enforcement */
7438 if( sol == NULL )
7439 {
7440 SCIP_CALL( SCIPincConsAge(scip, cons) );
7441 }
7442 }
7443 else
7444 {
7445 *violated = TRUE;
7446
7447 /* only reset constraint age if we are in enforcement */
7448 if( sol == NULL )
7449 {
7450 SCIP_CALL( SCIPresetConsAge(scip, cons) );
7451 }
7452 }
7453 }
7454 else
7455 {
7456 *violated = TRUE;
7457
7458 /* only reset constraint age if we are in enforcement */
7459 if( sol == NULL )
7460 {
7461 SCIP_CALL( SCIPresetConsAge(scip, cons) );
7462 }
7463 }
7464 }
7465 }
7466 }
7467 /* check with absolute tolerances */
7468 else if( consdata->checkabsolute &&
7469 ((!SCIPisInfinity(scip, -consdata->lhs) && SCIPisGT(scip, consdata->lhs-activity, SCIPfeastol(scip))) ||
7470 (!SCIPisInfinity(scip, consdata->rhs) && SCIPisGT(scip, activity-consdata->rhs, SCIPfeastol(scip)))) )
7471 {
7472 *violated = TRUE;
7473
7474 /* only reset constraint age if we are in enforcement */
7475 if( sol == NULL )
7476 {
7477 SCIP_CALL( SCIPresetConsAge(scip, cons) );
7478 }
7479 }
7480 else
7481 {
7482 /* only increase constraint age if we are in enforcement */
7483 if( sol == NULL )
7484 {
7485 SCIP_CALL( SCIPincConsAge(scip, cons) );
7486 }
7487 }
7488
7489 /* update absolute and relative violation of the solution */
7490 if( sol != NULL )
7491 SCIPupdateSolLPConsViolation(scip, sol, absviol, relviol);
7492
7493 return SCIP_OKAY;
7494 }
7495
7496 /** creates an LP row in a linear constraint data */
7497 static
createRow(SCIP * scip,SCIP_CONS * cons)7498 SCIP_RETCODE createRow(
7499 SCIP* scip, /**< SCIP data structure */
7500 SCIP_CONS* cons /**< linear constraint */
7501 )
7502 {
7503 SCIP_CONSDATA* consdata;
7504
7505 assert(scip != NULL);
7506 assert(cons != NULL);
7507
7508 consdata = SCIPconsGetData(cons);
7509 assert(consdata != NULL);
7510 assert(consdata->row == NULL);
7511
7512 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons), consdata->lhs, consdata->rhs,
7513 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), SCIPconsIsRemovable(cons)) );
7514
7515 SCIP_CALL( SCIPaddVarsToRow(scip, consdata->row, consdata->nvars, consdata->vars, consdata->vals) );
7516
7517 return SCIP_OKAY;
7518 }
7519
7520 /** adds linear constraint as cut to the LP */
7521 static
addRelaxation(SCIP * scip,SCIP_CONS * cons,SCIP_Bool * cutoff)7522 SCIP_RETCODE addRelaxation(
7523 SCIP* scip, /**< SCIP data structure */
7524 SCIP_CONS* cons, /**< linear constraint */
7525 SCIP_Bool* cutoff /**< pointer to store whether a cutoff was found */
7526 )
7527 {
7528 SCIP_CONSDATA* consdata;
7529
7530 assert(scip != NULL);
7531 assert(cons != NULL);
7532
7533 consdata = SCIPconsGetData(cons);
7534 assert(consdata != NULL);
7535
7536 if( consdata->row == NULL )
7537 {
7538 if( !SCIPconsIsModifiable(cons) )
7539 {
7540 /* replace all fixed variables by active counterparts, as we have no chance to do this anymore after the row has been added to the LP
7541 * removing this here will make test cons/linear/fixedvar.c fail (as of 2018-12-03)
7542 */
7543 SCIP_CALL( applyFixings(scip, cons, cutoff) );
7544 if( *cutoff )
7545 return SCIP_OKAY;
7546 }
7547
7548 /* convert consdata object into LP row */
7549 SCIP_CALL( createRow(scip, cons) );
7550 }
7551 assert(consdata->row != NULL);
7552
7553 if( consdata->nvars == 0 )
7554 {
7555 SCIPdebugMsg(scip, "Empty linear constraint enters LP: <%s>\n", SCIPconsGetName(cons));
7556 }
7557
7558 /* insert LP row as cut */
7559 if( !SCIProwIsInLP(consdata->row) )
7560 {
7561 SCIPdebugMsg(scip, "adding relaxation of linear constraint <%s>: ", SCIPconsGetName(cons));
7562 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, consdata->row, NULL)) );
7563 /* if presolving is turned off, the row might be trivial */
7564 if ( ! SCIPisInfinity(scip, -consdata->lhs) || ! SCIPisInfinity(scip, consdata->rhs) )
7565 {
7566 SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) );
7567 }
7568 #ifndef NDEBUG
7569 else
7570 {
7571 int pr;
7572 int cr;
7573 SCIP_CALL( SCIPgetIntParam(scip, "presolving/maxrounds", &pr) );
7574 SCIP_CALL( SCIPgetIntParam(scip, "constraints/linear/maxprerounds", &cr) );
7575 assert( pr == 0 || cr == 0 );
7576 }
7577 #endif
7578 }
7579
7580 return SCIP_OKAY;
7581 }
7582
7583 /** separates linear constraint: adds linear constraint as cut, if violated by given solution */
7584 static
separateCons(SCIP * scip,SCIP_CONS * cons,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_SOL * sol,SCIP_Bool separatecards,SCIP_Bool separateall,int * ncuts,SCIP_Bool * cutoff)7585 SCIP_RETCODE separateCons(
7586 SCIP* scip, /**< SCIP data structure */
7587 SCIP_CONS* cons, /**< linear constraint */
7588 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7589 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
7590 SCIP_Bool separatecards, /**< should knapsack cardinality cuts be generated? */
7591 SCIP_Bool separateall, /**< should all constraints be subject to cardinality cut generation instead of only
7592 * the ones with non-zero dual value? */
7593 int* ncuts, /**< pointer to add up the number of found cuts */
7594 SCIP_Bool* cutoff /**< pointer to store whether a cutoff was found */
7595 )
7596 {
7597 SCIP_CONSDATA* consdata;
7598 SCIP_Bool violated;
7599 int oldncuts;
7600
7601 assert(scip != NULL);
7602 assert(conshdlrdata != NULL);
7603 assert(cons != NULL);
7604 assert(cutoff != NULL);
7605
7606 consdata = SCIPconsGetData(cons);
7607 assert(ncuts != NULL);
7608 assert(consdata != NULL);
7609
7610 oldncuts = *ncuts;
7611 *cutoff = FALSE;
7612
7613 SCIP_CALL( checkCons(scip, cons, sol, (sol != NULL), conshdlrdata->checkrelmaxabs, &violated) );
7614
7615 if( violated )
7616 {
7617 /* insert LP row as cut */
7618 SCIP_CALL( addRelaxation(scip, cons, cutoff) );
7619 (*ncuts)++;
7620 }
7621 else if( !SCIPconsIsModifiable(cons) && separatecards )
7622 {
7623 /* relax linear constraint into knapsack constraint and separate lifted cardinality cuts */
7624 if( !separateall && sol == NULL )
7625 {
7626 /* we only want to call the knapsack cardinality cut separator for rows that have a non-zero dual solution */
7627 if( consdata->row != NULL && SCIProwIsInLP(consdata->row) )
7628 {
7629 SCIP_Real dualsol;
7630
7631 dualsol = SCIProwGetDualsol(consdata->row);
7632 if( SCIPisFeasNegative(scip, dualsol) )
7633 {
7634 if( !SCIPisInfinity(scip, consdata->rhs) )
7635 {
7636 SCIP_CALL( SCIPseparateRelaxedKnapsack(scip, cons, NULL, consdata->nvars, consdata->vars,
7637 consdata->vals, +1.0, consdata->rhs, sol, cutoff, ncuts) );
7638 }
7639 }
7640 else if( SCIPisFeasPositive(scip, dualsol) )
7641 {
7642 if( !SCIPisInfinity(scip, -consdata->lhs) )
7643 {
7644 SCIP_CALL( SCIPseparateRelaxedKnapsack(scip, cons, NULL, consdata->nvars, consdata->vars,
7645 consdata->vals, -1.0, -consdata->lhs, sol, cutoff, ncuts) );
7646 }
7647 }
7648 }
7649 }
7650 else
7651 {
7652 if( !SCIPisInfinity(scip, consdata->rhs) )
7653 {
7654 SCIP_CALL( SCIPseparateRelaxedKnapsack(scip, cons, NULL, consdata->nvars, consdata->vars,
7655 consdata->vals, +1.0, consdata->rhs, sol, cutoff, ncuts) );
7656 }
7657 if( !SCIPisInfinity(scip, -consdata->lhs) )
7658 {
7659 SCIP_CALL( SCIPseparateRelaxedKnapsack(scip, cons, NULL, consdata->nvars, consdata->vars,
7660 consdata->vals, -1.0, -consdata->lhs, sol, cutoff, ncuts) );
7661 }
7662 }
7663 }
7664
7665 if( *ncuts > oldncuts )
7666 {
7667 SCIP_CALL( SCIPresetConsAge(scip, cons) );
7668 }
7669
7670 return SCIP_OKAY;
7671 }
7672
7673 /** propagation method for linear constraints */
7674 static
propagateCons(SCIP * scip,SCIP_CONS * cons,SCIP_Bool tightenbounds,SCIP_Bool rangedrowpropagation,SCIP_Real maxeasyactivitydelta,SCIP_Bool sortvars,SCIP_Bool * cutoff,int * nchgbds)7675 SCIP_RETCODE propagateCons(
7676 SCIP* scip, /**< SCIP data structure */
7677 SCIP_CONS* cons, /**< linear constraint */
7678 SCIP_Bool tightenbounds, /**< should the variable's bounds be tightened? */
7679 SCIP_Bool rangedrowpropagation,/**< should ranged row propagation be performed? */
7680 SCIP_Real maxeasyactivitydelta,/**< maximum activity delta to run easy propagation on linear constraint */
7681 SCIP_Bool sortvars, /**< should variable sorting for faster propagation be used? */
7682 SCIP_Bool* cutoff, /**< pointer to store whether the node can be cut off */
7683 int* nchgbds /**< pointer to count the total number of tightened bounds */
7684 )
7685 {
7686 SCIP_CONSDATA* consdata;
7687 SCIP_Real minactivity;
7688 SCIP_Real maxactivity;
7689 SCIP_Bool minactisrelax;
7690 SCIP_Bool maxactisrelax;
7691 SCIP_Bool isminsettoinfinity;
7692 SCIP_Bool ismaxsettoinfinity;
7693
7694 assert(scip != NULL);
7695 assert(cons != NULL);
7696 assert(cutoff != NULL);
7697 assert(nchgbds != NULL);
7698
7699 /*SCIPdebugMsg(scip, "propagating linear constraint <%s>\n", SCIPconsGetName(cons));*/
7700
7701 consdata = SCIPconsGetData(cons);
7702 assert(consdata != NULL);
7703
7704 if( consdata->eventdata == NULL )
7705 {
7706 SCIP_CONSHDLR* conshdlr;
7707 SCIP_CONSHDLRDATA* conshdlrdata;
7708
7709 conshdlr = SCIPconsGetHdlr(cons);
7710 assert(conshdlr != NULL);
7711
7712 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7713 assert(conshdlrdata != NULL);
7714
7715 /* catch bound change events of variables */
7716 SCIP_CALL( consCatchAllEvents(scip, cons, conshdlrdata->eventhdlr) );
7717 assert(consdata->eventdata != NULL);
7718 }
7719
7720 *cutoff = FALSE;
7721
7722 /* we can only infer activity bounds of the linear constraint, if it is not modifiable */
7723 if( !SCIPconsIsModifiable(cons) )
7724 {
7725 /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
7726 if( !SCIPinRepropagation(scip) )
7727 {
7728 SCIP_CALL( SCIPincConsAge(scip, cons) );
7729 }
7730
7731 /* tighten the variable's bounds */
7732 if( tightenbounds )
7733 {
7734 int oldnchgbds;
7735
7736 oldnchgbds = *nchgbds;
7737
7738 SCIP_CALL( tightenBounds(scip, cons, maxeasyactivitydelta, sortvars, cutoff, nchgbds) );
7739
7740 if( *nchgbds > oldnchgbds )
7741 {
7742 SCIP_CALL( SCIPresetConsAge(scip, cons) );
7743 }
7744 }
7745
7746 /* propagate ranged rows */
7747 if( rangedrowpropagation && tightenbounds && !(*cutoff) )
7748 {
7749 int nfixedvars;
7750 int naddconss;
7751 SCIPdebug( int oldnchgbds = *nchgbds; )
7752
7753 nfixedvars = 0;
7754 naddconss = 0;
7755
7756 SCIP_CALL( rangedRowPropagation(scip, cons, cutoff, &nfixedvars, nchgbds, &naddconss) );
7757
7758 if( *cutoff )
7759 {
7760 SCIPdebugMsg(scip, "linear constraint <%s> is infeasible\n", SCIPconsGetName(cons));
7761 }
7762 else
7763 {
7764 SCIPdebug( SCIPdebugMsg(scip, "linear constraint <%s> found %d bound changes and %d fixings\n", SCIPconsGetName(cons), *nchgbds - oldnchgbds, nfixedvars); )
7765 }
7766
7767 if( nfixedvars > 0 )
7768 *nchgbds += 2*nfixedvars;
7769 } /*lint !e438*/
7770
7771 /* check constraint for infeasibility and redundancy */
7772 if( !(*cutoff) )
7773 {
7774 consdataGetActivityBounds(scip, consdata, TRUE, &minactivity, &maxactivity, &minactisrelax, &maxactisrelax,
7775 &isminsettoinfinity, &ismaxsettoinfinity);
7776
7777 if( SCIPisFeasGT(scip, minactivity, consdata->rhs) )
7778 {
7779 SCIPdebugMsg(scip, "linear constraint <%s> is infeasible (rhs): activitybounds=[%.15g,%.15g], sides=[%.15g,%.15g]\n",
7780 SCIPconsGetName(cons), minactivity, maxactivity, consdata->lhs, consdata->rhs);
7781
7782 /* analyze conflict */
7783 SCIP_CALL( analyzeConflict(scip, cons, TRUE) );
7784
7785 SCIP_CALL( SCIPresetConsAge(scip, cons) );
7786 *cutoff = TRUE;
7787 }
7788 else if( SCIPisFeasLT(scip, maxactivity, consdata->lhs) )
7789 {
7790 SCIPdebugMsg(scip, "linear constraint <%s> is infeasible (lhs): activitybounds=[%.15g,%.15g], sides=[%.15g,%.15g]\n",
7791 SCIPconsGetName(cons), minactivity, maxactivity, consdata->lhs, consdata->rhs);
7792
7793 /* analyze conflict */
7794 SCIP_CALL( analyzeConflict(scip, cons, FALSE) );
7795
7796 SCIP_CALL( SCIPresetConsAge(scip, cons) );
7797 *cutoff = TRUE;
7798 }
7799 else if( SCIPisGE(scip, minactivity, consdata->lhs) && SCIPisLE(scip, maxactivity, consdata->rhs) )
7800 {
7801 SCIPdebugMsg(scip, "linear constraint <%s> is redundant: activitybounds=[%.15g,%.15g], sides=[%.15g,%.15g]\n",
7802 SCIPconsGetName(cons), minactivity, maxactivity, consdata->lhs, consdata->rhs);
7803
7804 /* remove the constraint locally unless it has become empty, in which case it is removed globally */
7805 if( consdata->nvars > 0 )
7806 SCIP_CALL( SCIPdelConsLocal(scip, cons) );
7807 else
7808 SCIP_CALL( SCIPdelCons(scip, cons) );
7809 }
7810 }
7811 }
7812
7813 return SCIP_OKAY;
7814 }
7815
7816
7817 /*
7818 * Presolving methods
7819 */
7820
7821 /** converts all variables with fixed domain into FIXED variables */
7822 static
fixVariables(SCIP * scip,SCIP_CONS * cons,SCIP_Bool * cutoff,int * nfixedvars)7823 SCIP_RETCODE fixVariables(
7824 SCIP* scip, /**< SCIP data structure */
7825 SCIP_CONS* cons, /**< linear constraint */
7826 SCIP_Bool* cutoff, /**< pointer to store TRUE, if a cutoff was found */
7827 int* nfixedvars /**< pointer to count the total number of fixed variables */
7828 )
7829 {
7830 SCIP_CONSDATA* consdata;
7831 SCIP_VAR* var;
7832 SCIP_VARSTATUS varstatus;
7833 SCIP_Real lb;
7834 SCIP_Real ub;
7835 SCIP_Bool fixed;
7836 SCIP_Bool infeasible;
7837 int v;
7838
7839 assert(scip != NULL);
7840 assert(cons != NULL);
7841 assert(cutoff != NULL);
7842 assert(nfixedvars != NULL);
7843
7844 consdata = SCIPconsGetData(cons);
7845 assert(consdata != NULL);
7846
7847 for( v = 0; v < consdata->nvars; ++v )
7848 {
7849 assert(consdata->vars != NULL);
7850 var = consdata->vars[v];
7851 varstatus = SCIPvarGetStatus(var);
7852
7853 if( varstatus != SCIP_VARSTATUS_FIXED )
7854 {
7855 lb = SCIPvarGetLbGlobal(var);
7856 ub = SCIPvarGetUbGlobal(var);
7857 if( SCIPisEQ(scip, lb, ub) )
7858 {
7859 SCIP_Real fixval;
7860
7861 fixval = SCIPselectSimpleValue(lb, ub, MAXDNOM);
7862 SCIPdebugMsg(scip, "converting variable <%s> with fixed bounds [%.15g,%.15g] into fixed variable fixed at %.15g\n",
7863 SCIPvarGetName(var), lb, ub, fixval);
7864 SCIP_CALL( SCIPfixVar(scip, var, fixval, &infeasible, &fixed) );
7865 if( infeasible )
7866 {
7867 SCIPdebugMsg(scip, " -> infeasible fixing\n");
7868 *cutoff = TRUE;
7869 return SCIP_OKAY;
7870 }
7871 if( fixed )
7872 (*nfixedvars)++;
7873 }
7874 }
7875 }
7876
7877 SCIP_CALL( applyFixings(scip, cons, &infeasible) );
7878
7879 if( infeasible )
7880 {
7881 SCIPdebugMsg(scip, " -> infeasible fixing\n");
7882 *cutoff = TRUE;
7883 return SCIP_OKAY;
7884 }
7885
7886 assert(consdata->removedfixings);
7887
7888 return SCIP_OKAY;
7889 }
7890
7891 #define MAX_CLIQUE_NONZEROS_PER_CONS 1000000
7892
7893 /** extracts cliques of the constraint and adds them to SCIP
7894 *
7895 * The following clique extraction mechanism are implemeneted
7896 *
7897 * 1. collect binary variables and sort them in non increasing order, then
7898 *
7899 * a) if the constraint has a finite right hand side and the negative infinity counters for the minactivity are zero
7900 * then add the variables as a clique for which all successive pairs of coefficients fullfill the following
7901 * condition
7902 *
7903 * minactivity + vals[i] + vals[i+1] > rhs
7904 *
7905 * and also add the binary to binary implication also for non-successive variables for which the same argument
7906 * holds
7907 *
7908 * minactivity + vals[i] + vals[j] > rhs
7909 *
7910 * e.g. 5.3 x1 + 3.6 x2 + 3.3 x3 + 2.1 x4 <= 5.5 (all x are binary) would lead to the clique (x1, x2, x3) and the
7911 * binary to binary implications x1 = 1 => x4 = 0 and x2 = 1 => x4 = 0
7912 *
7913 * b) if the constraint has a finite left hand side and the positive infinity counters for the maxactivity are zero
7914 * then add the variables as a clique for which all successive pairs of coefficients fullfill the follwoing
7915 * condition
7916 *
7917 * maxactivity + vals[i] + vals[i-1] < lhs
7918 *
7919 * and also add the binary to binary implication also for non-successive variables for which the same argument
7920 * holds
7921 *
7922 * maxactivity + vals[i] + vals[j] < lhs
7923 *
7924 * e.g. you could multiply the above example by -1
7925 *
7926 * c) the constraint has a finite right hand side and a finite minactivity then add the variables as a negated
7927 * clique(clique on the negated variables) for which all successive pairs of coefficients fullfill the following
7928 * condition
7929 *
7930 * minactivity - vals[i] - vals[i-1] > rhs
7931 *
7932 * and also add the binary to binary implication also for non-successive variables for which the
7933 * same argument holds
7934 *
7935 * minactivity - vals[i] - vals[j] > rhs
7936 *
7937 * e.g. -4 x1 -3 x2 - 2 x3 + 2 x4 <= -4 would lead to the (negated) clique (~x1, ~x2) and the binary to binary
7938 * implication x1 = 0 => x3 = 1
7939 *
7940 * d) the constraint has a finite left hand side and a finite maxactivity then add the variables as a negated
7941 * clique(clique on the negated variables) for which all successive pairs of coefficients fullfill the following
7942 * condition
7943 *
7944 * maxactivity - vals[i] - vals[i+1] < lhs
7945 *
7946 * and also add the binary to binary implication also for non-successive variables for which the same argument
7947 * holds
7948 *
7949 * maxactivity - vals[i] - vals[j] < lhs
7950 *
7951 * e.g. you could multiply the above example by -1
7952 *
7953 * 2. if the linear constraint represents a set-packing or set-partitioning constraint, the whole constraint is added
7954 * as clique, (this part is done at the end of the method)
7955 *
7956 */
7957 static
extractCliques(SCIP * scip,SCIP_CONS * cons,SCIP_Real maxeasyactivitydelta,SCIP_Bool sortvars,int * nfixedvars,int * nchgbds,SCIP_Bool * cutoff)7958 SCIP_RETCODE extractCliques(
7959 SCIP* scip, /**< SCIP data structure */
7960 SCIP_CONS* cons, /**< linear constraint */
7961 SCIP_Real maxeasyactivitydelta,/**< maximum activity delta to run easy propagation on linear constraint */
7962 SCIP_Bool sortvars, /**< should variables be used in sorted order? */
7963 int* nfixedvars, /**< pointer to count number of fixed variables */
7964 int* nchgbds, /**< pointer to count the total number of tightened bounds */
7965 SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was found */
7966 )
7967 {
7968 SCIP_VAR** vars;
7969 SCIP_Real* vals;
7970 SCIP_CONSDATA* consdata;
7971 SCIP_Bool lhsclique;
7972 SCIP_Bool rhsclique;
7973 SCIP_Bool finitelhs;
7974 SCIP_Bool finiterhs;
7975 SCIP_Bool finiteminact;
7976 SCIP_Bool finitemaxact;
7977 SCIP_Bool finitenegminact;
7978 SCIP_Bool finitenegmaxact;
7979 SCIP_Bool finiteposminact;
7980 SCIP_Bool finiteposmaxact;
7981 SCIP_Bool infeasible;
7982 SCIP_Bool stopped;
7983 int cliquenonzerosadded;
7984 int v;
7985 int i;
7986 int nposcoefs;
7987 int nnegcoefs;
7988 int nvars;
7989
7990 assert(scip != NULL);
7991 assert(cons != NULL);
7992 assert(nfixedvars != NULL);
7993 assert(nchgbds != NULL);
7994 assert(cutoff != NULL);
7995 assert(!SCIPconsIsDeleted(cons));
7996
7997 consdata = SCIPconsGetData(cons);
7998 assert(consdata != NULL);
7999
8000 if( consdata->nvars < 2 )
8001 return SCIP_OKAY;
8002
8003 /* add implications if posibble
8004 *
8005 * for now we only add binary to non-binary implications, and this is only done for the binary variable with the
8006 * maximal absolute contribution and also only if this variable would force all other variables to their bound
8007 * corresponding to the global minimal activity of the constraint
8008 */
8009 if( !consdata->implsadded )
8010 {
8011 /* sort variables by variable type */
8012 SCIP_CALL( consdataSort(scip, consdata) );
8013
8014 /* @todo we might extract implications/cliques if SCIPvarIsBinary() variables exist and we have integer variables
8015 * up front, might change sorting correspondingly
8016 */
8017 /* fast abort if no binaries exist */
8018 if( !SCIPvarIsBinary(consdata->vars[0]) )
8019 {
8020 #ifndef NDEBUG
8021 for( i = 1; i < consdata->nvars; i++ )
8022 assert(!SCIPvarIsBinary(consdata->vars[i]));
8023 #endif
8024 return SCIP_OKAY;
8025 }
8026 nvars = consdata->nvars;
8027 vars = consdata->vars;
8028 vals = consdata->vals;
8029
8030 /* recompute activities if needed */
8031 if( !consdata->validactivities )
8032 consdataCalcActivities(scip, consdata);
8033 assert(consdata->validactivities);
8034
8035 finitelhs = !SCIPisInfinity(scip, -consdata->lhs);
8036 finiterhs = !SCIPisInfinity(scip, consdata->rhs);
8037 finitenegminact = (consdata->glbminactivityneginf == 0 && consdata->glbminactivityneghuge == 0);
8038 finitenegmaxact = (consdata->glbmaxactivityneginf == 0 && consdata->maxactivityneghuge == 0);
8039 finiteposminact = (consdata->glbminactivityposinf == 0 && consdata->glbminactivityposhuge == 0);
8040 finiteposmaxact = (consdata->glbmaxactivityposinf == 0 && consdata->glbmaxactivityposhuge == 0);
8041 finiteminact = (finitenegminact && finiteposminact);
8042 finitemaxact = (finitenegmaxact && finiteposmaxact);
8043
8044 if( (finiterhs || finitelhs) && (finitenegminact || finiteposminact || finitenegmaxact || finiteposmaxact) )
8045 {
8046 SCIP_Real maxabscontrib = -1.0;
8047 SCIP_Bool posval = FALSE;
8048 SCIP_Bool allbinary = TRUE;
8049 int oldnchgbds = *nchgbds;
8050 int nbdchgs = 0;
8051 int nimpls = 0;
8052 int position = -1;
8053
8054 /* we need a valid minimal/maximal activity to add cliques */
8055 if( (finitenegminact || finiteposminact) && !consdata->validglbminact )
8056 {
8057 consdataRecomputeGlbMinactivity(scip, consdata);
8058 assert(consdata->validglbminact);
8059 }
8060
8061 if( (finitenegmaxact || finiteposmaxact) && !consdata->validglbmaxact )
8062 {
8063 consdataRecomputeGlbMaxactivity(scip, consdata);
8064 assert(consdata->validglbmaxact);
8065 }
8066 assert(consdata->validglbminact || consdata->validglbmaxact);
8067
8068 /* @todo extend this to local/constraint probing */
8069
8070 /* determine maximal contribution to the activity */
8071 for( v = nvars - 1; v >= 0; --v )
8072 {
8073 if( SCIPvarIsBinary(vars[v]) )
8074 {
8075 if( vals[v] > 0 )
8076 {
8077 SCIP_Real value = vals[v] * SCIPvarGetUbGlobal(vars[v]);
8078
8079 if( value > maxabscontrib )
8080 {
8081 maxabscontrib = value;
8082 position = v;
8083 posval = TRUE;
8084 }
8085 }
8086 else
8087 {
8088 SCIP_Real value = vals[v] * SCIPvarGetLbGlobal(vars[v]);
8089
8090 value = REALABS(value);
8091
8092 if( value > maxabscontrib )
8093 {
8094 maxabscontrib = value;
8095 position = v;
8096 posval = FALSE;
8097 }
8098 }
8099 }
8100 else
8101 allbinary = FALSE;
8102 }
8103 assert(0 <= position && position < nvars);
8104
8105 if( !SCIPisEQ(scip, maxabscontrib, 1.0) && !allbinary )
8106 {
8107 /* if the right hand side and the minimal activity are finite and changing the variable with the biggest
8108 * influence to their bound forces all other variables to be at their minimal contribution, we can add these
8109 * implications
8110 */
8111 if( finiterhs && finiteminact && SCIPisEQ(scip, consdata->glbminactivity, consdata->rhs - maxabscontrib) )
8112 {
8113 for( v = nvars - 1; v >= 0; --v )
8114 {
8115 /* binary to binary implications will be collected when extrating cliques */
8116 if( !SCIPvarIsBinary(vars[v]) )
8117 {
8118 if( v != position )
8119 {
8120 if( vals[v] > 0 )
8121 {
8122 /* add implications */
8123 SCIP_CALL( SCIPaddVarImplication(scip, vars[position], posval, vars[v], SCIP_BOUNDTYPE_UPPER, SCIPvarGetLbGlobal(vars[v]), &infeasible, &nbdchgs) );
8124 ++nimpls;
8125 *nchgbds += nbdchgs;
8126 }
8127 else
8128 {
8129 /* add implications */
8130 SCIP_CALL( SCIPaddVarImplication(scip, vars[position], posval, vars[v], SCIP_BOUNDTYPE_LOWER, SCIPvarGetUbGlobal(vars[v]), &infeasible, &nbdchgs) );
8131 ++nimpls;
8132 *nchgbds += nbdchgs;
8133 }
8134
8135 if( infeasible )
8136 {
8137 *cutoff = TRUE;
8138 break;
8139 }
8140 }
8141 }
8142 /* stop when reaching a 'real' binary variable because the variables are sorted after their type */
8143 else if( SCIPvarGetType(vars[v]) == SCIP_VARTYPE_BINARY )
8144 break;
8145 }
8146 }
8147
8148 /* if the left hand side and the maximal activity are finite and changing the variable with the biggest
8149 * influence to their bound forces all other variables to be at their minimal contribution, we can add these
8150 * implications
8151 */
8152 if( finitelhs && finitemaxact && SCIPisEQ(scip, consdata->glbmaxactivity, consdata->lhs - maxabscontrib) )
8153 {
8154 for( v = nvars - 1; v >= 0; --v )
8155 {
8156 /* binary to binary implications will be collected when extrating cliques */
8157 if( !SCIPvarIsBinary(vars[v]) )
8158 {
8159 if( v != position )
8160 {
8161 if( vals[v] > 0 )
8162 {
8163 /* add implications */
8164 SCIP_CALL( SCIPaddVarImplication(scip, vars[position], posval, vars[v], SCIP_BOUNDTYPE_LOWER, SCIPvarGetUbGlobal(vars[v]), &infeasible, &nbdchgs) );
8165 ++nimpls;
8166 *nchgbds += nbdchgs;
8167 }
8168 else
8169 {
8170 /* add implications */
8171 SCIP_CALL( SCIPaddVarImplication(scip, vars[position], posval, vars[v], SCIP_BOUNDTYPE_UPPER, SCIPvarGetLbGlobal(vars[v]), &infeasible, &nbdchgs) );
8172 ++nimpls;
8173 *nchgbds += nbdchgs;
8174 }
8175
8176 if( infeasible )
8177 {
8178 *cutoff = TRUE;
8179 break;
8180 }
8181 }
8182 }
8183 /* stop when reaching a 'real' binary variable because the variables are sorted after their type */
8184 else if( SCIPvarGetType(vars[v]) == SCIP_VARTYPE_BINARY )
8185 break;
8186 }
8187 }
8188
8189 /* did we find some implications */
8190 if( nimpls > 0 )
8191 {
8192 SCIPdebugMsg(scip, "extracted %d implications from constraint %s which led to %d bound changes, %scutoff detetcted\n", nimpls, SCIPconsGetName(cons), *nchgbds - oldnchgbds, *cutoff ? "" : "no ");
8193
8194 if( *cutoff )
8195 return SCIP_OKAY;
8196
8197 /* did we find some boundchanges, then we need to remove fixings and tighten the bounds further */
8198 if( *nchgbds - oldnchgbds > 0 )
8199 {
8200 /* check for fixed variables */
8201 SCIP_CALL( fixVariables(scip, cons, cutoff, nfixedvars) );
8202 if( *cutoff )
8203 return SCIP_OKAY;
8204
8205 /* tighten variable's bounds */
8206 SCIP_CALL( tightenBounds(scip, cons, maxeasyactivitydelta, sortvars, cutoff, nchgbds) );
8207 if( *cutoff )
8208 return SCIP_OKAY;
8209
8210 /* check for fixed variables */
8211 SCIP_CALL( fixVariables(scip, cons, cutoff, nfixedvars) );
8212 if( *cutoff )
8213 return SCIP_OKAY;
8214 }
8215 }
8216 }
8217 }
8218
8219 consdata->implsadded = TRUE;
8220 }
8221
8222 /* check if we already added the cliques of this constraint */
8223 if( consdata->cliquesadded )
8224 return SCIP_OKAY;
8225
8226 consdata->cliquesadded = TRUE;
8227 cliquenonzerosadded = 0;
8228 stopped = FALSE;
8229
8230 /* sort variables by variable type */
8231 SCIP_CALL( consdataSort(scip, consdata) );
8232
8233 nvars = consdata->nvars;
8234 vars = consdata->vars;
8235 vals = consdata->vals;
8236
8237 /**@todo extract more cliques, implications and variable bounds from linear constraints */
8238
8239 /* recompute activities if needed */
8240 if( !consdata->validactivities )
8241 consdataCalcActivities(scip, consdata);
8242 assert(consdata->validactivities);
8243
8244 finitelhs = !SCIPisInfinity(scip, -consdata->lhs);
8245 finiterhs = !SCIPisInfinity(scip, consdata->rhs);
8246 finitenegminact = (consdata->glbminactivityneginf == 0 && consdata->glbminactivityneghuge == 0);
8247 finitenegmaxact = (consdata->glbmaxactivityneginf == 0 && consdata->maxactivityneghuge == 0);
8248 finiteposminact = (consdata->glbminactivityposinf == 0 && consdata->glbminactivityposhuge == 0);
8249 finiteposmaxact = (consdata->glbmaxactivityposinf == 0 && consdata->glbmaxactivityposhuge == 0);
8250 finiteminact = (finitenegminact && finiteposminact);
8251 finitemaxact = (finitenegmaxact && finiteposmaxact);
8252
8253 /* 1. we wheck whether some variables do not fit together into this constraint and add the corresponding clique
8254 * information
8255 */
8256 if( (finiterhs || finitelhs) && (finitenegminact || finiteposminact || finitenegmaxact || finiteposmaxact) )
8257 {
8258 SCIP_VAR** binvars;
8259 SCIP_Real* binvarvals;
8260 int nposbinvars = 0;
8261 int nnegbinvars = 0;
8262 int allonebinary = 0;
8263
8264 SCIP_CALL( SCIPallocBufferArray(scip, &binvars, nvars) );
8265 SCIP_CALL( SCIPallocBufferArray(scip, &binvarvals, nvars) );
8266
8267 /* collect binary variables */
8268 for( i = 0; i < nvars; ++i )
8269 {
8270 if( SCIPvarIsBinary(vars[i]) )
8271 {
8272 assert(!SCIPisZero(scip, vals[i]));
8273
8274 if( SCIPisEQ(scip, REALABS(vals[i]), 1.0) )
8275 ++allonebinary;
8276
8277 binvars[nposbinvars + nnegbinvars] = vars[i];
8278 binvarvals[nposbinvars + nnegbinvars] = vals[i];
8279
8280 if( SCIPisPositive(scip, vals[i]) )
8281 ++nposbinvars;
8282 else
8283 ++nnegbinvars;
8284
8285 assert(nposbinvars + nnegbinvars <= nvars);
8286 }
8287 /* stop searching for binary variables, because the constraint data is sorted */
8288 else if( SCIPvarGetType(vars[i]) == SCIP_VARTYPE_CONTINUOUS )
8289 break;
8290 }
8291 assert(nposbinvars + nnegbinvars <= nvars);
8292
8293 /* setppc constraints will be handled later; we need at least two binary variables with same sign to extract
8294 * cliques
8295 */
8296 if( allonebinary < nvars && (nposbinvars >= 2 || nnegbinvars >= 2) )
8297 {
8298 SCIP_Real threshold;
8299 int oldnchgbds = *nchgbds;
8300 int nbdchgs;
8301 int jstart;
8302 int j;
8303
8304 /* we need a valid minimal/maximal activity to add cliques */
8305 if( (finitenegminact || finiteposminact) && !consdata->validglbminact )
8306 {
8307 consdataRecomputeGlbMinactivity(scip, consdata);
8308 assert(consdata->validglbminact);
8309 }
8310
8311 if( (finitenegmaxact || finiteposmaxact) && !consdata->validglbmaxact )
8312 {
8313 consdataRecomputeGlbMaxactivity(scip, consdata);
8314 assert(consdata->validglbmaxact);
8315 }
8316 assert(consdata->validglbminact || consdata->validglbmaxact);
8317
8318 /* sort coefficients non-increasing to be faster in the clique search */
8319 SCIPsortDownRealPtr(binvarvals, (void**) binvars, nposbinvars + nnegbinvars);
8320
8321 /* case a) */
8322 if( finiterhs && finitenegminact && nposbinvars >= 2 )
8323 {
8324 /* compute value that needs to be exceeded */
8325 threshold = consdata->rhs - consdata->glbminactivity;
8326
8327 j = 1;
8328 #ifdef SCIP_DISABLED_CODE /* assertion should only hold when constraints were fully propagated and boundstightened */
8329 /* check that it is possible to choose binvar[i], otherwise it should have been fixed to zero */
8330 assert(SCIPisFeasLE(scip, binvarvals[0], threshold));
8331 #endif
8332 /* check if at least two variables are in a clique */
8333 if( SCIPisFeasGT(scip, binvarvals[0] + binvarvals[j], threshold) )
8334 {
8335 ++j;
8336 /* check for extending the clique */
8337 while( j < nposbinvars )
8338 {
8339 if( !SCIPisFeasGT(scip, binvarvals[j-1] + binvarvals[j], threshold) )
8340 break;
8341 ++j;
8342 }
8343 assert(j >= 2);
8344
8345 /* add clique with at least two variables */
8346 SCIP_CALL( SCIPaddClique(scip, binvars, NULL, j, FALSE, &infeasible, &nbdchgs) );
8347
8348 if( infeasible )
8349 *cutoff = TRUE;
8350
8351 *nchgbds += nbdchgs;
8352
8353 cliquenonzerosadded += j;
8354 if( cliquenonzerosadded >= MAX_CLIQUE_NONZEROS_PER_CONS )
8355 stopped = TRUE;
8356
8357 /* exchange the last variable in the clique if possible and add all new ones */
8358 if( !stopped && !(*cutoff) && j < nposbinvars )
8359 {
8360 SCIP_VAR** clqvars;
8361 int lastfit = j - 2;
8362 assert(lastfit >= 0);
8363
8364 /* copy all 'main'-clique variables */
8365 SCIP_CALL( SCIPduplicateBufferArray(scip, &clqvars, binvars, j) );
8366
8367 /* iterate up to the end with j and up to the front with lastfit, and check for different cliques */
8368 while( lastfit >= 0 && j < nposbinvars )
8369 {
8370 /* check if two variables are in a clique */
8371 if( SCIPisFeasGT(scip, binvarvals[lastfit] + binvarvals[j], threshold) )
8372 {
8373 clqvars[lastfit + 1] = binvars[j];
8374
8375 /* add clique with at least two variables */
8376 SCIP_CALL( SCIPaddClique(scip, clqvars, NULL, lastfit + 2, FALSE, &infeasible, &nbdchgs) );
8377
8378 if( infeasible )
8379 {
8380 *cutoff = TRUE;
8381 break;
8382 }
8383
8384 *nchgbds += nbdchgs;
8385
8386 cliquenonzerosadded += (lastfit + 2);
8387 if( cliquenonzerosadded >= MAX_CLIQUE_NONZEROS_PER_CONS )
8388 {
8389 stopped = TRUE;
8390 break;
8391 }
8392
8393 ++j;
8394 }
8395 else
8396 --lastfit;
8397 }
8398
8399 SCIPfreeBufferArray(scip, &clqvars);
8400 }
8401 }
8402 }
8403
8404 /* did we find some boundchanges, then we need to remove fixings and tighten the bounds further */
8405 if( !stopped && !*cutoff && *nchgbds - oldnchgbds > 0 )
8406 {
8407 /* check for fixed variables */
8408 SCIP_CALL( fixVariables(scip, cons, cutoff, nfixedvars) );
8409
8410 if( !*cutoff )
8411 {
8412 /* tighten variable's bounds */
8413 SCIP_CALL( tightenBounds(scip, cons, maxeasyactivitydelta, sortvars, cutoff, nchgbds) );
8414
8415 if( !*cutoff )
8416 {
8417 /* check for fixed variables */
8418 SCIP_CALL( fixVariables(scip, cons, cutoff, nfixedvars) );
8419
8420 if( !*cutoff )
8421 {
8422 /* sort variables by variable type */
8423 SCIP_CALL( consdataSort(scip, consdata) );
8424
8425 /* recompute activities if needed */
8426 if( !consdata->validactivities )
8427 consdataCalcActivities(scip, consdata);
8428 assert(consdata->validactivities);
8429
8430 nvars = consdata->nvars;
8431 vars = consdata->vars;
8432 vals = consdata->vals;
8433 nposbinvars = 0;
8434 nnegbinvars = 0;
8435 allonebinary = 0;
8436
8437 /* update binary variables */
8438 for( i = 0; i < nvars; ++i )
8439 {
8440 if( SCIPvarIsBinary(vars[i]) )
8441 {
8442 assert(!SCIPisZero(scip, vals[i]));
8443
8444 if( SCIPisEQ(scip, REALABS(vals[i]), 1.0) )
8445 ++allonebinary;
8446
8447 binvars[nposbinvars + nnegbinvars] = vars[i];
8448 binvarvals[nposbinvars + nnegbinvars] = vals[i];
8449
8450 if( SCIPisPositive(scip, vals[i]) )
8451 ++nposbinvars;
8452 else
8453 ++nnegbinvars;
8454
8455 assert(nposbinvars + nnegbinvars <= nvars);
8456 }
8457 /* stop searching for binary variables, because the constraint data is sorted */
8458 else if( SCIPvarGetType(vars[i]) == SCIP_VARTYPE_CONTINUOUS )
8459 break;
8460 }
8461 assert(nposbinvars + nnegbinvars <= nvars);
8462 }
8463 }
8464 }
8465
8466 oldnchgbds = *nchgbds;
8467 }
8468
8469 /* case b) */
8470 if( !stopped && !(*cutoff) && finitelhs && finiteposmaxact && nnegbinvars >= 2 )
8471 {
8472 /* compute value that needs to be deceeded */
8473 threshold = consdata->lhs - consdata->glbmaxactivity;
8474
8475 i = nposbinvars + nnegbinvars - 1;
8476 j = i - 1;
8477 #if 0 /* assertion should only holds when constraints were fully propagated and boundstightened */
8478 /* check that it is possible to choose binvar[i], otherwise it should have been fixed to zero */
8479 assert(SCIPisFeasGE(scip, binvarvals[i], threshold));
8480 #endif
8481 /* check if two variables are in a clique */
8482 if( SCIPisFeasLT(scip, binvarvals[i] + binvarvals[j], threshold) )
8483 {
8484 --j;
8485 /* check for extending the clique */
8486 while( j >= nposbinvars )
8487 {
8488 if( !SCIPisFeasLT(scip, binvarvals[j+1] + binvarvals[j], threshold) )
8489 break;
8490 --j;
8491 }
8492 jstart = j;
8493
8494 assert(i - j >= 2);
8495 /* add clique with at least two variables */
8496 SCIP_CALL( SCIPaddClique(scip, &(binvars[j+1]), NULL, i - j, FALSE, &infeasible, &nbdchgs) );
8497
8498 if( infeasible )
8499 *cutoff = TRUE;
8500
8501 *nchgbds += nbdchgs;
8502
8503 cliquenonzerosadded += (i - j);
8504 if( cliquenonzerosadded >= MAX_CLIQUE_NONZEROS_PER_CONS )
8505 stopped = TRUE;
8506
8507 /* exchange the last variable in the clique if possible and add all new ones */
8508 if( !stopped && !(*cutoff) && jstart >= nposbinvars )
8509 {
8510 SCIP_VAR** clqvars;
8511 int lastfit = jstart + 1;
8512 assert(lastfit < i);
8513
8514 /* copy all 'main'-clique variables */
8515 SCIP_CALL( SCIPduplicateBufferArray(scip, &clqvars, &(binvars[lastfit]), i - j) );
8516 ++lastfit;
8517
8518 /* iterate up to the front with j and up to the end with lastfit, and check for different cliques */
8519 while( lastfit <= i && j >= nposbinvars )
8520 {
8521 /* check if two variables are in a clique */
8522 if( SCIPisFeasLT(scip, binvarvals[lastfit] + binvarvals[j], threshold) )
8523 {
8524 assert(lastfit - jstart - 2 >= 0 && lastfit - jstart - 2 < i);
8525 clqvars[lastfit - jstart - 2] = binvars[j];
8526
8527 assert(i - lastfit + 2 >= 2);
8528 /* add clique with at least two variables */
8529 SCIP_CALL( SCIPaddClique(scip, &(clqvars[lastfit - jstart - 2]), NULL, i - lastfit + 2, FALSE, &infeasible, &nbdchgs) );
8530
8531 if( infeasible )
8532 {
8533 *cutoff = TRUE;
8534 break;
8535 }
8536
8537 *nchgbds += nbdchgs;
8538
8539 cliquenonzerosadded += (i - lastfit + 2);
8540 if( cliquenonzerosadded >= MAX_CLIQUE_NONZEROS_PER_CONS )
8541 {
8542 stopped = TRUE;
8543 break;
8544 }
8545
8546 --j;
8547 }
8548 else
8549 ++lastfit;
8550 }
8551
8552 SCIPfreeBufferArray(scip, &clqvars);
8553 }
8554 }
8555 }
8556
8557 /* did we find some boundchanges, then we need to remove fixings and tighten the bounds further */
8558 if( !stopped && !*cutoff && *nchgbds - oldnchgbds > 0 )
8559 {
8560 /* check for fixed variables */
8561 SCIP_CALL( fixVariables(scip, cons, cutoff, nfixedvars) );
8562
8563 if( !*cutoff )
8564 {
8565 /* tighten variable's bounds */
8566 SCIP_CALL( tightenBounds(scip, cons, maxeasyactivitydelta, sortvars, cutoff, nchgbds) );
8567
8568 if( !*cutoff )
8569 {
8570 /* check for fixed variables */
8571 SCIP_CALL( fixVariables(scip, cons, cutoff, nfixedvars) );
8572
8573 if( !*cutoff )
8574 {
8575 /* sort variables by variable type */
8576 SCIP_CALL( consdataSort(scip, consdata) );
8577
8578 /* recompute activities if needed */
8579 if( !consdata->validactivities )
8580 consdataCalcActivities(scip, consdata);
8581 assert(consdata->validactivities);
8582
8583 nvars = consdata->nvars;
8584 vars = consdata->vars;
8585 vals = consdata->vals;
8586 nposbinvars = 0;
8587 nnegbinvars = 0;
8588 allonebinary = 0;
8589
8590 /* update binary variables */
8591 for( i = 0; i < nvars; ++i )
8592 {
8593 if( SCIPvarIsBinary(vars[i]) )
8594 {
8595 assert(!SCIPisZero(scip, vals[i]));
8596
8597 if( SCIPisEQ(scip, REALABS(vals[i]), 1.0) )
8598 ++allonebinary;
8599
8600 binvars[nposbinvars + nnegbinvars] = vars[i];
8601 binvarvals[nposbinvars + nnegbinvars] = vals[i];
8602
8603 if( SCIPisPositive(scip, vals[i]) )
8604 ++nposbinvars;
8605 else
8606 ++nnegbinvars;
8607
8608 assert(nposbinvars + nnegbinvars <= nvars);
8609 }
8610 /* stop searching for binary variables, because the constraint data is sorted */
8611 else if( SCIPvarGetType(vars[i]) == SCIP_VARTYPE_CONTINUOUS )
8612 break;
8613 }
8614 assert(nposbinvars + nnegbinvars <= nvars);
8615 }
8616 }
8617 }
8618
8619 oldnchgbds = *nchgbds;
8620 }
8621
8622 /* case c) */
8623 if( !(*cutoff) && finiterhs && finiteminact && nnegbinvars >= 2 )
8624 {
8625 SCIP_Bool* values;
8626
8627 /* initialize clique values array for adding a negated clique */
8628 SCIP_CALL( SCIPallocBufferArray(scip, &values, nnegbinvars) );
8629 BMSclearMemoryArray(values, nnegbinvars);
8630
8631 /* compute value that needs to be exceeded */
8632 threshold = consdata->rhs - consdata->glbminactivity;
8633
8634 i = nposbinvars + nnegbinvars - 1;
8635 j = i - 1;
8636
8637 #if 0 /* assertion should only holds when constraints were fully propagated and boundstightened */
8638 /* check if the variable should not have already been fixed to one */
8639 assert(!SCIPisFeasGT(scip, binvarvals[i], threshold));
8640 #endif
8641
8642 if( SCIPisFeasGT(scip, -binvarvals[i] - binvarvals[j], threshold) )
8643 {
8644 --j;
8645 /* check for extending the clique */
8646 while( j >= nposbinvars )
8647 {
8648 if( !SCIPisFeasGT(scip, -binvarvals[j+1] - binvarvals[j], threshold) )
8649 break;
8650 --j;
8651 }
8652 jstart = j;
8653
8654 assert(i - j >= 2);
8655 /* add negated clique with at least two variables */
8656 SCIP_CALL( SCIPaddClique(scip, &(binvars[j+1]), values, i - j, FALSE, &infeasible, &nbdchgs) );
8657
8658 if( infeasible )
8659 *cutoff = TRUE;
8660
8661 *nchgbds += nbdchgs;
8662
8663 cliquenonzerosadded += (i - j);
8664 if( cliquenonzerosadded >= MAX_CLIQUE_NONZEROS_PER_CONS )
8665 stopped = TRUE;
8666
8667 /* exchange the last variable in the clique if possible and add all new ones */
8668 if( !stopped && !(*cutoff) && jstart >= nposbinvars )
8669 {
8670 SCIP_VAR** clqvars;
8671 int lastfit = j + 1;
8672 assert(lastfit < i);
8673
8674 /* copy all 'main'-clique variables */
8675 SCIP_CALL( SCIPduplicateBufferArray(scip, &clqvars, &(binvars[lastfit]), i - j) );
8676 ++lastfit;
8677
8678 /* iterate up to the front with j and up to the end with lastfit, and check for different cliques */
8679 while( lastfit <= i && j >= nposbinvars )
8680 {
8681 /* check if two variables are in a negated clique */
8682 if( SCIPisFeasGT(scip, -binvarvals[lastfit] - binvarvals[j], threshold) )
8683 {
8684 assert(lastfit - jstart - 2 >= 0 && lastfit - jstart - 2 < i);
8685 clqvars[lastfit - jstart - 2] = binvars[j];
8686
8687 assert(i - lastfit + 2 >= 2);
8688 /* add clique with at least two variables */
8689 SCIP_CALL( SCIPaddClique(scip, &(clqvars[lastfit - jstart - 2]), values, i - lastfit + 2, FALSE, &infeasible, &nbdchgs) );
8690
8691 if( infeasible )
8692 {
8693 *cutoff = TRUE;
8694 break;
8695 }
8696
8697 *nchgbds += nbdchgs;
8698
8699 cliquenonzerosadded += (i - lastfit + 2);
8700 if( cliquenonzerosadded >= MAX_CLIQUE_NONZEROS_PER_CONS )
8701 {
8702 stopped = TRUE;
8703 break;
8704 }
8705
8706 --j;
8707 }
8708 else
8709 ++lastfit;
8710 }
8711
8712 SCIPfreeBufferArray(scip, &clqvars);
8713 }
8714 }
8715
8716 SCIPfreeBufferArray(scip, &values);
8717 }
8718
8719 /* did we find some boundchanges, then we need to remove fixings and tighten the bounds further */
8720 if( !stopped && !*cutoff && *nchgbds - oldnchgbds > 0 )
8721 {
8722 /* check for fixed variables */
8723 SCIP_CALL( fixVariables(scip, cons, cutoff, nfixedvars) );
8724
8725 if( !*cutoff )
8726 {
8727 /* tighten variable's bounds */
8728 SCIP_CALL( tightenBounds(scip, cons, maxeasyactivitydelta, sortvars, cutoff, nchgbds) );
8729
8730 if( !*cutoff )
8731 {
8732 /* check for fixed variables */
8733 SCIP_CALL( fixVariables(scip, cons, cutoff, nfixedvars) );
8734
8735 if( !*cutoff )
8736 {
8737 /* sort variables by variable type */
8738 SCIP_CALL( consdataSort(scip, consdata) );
8739
8740 /* recompute activities if needed */
8741 if( !consdata->validactivities )
8742 consdataCalcActivities(scip, consdata);
8743 assert(consdata->validactivities);
8744
8745 nvars = consdata->nvars;
8746 vars = consdata->vars;
8747 vals = consdata->vals;
8748 nposbinvars = 0;
8749 nnegbinvars = 0;
8750 allonebinary = 0;
8751
8752 /* update binary variables */
8753 for( i = 0; i < nvars; ++i )
8754 {
8755 if( SCIPvarIsBinary(vars[i]) )
8756 {
8757 assert(!SCIPisZero(scip, vals[i]));
8758
8759 if( SCIPisEQ(scip, REALABS(vals[i]), 1.0) )
8760 ++allonebinary;
8761
8762 binvars[nposbinvars + nnegbinvars] = vars[i];
8763 binvarvals[nposbinvars + nnegbinvars] = vals[i];
8764
8765 if( SCIPisPositive(scip, vals[i]) )
8766 ++nposbinvars;
8767 else
8768 ++nnegbinvars;
8769
8770 assert(nposbinvars + nnegbinvars <= nvars);
8771 }
8772 /* stop searching for binary variables, because the constraint data is sorted */
8773 else if( SCIPvarGetType(vars[i]) == SCIP_VARTYPE_CONTINUOUS )
8774 break;
8775 }
8776 assert(nposbinvars + nnegbinvars <= nvars);
8777 }
8778 }
8779 }
8780 }
8781
8782 /* case d) */
8783 if( !stopped && !(*cutoff) && finitelhs && finitemaxact && nposbinvars >= 2 )
8784 {
8785 SCIP_Bool* values;
8786
8787 /* initialize clique values array for adding a negated clique */
8788 SCIP_CALL( SCIPallocBufferArray(scip, &values, nposbinvars) );
8789 BMSclearMemoryArray(values, nposbinvars);
8790
8791 /* compute value that needs to be exceeded */
8792 threshold = consdata->lhs - consdata->glbmaxactivity;
8793
8794 j = 1;
8795
8796 #if 0 /* assertion should only holds when constraints were fully propagated and boundstightened */
8797 /* check if the variable should not have already been fixed to one */
8798 assert(!SCIPisFeasLT(scip, -binvarvals[0], threshold));
8799 #endif
8800
8801 if( SCIPisFeasLT(scip, -binvarvals[0] - binvarvals[j], threshold) )
8802 {
8803 ++j;
8804 /* check for extending the clique */
8805 while( j < nposbinvars )
8806 {
8807 if( !SCIPisFeasLT(scip, -binvarvals[j-1] - binvarvals[j], threshold) )
8808 break;
8809 ++j;
8810 }
8811 assert(j >= 2);
8812
8813 /* add negated clique with at least two variables */
8814 SCIP_CALL( SCIPaddClique(scip, binvars, values, j, FALSE, &infeasible, &nbdchgs) );
8815
8816 if( infeasible )
8817 *cutoff = TRUE;
8818
8819 *nchgbds += nbdchgs;
8820
8821 cliquenonzerosadded += j;
8822 if( cliquenonzerosadded >= MAX_CLIQUE_NONZEROS_PER_CONS )
8823 stopped = TRUE;
8824
8825 /* exchange the last variable in the clique if possible and add all new ones */
8826 if( !stopped && !(*cutoff) && j < nposbinvars )
8827 {
8828 SCIP_VAR** clqvars;
8829 int lastfit = j - 2;
8830 assert(lastfit >= 0);
8831
8832 /* copy all 'main'-clique variables */
8833 SCIP_CALL( SCIPduplicateBufferArray(scip, &clqvars, binvars, j) );
8834
8835 /* iterate up to the end with j and up to the front with lastfit, and check for different cliques */
8836 while( lastfit >= 0 && j < nposbinvars )
8837 {
8838 /* check if two variables are in a negated clique */
8839 if( SCIPisFeasLT(scip, -binvarvals[lastfit] - binvarvals[j], threshold) )
8840 {
8841 clqvars[lastfit + 1] = binvars[j];
8842
8843 /* add clique with at least two variables */
8844 SCIP_CALL( SCIPaddClique(scip, clqvars, values, lastfit + 2, FALSE, &infeasible, &nbdchgs) );
8845
8846 if( infeasible )
8847 {
8848 *cutoff = TRUE;
8849 break;
8850 }
8851
8852 *nchgbds += nbdchgs;
8853
8854 cliquenonzerosadded += lastfit + 2;
8855 if( cliquenonzerosadded >= MAX_CLIQUE_NONZEROS_PER_CONS )
8856 break;
8857
8858 ++j;
8859 }
8860 else
8861 --lastfit;
8862 }
8863
8864 SCIPfreeBufferArray(scip, &clqvars);
8865 }
8866 }
8867
8868 SCIPfreeBufferArray(scip, &values);
8869 }
8870 }
8871
8872 SCIPfreeBufferArray(scip, &binvarvals);
8873 SCIPfreeBufferArray(scip, &binvars);
8874
8875 if( *cutoff )
8876 return SCIP_OKAY;
8877 }
8878
8879 /* 2. we only check if the constraint is a set packing / partitioning constraint */
8880
8881 /* check if all variables are binary, if the coefficients are +1 or -1, and if the right hand side is equal
8882 * to 1 - number of negative coefficients, or if the left hand side is equal to number of positive coefficients - 1
8883 */
8884 nposcoefs = 0;
8885 nnegcoefs = 0;
8886 for( i = 0; i < nvars; ++i )
8887 {
8888 if( !SCIPvarIsBinary(vars[i]) )
8889 return SCIP_OKAY;
8890 else if( SCIPisEQ(scip, vals[i], +1.0) )
8891 nposcoefs++;
8892 else if( SCIPisEQ(scip, vals[i], -1.0) )
8893 nnegcoefs++;
8894 else
8895 return SCIP_OKAY;
8896 }
8897
8898 lhsclique = SCIPisEQ(scip, consdata->lhs, (SCIP_Real)nposcoefs - 1.0);
8899 rhsclique = SCIPisEQ(scip, consdata->rhs, 1.0 - (SCIP_Real)nnegcoefs);
8900
8901 if( lhsclique || rhsclique )
8902 {
8903 SCIP_Bool* values;
8904 int nbdchgs;
8905
8906 SCIPdebugMsg(scip, "linear constraint <%s>: adding clique with %d vars (%d pos, %d neg)\n",
8907 SCIPconsGetName(cons), nvars, nposcoefs, nnegcoefs);
8908 SCIP_CALL( SCIPallocBufferArray(scip, &values, nvars) );
8909
8910 for( i = 0; i < nvars; ++i )
8911 values[i] = (rhsclique == (vals[i] > 0.0));
8912
8913 SCIP_CALL( SCIPaddClique(scip, vars, values, nvars, SCIPisEQ(scip, consdata->lhs, consdata->rhs), &infeasible, &nbdchgs) );
8914
8915 if( infeasible )
8916 *cutoff = TRUE;
8917
8918 *nchgbds += nbdchgs;
8919 SCIPfreeBufferArray(scip, &values);
8920 }
8921
8922 return SCIP_OKAY;
8923 }
8924
8925 /** tightens left and right hand side of constraint due to integrality */
8926 static
tightenSides(SCIP * scip,SCIP_CONS * cons,int * nchgsides,SCIP_Bool * infeasible)8927 SCIP_RETCODE tightenSides(
8928 SCIP* scip, /**< SCIP data structure */
8929 SCIP_CONS* cons, /**< linear constraint */
8930 int* nchgsides, /**< pointer to count number of side changes */
8931 SCIP_Bool* infeasible /**< pointer to store whether infeasibility was detected */
8932 )
8933 {
8934 SCIP_CONSDATA* consdata;
8935 SCIP_Real newlhs;
8936 SCIP_Real newrhs;
8937 SCIP_Bool chglhs;
8938 SCIP_Bool chgrhs;
8939 SCIP_Bool integral;
8940 int i;
8941
8942 assert(scip != NULL);
8943 assert(cons != NULL);
8944 assert(nchgsides != NULL);
8945 assert(infeasible != NULL);
8946
8947 consdata = SCIPconsGetData(cons);
8948 assert(consdata != NULL);
8949
8950 *infeasible = FALSE;
8951
8952 chglhs = FALSE;
8953 chgrhs = FALSE;
8954 newlhs = -SCIPinfinity(scip);
8955 newrhs = SCIPinfinity(scip);
8956
8957 if( !SCIPisIntegral(scip, consdata->lhs) || !SCIPisIntegral(scip, consdata->rhs) )
8958 {
8959 integral = TRUE;
8960 for( i = 0; i < consdata->nvars && integral; ++i )
8961 {
8962 integral = SCIPisIntegral(scip, consdata->vals[i])
8963 && (SCIPvarGetType(consdata->vars[i]) != SCIP_VARTYPE_CONTINUOUS);
8964 }
8965 if( integral )
8966 {
8967 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisIntegral(scip, consdata->lhs) )
8968 {
8969 newlhs = SCIPfeasCeil(scip, consdata->lhs);
8970 chglhs = TRUE;
8971 }
8972 if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisIntegral(scip, consdata->rhs) )
8973 {
8974 newrhs = SCIPfeasFloor(scip, consdata->rhs);
8975 chgrhs = TRUE;
8976 }
8977
8978 /* check whether rounding would lead to an unsatisfiable constraint */
8979 if( SCIPisGT(scip, newlhs, newrhs) )
8980 {
8981 SCIPdebugMsg(scip, "rounding sides=[%.15g,%.15g] of linear constraint <%s> with integral coefficients and variables only "
8982 "is infeasible\n", consdata->lhs, consdata->rhs, SCIPconsGetName(cons));
8983
8984 *infeasible = TRUE;
8985 return SCIP_OKAY;
8986 }
8987
8988 SCIPdebugMsg(scip, "linear constraint <%s>: make sides integral: sides=[%.15g,%.15g]\n",
8989 SCIPconsGetName(cons), consdata->lhs, consdata->rhs);
8990
8991 if( chglhs )
8992 {
8993 assert(!SCIPisInfinity(scip, -newlhs));
8994
8995 SCIP_CALL( chgLhs(scip, cons, newlhs) );
8996 if( !consdata->upgraded )
8997 (*nchgsides)++;
8998 }
8999 if( chgrhs )
9000 {
9001 assert(!SCIPisInfinity(scip, newrhs));
9002
9003 SCIP_CALL( chgRhs(scip, cons, newrhs) );
9004 if( !consdata->upgraded )
9005 (*nchgsides)++;
9006 }
9007 SCIPdebugMsg(scip, "linear constraint <%s>: new integral sides: sides=[%.15g,%.15g]\n",
9008 SCIPconsGetName(cons), consdata->lhs, consdata->rhs);
9009 }
9010 }
9011
9012 return SCIP_OKAY;
9013 }
9014
9015 /** tightens coefficients of binary, integer, and implicit integer variables due to activity bounds in presolving:
9016 * given an inequality lhs <= a*x + ai*xi <= rhs, with a non-continuous variable li <= xi <= ui
9017 * let minact := min{a*x + ai*xi}, maxact := max{a*x + ai*xi}
9018 * (i) ai >= 0:
9019 * if minact + ai >= lhs and maxact - ai <= rhs: (**)
9020 * - a deviation from the lower/upper bound of xi would make the left/right hand side redundant
9021 * - ai, lhs and rhs can be changed to have the same redundancy effect and the same results for
9022 * xi fixed to its bounds, but with a reduced ai and tightened sides to tighten the LP relaxation
9023 * - change coefficients:
9024 * ai' := max(lhs - minact, maxact - rhs)
9025 * lhs' := lhs - (ai - ai')*li
9026 * rhs' := rhs - (ai - ai')*ui
9027 * (ii) ai < 0:
9028 * if minact - ai >= lhs and maxact + ai <= rhs: (***)
9029 * - a deviation from the upper/lower bound of xi would make the left/right hand side redundant
9030 * - ai, lhs and rhs can be changed to have the same redundancy effect and the same results for
9031 * xi fixed to its bounds, but with a reduced ai and tightened sides to tighten the LP relaxation
9032 * - change coefficients:
9033 * ai' := min(rhs - maxact, minact - lhs)
9034 * lhs' := lhs - (ai - ai')*ui
9035 * rhs' := rhs - (ai - ai')*li
9036 *
9037 * We further try to remove redundant variable from the constraint;
9038 * Variables which fulfill conditions (**) or (***) are called surely non-redundant variables.
9039 * A deviation of only one from their bound makes the lhs/rhs feasible (i.e., redundant), even if all other
9040 * variables are set to their "worst" bound. If all variables which are not surely non-redundant cannot make
9041 * the lhs/rhs redundant, even if they are set to their "best" bound, they can be removed from the constraint.
9042 * E.g., for binary variables and an inequality x_1 +x_2 +10y_1 +10y_2 >= 5, setting either of the y_i to one
9043 * suffices to fulfill the inequality, whereas the x_i do not contribute to feasibility and can be removed.
9044 *
9045 * @todo use also some tightening procedures for (knapsack) constraints with non-integer coefficients, see
9046 * cons_knapsack.c the following methods detectRedundantVars() and tightenWeights()
9047 */
9048 static
consdataTightenCoefs(SCIP * scip,SCIP_CONS * cons,int * nchgcoefs,int * nchgsides)9049 SCIP_RETCODE consdataTightenCoefs(
9050 SCIP* scip, /**< SCIP data structure */
9051 SCIP_CONS* cons, /**< linear constraint */
9052 int* nchgcoefs, /**< pointer to count total number of changed coefficients */
9053 int* nchgsides /**< pointer to count number of side changes */
9054 )
9055 {
9056 SCIP_CONSDATA* consdata;
9057 SCIP_VAR* var;
9058 SCIP_Real minactivity; /* minimal value w.r.t. the variable's local bounds for the constraint's
9059 * activity, ignoring the coefficients contributing with infinite value */
9060 SCIP_Real maxactivity; /* maximal value w.r.t. the variable's local bounds for the constraint's
9061 * activity, ignoring the coefficients contributing with infinite value */
9062 SCIP_Bool minactisrelax; /* do huge finite values contribute to the minactivity? */
9063 SCIP_Bool maxactisrelax; /* do huge finite values contribute to the maxactivity? */
9064 SCIP_Bool isminsettoinfinity;
9065 SCIP_Bool ismaxsettoinfinity;
9066 SCIP_Real minleftactivity; /* minimal activity without surely non-redundant variables. */
9067 SCIP_Real maxleftactivity; /* maximal activity without surely non-redundant variables. */
9068 SCIP_Real aggrlhs; /* lhs without minimal activity of surely non-redundant variables. */
9069 SCIP_Real aggrrhs; /* rhs without maximal activity of surely non-redundant variables. */
9070 SCIP_Real lval; /* candidate for new value arising from considering the left hand side */
9071 SCIP_Real rval; /* candidate for new value arising from considering the left hand side */
9072 SCIP_Real val;
9073 SCIP_Real newval;
9074 SCIP_Real newlhs;
9075 SCIP_Real newrhs;
9076 SCIP_Real lb;
9077 SCIP_Real ub;
9078 int i;
9079
9080 assert(scip != NULL);
9081 assert(cons != NULL);
9082 assert(nchgcoefs != NULL);
9083 assert(nchgsides != NULL);
9084
9085 consdata = SCIPconsGetData(cons);
9086 assert(consdata != NULL);
9087
9088 /* @todo Is this still needed with automatic recomputation of activities? */
9089 /* if the maximal coefficient is too large, recompute the activities */
9090 if( (consdata->validmaxabsval && consdata->maxabsval > MAXVALRECOMP)
9091 || (consdata->validminabsval && consdata->minabsval < MINVALRECOMP) )
9092 {
9093 consdataRecomputeMinactivity(scip, consdata);
9094 consdataRecomputeMaxactivity(scip, consdata);
9095 }
9096
9097 /* get the minimal and maximal activity of the constraint */
9098 consdataGetActivityBounds(scip, consdata, TRUE, &minactivity, &maxactivity, &minactisrelax, &maxactisrelax,
9099 &isminsettoinfinity, &ismaxsettoinfinity);
9100
9101 minleftactivity = 0.0;
9102 maxleftactivity = 0.0;
9103
9104 /* try to tighten each coefficient */
9105 i = 0;
9106 while( i < consdata->nvars )
9107 {
9108 var = consdata->vars[i];
9109
9110 /* get coefficient and variable's bounds */
9111 lb = SCIPvarGetLbLocal(var);
9112 ub = SCIPvarGetUbLocal(var);
9113 val = consdata->vals[i];
9114 assert(!SCIPisZero(scip, val));
9115
9116 /* check sign of coefficient */
9117 if( val >= 0.0 )
9118 {
9119 /* check, if a deviation from lower/upper bound would make lhs/rhs redundant */
9120 if( SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS &&
9121 SCIPisGE(scip, minactivity + val, consdata->lhs) && SCIPisLE(scip, maxactivity - val, consdata->rhs) )
9122 {
9123 /* change coefficients:
9124 * ai' := max(lhs - minact, maxact - rhs)
9125 * lhs' := lhs - (ai - ai')*li
9126 * rhs' := rhs - (ai - ai')*ui
9127 */
9128
9129 lval = consdata->lhs - minactivity;
9130 rval = maxactivity - consdata->rhs;
9131
9132 /* Try to avoid cancellation, if there are only two variables */
9133 if( consdata->nvars == 2 )
9134 {
9135 SCIP_Real otherval;
9136 otherval = consdata->vals[1-i];
9137
9138 if( !SCIPisInfinity(scip, -consdata->lhs) && !isminsettoinfinity )
9139 {
9140 lval = consdata->lhs - val*lb;
9141 lval -= otherval > 0.0 ? otherval * SCIPvarGetLbLocal(consdata->vars[1-i]) : otherval * SCIPvarGetUbLocal(consdata->vars[1-i]);
9142 }
9143
9144 if( !SCIPisInfinity(scip, consdata->rhs) && !ismaxsettoinfinity )
9145 {
9146 rval = val*ub - consdata->rhs;
9147 rval += otherval > 0.0 ? otherval * SCIPvarGetUbLocal(consdata->vars[1-i]) : otherval * SCIPvarGetLbLocal(consdata->vars[1-i]);
9148 }
9149 }
9150
9151 newval = MAX(lval, rval);
9152 assert(SCIPisSumRelLE(scip, newval, val));
9153
9154 /* Try to avoid cancellation in computation of lhs/rhs */
9155 newlhs = consdata->lhs - val * lb;
9156 newlhs += newval * lb;
9157 newrhs = consdata->rhs - val * ub;
9158 newrhs += newval * ub;
9159
9160 if( !SCIPisSumRelEQ(scip, newval, val) )
9161 {
9162 SCIPdebugMsg(scip, "linear constraint <%s>: change coefficient %+.15g<%s> to %+.15g<%s>, act=[%.15g,%.15g], side=[%.15g,%.15g]\n",
9163 SCIPconsGetName(cons), val, SCIPvarGetName(var), newval, SCIPvarGetName(var),
9164 minactivity, maxactivity, consdata->lhs, consdata->rhs);
9165
9166 /* update the coefficient and the activity bounds */
9167 if( SCIPisZero(scip, newval) )
9168 {
9169 SCIP_CALL( delCoefPos(scip, cons, i) );
9170 i--;
9171 }
9172 else
9173 {
9174 SCIP_CALL( chgCoefPos(scip, cons, i, newval) );
9175 }
9176 (*nchgcoefs)++;
9177
9178 /* get the new minimal and maximal activity of the constraint */
9179 consdataGetActivityBounds(scip, consdata, TRUE, &minactivity, &maxactivity, &minactisrelax, &maxactisrelax,
9180 &isminsettoinfinity, &ismaxsettoinfinity);
9181
9182 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisEQ(scip, newlhs, consdata->lhs) )
9183 {
9184 SCIPdebugMsg(scip, "linear constraint <%s>: change lhs %.15g to %.15g\n", SCIPconsGetName(cons), consdata->lhs, newlhs);
9185
9186 SCIP_CALL( chgLhs(scip, cons, newlhs) );
9187 (*nchgsides)++;
9188 assert(SCIPisEQ(scip, consdata->lhs, newlhs));
9189 }
9190
9191 if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisEQ(scip, newrhs, consdata->rhs) )
9192 {
9193 SCIPdebugMsg(scip, "linear constraint <%s>: change rhs %.15g to %.15g\n", SCIPconsGetName(cons), consdata->rhs, newrhs);
9194
9195 SCIP_CALL( chgRhs(scip, cons, newrhs) );
9196 (*nchgsides)++;
9197 assert(SCIPisEQ(scip, consdata->rhs, newrhs));
9198 }
9199 }
9200 }
9201 else
9202 {
9203 if( !SCIPisInfinity(scip, -minleftactivity) )
9204 {
9205 assert(!SCIPisInfinity(scip, val));
9206 assert(!SCIPisInfinity(scip, lb));
9207 if( SCIPisInfinity(scip, -lb) )
9208 minleftactivity = -SCIPinfinity(scip);
9209 else
9210 minleftactivity += val * lb;
9211 }
9212
9213 if( !SCIPisInfinity(scip, maxleftactivity) )
9214 {
9215 assert(!SCIPisInfinity(scip, val));
9216 assert(!SCIPisInfinity(scip, -ub));
9217 if( SCIPisInfinity(scip,ub) )
9218 maxleftactivity = SCIPinfinity(scip);
9219 else
9220 maxleftactivity += val * ub;
9221 }
9222 }
9223 }
9224 else
9225 {
9226 /* check, if a deviation from lower/upper bound would make lhs/rhs redundant */
9227 if( SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS &&
9228 SCIPisGE(scip, minactivity - val, consdata->lhs) && SCIPisLE(scip, maxactivity + val, consdata->rhs) )
9229 {
9230 /* change coefficients:
9231 * ai' := min(rhs - maxact, minact - lhs)
9232 * lhs' := lhs - (ai - ai')*ui
9233 * rhs' := rhs - (ai - ai')*li
9234 */
9235
9236 lval = minactivity - consdata->lhs;
9237 rval = consdata->rhs - maxactivity;
9238
9239 /* Try to avoid cancellation, if there are only two variables */
9240 if( consdata->nvars == 2 )
9241 {
9242 SCIP_Real otherval;
9243 otherval = consdata->vals[1-i];
9244
9245 if( !SCIPisInfinity(scip, -consdata->lhs) && !isminsettoinfinity )
9246 {
9247 lval = val*ub - consdata->lhs;
9248 lval += otherval > 0.0 ? otherval * SCIPvarGetLbLocal(consdata->vars[1-i]) : otherval * SCIPvarGetUbLocal(consdata->vars[1-i]);
9249 }
9250
9251 if( !SCIPisInfinity(scip, consdata->rhs) && !ismaxsettoinfinity )
9252 {
9253 rval = consdata->rhs - val*lb;
9254 rval -= otherval > 0.0 ? otherval * SCIPvarGetUbLocal(consdata->vars[1-i]) : otherval * SCIPvarGetLbLocal(consdata->vars[1-i]);
9255 }
9256 }
9257
9258 newval = MIN(lval, rval);
9259 assert(SCIPisSumRelGE(scip, newval, val));
9260
9261 /* Try to avoid cancellation in computation of lhs/rhs */
9262 newlhs = consdata->lhs - val * ub;
9263 newlhs += newval * ub;
9264 newrhs = consdata->rhs - val * lb;
9265 newrhs += newval * lb;
9266
9267 if( !SCIPisSumRelEQ(scip, newval, val) )
9268 {
9269 SCIPdebugMsg(scip, "linear constraint <%s>: change coefficient %+.15g<%s> to %+.15g<%s>, act=[%.15g,%.15g], side=[%.15g,%.15g]\n",
9270 SCIPconsGetName(cons), val, SCIPvarGetName(var), newval, SCIPvarGetName(var),
9271 minactivity, maxactivity, consdata->lhs, consdata->rhs);
9272
9273 /* update the coefficient and the activity bounds */
9274 if( SCIPisZero(scip, newval) )
9275 {
9276 SCIP_CALL( delCoefPos(scip, cons, i) );
9277 i--;
9278 }
9279 else
9280 {
9281 SCIP_CALL( chgCoefPos(scip, cons, i, newval) );
9282 }
9283 (*nchgcoefs)++;
9284
9285 /* get the new minimal and maximal activity of the constraint */
9286 consdataGetActivityBounds(scip, consdata, TRUE, &minactivity, &maxactivity, &minactisrelax, &maxactisrelax,
9287 &isminsettoinfinity, &ismaxsettoinfinity);
9288
9289 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisEQ(scip, newlhs, consdata->lhs) )
9290 {
9291 SCIPdebugMsg(scip, "linear constraint <%s>: change lhs %.15g to %.15g\n", SCIPconsGetName(cons), consdata->lhs, newlhs);
9292
9293 SCIP_CALL( chgLhs(scip, cons, newlhs) );
9294 (*nchgsides)++;
9295 assert(SCIPisEQ(scip, consdata->lhs, newlhs));
9296 }
9297
9298 if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisEQ(scip, newrhs, consdata->rhs) )
9299 {
9300 SCIPdebugMsg(scip, "linear constraint <%s>: change rhs %.15g to %.15g\n", SCIPconsGetName(cons), consdata->rhs, newrhs);
9301
9302 SCIP_CALL( chgRhs(scip, cons, newrhs) );
9303 (*nchgsides)++;
9304 assert(SCIPisEQ(scip, consdata->rhs, newrhs));
9305 }
9306 }
9307 }
9308 else
9309 {
9310 if( !SCIPisInfinity(scip, -minleftactivity) )
9311 {
9312 assert(!SCIPisInfinity(scip, -val));
9313 assert(!SCIPisInfinity(scip, -ub));
9314 if( SCIPisInfinity(scip, ub) )
9315 minleftactivity = -SCIPinfinity(scip);
9316 else
9317 minleftactivity += val * ub;
9318 }
9319
9320 if( !SCIPisInfinity(scip, maxleftactivity) )
9321 {
9322 assert(!SCIPisInfinity(scip, -val));
9323 assert(!SCIPisInfinity(scip, lb));
9324 if( SCIPisInfinity(scip, -lb) )
9325 maxleftactivity = SCIPinfinity(scip);
9326 else
9327 maxleftactivity += val * lb;
9328 }
9329 }
9330 }
9331 ++i;
9332 }
9333
9334 SCIPdebugMsg(scip, "minleftactivity = %.15g, rhs = %.15g\n",
9335 minleftactivity, consdata->rhs);
9336 SCIPdebugMsg(scip, "maxleftactivity = %.15g, lhs = %.15g\n",
9337 maxleftactivity, consdata->lhs);
9338
9339 /* minleft == \infty ==> minactivity == \infty */
9340 assert(!SCIPisInfinity(scip, -minleftactivity) || SCIPisInfinity(scip, -minactivity));
9341 assert(!SCIPisInfinity(scip, maxleftactivity) || SCIPisInfinity(scip, maxactivity));
9342
9343 /* if the lhs is finite, we will check in the following whether the not non-redundant variables can make lhs feasible;
9344 * this is not valid, if the minactivity is -\infty (aggrlhs would be minus infinity in the following computation)
9345 * or if huge values contributed to the minactivity, because the minactivity is then just a relaxation
9346 * (<= the exact minactivity), and we might falsely claim variables to be redundant in the following
9347 */
9348 assert(!SCIPisInfinity(scip, minactivity));
9349 if( !SCIPisInfinity(scip, -consdata->lhs) && (SCIPisInfinity(scip, -minactivity) || minactisrelax) )
9350 return SCIP_OKAY;
9351
9352 /* if the rhs is finite, we will check in the following whether the not non-redundant variables can make rhs feasible;
9353 * this is not valid, if the maxactivity is \infty (aggrrhs would be infinity in the following computation)
9354 * or if huge values contributed to the maxactivity, because the maxactivity is then just a relaxation
9355 * (>= the exact maxactivity), and we might falsely claim variables to be redundant in the following
9356 */
9357 assert(!SCIPisInfinity(scip, -maxactivity));
9358 if( !SCIPisInfinity(scip, consdata->rhs) && (SCIPisInfinity(scip, maxactivity) || maxactisrelax) )
9359 return SCIP_OKAY;
9360
9361 /* correct lhs and rhs by min/max activity of surely non-redundant variables
9362 * surely non-redundant variables are all those where a deviation from the bound makes the lhs/rhs redundant
9363 */
9364 aggrlhs = consdata->lhs - minactivity + minleftactivity;
9365 aggrrhs = consdata->rhs - maxactivity + maxleftactivity;
9366
9367 /* check if the constraint contains variables which are redundant. The reasoning is the following:
9368 * Each non-redundant variable can make the lhs/rhs feasible with a deviation of only one in the bound.
9369 * If _all_ variables which are not non-redundant together cannot make lhs/rhs feasible,
9370 * they can be removed from the constraint.
9371 * aggrrhs may contain some near-infinity value, but only if rhs is infinity.
9372 */
9373 if( (SCIPisInfinity(scip, -consdata->lhs) || SCIPisFeasLT(scip, maxleftactivity, aggrlhs))
9374 && (SCIPisInfinity(scip, consdata->rhs) || SCIPisFeasGT(scip, minleftactivity, aggrrhs)) )
9375 {
9376 SCIP_Real minleftactivitypart;
9377 SCIP_Real maxleftactivitypart;
9378
9379 assert(!SCIPisInfinity(scip, -consdata->lhs) || !SCIPisInfinity(scip, consdata->rhs));
9380
9381 /* try to remove redundant variables from constraint */
9382 i = 0;
9383 while( i < consdata->nvars )
9384 {
9385 var = consdata->vars[i];
9386 minleftactivitypart = 0.0;
9387 maxleftactivitypart = 0.0;
9388 lb = SCIPvarGetLbLocal(var);
9389 ub = SCIPvarGetUbLocal(var);
9390
9391 /* get coefficient and variable's bounds */
9392 val = consdata->vals[i];
9393 assert(!SCIPisZero(scip, val));
9394
9395 /* check sign of coefficient */
9396 if( val >= 0.0 )
9397 {
9398 /* negation of condition above in case of positive val */
9399 if( SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS ||
9400 SCIPisLT(scip, minactivity + val, consdata->lhs) || SCIPisGT(scip, maxactivity - val, consdata->rhs) )
9401 {
9402 SCIPdebugMsg(scip, "minactivity = %g\tval = %g\tlhs = %g\n", minactivity, val, consdata->lhs);
9403 SCIPdebugMsg(scip, "maxactivity = %g\tval = %g\trhs = %g\n", maxactivity, val, consdata->rhs);
9404 SCIPdebugMsg(scip, "linear constraint <%s>: remove variable <%s> with coefficient <%g> from constraint since it is redundant\n",
9405 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), val);
9406
9407 minleftactivitypart = val * lb;
9408 maxleftactivitypart = val * ub;
9409
9410 SCIP_CALL( delCoefPos(scip, cons, i) );
9411 i--;
9412
9413 /* get the new minimal and maximal activity of the constraint */
9414 consdataGetActivityBounds(scip, consdata, FALSE, &minactivity, &maxactivity, &minactisrelax, &maxactisrelax,
9415 &isminsettoinfinity, &ismaxsettoinfinity);
9416
9417 /* we return above if the condition does not hold and deleting a variable cannot increase the number of
9418 * huge contributions
9419 */
9420 assert(!minactisrelax || SCIPisInfinity(scip, -consdata->lhs));
9421 assert(!maxactisrelax || SCIPisInfinity(scip, consdata->rhs));
9422 }
9423 }
9424 else
9425 {
9426 /* negation of condition above in case of negative val */
9427 if( SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS ||
9428 SCIPisLT(scip, minactivity - val, consdata->lhs) || SCIPisGT(scip, maxactivity + val, consdata->rhs) )
9429 {
9430 SCIPdebugMsg(scip, "linear constraint <%s>: remove variable <%s> with coefficient <%g> from constraint since it is redundant\n",
9431 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]), val);
9432
9433 minleftactivitypart = val * ub;
9434 maxleftactivitypart = val * lb;
9435
9436 SCIP_CALL( delCoefPos(scip, cons, i) );
9437 i--;
9438
9439 /* get the new minimal and maximal activity of the constraint */
9440 consdataGetActivityBounds(scip, consdata, FALSE, &minactivity, &maxactivity, &minactisrelax, &maxactisrelax,
9441 &isminsettoinfinity, &ismaxsettoinfinity);
9442
9443 /* we return above if the condition does not hold and deleting a variable cannot increase the number of
9444 * huge contributions
9445 */
9446 assert(!minactisrelax || SCIPisInfinity(scip, -consdata->lhs));
9447 assert(!maxactisrelax || SCIPisInfinity(scip, consdata->rhs));
9448 }
9449 }
9450
9451 /* the following update step is needed in every iteration cause otherwise it is possible that the surely none-
9452 * redundant variables could get deleted,
9453 * e.g. y_1 + 16y_2 >= 25, y1 with bounds [9,12], y2 with bounds [0,2], minactivity would be 9, it follows that
9454 * y_2 is surely not redundant and y_1 is redundant so we would first delete y1 and without updating the sides
9455 * we would also delete y2 and as a result we would have gotten infeasibility */
9456 /* adjust lhs and right hand side */
9457 newlhs = consdata->lhs - minleftactivitypart;
9458 newrhs = consdata->rhs - maxleftactivitypart;
9459
9460 if( !SCIPisInfinity(scip, -consdata->lhs) && !SCIPisFeasEQ(scip, newlhs, consdata->lhs) )
9461 {
9462 SCIPdebugMsg(scip, "linear constraint <%s>: change lhs %.15g to %.15g\n", SCIPconsGetName(cons), consdata->lhs, newlhs);
9463 SCIP_CALL( chgLhs(scip, cons, newlhs) );
9464 ++(*nchgsides);
9465 assert(SCIPisEQ(scip, consdata->lhs, newlhs));
9466 }
9467 if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisFeasEQ(scip, newrhs, consdata->rhs) )
9468 {
9469 SCIPdebugMsg(scip, "linear constraint <%s>: change rhs %.15g to %.15g\n", SCIPconsGetName(cons), consdata->rhs, newrhs);
9470 SCIP_CALL( chgRhs(scip, cons, newrhs) );
9471 ++(*nchgsides);
9472 assert(SCIPisEQ(scip, consdata->rhs, newrhs));
9473 }
9474 ++i;
9475 }
9476 }
9477
9478 return SCIP_OKAY;
9479 }
9480
9481 /** processes equality with only one variable by fixing the variable and deleting the constraint */
9482 static
convertUnaryEquality(SCIP * scip,SCIP_CONS * cons,SCIP_Bool * cutoff,int * nfixedvars,int * ndelconss)9483 SCIP_RETCODE convertUnaryEquality(
9484 SCIP* scip, /**< SCIP data structure */
9485 SCIP_CONS* cons, /**< linear constraint */
9486 SCIP_Bool* cutoff, /**< pointer to store TRUE, if a cutoff was found */
9487 int* nfixedvars, /**< pointer to count number of fixed variables */
9488 int* ndelconss /**< pointer to count number of deleted constraints */
9489 )
9490 {
9491 SCIP_CONSDATA* consdata;
9492 SCIP_VAR* var;
9493 SCIP_Real val;
9494 SCIP_Real fixval;
9495 SCIP_Bool infeasible;
9496 SCIP_Bool fixed;
9497
9498 assert(scip != NULL);
9499 assert(cons != NULL);
9500 assert(cutoff != NULL);
9501 assert(nfixedvars != NULL);
9502 assert(ndelconss != NULL);
9503
9504 consdata = SCIPconsGetData(cons);
9505 assert(consdata != NULL);
9506 assert(consdata->nvars == 1);
9507 assert(SCIPisEQ(scip, consdata->lhs, consdata->rhs));
9508
9509 /* calculate the value to fix the variable to */
9510 var = consdata->vars[0];
9511 val = consdata->vals[0];
9512 assert(!SCIPisZero(scip, val));
9513 fixval = SCIPselectSimpleValue(consdata->lhs/val - 0.9 * SCIPepsilon(scip),
9514 consdata->rhs/val + 0.9 * SCIPepsilon(scip), MAXDNOM);
9515 SCIPdebugMsg(scip, "linear equality <%s>: fix <%s> == %.15g\n",
9516 SCIPconsGetName(cons), SCIPvarGetName(var), fixval);
9517
9518 /* fix variable */
9519 SCIP_CALL( SCIPfixVar(scip, var, fixval, &infeasible, &fixed) );
9520 if( infeasible )
9521 {
9522 SCIPdebugMsg(scip, " -> infeasible fixing\n");
9523 *cutoff = TRUE;
9524 return SCIP_OKAY;
9525 }
9526 if( fixed )
9527 (*nfixedvars)++;
9528
9529 /* disable constraint */
9530 SCIP_CALL( SCIPdelCons(scip, cons) );
9531 if( !consdata->upgraded )
9532 (*ndelconss)++;
9533
9534 return SCIP_OKAY;
9535 }
9536
9537 /** processes equality with exactly two variables by aggregating one of the variables and deleting the constraint */
9538 static
convertBinaryEquality(SCIP * scip,SCIP_CONS * cons,SCIP_Bool * cutoff,int * naggrvars,int * ndelconss)9539 SCIP_RETCODE convertBinaryEquality(
9540 SCIP* scip, /**< SCIP data structure */
9541 SCIP_CONS* cons, /**< linear constraint */
9542 SCIP_Bool* cutoff, /**< pointer to store TRUE, if a cutoff was found */
9543 int* naggrvars, /**< pointer to count number of aggregated variables */
9544 int* ndelconss /**< pointer to count number of deleted constraints */
9545 )
9546 {
9547 SCIP_CONSDATA* consdata;
9548 SCIP_Bool infeasible;
9549 SCIP_Bool redundant;
9550 SCIP_Bool aggregated;
9551
9552 assert(scip != NULL);
9553 assert(cons != NULL);
9554 assert(cutoff != NULL);
9555 assert(naggrvars != NULL);
9556 assert(ndelconss != NULL);
9557
9558 consdata = SCIPconsGetData(cons);
9559 assert(consdata != NULL);
9560 assert(consdata->nvars == 2);
9561 assert(SCIPisEQ(scip, consdata->lhs, consdata->rhs));
9562
9563 SCIPdebugMsg(scip, "linear constraint <%s>: aggregate %.15g<%s> + %.15g<%s> == %.15g\n",
9564 SCIPconsGetName(cons), consdata->vals[0], SCIPvarGetName(consdata->vars[0]),
9565 consdata->vals[1], SCIPvarGetName(consdata->vars[1]), consdata->rhs);
9566
9567 /* aggregate the equality */
9568 SCIP_CALL( SCIPaggregateVars(scip, consdata->vars[0], consdata->vars[1], consdata->vals[0], consdata->vals[1],
9569 consdata->rhs, &infeasible, &redundant, &aggregated) );
9570
9571 /* check for infeasibility of aggregation */
9572 if( infeasible )
9573 {
9574 SCIPdebugMsg(scip, " -> infeasible aggregation\n");
9575 *cutoff = TRUE;
9576 return SCIP_OKAY;
9577 }
9578
9579 /* count the aggregation */
9580 if( aggregated )
9581 (*naggrvars)++;
9582
9583 /* delete the constraint, if it is redundant */
9584 if( redundant )
9585 {
9586 SCIP_CALL( SCIPdelCons(scip, cons) );
9587
9588 if( !consdata->upgraded )
9589 (*ndelconss)++;
9590 }
9591
9592 return SCIP_OKAY;
9593 }
9594
9595 /** calculates the new lhs and rhs of the constraint after the given variable is aggregated out */
9596 static
getNewSidesAfterAggregation(SCIP * scip,SCIP_CONSDATA * consdata,SCIP_VAR * slackvar,SCIP_Real slackcoef,SCIP_Real * newlhs,SCIP_Real * newrhs)9597 void getNewSidesAfterAggregation(
9598 SCIP* scip, /**< SCIP data structure */
9599 SCIP_CONSDATA* consdata, /**< linear constraint data */
9600 SCIP_VAR* slackvar, /**< variable to be aggregated out */
9601 SCIP_Real slackcoef, /**< coefficient of variable in constraint */
9602 SCIP_Real* newlhs, /**< pointer to store new lhs of constraint */
9603 SCIP_Real* newrhs /**< pointer to store new rhs of constraint */
9604 )
9605 {
9606 SCIP_Real slackvarlb;
9607 SCIP_Real slackvarub;
9608
9609 assert(scip != NULL);
9610 assert(consdata != NULL);
9611 assert(newlhs != NULL);
9612 assert(newrhs != NULL);
9613 assert(!SCIPisInfinity(scip, -consdata->lhs));
9614 assert(!SCIPisInfinity(scip, consdata->rhs));
9615
9616 slackvarlb = SCIPvarGetLbGlobal(slackvar);
9617 slackvarub = SCIPvarGetUbGlobal(slackvar);
9618 if( slackcoef > 0.0 )
9619 {
9620 if( SCIPisInfinity(scip, -slackvarlb) )
9621 *newrhs = SCIPinfinity(scip);
9622 else
9623 *newrhs = consdata->rhs - slackcoef * slackvarlb;
9624 if( SCIPisInfinity(scip, slackvarub) )
9625 *newlhs = -SCIPinfinity(scip);
9626 else
9627 *newlhs = consdata->lhs - slackcoef * slackvarub;
9628 }
9629 else
9630 {
9631 if( SCIPisInfinity(scip, -slackvarlb) )
9632 *newlhs = -SCIPinfinity(scip);
9633 else
9634 *newlhs = consdata->rhs - slackcoef * slackvarlb;
9635 if( SCIPisInfinity(scip, slackvarub) )
9636 *newrhs = SCIPinfinity(scip);
9637 else
9638 *newrhs = consdata->lhs - slackcoef * slackvarub;
9639 }
9640 assert(SCIPisLE(scip, *newlhs, *newrhs));
9641 }
9642
9643 /** processes equality with more than two variables by multi-aggregating one of the variables and converting the equality
9644 * into an inequality; if multi-aggregation is not possible, tries to identify one continuous or integer variable that
9645 * is implicitly integral by this constraint
9646 *
9647 * @todo Check whether a more clever way of avoiding aggregation of variables containing implicitly integer variables
9648 * can help.
9649 */
9650 static
convertLongEquality(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_CONS * cons,SCIP_Bool * cutoff,int * naggrvars,int * ndelconss)9651 SCIP_RETCODE convertLongEquality(
9652 SCIP* scip, /**< SCIP data structure */
9653 SCIP_CONSHDLRDATA* conshdlrdata, /**< linear constraint handler data */
9654 SCIP_CONS* cons, /**< linear constraint */
9655 SCIP_Bool* cutoff, /**< pointer to store TRUE, if a cutoff was found */
9656 int* naggrvars, /**< pointer to count number of aggregated variables */
9657 int* ndelconss /**< pointer to count number of deleted constraints */
9658 )
9659 {
9660 SCIP_CONSDATA* consdata;
9661 SCIP_VAR** vars;
9662 SCIP_Real* vals;
9663 SCIP_VARTYPE bestslacktype;
9664 SCIP_VARTYPE slacktype;
9665 SCIP_Real lhs;
9666 SCIP_Real rhs;
9667 SCIP_Real bestslackdomrng;
9668 SCIP_Real minabsval;
9669 SCIP_Real maxabsval;
9670 SCIP_Bool bestremovescons;
9671 SCIP_Bool coefszeroone;
9672 SCIP_Bool coefsintegral;
9673 SCIP_Bool varsintegral;
9674 SCIP_Bool infeasible;
9675 SCIP_Bool samevar;
9676 int supinf; /* counter for infinite contributions to the supremum of a possible
9677 * multi-aggregation
9678 */
9679 int infinf; /* counter for infinite contributions to the infimum of a possible
9680 * multi-aggregation
9681 */
9682 int maxnlocksstay;
9683 int maxnlocksremove;
9684 int bestslackpos;
9685 int bestnlocks;
9686 int ncontvars;
9687 int contvarpos;
9688 int nintvars;
9689 int nimplvars;
9690 int intvarpos;
9691 int v;
9692
9693 assert(scip != NULL);
9694 assert(cons != NULL);
9695 assert(cutoff != NULL);
9696 assert(naggrvars != NULL);
9697
9698 consdata = SCIPconsGetData(cons);
9699 assert(consdata != NULL);
9700 assert(consdata->nvars > 2);
9701 assert(SCIPisEQ(scip, consdata->lhs, consdata->rhs));
9702
9703 SCIPdebugMsg(scip, "linear constraint <%s>: try to multi-aggregate equality\n", SCIPconsGetName(cons));
9704
9705 /* We do not want to increase the total number of non-zeros due to the multi-aggregation.
9706 * Therefore, we have to restrict the number of locks of a variable that is aggregated out.
9707 * maxnlocksstay: maximal sum of lock numbers if the constraint does not become redundant after the aggregation
9708 * maxnlocksremove: maximal sum of lock numbers if the constraint can be deleted after the aggregation
9709 */
9710 lhs = consdata->lhs;
9711 rhs = consdata->rhs;
9712 maxnlocksstay = 0;
9713 if( consdata->nvars == 3 )
9714 {
9715 /* If the constraint becomes redundant, 3 non-zeros are removed, and we get 1 additional non-zero for each
9716 * constraint the variable appears in. Thus, the variable must appear in at most 3 other constraints.
9717 */
9718 maxnlocksremove = 3;
9719 }
9720 else if( consdata->nvars == 4 )
9721 {
9722 /* If the constraint becomes redundant, 4 non-zeros are removed, and we get 2 additional non-zeros for each
9723 * constraint the variable appears in. Thus, the variable must appear in at most 2 other constraints.
9724 */
9725 maxnlocksremove = 2;
9726 }
9727 else
9728 {
9729 /* If the constraint is redundant but has more than 4 variables, we can only accept one other constraint. */
9730 maxnlocksremove = 1;
9731 }
9732
9733 /* the locks on this constraint can be ignored */
9734 if( SCIPconsIsChecked(cons) )
9735 {
9736 if( !SCIPisInfinity(scip, -lhs) )
9737 {
9738 maxnlocksstay++;
9739 maxnlocksremove++;
9740 }
9741 if( !SCIPisInfinity(scip, rhs) )
9742 {
9743 maxnlocksstay++;
9744 maxnlocksremove++;
9745 }
9746 }
9747
9748 /* look for a slack variable s to convert a*x + s == b into lhs <= a*x <= rhs */
9749 vars = consdata->vars;
9750 vals = consdata->vals;
9751 bestslackpos = -1;
9752 bestslacktype = SCIP_VARTYPE_BINARY;
9753 bestnlocks = INT_MAX;
9754 bestremovescons = FALSE;
9755 bestslackdomrng = 0.0;
9756 coefszeroone = TRUE;
9757 coefsintegral = TRUE;
9758 varsintegral = TRUE;
9759 ncontvars = 0;
9760 contvarpos = -1;
9761 nintvars = 0;
9762 nimplvars = 0;
9763 intvarpos = -1;
9764 minabsval = SCIPinfinity(scip);
9765 maxabsval = -1.0;
9766 for( v = 0; v < consdata->nvars; ++v )
9767 {
9768 SCIP_VAR* var;
9769 SCIP_Real val;
9770 SCIP_Real absval;
9771 SCIP_Real varlb;
9772 SCIP_Real varub;
9773 SCIP_Bool iscont;
9774 int nlocks;
9775
9776 assert(vars != NULL);
9777 assert(vals != NULL);
9778
9779 var = vars[v];
9780 assert(!SCIPconsIsChecked(cons) || SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) >= 1); /* because variable is locked in this equality */
9781 assert(!SCIPconsIsChecked(cons) || SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) >= 1);
9782 varlb = SCIPvarGetLbGlobal(var);
9783 varub = SCIPvarGetUbGlobal(var);
9784
9785 val = vals[v];
9786 absval = REALABS(val);
9787 assert(SCIPisPositive(scip, absval));
9788
9789 /* calculate minimal and maximal absolute value */
9790 if( absval < minabsval )
9791 minabsval = absval;
9792 if( absval > maxabsval )
9793 maxabsval = absval;
9794
9795 /* do not try to multi aggregate, when numerical bad */
9796 if( maxabsval / minabsval > conshdlrdata->maxmultaggrquot )
9797 return SCIP_OKAY;
9798
9799 slacktype = SCIPvarGetType(var);
9800 coefszeroone = coefszeroone && SCIPisEQ(scip, absval, 1.0);
9801 coefsintegral = coefsintegral && SCIPisIntegral(scip, val);
9802 varsintegral = varsintegral && (slacktype != SCIP_VARTYPE_CONTINUOUS);
9803 iscont = (slacktype == SCIP_VARTYPE_CONTINUOUS || slacktype == SCIP_VARTYPE_IMPLINT);
9804
9805 /* update candidates for continuous -> implint and integer -> implint conversion */
9806 if( slacktype == SCIP_VARTYPE_CONTINUOUS )
9807 {
9808 ncontvars++;
9809 contvarpos = v;
9810 }
9811 else if( slacktype == SCIP_VARTYPE_IMPLINT )
9812 {
9813 ++nimplvars;
9814 }
9815 else if( slacktype == SCIP_VARTYPE_INTEGER )
9816 {
9817 nintvars++;
9818 intvarpos = v;
9819 }
9820
9821 /* check, if variable is already fixed or aggregated */
9822 if( !SCIPvarIsActive(var) )
9823 continue;
9824
9825 /* check, if variable is used in too many other constraints, even if this constraint could be deleted */
9826 nlocks = SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) + SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL);
9827
9828 if( nlocks > maxnlocksremove )
9829 continue;
9830
9831 /* check, if variable can be used as a slack variable */
9832 if( (iscont || (coefsintegral && varsintegral && SCIPisEQ(scip, absval, 1.0))) &&
9833 !SCIPdoNotMultaggrVar(scip, var) )
9834 {
9835 SCIP_Bool better;
9836 SCIP_Bool equal;
9837 SCIP_Real slackdomrng;
9838
9839 if( SCIPisInfinity(scip, varub) || SCIPisInfinity(scip, -varlb) )
9840 slackdomrng = SCIPinfinity(scip);
9841 /* we do not want to perform multi-aggregation due to numerics, if the bounds are huge */
9842 else if( SCIPisHugeValue(scip, varub) || SCIPisHugeValue(scip, -varlb) )
9843 return SCIP_OKAY;
9844 else
9845 {
9846 slackdomrng = (varub - varlb)*absval;
9847 assert(!SCIPisInfinity(scip, slackdomrng));
9848 }
9849 equal = FALSE;
9850 better = (slacktype > bestslacktype) || (bestslackpos == -1);
9851 if( !better && slacktype == bestslacktype )
9852 {
9853 better = (nlocks < bestnlocks);
9854 if( nlocks == bestnlocks && !bestremovescons )
9855 {
9856 better = SCIPisGT(scip, slackdomrng, bestslackdomrng);
9857 equal = !better && SCIPisGE(scip, slackdomrng, bestslackdomrng);
9858 }
9859 }
9860
9861 if( better || equal )
9862 {
9863 SCIP_Real minresactivity;
9864 SCIP_Real maxresactivity;
9865 SCIP_Real newlhs;
9866 SCIP_Real newrhs;
9867 SCIP_Bool removescons;
9868 SCIP_Bool minisrelax;
9869 SCIP_Bool maxisrelax;
9870 SCIP_Bool isminsettoinfinity;
9871 SCIP_Bool ismaxsettoinfinity;
9872
9873 /* check if the constraint becomes redundant after multi-aggregation */
9874 consdataGetActivityResiduals(scip, consdata, var, val, FALSE, &minresactivity, &maxresactivity,
9875 &minisrelax, &maxisrelax, &isminsettoinfinity, &ismaxsettoinfinity);
9876
9877 /* do not perform the multi-aggregation due to numerics, if we have huge contributions in the residual
9878 * activity
9879 */
9880 if( minisrelax || maxisrelax )
9881 continue;
9882
9883 getNewSidesAfterAggregation(scip, consdata, var, val, &newlhs, &newrhs);
9884 removescons = (SCIPisFeasLE(scip, newlhs, minresactivity) && SCIPisFeasLE(scip, maxresactivity, newrhs));
9885
9886 /* check resactivities for reliability */
9887 if( removescons )
9888 {
9889 if( !isminsettoinfinity && SCIPisUpdateUnreliable(scip, minresactivity, consdata->lastminactivity) )
9890 consdataGetReliableResidualActivity(scip, consdata, var, &minresactivity, TRUE, FALSE);
9891
9892 if( !ismaxsettoinfinity && SCIPisUpdateUnreliable(scip, maxresactivity, consdata->lastmaxactivity)
9893 && SCIPisFeasLE(scip, newlhs, minresactivity))
9894 consdataGetReliableResidualActivity(scip, consdata, var, &maxresactivity, FALSE, FALSE);
9895
9896 removescons = (SCIPisFeasLE(scip, newlhs, minresactivity) && SCIPisFeasLE(scip, maxresactivity, newrhs));
9897 }
9898
9899 /* if parameter multaggrremove is set to TRUE, only aggregate when this removes constraint */
9900 if( conshdlrdata->multaggrremove && !removescons )
9901 continue;
9902
9903 /* prefer variables that make the constraints redundant */
9904 if( bestremovescons && !removescons )
9905 continue;
9906
9907 /* if the constraint does not become redundant, only accept the variable if it does not appear in
9908 * other constraints
9909 */
9910 if( !removescons && nlocks > maxnlocksstay )
9911 continue;
9912
9913 better = better || (!bestremovescons && removescons);
9914 if( better )
9915 {
9916 bestslackpos = v;
9917 bestslacktype = slacktype;
9918 bestnlocks = nlocks;
9919 bestslackdomrng = slackdomrng;
9920 bestremovescons = removescons;
9921 }
9922 }
9923 }
9924 }
9925
9926 /* if all coefficients and variables are integral, the right hand side must also be integral */
9927 if( coefsintegral && varsintegral && !SCIPisFeasIntegral(scip, consdata->rhs) )
9928 {
9929 SCIPdebugMsg(scip, "linear equality <%s> is integer infeasible\n", SCIPconsGetName(cons));
9930 SCIPdebugPrintCons(scip, cons, NULL);
9931 *cutoff = TRUE;
9932 return SCIP_OKAY;
9933 }
9934
9935 supinf = 0;
9936 infinf = 0;
9937 samevar = FALSE;
9938
9939 /* check whether the the infimum and the supremum of the multi-aggregation can be get infinite */
9940 for( v = 0; v < consdata->nvars; ++v )
9941 {
9942 if( v != bestslackpos )
9943 {
9944 if( SCIPisPositive(scip, consdata->vals[v]) )
9945 {
9946 if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(consdata->vars[v])) )
9947 {
9948 ++supinf;
9949 if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->vars[v])) )
9950 {
9951 ++infinf;
9952 samevar = TRUE;
9953 }
9954 }
9955 else if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->vars[v])) )
9956 ++infinf;
9957 }
9958 else if( SCIPisNegative(scip, consdata->vals[v]) )
9959 {
9960 if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->vars[v])) )
9961 {
9962 ++supinf;
9963 if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(consdata->vars[v])) )
9964 {
9965 ++infinf;
9966 samevar = TRUE;
9967 }
9968 }
9969 else if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(consdata->vars[v])) )
9970 ++infinf;
9971 }
9972 }
9973 }
9974 assert(!samevar || (supinf > 0 && infinf > 0));
9975
9976 /* If the infimum and the supremum of a multi-aggregation are both infinite, then the multi-aggregation might not be resolvable.
9977 * E.g., consider the equality z = x-y. If x and y are both fixed to +infinity, the value for z is not determined */
9978 if( (samevar && (supinf > 1 || infinf > 1)) || (!samevar && supinf > 0 && infinf > 0) )
9979 {
9980 SCIPdebugMsg(scip, "do not perform multi-aggregation: infimum and supremum are both infinite\n");
9981 return SCIP_OKAY;
9982 }
9983
9984 /* if the slack variable is of integer type, and the constraint itself may take fractional values,
9985 * we cannot aggregate the variable, because the integrality condition would get lost
9986 * Similarly, if there are implicitly integral variables we cannot aggregate, since we might
9987 * loose the integrality condition for this variable.
9988 */
9989 if( bestslackpos >= 0
9990 && (bestslacktype == SCIP_VARTYPE_CONTINUOUS || bestslacktype == SCIP_VARTYPE_IMPLINT
9991 || (coefsintegral && varsintegral && nimplvars == 0)) )
9992 {
9993 SCIP_VAR* slackvar;
9994 SCIP_Real* scalars;
9995 SCIP_Real slackcoef;
9996 SCIP_Real aggrconst;
9997 SCIP_Real newlhs;
9998 SCIP_Real newrhs;
9999 SCIP_Bool aggregated;
10000
10001 /* we found a slack variable that only occurs in at most one other constraint:
10002 * a_1*x_1 + ... + a_k*x_k + a'*s == rhs -> s == rhs - a_1/a'*x_1 - ... - a_k/a'*x_k
10003 */
10004 assert(bestslackpos < consdata->nvars);
10005
10006 /* do not multi aggregate binary variables */
10007 if( SCIPvarIsBinary(vars[bestslackpos]) )
10008 return SCIP_OKAY;
10009
10010 /* convert equality into inequality by deleting the slack variable:
10011 * x + a*s == b, l <= s <= u -> b - a*u <= x <= b - a*l
10012 */
10013 slackvar = vars[bestslackpos];
10014 slackcoef = vals[bestslackpos];
10015 assert(!SCIPisZero(scip, slackcoef));
10016 aggrconst = consdata->rhs/slackcoef;
10017
10018 getNewSidesAfterAggregation(scip, consdata, slackvar, slackcoef, &newlhs, &newrhs);
10019 assert(SCIPisLE(scip, newlhs, newrhs));
10020 SCIP_CALL( chgLhs(scip, cons, newlhs) );
10021 SCIP_CALL( chgRhs(scip, cons, newrhs) );
10022 SCIP_CALL( delCoefPos(scip, cons, bestslackpos) );
10023
10024 /* allocate temporary memory */
10025 SCIP_CALL( SCIPallocBufferArray(scip, &scalars, consdata->nvars) );
10026
10027 /* set up the multi-aggregation */
10028 SCIPdebugMsg(scip, "linear constraint <%s>: multi-aggregate <%s> ==", SCIPconsGetName(cons), SCIPvarGetName(slackvar));
10029 for( v = 0; v < consdata->nvars; ++v )
10030 {
10031 scalars[v] = -consdata->vals[v]/slackcoef;
10032 SCIPdebugMsgPrint(scip, " %+.15g<%s>", scalars[v], SCIPvarGetName(vars[v]));
10033 }
10034 SCIPdebugMsgPrint(scip, " %+.15g, bounds of <%s>: [%.15g,%.15g], nlocks=%d, maxnlocks=%d, removescons=%u\n",
10035 aggrconst, SCIPvarGetName(slackvar), SCIPvarGetLbGlobal(slackvar), SCIPvarGetUbGlobal(slackvar),
10036 bestnlocks, bestremovescons ? maxnlocksremove : maxnlocksstay, bestremovescons);
10037
10038 /* perform the multi-aggregation */
10039 SCIP_CALL( SCIPmultiaggregateVar(scip, slackvar, consdata->nvars, vars, scalars, aggrconst,
10040 &infeasible, &aggregated) );
10041 assert(aggregated);
10042
10043 /* free temporary memory */
10044 SCIPfreeBufferArray(scip, &scalars);
10045
10046 /* check for infeasible aggregation */
10047 if( infeasible )
10048 {
10049 SCIPdebugMsg(scip, "linear constraint <%s>: infeasible multi-aggregation\n", SCIPconsGetName(cons));
10050 *cutoff = TRUE;
10051 return SCIP_OKAY;
10052 }
10053
10054 (*naggrvars)++;
10055
10056 /* delete the constraint if it became redundant */
10057 if( bestremovescons )
10058 {
10059 SCIPdebugMsg(scip, "linear constraint <%s>: redundant after multi-aggregation\n", SCIPconsGetName(cons));
10060 SCIP_CALL( SCIPdelCons(scip, cons) );
10061
10062 if( !consdata->upgraded )
10063 (*ndelconss)++;
10064 }
10065 }
10066 else if( ncontvars == 1 )
10067 {
10068 SCIP_VAR* var;
10069
10070 assert(0 <= contvarpos && contvarpos < consdata->nvars);
10071 var = vars[contvarpos];
10072 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS);
10073
10074 if( coefsintegral && SCIPisFeasIntegral(scip, consdata->rhs) )
10075 {
10076 /* upgrade continuous variable to an implicit one, if the absolute value of the coefficient is one */
10077 if( SCIPisEQ(scip, REALABS(vals[contvarpos]), 1.0) )
10078 {
10079 /* convert the continuous variable with coefficient 1.0 into an implicit integer variable */
10080 SCIPdebugMsg(scip, "linear constraint <%s>: converting continuous variable <%s> to implicit integer variable\n",
10081 SCIPconsGetName(cons), SCIPvarGetName(var));
10082 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_IMPLINT, &infeasible) );
10083 if( infeasible )
10084 {
10085 SCIPdebugMsg(scip, "infeasible upgrade of variable <%s> to integral type, domain is empty\n", SCIPvarGetName(var));
10086 *cutoff = TRUE;
10087
10088 return SCIP_OKAY;
10089 }
10090 }
10091 /* aggregate continuous variable to an implicit one, if the absolute value of the coefficient is unequal to one */
10092 /* @todo check if the aggregation coefficient should be in some range(, which is not too big) */
10093 else if( !SCIPdoNotAggr(scip) )
10094 {
10095 SCIP_VAR* newvar;
10096 SCIP_Real absval;
10097 char newvarname[SCIP_MAXSTRLEN];
10098 SCIP_Bool redundant;
10099 SCIP_Bool aggregated;
10100
10101 absval = REALABS(vals[contvarpos]);
10102
10103 (void) SCIPsnprintf(newvarname, SCIP_MAXSTRLEN, "%s_impl", SCIPvarGetName(var));
10104
10105 /* create new implicit variable for aggregation */
10106 SCIP_CALL( SCIPcreateVar(scip, &newvar, newvarname, -SCIPinfinity(scip), SCIPinfinity(scip), 0.0,
10107 SCIP_VARTYPE_IMPLINT, SCIPvarIsInitial(var), SCIPvarIsRemovable(var), NULL, NULL, NULL, NULL, NULL) );
10108
10109 /* add new variable to problem */
10110 SCIP_CALL( SCIPaddVar(scip, newvar) );
10111
10112 #ifdef WITH_DEBUG_SOLUTION
10113 if( SCIPdebugIsMainscip(scip) )
10114 {
10115 SCIP_Real varval;
10116 SCIP_CALL( SCIPdebugGetSolVal(scip, var, &varval) );
10117 SCIP_CALL( SCIPdebugAddSolVal(scip, newvar, absval * varval) );
10118 }
10119 #endif
10120
10121 /* convert the continuous variable with coefficient 1.0 into an implicit integer variable */
10122 SCIPdebugMsg(scip, "linear constraint <%s>: aggregating continuous variable <%s> to newly created implicit integer variable <%s>, aggregation factor = %g\n",
10123 SCIPconsGetName(cons), SCIPvarGetName(var), SCIPvarGetName(newvar), absval);
10124
10125 /* aggregate continuous and implicit variable */
10126 SCIP_CALL( SCIPaggregateVars(scip, var, newvar, absval, -1.0, 0.0, &infeasible, &redundant, &aggregated) );
10127
10128 if( infeasible )
10129 {
10130 SCIPdebugMsg(scip, "infeasible aggregation of variable <%s> to implicit variable <%s>, domain is empty\n",
10131 SCIPvarGetName(var), SCIPvarGetName(newvar));
10132 *cutoff = TRUE;
10133
10134 /* release implicit variable */
10135 SCIP_CALL( SCIPreleaseVar(scip, &newvar) );
10136
10137 return SCIP_OKAY;
10138 }
10139
10140 /* release implicit variable */
10141 SCIP_CALL( SCIPreleaseVar(scip, &newvar) );
10142
10143 if( aggregated )
10144 (*naggrvars)++;
10145 else
10146 return SCIP_OKAY;
10147 }
10148
10149 /* we do not have any event on vartype changes, so we need to manually force this constraint to be presolved
10150 * again
10151 */
10152 consdata->boundstightened = 0;
10153 consdata->rangedrowpropagated = 0;
10154 consdata->presolved = FALSE;
10155 }
10156 }
10157 else if( ncontvars == 0 && nimplvars == 0 && nintvars == 1 && !coefszeroone )
10158 {
10159 SCIP_VAR* var;
10160
10161 /* this seems to help for rococo instances, but does not for rout (where all coefficients are +/- 1.0)
10162 * -> we don't convert integers into implints if the row is a 0/1-row
10163 */
10164 assert(varsintegral);
10165 assert(0 <= intvarpos && intvarpos < consdata->nvars);
10166 var = vars[intvarpos];
10167 assert(SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER);
10168
10169 if( coefsintegral
10170 && SCIPisEQ(scip, REALABS(vals[intvarpos]), 1.0)
10171 && SCIPisFeasIntegral(scip, consdata->rhs) )
10172 {
10173 /* convert the integer variable with coefficient 1.0 into an implicit integer variable */
10174 SCIPdebugMsg(scip, "linear constraint <%s>: converting integer variable <%s> to implicit integer variable\n",
10175 SCIPconsGetName(cons), SCIPvarGetName(var));
10176 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_IMPLINT, &infeasible) );
10177 if( infeasible )
10178 {
10179 SCIPdebugMsg(scip, "infeasible upgrade of variable <%s> to integral type, domain is empty\n", SCIPvarGetName(var));
10180 *cutoff = TRUE;
10181
10182 return SCIP_OKAY;
10183 }
10184 }
10185 }
10186
10187 return SCIP_OKAY;
10188 }
10189
10190 /** checks if the given variables and their coefficient are equal (w.r.t. scaling factor) to the objective function */
10191 static
checkEqualObjective(SCIP * scip,SCIP_CONSDATA * consdata,SCIP_Real * scale,SCIP_Real * offset)10192 SCIP_Bool checkEqualObjective(
10193 SCIP* scip, /**< SCIP data structure */
10194 SCIP_CONSDATA* consdata, /**< linear constraint data */
10195 SCIP_Real* scale, /**< pointer to store the scaling factor between the constraint and the
10196 * objective function */
10197 SCIP_Real* offset /**< pointer to store the offset of the objective function resulting by
10198 * this constraint */
10199 )
10200 {
10201 SCIP_VAR** vars;
10202 SCIP_VAR* var;
10203 SCIP_Real objval;
10204 SCIP_Bool negated;
10205 int nvars;
10206 int v;
10207
10208 vars = consdata->vars;
10209 nvars = consdata->nvars;
10210
10211 assert(vars != NULL);
10212
10213 for( v = 0; v < nvars; ++v )
10214 {
10215 negated = FALSE;
10216 var = vars[v];
10217 assert(var != NULL);
10218
10219 if( SCIPvarIsNegated(var) )
10220 {
10221 negated = TRUE;
10222 var = SCIPvarGetNegatedVar(var);
10223 assert(var != NULL);
10224 }
10225
10226 objval = SCIPvarGetObj(var);
10227
10228 /* if a variable has a zero objective coefficient the linear constraint is not a subset of the objective
10229 * function
10230 */
10231 if( SCIPisZero(scip, objval) )
10232 return FALSE;
10233 else
10234 {
10235 SCIP_Real val;
10236
10237 val = consdata->vals[v];
10238
10239 if( negated )
10240 {
10241 if( v == 0 )
10242 {
10243 /* the first variable defines the scale */
10244 (*scale) = val / -objval;
10245
10246 (*offset) += val;
10247 }
10248 else if( SCIPisEQ(scip, -objval * (*scale), val) )
10249 (*offset) += val;
10250 else
10251 return FALSE;
10252 }
10253 else if( v == 0 )
10254 {
10255 /* the first variable defines the scale */
10256 (*scale) = val / objval;
10257 }
10258 else if( !SCIPisEQ(scip, objval * (*scale), val) )
10259 return FALSE;
10260 }
10261 }
10262
10263 return TRUE;
10264 }
10265
10266 /** check if the linear equality constraint is equal to a subset of the objective function; if so we can remove the
10267 * objective coefficients and add an objective offset
10268 */
10269 static
checkPartialObjective(SCIP * scip,SCIP_CONS * cons,SCIP_CONSHDLRDATA * conshdlrdata)10270 SCIP_RETCODE checkPartialObjective(
10271 SCIP* scip, /**< SCIP data structure */
10272 SCIP_CONS* cons, /**< linear equation constraint */
10273 SCIP_CONSHDLRDATA* conshdlrdata /**< linear constraint handler data */
10274 )
10275 {
10276 SCIP_CONSDATA* consdata;
10277 SCIP_Real offset;
10278 SCIP_Real scale;
10279 SCIP_Bool applicable;
10280 int nobjvars;
10281 int nvars;
10282 int v;
10283
10284 assert(scip != NULL);
10285 assert(cons != NULL);
10286 assert(conshdlrdata != NULL);
10287
10288 consdata = SCIPconsGetData(cons);
10289 assert(consdata != NULL);
10290 assert(SCIPisEQ(scip, consdata->lhs, consdata->rhs));
10291
10292 nvars = consdata->nvars;
10293 nobjvars = SCIPgetNObjVars(scip);
10294
10295 /* check if the linear equality constraints does not have more variables than the objective function */
10296 if( nvars > nobjvars || nvars == 0 )
10297 return SCIP_OKAY;
10298
10299 /* check for allowance of algorithm */
10300 if( (nvars < nobjvars && !conshdlrdata->detectpartialobjective) ||
10301 (nvars == nobjvars && (!conshdlrdata->detectcutoffbound || !conshdlrdata->detectlowerbound)) )
10302 return SCIP_OKAY;
10303
10304 offset = consdata->rhs;
10305 scale = 1.0;
10306
10307 /* checks if the variables and their coefficients are equal (w.r.t. scaling factor) to the objective function */
10308 applicable = checkEqualObjective(scip, consdata, &scale, &offset);
10309
10310 if( applicable )
10311 {
10312 SCIP_VAR** vars;
10313
10314 vars = consdata->vars;
10315 assert(vars != NULL);
10316
10317 offset /= scale;
10318
10319 SCIPdebugMsg(scip, "linear equality constraint <%s> == %g (offset %g) is a subset of the objective function\n",
10320 SCIPconsGetName(cons), consdata->rhs, offset);
10321
10322 /* set all objective coefficient to zero */
10323 for( v = 0; v < nvars; ++v )
10324 {
10325 SCIP_CALL( SCIPchgVarObj(scip, vars[v], 0.0) );
10326 }
10327
10328 /* add an objective offset */
10329 SCIP_CALL( SCIPaddObjoffset(scip, offset) );
10330 }
10331
10332 return SCIP_OKAY;
10333 }
10334
10335 /** updates the cutoff if the given primal bound (which is implied by the given constraint) is better */
10336 static
updateCutoffbound(SCIP * scip,SCIP_CONS * cons,SCIP_Real primalbound)10337 SCIP_RETCODE updateCutoffbound(
10338 SCIP* scip, /**< SCIP data structure */
10339 SCIP_CONS* cons, /**< constraint */
10340 SCIP_Real primalbound /**< feasible primal bound */
10341 )
10342 {
10343 SCIP_Real cutoffbound;
10344
10345 /* increase the cutoff bound value by an epsilon to ensue that solution with the value of the cutoff bound are still
10346 * accepted
10347 */
10348 cutoffbound = primalbound + SCIPcutoffbounddelta(scip);
10349
10350 if( cutoffbound < SCIPgetCutoffbound(scip) )
10351 {
10352 SCIPdebugMsg(scip, "update cutoff bound <%g>\n", cutoffbound);
10353
10354 SCIP_CALL( SCIPupdateCutoffbound(scip, cutoffbound) );
10355 }
10356 else
10357 {
10358 SCIP_CONSDATA* consdata;
10359
10360 consdata = SCIPconsGetData(cons);
10361 assert(consdata != NULL);
10362
10363 /* we cannot disable the enforcement and propagation on ranged rows, because the cutoffbound could only have
10364 * resulted from one side
10365 */
10366 if( SCIPisInfinity(scip, -consdata->lhs) || SCIPisInfinity(scip, consdata->rhs) )
10367 {
10368 /* in case the cutoff bound is worse then the currently known one, we additionally avoid enforcement and
10369 * propagation
10370 */
10371 SCIP_CALL( SCIPsetConsEnforced(scip, cons, FALSE) );
10372 SCIP_CALL( SCIPsetConsPropagated(scip, cons, FALSE) );
10373 }
10374 }
10375
10376 return SCIP_OKAY;
10377 }
10378
10379 /** check if the linear constraint is parallel to objective function; if so update the cutoff bound and avoid that the
10380 * constraint enters the LP by setting the initial and separated flag to FALSE
10381 */
10382 static
checkParallelObjective(SCIP * scip,SCIP_CONS * cons,SCIP_CONSHDLRDATA * conshdlrdata)10383 SCIP_RETCODE checkParallelObjective(
10384 SCIP* scip, /**< SCIP data structure */
10385 SCIP_CONS* cons, /**< linear constraint */
10386 SCIP_CONSHDLRDATA* conshdlrdata /**< linear constraint handler data */
10387 )
10388 {
10389 SCIP_CONSDATA* consdata;
10390 SCIP_Real offset;
10391 SCIP_Real scale;
10392 SCIP_Bool applicable;
10393 int nobjvars;
10394 int nvars;
10395
10396 assert(scip != NULL);
10397 assert(cons != NULL);
10398 assert(conshdlrdata != NULL);
10399
10400 consdata = SCIPconsGetData(cons);
10401 assert(consdata != NULL);
10402
10403 /* ignore equalities since these are covered by the method checkPartialObjective() */
10404 if( SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
10405 return SCIP_OKAY;
10406
10407 nvars = consdata->nvars;
10408 nobjvars = SCIPgetNObjVars(scip);
10409
10410 /* check if the linear inequality constraints has the same number of variables as the objective function and if the
10411 * initial and/or separated flag is set to FALSE
10412 */
10413 if( nvars != nobjvars || (!SCIPconsIsInitial(cons) && !SCIPconsIsSeparated(cons)) )
10414 return SCIP_OKAY;
10415
10416 offset = 0.0;
10417 scale = 1.0;
10418
10419 /* There are no variables in the ojective function and in the constraint. Thus, the constraint is redundant or proves
10420 * infeasibility. Since we have a pure feasibility problem, we do not want to set a cutoff or lower bound.
10421 */
10422 if( nobjvars == 0 )
10423 return SCIP_OKAY;
10424
10425 /* checks if the variables and their coefficients are equal (w.r.t. scaling factor) to the objective function */
10426 applicable = checkEqualObjective(scip, consdata, &scale, &offset);
10427
10428 if( applicable )
10429 {
10430 SCIP_Bool rhsfinite = !SCIPisInfinity(scip, consdata->rhs);
10431 SCIP_Bool lhsfinite = !SCIPisInfinity(scip, -consdata->lhs);
10432
10433 if( SCIPisPositive(scip, scale) )
10434 {
10435 if( conshdlrdata->detectcutoffbound && rhsfinite )
10436 {
10437 SCIP_Real primalbound;
10438
10439 primalbound = (consdata->rhs - offset) / scale;
10440
10441 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provides a cutoff bound <%g>\n",
10442 SCIPconsGetName(cons), primalbound);
10443
10444 SCIP_CALL( updateCutoffbound(scip, cons, primalbound) );
10445 }
10446
10447 if( conshdlrdata->detectlowerbound && lhsfinite )
10448 {
10449 SCIP_Real lowerbound;
10450
10451 lowerbound = (consdata->lhs - offset) / scale;
10452
10453 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provides a lower bound <%g>\n",
10454 SCIPconsGetName(cons), lowerbound);
10455
10456 SCIP_CALL( SCIPupdateLocalLowerbound(scip, lowerbound) );
10457 }
10458
10459 if( (conshdlrdata->detectcutoffbound && (conshdlrdata->detectlowerbound || !lhsfinite)) ||
10460 (conshdlrdata->detectlowerbound && !rhsfinite) )
10461 {
10462 /* avoid that the linear constraint enters the LP since it is parallel to the objective function */
10463 SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
10464 SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
10465 }
10466 }
10467 else
10468 {
10469 if( conshdlrdata->detectlowerbound && rhsfinite )
10470 {
10471 SCIP_Real lowerbound;
10472
10473 lowerbound = (consdata->rhs - offset) / scale;
10474
10475 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provides a lower bound <%g>\n",
10476 SCIPconsGetName(cons), lowerbound);
10477
10478 SCIP_CALL( SCIPupdateLocalLowerbound(scip, lowerbound) );
10479 }
10480
10481 if( conshdlrdata->detectcutoffbound && lhsfinite )
10482 {
10483 SCIP_Real primalbound;
10484
10485 primalbound = (consdata->lhs - offset) / scale;
10486
10487 SCIPdebugMsg(scip, "constraint <%s> is parallel to objective function and provides a cutoff bound <%g>\n",
10488 SCIPconsGetName(cons), primalbound);
10489
10490 SCIP_CALL( updateCutoffbound(scip, cons, primalbound) );
10491 }
10492
10493 if( (conshdlrdata->detectcutoffbound && (conshdlrdata->detectlowerbound || !rhsfinite)) ||
10494 (conshdlrdata->detectlowerbound && !lhsfinite) )
10495 {
10496 /* avoid that the linear constraint enters the LP since it is parallel to the objective function */
10497 SCIP_CALL( SCIPsetConsInitial(scip, cons, FALSE) );
10498 SCIP_CALL( SCIPsetConsSeparated(scip, cons, FALSE) );
10499 }
10500 }
10501 }
10502
10503 return SCIP_OKAY;
10504 }
10505
10506 /** converts special equalities */
10507 static
convertEquality(SCIP * scip,SCIP_CONS * cons,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_Bool * cutoff,int * nfixedvars,int * naggrvars,int * ndelconss)10508 SCIP_RETCODE convertEquality(
10509 SCIP* scip, /**< SCIP data structure */
10510 SCIP_CONS* cons, /**< linear constraint */
10511 SCIP_CONSHDLRDATA* conshdlrdata, /**< linear constraint handler data */
10512 SCIP_Bool* cutoff, /**< pointer to store TRUE, if a cutoff was found */
10513 int* nfixedvars, /**< pointer to count number of fixed variables */
10514 int* naggrvars, /**< pointer to count number of aggregated variables */
10515 int* ndelconss /**< pointer to count number of deleted constraints */
10516 )
10517 {
10518 SCIP_CONSDATA* consdata;
10519
10520 assert(scip != NULL);
10521 assert(cons != NULL);
10522 assert(conshdlrdata != NULL);
10523 assert(cutoff != NULL);
10524 assert(nfixedvars != NULL);
10525 assert(naggrvars != NULL);
10526 assert(ndelconss != NULL);
10527
10528 consdata = SCIPconsGetData(cons);
10529 assert(consdata != NULL);
10530 assert(consdata->removedfixings);
10531
10532 /* do nothing on inequalities */
10533 if( !SCIPisEQ(scip, consdata->lhs, consdata->rhs) )
10534 return SCIP_OKAY;
10535
10536 /* depending on the number of variables, call a special conversion method */
10537 if( consdata->nvars == 1 )
10538 {
10539 /* fix variable */
10540 SCIP_CALL( convertUnaryEquality(scip, cons, cutoff, nfixedvars, ndelconss) );
10541 }
10542 else if( consdata->nvars == 2 )
10543 {
10544 /* aggregate one of the variables */
10545 SCIP_CALL( convertBinaryEquality(scip, cons, cutoff, naggrvars, ndelconss) );
10546 }
10547 else
10548 {
10549 /* check if the equality is part of the objective function */
10550 SCIP_CALL( checkPartialObjective(scip, cons, conshdlrdata) );
10551
10552 /* try to multi-aggregate one of the variables */
10553 SCIP_CALL( convertLongEquality(scip, conshdlrdata, cons, cutoff, naggrvars, ndelconss) );
10554 }
10555
10556 return SCIP_OKAY;
10557 }
10558
10559 /** returns whether the linear sum of all variables/coefficients except the given one divided by the given value is always
10560 * integral
10561 */
10562 static
consdataIsResidualIntegral(SCIP * scip,SCIP_CONSDATA * consdata,int pos,SCIP_Real val)10563 SCIP_Bool consdataIsResidualIntegral(
10564 SCIP* scip, /**< SCIP data structure */
10565 SCIP_CONSDATA* consdata, /**< linear constraint */
10566 int pos, /**< position of variable to be left out */
10567 SCIP_Real val /**< value to divide the coefficients by */
10568 )
10569 {
10570 int v;
10571
10572 assert(scip != NULL);
10573 assert(consdata != NULL);
10574 assert(0 <= pos && pos < consdata->nvars);
10575
10576 for( v = 0; v < consdata->nvars; ++v )
10577 {
10578 if( v != pos && (!SCIPvarIsIntegral(consdata->vars[v]) || !SCIPisIntegral(scip, consdata->vals[v]/val)) )
10579 return FALSE;
10580 }
10581
10582 return TRUE;
10583 }
10584
10585 /** check if \f$lhs/a_i - \sum_{j \neq i} a_j/a_i x_j\f$ is always inside the bounds of \f$x_i\f$,
10586 * check if \f$rhs/a_i - \sum_{j \neq i} a_j/a_i x_j\f$ is always inside the bounds of \f$x_i\f$
10587 */
10588 static
calculateMinvalAndMaxval(SCIP * scip,SCIP_Real side,SCIP_Real val,SCIP_Real minresactivity,SCIP_Real maxresactivity,SCIP_Real * minval,SCIP_Real * maxval)10589 void calculateMinvalAndMaxval(
10590 SCIP* scip, /**< SCIP data structure */
10591 SCIP_Real side, /**< lhs or rhs */
10592 SCIP_Real val, /**< coefficient */
10593 SCIP_Real minresactivity, /**< minimal residual activity */
10594 SCIP_Real maxresactivity, /**< maximal residual activity */
10595 SCIP_Real* minval, /**< pointer to store calculated minval */
10596 SCIP_Real* maxval /**< pointer to store calculated maxval */
10597 )
10598 {
10599 assert(scip != NULL);
10600 assert(minval != NULL);
10601 assert(maxval != NULL);
10602
10603 if( val > 0.0 )
10604 {
10605 if( SCIPisInfinity(scip, ABS(maxresactivity)) )
10606 *minval = -maxresactivity;
10607 else
10608 *minval = (side - maxresactivity)/val;
10609
10610 if( SCIPisInfinity(scip, ABS(minresactivity)) )
10611 *maxval = -minresactivity;
10612 else
10613 *maxval = (side - minresactivity)/val;
10614 }
10615 else
10616 {
10617 if( SCIPisInfinity(scip, ABS(minresactivity)) )
10618 *minval = minresactivity;
10619 else
10620 *minval = (side - minresactivity)/val;
10621
10622 if( SCIPisInfinity(scip, ABS(maxresactivity)) )
10623 *maxval = maxresactivity;
10624 else
10625 *maxval = (side - maxresactivity)/val;
10626 }
10627 }
10628
10629
10630 /** applies dual presolving for variables that are locked only once in a direction, and this locking is due to a
10631 * linear inequality
10632 */
10633 static
dualPresolve(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_CONS * cons,SCIP_Bool * cutoff,int * nfixedvars,int * naggrvars,int * ndelconss)10634 SCIP_RETCODE dualPresolve(
10635 SCIP* scip, /**< SCIP data structure */
10636 SCIP_CONSHDLRDATA* conshdlrdata, /**< linear constraint handler data */
10637 SCIP_CONS* cons, /**< linear constraint */
10638 SCIP_Bool* cutoff, /**< pointer to store TRUE, if a cutoff was found */
10639 int* nfixedvars, /**< pointer to count number of fixed variables */
10640 int* naggrvars, /**< pointer to count number of aggregated variables */
10641 int* ndelconss /**< pointer to count number of deleted constraints */
10642 )
10643 {
10644 SCIP_CONSDATA* consdata;
10645 SCIP_Bool lhsexists;
10646 SCIP_Bool rhsexists;
10647 SCIP_Bool bestisint;
10648 SCIP_Bool bestislhs;
10649 SCIP_Real minabsval;
10650 SCIP_Real maxabsval;
10651 int bestpos;
10652 int i;
10653 int maxotherlocks;
10654
10655 assert(scip != NULL);
10656 assert(cons != NULL);
10657 assert(cutoff != NULL);
10658 assert(nfixedvars != NULL);
10659 assert(naggrvars != NULL);
10660 assert(ndelconss != NULL);
10661
10662 /* only process checked constraints (for which the locks are increased);
10663 * otherwise we would have to check for variables with nlocks == 0, and these are already processed by the
10664 * dualfix presolver
10665 */
10666 if( !SCIPconsIsChecked(cons) )
10667 return SCIP_OKAY;
10668
10669 consdata = SCIPconsGetData(cons);
10670 assert(consdata != NULL);
10671
10672 lhsexists = !SCIPisInfinity(scip, -consdata->lhs);
10673 rhsexists = !SCIPisInfinity(scip, consdata->rhs);
10674
10675 /* search for a single-locked variable which can be multi-aggregated; if a valid continuous variable was found, we
10676 * can use it safely for aggregation and break the search loop
10677 */
10678 bestpos = -1;
10679 bestisint = TRUE;
10680 bestislhs = FALSE;
10681
10682 /* We only want to multi-aggregate variables, if they appear in maximal one additional constraint,
10683 * everything else would produce fill-in. Exceptions:
10684 * - If there are only two variables in the constraint from which the multi-aggregation arises, no fill-in will be
10685 * produced.
10686 * - If there are three variables in the constraint, multi-aggregation in three additional constraints will remove
10687 * six nonzeros (three from the constraint and the three entries of the multi-aggregated variable) and add
10688 * six nonzeros (two variables per substitution).
10689 * - If there at most four variables in the constraint, multi-aggregation in two additional constraints will remove
10690 * six nonzeros (four from the constraint and the two entries of the multi-aggregated variable) and add
10691 * six nonzeros (three variables per substitution). God exists!
10692 */
10693 if( consdata->nvars <= 2 )
10694 maxotherlocks = INT_MAX;
10695 else if( consdata->nvars == 3 )
10696 maxotherlocks = 3;
10697 else if( consdata->nvars == 4 )
10698 maxotherlocks = 2;
10699 else
10700 maxotherlocks = 1;
10701
10702 /* if this constraint has both sides, it also provides a lock for the other side and thus we can allow one more lock */
10703 if( lhsexists && rhsexists && maxotherlocks < INT_MAX )
10704 maxotherlocks++;
10705
10706 minabsval = SCIPinfinity(scip);
10707 maxabsval = -1.0;
10708 for( i = 0; i < consdata->nvars && bestisint; ++i )
10709 {
10710 SCIP_VAR* var;
10711 SCIP_Bool isint;
10712 SCIP_Real val;
10713 SCIP_Real absval;
10714 SCIP_Real obj;
10715 SCIP_Real lb;
10716 SCIP_Real ub;
10717 SCIP_Bool agglhs;
10718 SCIP_Bool aggrhs;
10719
10720 val = consdata->vals[i];
10721 absval = REALABS(val);
10722
10723 /* calculate minimal and maximal absolute value */
10724 if( absval < minabsval )
10725 minabsval = absval;
10726 if( absval > maxabsval )
10727 maxabsval = absval;
10728
10729 /* do not try to multi aggregate, when numerical bad */
10730 if( maxabsval / minabsval > conshdlrdata->maxdualmultaggrquot )
10731 return SCIP_OKAY;
10732
10733 var = consdata->vars[i];
10734 isint = (SCIPvarGetType(var) == SCIP_VARTYPE_BINARY || SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER);
10735
10736 /* if we already found a candidate, skip integers */
10737 if( bestpos >= 0 && isint )
10738 continue;
10739
10740 /* better do not multi-aggregate binary variables, since most plugins rely on their binary variables to be either
10741 * active, fixed, or single-aggregated with another binary variable
10742 */
10743 if( SCIPvarIsBinary(var) && consdata->nvars > 2 )
10744 continue;
10745
10746 if ( SCIPdoNotMultaggrVar(scip, var) )
10747 continue;
10748
10749 val = consdata->vals[i];
10750 obj = SCIPvarGetObj(var);
10751 lb = SCIPvarGetLbGlobal(var);
10752 ub = SCIPvarGetUbGlobal(var);
10753
10754 /* lhs <= a_0 * x_0 + a_1 * x_1 + ... + a_{n-1} * x_{n-1} <= rhs
10755 *
10756 * a_i >= 0, c_i >= 0, lhs exists, nlocksdown(x_i) == 1:
10757 * - constraint is the only one that forbids fixing the variable to its lower bound
10758 * - fix x_i to the smallest value for this constraint: x_i := lhs/a_i - \sum_{j \neq i} a_j/a_i * x_j
10759 *
10760 * a_i <= 0, c_i <= 0, lhs exists, nlocksup(x_i) == 1:
10761 * - constraint is the only one that forbids fixing the variable to its upper bound
10762 * - fix x_i to the largest value for this constraint: x_i := lhs/a_i - \sum_{j \neq i} a_j/a_i * x_j
10763 *
10764 * a_i >= 0, c_i <= 0, rhs exists, nlocksup(x_i) == 1:
10765 * - constraint is the only one that forbids fixing the variable to its upper bound
10766 * - fix x_i to the largest value for this constraint: x_i := rhs/a_i - \sum_{j \neq i} a_j/a_i * x_j
10767 *
10768 * a_i <= 0, c_i >= 0, rhs exists, nlocksdown(x_i) == 1:
10769 * - constraint is the only one that forbids fixing the variable to its lower bound
10770 * - fix x_i to the smallest value for this constraint: x_i := rhs/a_i - \sum_{j \neq i} a_j/a_i * x_j
10771 *
10772 * but: all this is only applicable, if the aggregated value is inside x_i's bounds for all possible values
10773 * of all x_j
10774 * furthermore: we only want to apply this, if no fill-in will be produced
10775 */
10776 agglhs = lhsexists
10777 && ((val > 0.0 && !SCIPisNegative(scip, obj) && SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == 1
10778 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) <= maxotherlocks)
10779 || (val < 0.0 && !SCIPisPositive(scip, obj) && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == 1
10780 && SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) <= maxotherlocks));
10781 aggrhs = rhsexists
10782 && ((val > 0.0 && !SCIPisPositive(scip, obj) && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == 1
10783 && SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) <= maxotherlocks)
10784 || (val < 0.0 && !SCIPisNegative(scip, obj) && SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == 1
10785 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) <= maxotherlocks));
10786 if( agglhs || aggrhs )
10787 {
10788 SCIP_Real minresactivity;
10789 SCIP_Real maxresactivity;
10790 SCIP_Real minval;
10791 SCIP_Real maxval;
10792 SCIP_Bool minisrelax;
10793 SCIP_Bool maxisrelax;
10794 SCIP_Bool isminsettoinfinity;
10795 SCIP_Bool ismaxsettoinfinity;
10796
10797 /* calculate bounds for \sum_{j \neq i} a_j * x_j */
10798 consdataGetActivityResiduals(scip, consdata, var, val, FALSE, &minresactivity, &maxresactivity,
10799 &minisrelax, &maxisrelax, &isminsettoinfinity, &ismaxsettoinfinity);
10800 assert(SCIPisLE(scip, minresactivity, maxresactivity));
10801
10802 /* We called consdataGetActivityResiduals() saying that we do not need a good relaxation,
10803 * so whenever we have a relaxed activity, it should be relaxed to +/- infinity.
10804 * This is needed, because we do not want to rely on relaxed finite resactivities.
10805 */
10806 assert((!minisrelax || isminsettoinfinity) && (!maxisrelax || ismaxsettoinfinity));
10807
10808 if( agglhs )
10809 {
10810 /* check if lhs/a_i - \sum_{j \neq i} a_j/a_i * x_j is always inside the bounds of x_i */
10811 calculateMinvalAndMaxval(scip, consdata->lhs, val, minresactivity, maxresactivity, &minval, &maxval);
10812
10813 assert(SCIPisLE(scip, minval, maxval));
10814 if( (!SCIPisInfinity(scip, -minval) && SCIPisFeasGE(scip, minval, lb)) &&
10815 (!SCIPisInfinity(scip, maxval) && SCIPisFeasLE(scip, maxval, ub)) )
10816 {
10817 SCIP_Real oldmaxresactivity;
10818 SCIP_Real oldminresactivity;
10819 SCIP_Bool recalculated;
10820
10821 recalculated = FALSE;
10822 oldmaxresactivity = maxresactivity;
10823 oldminresactivity = minresactivity;
10824
10825 /* check minresactivity for reliability */
10826 if( !isminsettoinfinity && SCIPisUpdateUnreliable(scip, minresactivity, consdata->lastminactivity) )
10827 {
10828 consdataGetReliableResidualActivity(scip, consdata, var, &minresactivity, TRUE, FALSE);
10829 recalculated = !SCIPisEQ(scip, oldminresactivity, minresactivity);
10830 isminsettoinfinity = TRUE; /* here it means only that it was even calculated */
10831 }
10832
10833 /* check maxresactivity for reliability */
10834 if( !ismaxsettoinfinity && SCIPisUpdateUnreliable(scip, maxresactivity, consdata->lastmaxactivity) )
10835 {
10836 consdataGetReliableResidualActivity(scip, consdata, var, &maxresactivity, FALSE, FALSE);
10837 recalculated = recalculated || !SCIPisEQ(scip, oldmaxresactivity, maxresactivity);
10838 ismaxsettoinfinity = TRUE; /* here it means only that it was even calculated */
10839 }
10840
10841 /* minresactivity or maxresactivity wasn't reliable so recalculate min- and maxval*/
10842 if( recalculated )
10843 {
10844 assert(SCIPisLE(scip, minresactivity, maxresactivity));
10845
10846 /* check again if lhs/a_i - \sum_{j \neq i} a_j/a_i * x_j is always inside the bounds of x_i */
10847 calculateMinvalAndMaxval(scip, consdata->lhs, val, minresactivity, maxresactivity, &minval, &maxval);
10848
10849 assert(SCIPisLE(scip, minval, maxval));
10850 }
10851
10852 if( !recalculated || (SCIPisFeasGE(scip, minval, lb) && SCIPisFeasLE(scip, maxval, ub)) )
10853 {
10854 /* if the variable is integer, we have to check whether the integrality condition would always be satisfied
10855 * in the multi-aggregation
10856 */
10857 if( !isint || (SCIPisIntegral(scip, consdata->lhs/val) && consdataIsResidualIntegral(scip, consdata, i, val)) )
10858 {
10859 bestpos = i;
10860 bestisint = isint;
10861 bestislhs = TRUE;
10862 continue; /* no need to also look at the right hand side */
10863 }
10864 }
10865 }
10866 }
10867
10868 if( aggrhs )
10869 {
10870 /* check if rhs/a_i - \sum_{j \neq i} a_j/a_i * x_j is always inside the bounds of x_i */
10871 calculateMinvalAndMaxval(scip, consdata->rhs, val, minresactivity, maxresactivity, &minval, &maxval);
10872
10873 assert(SCIPisLE(scip,minval,maxval));
10874 if( (!SCIPisInfinity(scip, -minval) && SCIPisFeasGE(scip, minval, lb)) &&
10875 (!SCIPisInfinity(scip, maxval) && SCIPisFeasLE(scip, maxval, ub)) )
10876 {
10877 SCIP_Real oldmaxresactivity;
10878 SCIP_Real oldminresactivity;
10879 SCIP_Bool recalculated;
10880
10881 recalculated = FALSE;
10882 oldmaxresactivity = maxresactivity;
10883 oldminresactivity = minresactivity;
10884
10885 /* check minresactivity for reliability */
10886 if( !isminsettoinfinity && SCIPisUpdateUnreliable(scip, minresactivity, consdata->lastminactivity) )
10887 {
10888 consdataGetReliableResidualActivity(scip, consdata, var, &minresactivity, TRUE, FALSE);
10889 recalculated = !SCIPisEQ(scip, oldminresactivity, minresactivity);
10890 }
10891
10892 /* check maxresactivity for reliability */
10893 if( !ismaxsettoinfinity && SCIPisUpdateUnreliable(scip, maxresactivity, consdata->lastmaxactivity) )
10894 {
10895 consdataGetReliableResidualActivity(scip, consdata, var, &maxresactivity, FALSE, FALSE);
10896 recalculated = recalculated || !SCIPisEQ(scip, oldmaxresactivity, maxresactivity);
10897 }
10898
10899 /* minresactivity or maxresactivity wasn't reliable so recalculate min- and maxval*/
10900 if( recalculated )
10901 {
10902 /* check again if rhs/a_i - \sum_{j \neq i} a_j/a_i * x_j is always inside the bounds of x_i */
10903 calculateMinvalAndMaxval(scip, consdata->rhs, val, minresactivity, maxresactivity, &minval, &maxval);
10904 assert(SCIPisLE(scip,minval,maxval));
10905 }
10906
10907 if( !recalculated || (SCIPisFeasGE(scip, minval, lb) && SCIPisFeasLE(scip, maxval, ub)) )
10908 {
10909 /* if the variable is integer, we have to check whether the integrality condition would always be satisfied
10910 * in the multi-aggregation
10911 */
10912 if( !isint || (SCIPisIntegral(scip, consdata->rhs/val) && consdataIsResidualIntegral(scip, consdata, i, val)) )
10913 {
10914 bestpos = i;
10915 bestisint = isint;
10916 bestislhs = FALSE;
10917 }
10918 }
10919 }
10920 }
10921 }
10922 }
10923
10924 if( bestpos >= 0 )
10925 {
10926 SCIP_VAR** aggrvars;
10927 SCIP_Real* aggrcoefs;
10928 SCIP_Real aggrconst;
10929 SCIP_VAR* bestvar;
10930 SCIP_Real bestval;
10931 SCIP_Real epsilon;
10932 int naggrs;
10933 int j;
10934 SCIP_Bool infeasible;
10935 SCIP_Bool aggregated;
10936 SCIP_Bool samevar;
10937 int supinf; /* counter for infinite contributions to the supremum of a possible
10938 * multi-aggregation
10939 */
10940 int infinf; /* counter for infinite contributions to the infimum of a possible
10941 * multi-aggregation
10942 */
10943
10944 assert(!bestislhs || lhsexists);
10945 assert(bestislhs || rhsexists);
10946
10947 bestvar = consdata->vars[bestpos];
10948 bestval = consdata->vals[bestpos];
10949 assert(bestisint ==
10950 (SCIPvarGetType(bestvar) == SCIP_VARTYPE_BINARY || SCIPvarGetType(bestvar) == SCIP_VARTYPE_INTEGER));
10951
10952 /* allocate temporary memory */
10953 SCIP_CALL( SCIPallocBufferArray(scip, &aggrvars, consdata->nvars-1) );
10954 SCIP_CALL( SCIPallocBufferArray(scip, &aggrcoefs, consdata->nvars-1) );
10955
10956 /* set up the multi-aggregation */
10957 SCIPdebugPrintCons(scip, cons, NULL);
10958 SCIPdebugMsg(scip, "linear constraint <%s> (dual): multi-aggregate <%s> ==", SCIPconsGetName(cons), SCIPvarGetName(bestvar));
10959 naggrs = 0;
10960 supinf = 0;
10961 infinf = 0;
10962 samevar = FALSE;
10963 epsilon = SCIPepsilon(scip);
10964
10965 for( j = 0; j < consdata->nvars; ++j )
10966 {
10967 if( j != bestpos )
10968 {
10969 SCIP_Real absaggrcoef;
10970
10971 aggrvars[naggrs] = consdata->vars[j];
10972 aggrcoefs[naggrs] = -consdata->vals[j]/consdata->vals[bestpos];
10973 SCIPdebugMsgPrint(scip, " %+.15g<%s>", aggrcoefs[naggrs], SCIPvarGetName(aggrvars[naggrs]));
10974
10975 absaggrcoef = REALABS(aggrcoefs[naggrs]);
10976
10977 /* do not try to multi aggregate, when numerical bad */
10978 if( absaggrcoef < epsilon )
10979 {
10980 SCIPdebugMsg(scip, "do not perform multi-aggregation: too large aggregation coefficients\n");
10981
10982 /* free temporary memory */
10983 SCIPfreeBufferArray(scip, &aggrcoefs);
10984 SCIPfreeBufferArray(scip, &aggrvars);
10985
10986 return SCIP_OKAY;
10987 }
10988
10989 if( bestisint )
10990 {
10991 /* coefficient must be integral: round it to exact integral value */
10992 assert(SCIPisIntegral(scip, aggrcoefs[naggrs]));
10993 aggrcoefs[naggrs] = SCIPfloor(scip, aggrcoefs[naggrs]+0.5);
10994 }
10995
10996 if( SCIPisPositive(scip, aggrcoefs[naggrs]) )
10997 {
10998 if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(consdata->vars[j])) )
10999 {
11000 ++supinf;
11001 if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->vars[j])) )
11002 {
11003 ++infinf;
11004 samevar = TRUE;
11005 }
11006 }
11007 else if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->vars[j])) )
11008 ++infinf;
11009 }
11010 else if( SCIPisNegative(scip, aggrcoefs[naggrs]) )
11011 {
11012 if( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(consdata->vars[j])) )
11013 {
11014 ++supinf;
11015 if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(consdata->vars[j])) )
11016 {
11017 ++infinf;
11018 samevar = TRUE;
11019 }
11020 }
11021 else if( SCIPisInfinity(scip, SCIPvarGetUbGlobal(consdata->vars[j])) )
11022 ++infinf;
11023 }
11024
11025 naggrs++;
11026 }
11027 }
11028 assert(!samevar || (supinf > 0 && infinf > 0));
11029
11030 aggrconst = (bestislhs ? consdata->lhs/bestval : consdata->rhs/bestval);
11031 SCIPdebugMsgPrint(scip, " %+.15g, bounds of <%s>: [%.15g,%.15g]\n", aggrconst, SCIPvarGetName(bestvar),
11032 SCIPvarGetLbGlobal(bestvar), SCIPvarGetUbGlobal(bestvar));
11033 assert(naggrs == consdata->nvars-1);
11034
11035 /* right hand side must be integral: round it to exact integral value */
11036 if( bestisint )
11037 {
11038 assert(SCIPisIntegral(scip, aggrconst));
11039 aggrconst = SCIPfloor(scip, aggrconst+0.5);
11040 }
11041
11042 aggregated = FALSE;
11043 infeasible = FALSE;
11044
11045 /* perform the multi-aggregation */
11046 if( (samevar && supinf == 1 && infinf == 1) || (!samevar && (supinf == 0 || infinf == 0)) )
11047 {
11048 /* @todo if multi-aggregate makes them numerical trouble, avoid them if the coefficients differ to much, see
11049 * also convertLongEquality() early termination due to coefficients
11050 */
11051 SCIP_CALL( SCIPmultiaggregateVar(scip, bestvar, naggrs, aggrvars, aggrcoefs, aggrconst, &infeasible, &aggregated) );
11052 }
11053 else
11054 {
11055 /* If the infimum and the supremum of a multi-aggregation are both infinite, then the multi-aggregation might not be resolvable.
11056 * E.g., consider the equality z = x-y. If x and y are both fixed to +infinity, the value for z is not determined */
11057 SCIPdebugMsg(scip, "do not perform multi-aggregation: infimum and supremum are both infinite\n");
11058 }
11059 /* free temporary memory */
11060 SCIPfreeBufferArray(scip, &aggrcoefs);
11061 SCIPfreeBufferArray(scip, &aggrvars);
11062
11063 /* check for infeasible aggregation */
11064 if( infeasible )
11065 {
11066 SCIPdebugMsg(scip, "linear constraint <%s>: infeasible multi-aggregation\n", SCIPconsGetName(cons));
11067 *cutoff = TRUE;
11068 return SCIP_OKAY;
11069 }
11070
11071 /* delete the constraint, if the aggregation was successful */
11072 if( aggregated )
11073 {
11074 SCIP_CALL( SCIPdelCons(scip, cons) );
11075
11076 if( !consdata->upgraded )
11077 (*ndelconss)++;
11078 (*naggrvars)++;
11079 }
11080 else
11081 {
11082 SCIPdebugMsg(scip, "aggregation non successful!\n");
11083 }
11084 }
11085
11086 return SCIP_OKAY;
11087 }
11088
11089 #define BINWEIGHT 1
11090 #define INTWEIGHT 4
11091 #define CONTWEIGHT 8
11092
11093 /** gets weight for variable in a "weighted number of variables" sum */
11094 static
getVarWeight(SCIP_VAR * var)11095 int getVarWeight(
11096 SCIP_VAR* var /**< variable to get weight for */
11097 )
11098 {
11099 switch( SCIPvarGetType(var) )
11100 {
11101 case SCIP_VARTYPE_BINARY:
11102 return BINWEIGHT;
11103 case SCIP_VARTYPE_INTEGER:
11104 case SCIP_VARTYPE_IMPLINT:
11105 return INTWEIGHT;
11106 case SCIP_VARTYPE_CONTINUOUS:
11107 return CONTWEIGHT;
11108 default:
11109 SCIPerrorMessage("invalid variable type\n");
11110 SCIPABORT();
11111 return 0; /*lint !e527*/
11112 }
11113 }
11114
11115 /** tries to aggregate variables in equations a^Tx = lhs
11116 * in case there are at most two binary variables with an odd coefficient and all other
11117 * variables are not continuous and have an even coefficient then:
11118 * - exactly one odd binary variables
11119 * this binary variables y can be fixed to 0 if the lhs is even and to 1 if the lhs is odd
11120 * - lhs is odd -> y = 1
11121 * - lhs is even -> y = 0
11122 * - exactly two odd binary variables
11123 * aggregate the two binary variables with odd coefficient
11124 * - lhs is odd -> exactly one of the variable has to be 1 -> var1 + var2 = 1
11125 * - lhs is even -> both have to take the same value -> var1 - var2 = 0
11126 */
11127 static
aggregateVariables(SCIP * scip,SCIP_CONS * cons,SCIP_Bool * cutoff,int * nfixedvars,int * naggrvars)11128 SCIP_RETCODE aggregateVariables(
11129 SCIP* scip, /**< SCIP data structure */
11130 SCIP_CONS* cons, /**< linear constraint */
11131 SCIP_Bool* cutoff, /**< pointer to store TRUE, if a cutoff was found */
11132 int* nfixedvars, /**< pointer to count number of fixed variables */
11133 int* naggrvars /**< pointer to count number of aggregated variables */
11134 )
11135 { /*lint --e{715}*/
11136 SCIP_CONSDATA* consdata;
11137 SCIP_Bool success;
11138
11139 assert( scip != NULL );
11140 assert( cons != NULL );
11141
11142 consdata = SCIPconsGetData(cons);
11143 assert( consdata != NULL );
11144
11145 /* check if the linear constraint is an equation with integral right hand side */
11146 if( !SCIPisEQ(scip, consdata->lhs, consdata->rhs) || !SCIPisIntegral(scip, consdata->lhs) )
11147 return SCIP_OKAY;
11148
11149 /* try to fix and aggregated variables until nothing is possible anymore */
11150 do
11151 {
11152 int v;
11153 int nvars;
11154 SCIP_VAR** vars;
11155 SCIP_Real* vals;
11156 SCIP_Real lhs;
11157 SCIP_Bool lhsodd;
11158
11159 SCIP_Bool infeasible;
11160 SCIP_Bool fixed;
11161 SCIP_Bool aggregated;
11162 SCIP_Bool redundant;
11163
11164 SCIP_VAR* var1;
11165 SCIP_VAR* var2;
11166 int noddvars;
11167
11168 success = FALSE;
11169
11170 lhs = consdata->lhs;
11171 vars = consdata->vars;
11172 vals = consdata->vals;
11173 nvars = consdata->nvars;
11174
11175 assert( !SCIPisInfinity(scip, ABS(lhs)) );
11176
11177 var1 = NULL;
11178 var2 = NULL;
11179 noddvars = 0;
11180
11181 /* search for binary variables with an odd coefficient */
11182 for( v = 0; v < nvars && noddvars < 3; ++v )
11183 {
11184 SCIP_Longint val;
11185
11186 /* all coefficients and variables have to be integral */
11187 if( !SCIPisIntegral(scip, vals[v]) || SCIPvarGetType(vars[v]) == SCIP_VARTYPE_CONTINUOUS )
11188 return SCIP_OKAY;
11189
11190 val = (SCIP_Longint)SCIPfeasFloor(scip, vals[v]);
11191 if( val % 2 != 0 )
11192 {
11193 /* the odd values have to belong to binary variables */
11194 if( !SCIPvarIsBinary(vars[v]) )
11195 return SCIP_OKAY;
11196
11197 if( noddvars == 0 )
11198 var1 = vars[v];
11199 else
11200 var2 = vars[v];
11201
11202 noddvars++;
11203 }
11204 }
11205
11206 /* check lhs is odd or even */
11207 lhsodd = (((SCIP_Longint)SCIPfeasFloor(scip, lhs)) % 2 != 0);
11208
11209 if( noddvars == 1 )
11210 {
11211 assert( var1 != NULL );
11212
11213 SCIPdebugMsg(scip, "linear constraint <%s>: try fixing variable <%s> to <%g>\n",
11214 SCIPconsGetName(cons), SCIPvarGetName(var1), lhsodd ? 1.0 : 0.0);
11215
11216 SCIP_CALL( SCIPfixVar(scip, var1, lhsodd? 1.0 : 0.0, &infeasible, &fixed) );
11217
11218 /* check for infeasibility of fixing */
11219 if( infeasible )
11220 {
11221 SCIPdebugMsg(scip, " -> infeasible fixing\n");
11222 *cutoff = TRUE;
11223 return SCIP_OKAY;
11224 }
11225
11226 if( fixed )
11227 {
11228 SCIPdebugMsg(scip, " -> feasible fixing\n");
11229 (*nfixedvars)++;
11230 success = TRUE;
11231 }
11232 }
11233 else if( noddvars == 2 )
11234 {
11235 assert( var1 != NULL );
11236 assert( var2 != NULL );
11237
11238 /* aggregate the two variables with odd coefficient
11239 * - lhs is odd -> exactly one of the variable has to be 1 -> var1 + var2 = 1
11240 * - lhs is even -> both have to take the same value -> var1 - var2 = 0
11241 */
11242 SCIPdebugMsg(scip, "linear constraint <%s>: try aggregation of variables <%s> and <%s>\n",
11243 SCIPconsGetName(cons), SCIPvarGetName(var1), SCIPvarGetName(var2));
11244
11245 SCIP_CALL( SCIPaggregateVars(scip, var1, var2, 1.0, lhsodd ? 1.0 : -1.0,
11246 lhsodd ? 1.0 : 0.0, &infeasible, &redundant, &aggregated) );
11247
11248 /* check for infeasibility of aggregation */
11249 if( infeasible )
11250 {
11251 SCIPdebugMsg(scip, " -> infeasible aggregation\n");
11252 *cutoff = TRUE;
11253 return SCIP_OKAY;
11254 }
11255
11256 /* count the aggregation */
11257 if( aggregated )
11258 {
11259 SCIPdebugMsg(scip, " -> feasible aggregation\n");
11260 (*naggrvars)++;
11261 success = TRUE;
11262 }
11263 }
11264
11265 if( success )
11266 {
11267 /* apply fixings and aggregation to successfully rerun this presolving step */
11268 SCIP_CALL( applyFixings(scip, cons, &infeasible) );
11269
11270 if( infeasible )
11271 {
11272 SCIPdebugMsg(scip, " -> infeasible fixing\n");
11273 *cutoff = TRUE;
11274 return SCIP_OKAY;
11275 }
11276
11277 /* normalize constraint */
11278 SCIP_CALL( normalizeCons(scip, cons, &infeasible) );
11279
11280 if( infeasible )
11281 {
11282 SCIPdebugMsg(scip, " -> infeasible normalization\n");
11283 *cutoff = TRUE;
11284 return SCIP_OKAY;
11285 }
11286 }
11287 }
11288 while( success );
11289
11290 return SCIP_OKAY;
11291 }
11292
11293
11294
11295 /** sorting method for constraint data, compares two variables on given indices, continuous variables will be sorted to
11296 * the end and for all other variables the sortation will be in non-increasing order of their absolute value of the
11297 * coefficients
11298 */
11299 static
SCIP_DECL_SORTINDCOMP(consdataCompSim)11300 SCIP_DECL_SORTINDCOMP(consdataCompSim)
11301 { /*lint --e{715}*/
11302 SCIP_CONSDATA* consdata = (SCIP_CONSDATA*)dataptr;
11303 SCIP_VARTYPE vartype1;
11304 SCIP_VARTYPE vartype2;
11305 SCIP_Real value;
11306
11307 assert(consdata != NULL);
11308 assert(0 <= ind1 && ind1 < consdata->nvars);
11309 assert(0 <= ind2 && ind2 < consdata->nvars);
11310
11311 vartype1 = SCIPvarGetType(consdata->vars[ind1]);
11312 vartype2 = SCIPvarGetType(consdata->vars[ind2]);
11313
11314 if( vartype1 == SCIP_VARTYPE_CONTINUOUS )
11315 {
11316 /* continuous varibles will be sorted to the back */
11317 if( vartype2 != vartype1 )
11318 return +1;
11319 /* both variables are continuous */
11320 else
11321 return 0;
11322 }
11323 /* continuous variables will be sorted to the back */
11324 else if( vartype2 == SCIP_VARTYPE_CONTINUOUS )
11325 return -1;
11326
11327 value = REALABS(consdata->vals[ind2]) - REALABS(consdata->vals[ind1]);
11328
11329 /* for all non-continuous variables, the variables are sorted after decreasing absolute coefficients */
11330 return (value > 0 ? +1 : (value < 0 ? -1 : 0));
11331 }
11332
11333 /** tries to simplify coefficients and delete variables in ranged row of the form lhs <= a^Tx <= rhs, e.g. using the greatest
11334 * common divisor
11335 *
11336 * 1. lhs <= a^Tx <= rhs, forall a_i >= lhs, a_i <= rhs, and forall pairs a_i + a_j > rhs then we can change this
11337 * constraint to 1^Tx = 1
11338 */
11339 static
rangedRowSimplify(SCIP * scip,SCIP_CONS * cons,int * nchgcoefs,int * nchgsides)11340 SCIP_RETCODE rangedRowSimplify(
11341 SCIP* scip, /**< SCIP data structure */
11342 SCIP_CONS* cons, /**< linear constraint */
11343 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
11344 int* nchgsides /**< pointer to store the amount of changed sides */
11345 )
11346 {
11347 SCIP_CONSDATA* consdata;
11348 SCIP_VAR** vars;
11349 SCIP_Real* vals;
11350 SCIP_Real minval;
11351 SCIP_Real secondminval;
11352 SCIP_Real maxval;
11353 SCIP_Real lhs;
11354 SCIP_Real rhs;
11355 int nvars;
11356 int v;
11357
11358 /* we must not change a modifiable constraint in any way */
11359 if( SCIPconsIsModifiable(cons) )
11360 return SCIP_OKAY;
11361
11362 if( SCIPconsIsDeleted(cons) )
11363 return SCIP_OKAY;
11364
11365 consdata = SCIPconsGetData(cons);
11366 assert(consdata != NULL);
11367
11368 nvars = consdata->nvars;
11369
11370 /* do not check empty or bound-constraints */
11371 if( nvars < 2 )
11372 return SCIP_OKAY;
11373
11374 vals = consdata->vals;
11375 vars = consdata->vars;
11376 assert(vars != NULL);
11377 assert(vals != NULL);
11378
11379 lhs = consdata->lhs;
11380 rhs = consdata->rhs;
11381 assert(!SCIPisInfinity(scip, -lhs) && !SCIPisInfinity(scip, rhs));
11382 assert(!SCIPisNegative(scip, rhs));
11383
11384 minval = SCIP_INVALID;
11385 secondminval = SCIP_INVALID;
11386 maxval = -SCIP_INVALID;
11387
11388 for( v = nvars - 1; v >= 0; --v )
11389 {
11390 if( SCIPvarIsBinary(vars[v]) )
11391 {
11392 if( minval > vals[v] || minval == SCIP_INVALID ) /*lint !e777*/
11393 {
11394 secondminval = minval;
11395 minval = vals[v];
11396 }
11397 else if( secondminval > vals[v] || secondminval == SCIP_INVALID ) /*lint !e777*/
11398 secondminval = vals[v];
11399
11400 if( maxval < vals[v] || maxval == -SCIP_INVALID ) /*lint !e777*/
11401 maxval = vals[v];
11402 }
11403 else
11404 break;
11405 }
11406
11407 /* check if all variables are binary */
11408 if( v == -1 )
11409 {
11410 if( SCIPisEQ(scip, minval, maxval) && SCIPisEQ(scip, lhs, rhs) )
11411 return SCIP_OKAY;
11412
11413 /* check if we can and need to choose exactly one binary variable */
11414 if( SCIPisGE(scip, minval, lhs) && SCIPisLE(scip, maxval, rhs) && SCIPisGT(scip, minval + secondminval, rhs) )
11415 {
11416 /* change all coefficients to 1.0 */
11417 for( v = nvars - 1; v >= 0; --v )
11418 {
11419 SCIP_CALL( chgCoefPos(scip, cons, v, 1.0) );
11420 }
11421 (*nchgcoefs) += nvars;
11422
11423 /* replace old right and left hand side with 1.0 */
11424 SCIP_CALL( chgRhs(scip, cons, 1.0) );
11425 SCIP_CALL( chgLhs(scip, cons, 1.0) );
11426 (*nchgsides) += 2;
11427 }
11428 }
11429
11430 return SCIP_OKAY;
11431 }
11432
11433 /** tries to simplify coefficients and delete variables in constraints of the form lhs <= a^Tx <= rhs
11434 * for equations @see rangedRowSimplify() will be called
11435 *
11436 * there are several different coefficient reduction steps which will be applied
11437 *
11438 * 1. We try to determine parts of the constraint which will not change anything on (in-)feasibility of the constraint
11439 *
11440 * e.g. 5x1 + 5x2 + 3z1 <= 8 => 3z1 is redundant if all x are binary and -2 < 3z1 <= 3
11441 *
11442 * 2. We try to remove redundant fractional parts in a constraint
11443 *
11444 * e.g. 5.2x1 + 5.1x2 + 3x3 <= 8.3 => will be changed to 5x1 + 5x2 + 3x3 <= 8 if all x are binary
11445 *
11446 * 3. We are using the greatest common divisor for further reductions
11447 *
11448 * e.g. 10x1 + 5y2 + 5x3 + 3x4 <= 15 => will be changed to 2x1 + y2 + x3 + x4 <= 3 if all xi are binary and y2 is
11449 * integral
11450 */
11451 static
simplifyInequalities(SCIP * scip,SCIP_CONS * cons,int * nchgcoefs,int * nchgsides,SCIP_Bool * infeasible)11452 SCIP_RETCODE simplifyInequalities(
11453 SCIP* scip, /**< SCIP data structure */
11454 SCIP_CONS* cons, /**< linear constraint */
11455 int* nchgcoefs, /**< pointer to store the amount of changed coefficients */
11456 int* nchgsides, /**< pointer to store the amount of changed sides */
11457 SCIP_Bool* infeasible /**< pointer to store whether infeasibility was detected */
11458 )
11459 {
11460 SCIP_CONSDATA* consdata;
11461 SCIP_VAR** vars;
11462 SCIP_Real* vals;
11463 int* perm;
11464 SCIP_Real minactsub;
11465 SCIP_Real maxactsub;
11466 SCIP_Real siderest;
11467 SCIP_Real feastol;
11468 SCIP_Real newcoef;
11469 SCIP_Real absval;
11470 SCIP_Real side;
11471 SCIP_Real lhs;
11472 SCIP_Real rhs;
11473 SCIP_Real lb;
11474 SCIP_Real ub;
11475 SCIP_Longint restcoef;
11476 SCIP_Longint oldgcd;
11477 SCIP_Longint rest;
11478 SCIP_Longint gcd;
11479 SCIP_Bool isminsettoinfinity;
11480 SCIP_Bool ismaxsettoinfinity;
11481 SCIP_Bool isminrelax;
11482 SCIP_Bool ismaxrelax;
11483 SCIP_Bool allcoefintegral;
11484 SCIP_Bool onlybin;
11485 SCIP_Bool hasrhs;
11486 SCIP_Bool haslhs;
11487 int oldnchgcoefs;
11488 int oldnchgsides;
11489 int foundbin;
11490 int candpos;
11491 int candpos2;
11492 int offsetv;
11493 int nvars;
11494 int v;
11495 int w;
11496
11497 assert(scip != NULL);
11498 assert(cons != NULL);
11499 assert(nchgcoefs != NULL);
11500 assert(nchgsides != NULL);
11501
11502 *infeasible = FALSE;
11503
11504 /* we must not change a modifiable constraint in any way */
11505 if( SCIPconsIsModifiable(cons) )
11506 return SCIP_OKAY;
11507
11508 if( SCIPconsIsDeleted(cons) )
11509 return SCIP_OKAY;
11510
11511 consdata = SCIPconsGetData(cons);
11512 assert(consdata != NULL);
11513
11514 nvars = consdata->nvars;
11515
11516 /* do not check empty or bound-constraints */
11517 if( nvars <= 2 )
11518 return SCIP_OKAY;
11519
11520 /* update maximal activity delta if necessary */
11521 if( consdata->maxactdelta == SCIP_INVALID ) /*lint !e777*/
11522 consdataRecomputeMaxActivityDelta(scip, consdata);
11523
11524 assert(consdata->maxactdelta != SCIP_INVALID); /*lint !e777*/
11525 assert(!SCIPisFeasNegative(scip, consdata->maxactdelta));
11526 checkMaxActivityDelta(scip, consdata);
11527
11528 /* @todo the following might be too hard, check which steps can be applied and what code must be corrected
11529 * accordingly
11530 */
11531 /* can only work with valid non-infinity activities per variable */
11532 if( SCIPisInfinity(scip, consdata->maxactdelta) )
11533 return SCIP_OKAY;
11534
11535 /* @todo: change the following: due to vartype changes, the status of the normalization can be wrong, need an event
11536 * but the eventsystem seems to be full
11537 */
11538 consdata->normalized = FALSE;
11539
11540 /* normalize constraint */
11541 SCIP_CALL( normalizeCons(scip, cons, infeasible) );
11542 assert(nvars == consdata->nvars);
11543
11544 if( *infeasible )
11545 return SCIP_OKAY;
11546
11547 if( !consdata->normalized )
11548 return SCIP_OKAY;
11549
11550 lhs = consdata->lhs;
11551 rhs = consdata->rhs;
11552 assert(!SCIPisInfinity(scip, -lhs) || !SCIPisInfinity(scip, rhs));
11553 assert(!SCIPisNegative(scip, rhs));
11554
11555 if( !SCIPisInfinity(scip, -lhs) )
11556 haslhs = TRUE;
11557 else
11558 haslhs = FALSE;
11559
11560 if( !SCIPisInfinity(scip, rhs) )
11561 hasrhs = TRUE;
11562 else
11563 hasrhs = FALSE;
11564
11565 SCIPdebug( oldnchgcoefs = *nchgcoefs; )
11566 SCIPdebug( oldnchgsides = *nchgsides; )
11567
11568 /* @todo also work on ranged rows */
11569 if( haslhs && hasrhs )
11570 {
11571 SCIP_CALL( rangedRowSimplify(scip, cons, nchgcoefs, nchgsides ) );
11572
11573 return SCIP_OKAY;
11574 }
11575 assert(haslhs != hasrhs);
11576
11577 /* if we have a normalized inequality (not ranged) the one side should be positive, @see normalizeCons() */
11578 assert(!hasrhs || !SCIPisNegative(scip, rhs));
11579 assert(!haslhs || !SCIPisNegative(scip, lhs));
11580
11581 /* get temporary memory to store the sorted permutation */
11582 SCIP_CALL( SCIPallocBufferArray(scip, &perm, nvars) );
11583
11584 /* call sorting method, order continuous variables to the end and all other variables after non-increasing absolute
11585 * value of their coefficients
11586 */
11587 SCIPsort(perm, consdataCompSim, (void*)consdata, nvars);
11588
11589 /* perform sorting after permutation array */
11590 permSortConsdata(consdata, perm, nvars);
11591 consdata->indexsorted = FALSE;
11592 consdata->coefsorted = FALSE;
11593
11594 vars = consdata->vars;
11595 vals = consdata->vals;
11596 assert(vars != NULL);
11597 assert(vals != NULL);
11598 assert(consdata->validmaxabsval ? (SCIPisFeasEQ(scip, consdata->maxabsval, REALABS(vals[0])) || SCIPvarGetType(vars[nvars - 1]) == SCIP_VARTYPE_CONTINUOUS) : TRUE);
11599
11600 /* free temporary memory */
11601 SCIPfreeBufferArray(scip, &perm);
11602
11603 /* only check constraints with at least two non continuous variables */
11604 if( SCIPvarGetType(vars[1]) == SCIP_VARTYPE_CONTINUOUS )
11605 return SCIP_OKAY;
11606
11607 /* do not process constraints when all coefficients are 1.0 */
11608 if( SCIPisEQ(scip, REALABS(vals[0]), 1.0) && ((hasrhs && SCIPisIntegral(scip, rhs)) || (haslhs && SCIPisIntegral(scip, lhs))) )
11609 return SCIP_OKAY;
11610
11611 feastol = SCIPfeastol(scip);
11612
11613 SCIPdebugMsg(scip, "starting simplification of coefficients\n");
11614 SCIPdebugPrintCons(scip, cons, NULL);
11615
11616 /* get global activities */
11617 consdataGetGlbActivityBounds(scip, consdata, FALSE, &minactsub, &maxactsub,
11618 &isminrelax, &ismaxrelax, &isminsettoinfinity, &ismaxsettoinfinity);
11619
11620 /* cannot work with infinite activities */
11621 if( isminsettoinfinity || ismaxsettoinfinity )
11622 return SCIP_OKAY;
11623
11624 assert(!isminrelax);
11625 assert(!ismaxrelax);
11626 assert(maxactsub > minactsub);
11627 assert(!SCIPisInfinity(scip, -minactsub));
11628 assert(!SCIPisInfinity(scip, maxactsub));
11629
11630 v = 0;
11631 offsetv = -1;
11632 side = haslhs ? lhs : rhs;
11633
11634 /* we now determine coefficients as large as the side of the constraint to retrieve a better reduction where we
11635 * do not need to look at the large coefficients
11636 *
11637 * e.g. all x are binary, z are positive integer
11638 * c1: +5x1 + 5x2 + 3x3 + 3x4 + x5 >= 5 (x5 is redundant and does not change (in-)feasibility of this constraint)
11639 * c2: +4x1 + 4x2 + 3x3 + 3x4 + x5 >= 4 (gcd (without the coefficient of x5) after the large coefficients is 3
11640 * c3: +30x1 + 29x2 + 14x3 + 14z1 + 7x5 + 7x6 <= 30 (gcd (without the coefficient of x2) after the large coefficients is 7
11641 *
11642 * can be changed to
11643 *
11644 * c1: +6x1 + 6x2 + 3x3 + 3x4 >= 6 (will be changed to c1: +2x1 + 2x2 + x3 + x4 >= 2)
11645 * c2: +6x1 + 6x2 + 3x3 + 3x4 + 3x5 >= 6 (will be changed to c2: +2x1 + 2x2 + x3 + x4 + x5 >= 2)
11646 * c3: +28x1 + 28x2 + 14x3 + 14z1 + 7x5 + 7x6 <= 28 (will be changed to c3: +4x1 + 4x2 + 2x3 + 2z1 + x5 + x6 <= 4)
11647 */
11648
11649 /* if the minimal activity is negative and we found more than one variable with a coefficient bigger than the left
11650 * hand side, we cannot apply the extra reduction step and need to reset v
11651 *
11652 * e.g. 7x1 + 7x2 - 4x3 - 4x4 >= 7 => xi = 1 for all i is not a solution, but if we would do a change on the
11653 * coefficients due to the gcd on the "small" coefficients we would get 8x1 + 8x2 - 4x3 - 4x4 >= 8 were xi = 1
11654 * for all i is a solution
11655 *
11656 * also redundancy of variables would not be correctly determined in such a case
11657 */
11658 if( nvars > 2 && SCIPisEQ(scip, vals[0], side) && !SCIPisNegative(scip, minactsub) )
11659 {
11660 v = 1;
11661
11662 while( v < nvars && SCIPisEQ(scip, side, vals[v]) )
11663 {
11664 /* if we have integer variable with "side"-coefficients but also with a lower bound greater than 0 we stop this
11665 * extra step, which might have worked
11666 */
11667 if( SCIPvarGetLbGlobal(vars[v]) > 0.5 )
11668 {
11669 v = 0;
11670 break;
11671 }
11672
11673 ++v;
11674 }
11675
11676 /* easy and quick fix: if all coefficients were equal to the side, we cannot apply further simplifications */
11677 /* todo find numerically stable normalization conditions to scale this cons to have coefficients almost equal to 1 */
11678 if( v == nvars )
11679 return SCIP_OKAY;
11680
11681 /* cannot work with continuous variables which have a big coefficient */
11682 if( v > 0 && SCIPvarGetType(vars[v - 1]) == SCIP_VARTYPE_CONTINUOUS )
11683 return SCIP_OKAY;
11684
11685 /* big negative coefficient, do not try to use the extra coefficient reduction step */
11686 if( SCIPisEQ(scip, side, -vals[v]) )
11687 v = 0;
11688
11689 /* all but one variable are processed or the next variable is continuous we cannot perform the extra coefficient
11690 * reduction
11691 */
11692 if( v == nvars - 1 || SCIPvarGetType(vars[v]) == SCIP_VARTYPE_CONTINUOUS )
11693 v = 0;
11694
11695 if( v > 0 )
11696 {
11697 assert(v < nvars);
11698
11699 offsetv = v - 1;
11700
11701 for( w = 0; w < v; ++w )
11702 {
11703 lb = SCIPvarGetLbGlobal(vars[w]);
11704 ub = SCIPvarGetUbGlobal(vars[w]);
11705
11706 assert(vals[w] > 0);
11707
11708 /* update residual activities */
11709 maxactsub -= ub * vals[w];
11710 minactsub -= lb * vals[w];
11711 assert(maxactsub > minactsub);
11712 }
11713 }
11714 }
11715
11716 /* find and remove redundant variables which do not interact with the (in-)feasibility of this constraint
11717 *
11718 * e.g. let all x are binary and y1 is continuous with bounds [-3,1] then we can reduce
11719 *
11720 * 15x1 + 15x2 + 7x3 + 3x4 + y1 <= 26
11721 * to
11722 * 15x1 + 15x2 <= 26 <=> x1 + x2 <= 1
11723 */
11724 if( nvars > 2 && SCIPisIntegral(scip, vals[v]) )
11725 {
11726 SCIP_Bool redundant = FALSE;
11727
11728 gcd = (SCIP_Longint)(REALABS(vals[v]) + feastol);
11729 assert(gcd >= 1);
11730
11731 if( v == 0 )
11732 {
11733 lb = SCIPvarGetLbGlobal(vars[0]);
11734 ub = SCIPvarGetUbGlobal(vars[0]);
11735
11736 /* update residual activities */
11737 if( vals[0] > 0 )
11738 {
11739 maxactsub -= ub * vals[0];
11740 minactsub -= lb * vals[0];
11741 }
11742 else
11743 {
11744 maxactsub -= lb * vals[0];
11745 minactsub -= ub * vals[0];
11746 }
11747 assert(maxactsub > minactsub);
11748 ++v;
11749 }
11750
11751 siderest = -SCIP_INVALID;
11752 allcoefintegral = TRUE;
11753
11754 /* check if some variables always fit into the given constraint */
11755 for( ; v < nvars - 1; ++v )
11756 {
11757 if( SCIPvarGetType(vars[v]) == SCIP_VARTYPE_CONTINUOUS )
11758 break;
11759
11760 if( !SCIPisIntegral(scip, vals[v]) )
11761 {
11762 allcoefintegral = FALSE;
11763 break;
11764 }
11765
11766 /* calculate greatest common divisor for all general and binary variables */
11767 gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)(REALABS(vals[v]) + feastol));
11768
11769 if( gcd == 1 )
11770 break;
11771
11772 lb = SCIPvarGetLbGlobal(vars[v]);
11773 ub = SCIPvarGetUbGlobal(vars[v]);
11774
11775 assert(!SCIPisInfinity(scip, -lb));
11776 assert(!SCIPisInfinity(scip, ub));
11777
11778 /* update residual activities */
11779 if( vals[v] > 0 )
11780 {
11781 maxactsub -= ub * vals[v];
11782 minactsub -= lb * vals[v];
11783 }
11784 else
11785 {
11786 maxactsub -= lb * vals[v];
11787 minactsub -= ub * vals[v];
11788 }
11789 assert(SCIPisGE(scip, maxactsub, minactsub));
11790
11791 if( hasrhs )
11792 {
11793 /* determine the remainder of the right hand side and the gcd */
11794 siderest = rhs - SCIPfeasFloor(scip, rhs/gcd) * gcd;
11795 }
11796 else
11797 {
11798 /* determine the remainder of the left hand side and the gcd */
11799 siderest = lhs - SCIPfeasFloor(scip, lhs/gcd) * gcd;
11800 if( SCIPisZero(scip, siderest) )
11801 siderest = gcd;
11802 }
11803
11804 /* early termination if the activities deceed the gcd */
11805 if( (offsetv == -1 && hasrhs && maxactsub <= siderest && SCIPisFeasGT(scip, minactsub, siderest - gcd)) ||
11806 (haslhs && SCIPisFeasLT(scip, maxactsub, siderest) && minactsub >= siderest - gcd) )
11807 {
11808 redundant = TRUE;
11809 break;
11810 }
11811 }
11812 assert(v < nvars || (offsetv >= 0 && gcd > 1));
11813
11814 if( !redundant )
11815 {
11816 if( hasrhs )
11817 {
11818 /* determine the remainder of the right hand side and the gcd */
11819 siderest = rhs - SCIPfeasFloor(scip, rhs/gcd) * gcd;
11820 }
11821 else
11822 {
11823 /* determine the remainder of the left hand side and the gcd */
11824 siderest = lhs - SCIPfeasFloor(scip, lhs/gcd) * gcd;
11825 if( SCIPisZero(scip, siderest) )
11826 siderest = gcd;
11827 }
11828 }
11829 else
11830 ++v;
11831
11832 SCIPdebugMsg(scip, "stopped at pos %d (of %d), subactivities [%g, %g], redundant = %u, hasrhs = %u, siderest = %g, gcd = %" SCIP_LONGINT_FORMAT ", offset position for 'side' coefficients = %d\n",
11833 v, nvars, minactsub, maxactsub, redundant, hasrhs, siderest, gcd, offsetv);
11834
11835 /* check if we can remove redundant variables */
11836 if( v < nvars && (redundant ||
11837 (offsetv == -1 && hasrhs && maxactsub <= siderest && SCIPisFeasGT(scip, minactsub, siderest - gcd)) ||
11838 (haslhs && SCIPisFeasLT(scip, maxactsub, siderest) && minactsub >= siderest - gcd)) )
11839 {
11840 SCIP_Real oldcoef;
11841
11842 /* double check the redundancy */
11843 #ifndef NDEBUG
11844 SCIP_Real tmpminactsub = 0.0;
11845 SCIP_Real tmpmaxactsub = 0.0;
11846
11847 /* recompute residual activities */
11848 for( w = v; w < nvars; ++w )
11849 {
11850 lb = SCIPvarGetLbGlobal(vars[w]);
11851 ub = SCIPvarGetUbGlobal(vars[w]);
11852
11853 assert(!SCIPisInfinity(scip, -lb));
11854 assert(!SCIPisInfinity(scip, ub));
11855
11856 /* update residual activities */
11857 if( vals[w] > 0 )
11858 {
11859 tmpmaxactsub += ub * vals[w];
11860 tmpminactsub += lb * vals[w];
11861 }
11862 else
11863 {
11864 tmpmaxactsub += lb * vals[w];
11865 tmpminactsub += ub * vals[w];
11866 }
11867 assert(tmpmaxactsub >= tmpminactsub);
11868 }
11869
11870 if( hasrhs )
11871 {
11872 assert(offsetv == -1);
11873
11874 /* determine the remainder of the right hand side and the gcd */
11875 siderest = rhs - SCIPfeasFloor(scip, rhs/gcd) * gcd;
11876 }
11877 else
11878 {
11879 /* determine the remainder of the left hand side and the gcd */
11880 siderest = lhs - SCIPfeasFloor(scip, lhs/gcd) * gcd;
11881 if( SCIPisZero(scip, siderest) )
11882 siderest = gcd;
11883 }
11884
11885 /* is the redundancy really fulfilled */
11886 assert((hasrhs && SCIPisFeasLE(scip, tmpmaxactsub, siderest) && tmpminactsub > siderest - gcd) ||
11887 (haslhs && tmpmaxactsub < siderest && SCIPisFeasGE(scip, tmpminactsub, siderest - gcd)));
11888 #endif
11889
11890 SCIPdebugMsg(scip, "removing %d last variables from constraint <%s>, because they never change anything on the feasibility of this constraint\n",
11891 nvars - v, SCIPconsGetName(cons));
11892
11893 /* remove redundant variables */
11894 for( w = nvars - 1; w >= v; --w )
11895 {
11896 SCIP_CALL( delCoefPos(scip, cons, w) );
11897 }
11898 (*nchgcoefs) += (nvars - v);
11899
11900 assert(w >= 0);
11901
11902 oldcoef = vals[w];
11903
11904 /* normalize constraint */
11905 SCIP_CALL( normalizeCons(scip, cons, infeasible) );
11906 assert(vars == consdata->vars);
11907 assert(vals == consdata->vals);
11908 assert(w < consdata->nvars);
11909
11910 if( *infeasible )
11911 return SCIP_OKAY;
11912
11913 /* compute new greatest common divisor due to normalization */
11914 gcd = (SCIP_Longint)(gcd / (oldcoef/vals[w]) + feastol);
11915 assert(gcd >= 1);
11916
11917 /* update side */
11918 if( hasrhs )
11919 {
11920 /* replace old with new right hand side */
11921 SCIP_CALL( chgRhs(scip, cons, SCIPfeasFloor(scip, consdata->rhs)) );
11922 rhs = consdata->rhs;
11923 }
11924 else
11925 {
11926 if( SCIPisFeasGT(scip, oldcoef/vals[w], 1.0) )
11927 {
11928 SCIP_CALL( chgLhs(scip, cons, SCIPfeasCeil(scip, consdata->lhs)) );
11929 lhs = consdata->lhs;
11930 }
11931 else
11932 assert(offsetv == -1 || SCIPisEQ(scip, vals[offsetv], consdata->lhs));
11933 }
11934 ++(*nchgsides);
11935
11936 assert(!hasrhs || !SCIPisNegative(scip, rhs));
11937 assert(!haslhs || !SCIPisNegative(scip, lhs));
11938
11939 /* get new constraint data */
11940 nvars = consdata->nvars;
11941 assert(nvars > 0);
11942
11943 allcoefintegral = TRUE;
11944
11945 #ifndef NDEBUG
11946 /* check integrality */
11947 for( w = offsetv + 1; w < nvars; ++w )
11948 {
11949 assert(SCIPisIntegral(scip, vals[w]));
11950 }
11951 #endif
11952 SCIPdebugPrintCons(scip, cons, NULL);
11953 }
11954
11955 /* try to find a better gcd, when having large coefficients */
11956 if( offsetv >= 0 && gcd == 1 )
11957 {
11958 /* calculate greatest common divisor for all general variables */
11959 gcd = (SCIP_Longint)(REALABS(vals[nvars - 1]) + feastol);
11960
11961 if( gcd > 1 )
11962 {
11963 gcd = -1;
11964 candpos = -1;
11965
11966 for( v = nvars - 1; v > offsetv; --v )
11967 {
11968 assert(!SCIPisZero(scip, vals[v]));
11969 if( SCIPvarGetType(vars[v]) == SCIP_VARTYPE_CONTINUOUS )
11970 break;
11971
11972 if( !SCIPisIntegral(scip, vals[v]) )
11973 {
11974 allcoefintegral = FALSE;
11975 break;
11976 }
11977
11978 oldgcd = gcd;
11979
11980 if( gcd == -1 )
11981 {
11982 gcd = (SCIP_Longint)(REALABS(vals[v]) + feastol);
11983 assert(gcd >= 1);
11984 }
11985 else
11986 {
11987 /* calculate greatest common divisor for all general and binary variables */
11988 gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)(REALABS(vals[v]) + feastol));
11989 }
11990
11991 /* if the greatest commmon divisor has become 1, we might have found the possible coefficient to change or we
11992 * can stop searching
11993 */
11994 if( gcd == 1 )
11995 {
11996 if( !SCIPvarIsBinary(vars[v]) )
11997 break;
11998
11999 /* found candidate */
12000 if( candpos == -1 )
12001 {
12002 gcd = oldgcd;
12003 candpos = v;
12004 }
12005 /* two different binary variables lead to a gcd of one, so we cannot change a coefficient */
12006 else
12007 break;
12008 }
12009 }
12010 assert(v > offsetv || candpos > offsetv);
12011 }
12012 else
12013 candpos = -1;
12014 }
12015 else
12016 candpos = nvars - 1;
12017
12018 /* check last coefficient for integrality */
12019 if( gcd > 1 && allcoefintegral && !redundant )
12020 {
12021 if( !SCIPisIntegral(scip, vals[nvars - 1]) )
12022 allcoefintegral = FALSE;
12023 }
12024
12025 /* check for further necessary coefficient adjustments */
12026 if( offsetv >= 0 && gcd > 1 && allcoefintegral )
12027 {
12028 assert(offsetv + 1 < nvars);
12029 assert(0 <= candpos && candpos < nvars);
12030
12031 if( SCIPvarGetType(vars[candpos]) != SCIP_VARTYPE_CONTINUOUS )
12032 {
12033 SCIP_Bool notchangable = FALSE;
12034
12035 #ifndef NDEBUG
12036 /* check integrality */
12037 for( w = offsetv + 1; w < nvars; ++w )
12038 {
12039 assert(SCIPisIntegral(scip, vals[w]));
12040 }
12041 #endif
12042
12043 if( vals[candpos] > 0 && SCIPvarIsBinary(vars[candpos]) &&
12044 SCIPcalcGreComDiv(gcd, (SCIP_Longint)(REALABS(vals[candpos]) + feastol)) < gcd )
12045 {
12046 /* determine the remainder of the side and the gcd */
12047 if( hasrhs )
12048 rest = ((SCIP_Longint)(rhs + feastol)) % gcd;
12049 else
12050 rest = ((SCIP_Longint)(lhs + feastol)) % gcd;
12051 assert(rest >= 0);
12052 assert(rest < gcd);
12053
12054 /* determine the remainder of the coefficient candidate and the gcd */
12055 restcoef = ((SCIP_Longint)(vals[candpos] + feastol)) % gcd;
12056 assert(restcoef >= 1);
12057 assert(restcoef < gcd);
12058
12059 if( hasrhs )
12060 {
12061 /* calculate new coefficient */
12062 if( restcoef > rest )
12063 newcoef = vals[candpos] - restcoef + gcd;
12064 else
12065 newcoef = vals[candpos] - restcoef;
12066 }
12067 else
12068 {
12069 /* calculate new coefficient */
12070 if( rest == 0 || restcoef < rest )
12071 newcoef = vals[candpos] - restcoef;
12072 else
12073 newcoef = vals[candpos] - restcoef + gcd;
12074 }
12075
12076 /* done */
12077
12078 /* new coeffcient must not be zero if we would loose the implication that a variable needs to be 0 if
12079 * another with the big coefficient was set to 1
12080 */
12081 if( hasrhs && SCIPisZero(scip, newcoef) )
12082 {
12083 notchangable = TRUE;
12084 }
12085 else if( SCIPisZero(scip, newcoef) )
12086 {
12087 /* delete old redundant coefficient */
12088 SCIP_CALL( delCoefPos(scip, cons, candpos) );
12089 ++(*nchgcoefs);
12090 }
12091 else
12092 {
12093 /* replace old with new coefficient */
12094 SCIP_CALL( chgCoefPos(scip, cons, candpos, newcoef) );
12095 ++(*nchgcoefs);
12096 }
12097 }
12098 else if( vals[candpos] < 0 || !SCIPvarIsBinary(vars[candpos]) )
12099 {
12100 gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)(REALABS(vals[candpos]) + feastol));
12101 }
12102
12103 /* correct side and big coefficients */
12104 if( (!notchangable && hasrhs && ((!SCIPisFeasIntegral(scip, rhs) || SCIPcalcGreComDiv(gcd, (SCIP_Longint)(rhs + feastol)) < gcd) && (SCIPcalcGreComDiv(gcd, (SCIP_Longint)(REALABS(vals[candpos]) + feastol)) == gcd))) ||
12105 ( haslhs && (!SCIPisFeasIntegral(scip, lhs) || SCIPcalcGreComDiv(gcd, (SCIP_Longint)(lhs + feastol)) < gcd) && (SCIPcalcGreComDiv(gcd, (SCIP_Longint)(REALABS(vals[candpos]) + feastol)) == gcd)) )
12106 {
12107 if( haslhs )
12108 {
12109 newcoef = (SCIP_Real)((SCIP_Longint)(SCIPfeasCeil(scip, lhs/gcd) * gcd + feastol));
12110
12111 SCIP_CALL( chgLhs(scip, cons, newcoef) );
12112 ++(*nchgsides);
12113 }
12114 else
12115 {
12116 assert(hasrhs);
12117 newcoef = (SCIP_Real)((SCIP_Longint)(SCIPfeasFloor(scip, rhs/gcd) * gcd + feastol));
12118
12119 SCIP_CALL( chgRhs(scip, cons, newcoef) );
12120 ++(*nchgsides);
12121 }
12122
12123 /* correct coefficients up front */
12124 for( w = offsetv; w >= 0; --w )
12125 {
12126 assert(vals[w] > 0);
12127
12128 SCIP_CALL( chgCoefPos(scip, cons, w, newcoef) );
12129 }
12130 (*nchgcoefs) += (offsetv + 1);
12131 }
12132
12133 if( !notchangable )
12134 {
12135 /* normalize constraint */
12136 SCIP_CALL( normalizeCons(scip, cons, infeasible) );
12137 assert(vars == consdata->vars);
12138 assert(vals == consdata->vals);
12139
12140 if( *infeasible )
12141 return SCIP_OKAY;
12142
12143 /* get new constraint data */
12144 nvars = consdata->nvars;
12145 assert(nvars >= 2);
12146
12147 SCIPdebugPrintCons(scip, cons, NULL);
12148
12149 lhs = consdata->lhs;
12150 rhs = consdata->rhs;
12151 assert(!hasrhs || !SCIPisNegative(scip, rhs));
12152 assert(!haslhs || !SCIPisNegative(scip, lhs));
12153 }
12154 }
12155 }
12156 }
12157
12158 /* @todo we still can remove continuous variables if they are redundant due to the non-integrality argument */
12159 /* no continuous variables are left over */
12160 if( SCIPvarGetType(vars[nvars - 1]) == SCIP_VARTYPE_CONTINUOUS )
12161 return SCIP_OKAY;
12162
12163 onlybin = TRUE;
12164 allcoefintegral = TRUE;
12165 /* check if all variables are of binary type */
12166 for( v = nvars - 1; v >= 0; --v )
12167 {
12168 if( !SCIPvarIsBinary(vars[v]) )
12169 onlybin = FALSE;
12170 if( !SCIPisIntegral(scip, vals[v]) )
12171 allcoefintegral = FALSE;
12172 }
12173
12174 /* check if the non-integrality part of all integral variables is smaller than the non-inegrality part of the right
12175 * hand side or bigger than the left hand side respectively, so we can make all of them integral
12176 *
12177 * @todo there are some steps missing ....
12178 */
12179 if( (hasrhs && !SCIPisFeasIntegral(scip, rhs)) || (haslhs && !SCIPisFeasIntegral(scip, lhs)) )
12180 {
12181 SCIP_Real val;
12182 SCIP_Real newval;
12183 SCIP_Real frac = 0.0;
12184 SCIP_Bool found = FALSE;
12185
12186 if( hasrhs )
12187 {
12188 if( allcoefintegral )
12189 {
12190 /* replace old with new right hand side */
12191 SCIP_CALL( chgRhs(scip, cons, SCIPfloor(scip, rhs)) );
12192 ++(*nchgsides);
12193 }
12194 else
12195 {
12196 siderest = rhs - SCIPfloor(scip, rhs);
12197
12198 /* try to round down all non-integral coefficients */
12199 for( v = nvars - 1; v >= 0; --v )
12200 {
12201 val = vals[v];
12202
12203 /* add up all possible fractional parts */
12204 if( !SCIPisIntegral(scip, val) )
12205 {
12206 lb = SCIPvarGetLbGlobal(vars[v]);
12207 ub = SCIPvarGetUbGlobal(vars[v]);
12208
12209 /* at least one bound need to be at zero */
12210 if( !onlybin && !SCIPisFeasZero(scip, lb) && !SCIPisFeasZero(scip, ub) )
12211 return SCIP_OKAY;
12212
12213 /* swap bounds for 'standard' form */
12214 if( !SCIPisFeasZero(scip, lb) )
12215 {
12216 ub = lb;
12217 val *= -1;
12218 }
12219
12220 found = TRUE;
12221
12222 frac += (val - SCIPfloor(scip, val)) * ub;
12223
12224 /* if we exceed the fractional part of the right hand side, we cannot tighten the coefficients
12225 *
12226 * e.g. 1.1x1 + 1.1x2 + 1.4x3 + 1.02x4 <= 2.4, here we cannot floor all fractionals because
12227 * x3, x4 set to 1 would be infeasible but feasible after flooring
12228 */
12229 if( SCIPisGT(scip, frac, siderest) )
12230 return SCIP_OKAY;
12231 }
12232 }
12233 assert(v == -1);
12234
12235 SCIPdebugMsg(scip, "rounding all non-integral coefficients and the right hand side down\n");
12236
12237 /* round rhs and coefficients to integral values */
12238 if( found )
12239 {
12240 for( v = nvars - 1; v >= 0; --v )
12241 {
12242 val = vals[v];
12243
12244 /* add the whole fractional part */
12245 if( !SCIPisIntegral(scip, val) )
12246 {
12247 lb = SCIPvarGetLbGlobal(vars[v]);
12248
12249 if( SCIPisFeasZero(scip, lb) )
12250 newval = SCIPfloor(scip, val);
12251 else
12252 newval = SCIPceil(scip, val);
12253
12254 if( SCIPisZero(scip, newval) )
12255 {
12256 /* delete old redundant coefficient */
12257 SCIP_CALL( delCoefPos(scip, cons, v) );
12258 ++(*nchgcoefs);
12259 }
12260 else
12261 {
12262 /* replace old with new coefficient */
12263 SCIP_CALL( chgCoefPos(scip, cons, v, newval) );
12264 ++(*nchgcoefs);
12265 }
12266 }
12267 }
12268 }
12269
12270 /* replace old with new right hand side */
12271 SCIP_CALL( chgRhs(scip, cons, SCIPfloor(scip, rhs)) );
12272 ++(*nchgsides);
12273 }
12274 }
12275 else
12276 {
12277 if( allcoefintegral )
12278 {
12279 /* replace old with new left hand side */
12280 SCIP_CALL( chgLhs(scip, cons, SCIPceil(scip, lhs)) );
12281 ++(*nchgsides);
12282 }
12283 else
12284 {
12285 /* cannot floor left hand side to zero */
12286 if( SCIPisLT(scip, lhs, 1.0) )
12287 return SCIP_OKAY;
12288
12289 siderest = lhs - SCIPfloor(scip, lhs);
12290
12291 /* try to round down all non-integral coefficients */
12292 for( v = nvars - 1; v >= 0; --v )
12293 {
12294 val = vals[v];
12295
12296 /* add up all possible fractional parts */
12297 if( !SCIPisIntegral(scip, val) )
12298 {
12299 lb = SCIPvarGetLbGlobal(vars[v]);
12300 ub = SCIPvarGetUbGlobal(vars[v]);
12301
12302 /* at least one bound need to be at zero */
12303 if( !SCIPisFeasZero(scip, lb) && !SCIPisFeasZero(scip, ub) )
12304 return SCIP_OKAY;
12305
12306 /* swap bounds for 'standard' form */
12307 if( !SCIPisFeasZero(scip, lb) )
12308 {
12309 ub = lb;
12310 val *= -1;
12311 }
12312
12313 /* cannot floor to zero */
12314 if( SCIPisLT(scip, val, 1.0) )
12315 return SCIP_OKAY;
12316
12317 /* the fractional part on each variable need to exceed the fractional part on the left hand side */
12318 if( SCIPisLT(scip, val - SCIPfloor(scip, val), siderest) )
12319 return SCIP_OKAY;
12320
12321 found = TRUE;
12322
12323 frac += (val - SCIPfloor(scip, val)) * ub;
12324
12325 /* if we exceed the fractional part of the left hand side plus one by summing up all maximal
12326 * fractional parts of the variables, we cannot tighten the coefficients
12327 *
12328 * e.g. 4.3x1 + 1.3x2 + 1.3x3 + 1.6x4 >= 4.2, here we cannot floor all fractionals because
12329 * x2-x4 set to 1 would be feasible but not after flooring
12330 */
12331 if( SCIPisGE(scip, frac, 1 + siderest) )
12332 return SCIP_OKAY;
12333 }
12334 /* all coefficients need to be integral, otherwise we might do an invalid reduction */
12335 else
12336 return SCIP_OKAY;
12337 }
12338 assert(v == -1);
12339
12340 SCIPdebugMsg(scip, "rounding all non-integral coefficients and the left hand side down\n");
12341
12342 /* round lhs and coefficients to integral values */
12343 if( found )
12344 {
12345 for( v = nvars - 1; v >= 0; --v )
12346 {
12347 val = vals[v];
12348
12349 /* add the whole fractional part */
12350 if( !SCIPisIntegral(scip, val) )
12351 {
12352 lb = SCIPvarGetLbGlobal(vars[v]);
12353
12354 if( SCIPisFeasZero(scip, lb) )
12355 newval = SCIPfloor(scip, val);
12356 else
12357 newval = SCIPceil(scip, val);
12358
12359 if( SCIPisZero(scip, newval) )
12360 {
12361 /* delete old redundant coefficient */
12362 SCIP_CALL( delCoefPos(scip, cons, v) );
12363 ++(*nchgcoefs);
12364 }
12365 else
12366 {
12367 /* replace old with new coefficient */
12368 SCIP_CALL( chgCoefPos(scip, cons, v, newval) );
12369 ++(*nchgcoefs);
12370 }
12371 }
12372 }
12373 }
12374
12375 /* replace old with new left hand side */
12376 SCIP_CALL( chgLhs(scip, cons, SCIPfloor(scip, lhs)) );
12377 ++(*nchgsides);
12378 }
12379 }
12380
12381 /* normalize constraint */
12382 SCIP_CALL( normalizeCons(scip, cons, infeasible) );
12383 assert(vars == consdata->vars);
12384 assert(vals == consdata->vals);
12385
12386 if( *infeasible )
12387 return SCIP_OKAY;
12388
12389 rhs = consdata->rhs;
12390 lhs = consdata->lhs;
12391
12392 assert(!hasrhs || !SCIPisNegative(scip, rhs));
12393 assert(!haslhs || !SCIPisNegative(scip, lhs));
12394
12395 SCIPdebugPrintCons(scip, cons, NULL);
12396
12397 nvars = consdata->nvars;
12398 if( nvars < 2 )
12399 return SCIP_OKAY;
12400
12401 allcoefintegral = TRUE;
12402 #ifndef NDEBUG
12403 /* debug check if all coefficients are really integral */
12404 for( v = nvars - 1; v >= 0; --v )
12405 assert(SCIPisIntegral(scip, vals[v]));
12406 #endif
12407 }
12408
12409 /* @todo following can also work on non integral coefficients, need more investigation */
12410 /* only check constraints with integral coefficients on all integral variables */
12411 if( !allcoefintegral )
12412 return SCIP_OKAY;
12413
12414 /* we want to avoid numerical troubles, therefore we do not change non-integral sides */
12415 if( (hasrhs && !SCIPisIntegral(scip, rhs)) || (haslhs && !SCIPisIntegral(scip, lhs)) )
12416 return SCIP_OKAY;
12417
12418 /* maximal absolute value of coefficients in constraint is one, so we cannot tighten it further */
12419 if( SCIPisEQ(scip, REALABS(vals[0]), 1.0) )
12420 return SCIP_OKAY;
12421
12422 /* stop if the last coeffcients is one in absolute value and the variable is not binary */
12423 if( !SCIPvarIsBinary(vars[nvars - 1]) && SCIPisEQ(scip, REALABS(vals[nvars - 1]), 1.0) )
12424 return SCIP_OKAY;
12425
12426 assert(nvars >= 2);
12427
12428 /* start gcd procedure for all variables */
12429 do
12430 {
12431 SCIPdebug( oldnchgcoefs = *nchgcoefs; )
12432 SCIPdebug( oldnchgsides = *nchgsides; )
12433
12434 /* stop if we have two coeffcients which are one in absolute value */
12435 if( SCIPisEQ(scip, REALABS(vals[nvars - 1]), 1.0) && SCIPisEQ(scip, REALABS(vals[nvars - 2]), 1.0) )
12436 return SCIP_OKAY;
12437
12438 gcd = -1;
12439
12440 /* calculate greatest common divisor over all integer variables; note that the onlybin flag needs to be recomputed
12441 * because coefficients of non-binary variables might have changed to zero */
12442 if( !onlybin )
12443 {
12444 foundbin = -1;
12445 onlybin = TRUE;
12446
12447 for( v = nvars - 1; v >= 0; --v )
12448 {
12449 assert(!SCIPisZero(scip, vals[v]));
12450 assert(SCIPvarGetType(vars[v]) != SCIP_VARTYPE_CONTINUOUS);
12451
12452 if( SCIPvarIsBinary(vars[v]) )
12453 {
12454 if( foundbin == -1 )
12455 foundbin = v;
12456 continue;
12457 }
12458 else
12459 onlybin = FALSE;
12460
12461 absval = REALABS(vals[v]);
12462 /* arithmetic precision can lead to the absolute value only being integral up to feasibility tolerance,
12463 * even though the value itself is feasible up to epsilon, but since we add feastol later, this is enough
12464 */
12465 assert(SCIPisFeasIntegral(scip, absval));
12466
12467 if( gcd == -1 )
12468 {
12469 gcd = (SCIP_Longint)(absval + feastol);
12470 assert(gcd >= 1);
12471 }
12472 else
12473 {
12474 /* calculate greatest common divisor for all general variables */
12475 gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)(absval + feastol));
12476 }
12477 if( gcd == 1 )
12478 break;
12479 }
12480 }
12481 else
12482 foundbin = nvars - 1;
12483
12484 /* we need at least one binary variable and a gcd greater than 1 to try to perform further coefficient changes */
12485 if( gcd == 1 || foundbin == -1)
12486 return SCIP_OKAY;
12487
12488 assert((onlybin && gcd == -1) || (!onlybin && gcd > 1));
12489
12490 candpos = -1;
12491 candpos2 = -1;
12492
12493 /* calculate greatest common divisor over all integer and binary variables and determine the candidate where we might
12494 * change the coefficient
12495 */
12496 for( v = foundbin; v >= 0; --v )
12497 {
12498 if( onlybin || SCIPvarIsBinary(vars[v]) )
12499 {
12500 absval = REALABS(vals[v]);
12501 /* arithmetic precision can lead to the absolute value only being integral up to feasibility tolerance,
12502 * even though the value itself is feasible up to epsilon, but since we add feastol later, this is enough
12503 */
12504 assert(SCIPisFeasIntegral(scip, absval));
12505
12506 oldgcd = gcd;
12507
12508 if( gcd == -1 )
12509 {
12510 gcd = (SCIP_Longint)(REALABS(vals[v]) + feastol);
12511 assert(gcd >= 1);
12512 }
12513 else
12514 {
12515 /* calculate greatest common divisor for all general and binary variables */
12516 gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)(REALABS(vals[v]) + feastol));
12517 }
12518
12519 /* if the greatest commmon divisor has become 1, we might have found the possible coefficient to change or we
12520 * can terminate
12521 */
12522 if( gcd == 1 )
12523 {
12524 /* found candidate */
12525 if( candpos == -1 )
12526 {
12527 gcd = oldgcd;
12528 candpos = v;
12529
12530 /* if we have only binary variables and both first coefficients have a gcd of 1, both are candidates for
12531 * the coefficient change
12532 */
12533 if( onlybin && v == foundbin - 1 )
12534 candpos2 = foundbin;
12535 }
12536 /* two different binary variables lead to a gcd of one, so we cannot change a coefficient */
12537 else
12538 {
12539 if( onlybin && candpos == v + 1 && candpos2 == v + 2 )
12540 {
12541 assert(candpos2 == nvars - 1);
12542
12543 /* take new candidates */
12544 candpos = candpos2;
12545
12546 /* recalculate gcd from scratch */
12547 gcd = (SCIP_Longint)(REALABS(vals[v+1]) + feastol);
12548 assert(gcd >= 1);
12549
12550 /* calculate greatest common divisor for all general and binary variables */
12551 gcd = SCIPcalcGreComDiv(gcd, (SCIP_Longint)(REALABS(vals[v]) + feastol));
12552 if( gcd == 1 )
12553 return SCIP_OKAY;
12554 }
12555 else
12556 /* cannot determine a possible coefficient for reduction */
12557 return SCIP_OKAY;
12558 }
12559 }
12560 }
12561 }
12562 assert(gcd >= 2);
12563
12564 /* we should have found one coefficient, that led to a gcd of 1, otherwise we could normalize the constraint
12565 * further
12566 */
12567 assert(candpos >= 0 && candpos < nvars);
12568
12569 /* all variables and all coefficients are integral, so the side should be too */
12570 assert((hasrhs && SCIPisIntegral(scip, rhs)) || (haslhs && SCIPisIntegral(scip, lhs)));
12571
12572 /* check again, if we have a normalized inequality (not ranged) the one side should be positive,
12573 * @see normalizeCons()
12574 */
12575 assert(!hasrhs || !SCIPisNegative(scip, rhs));
12576 assert(!haslhs || !SCIPisNegative(scip, lhs));
12577
12578 /* determine the remainder of the side and the gcd */
12579 if( hasrhs )
12580 rest = ((SCIP_Longint)(rhs + feastol)) % gcd;
12581 else
12582 rest = ((SCIP_Longint)(lhs + feastol)) % gcd;
12583 assert(rest >= 0);
12584 assert(rest < gcd);
12585
12586 /* determine the remainder of the coefficient candidate and the gcd */
12587 if( vals[candpos] < 0 )
12588 {
12589 restcoef = ((SCIP_Longint)(vals[candpos] - feastol)) % gcd;
12590 assert(restcoef <= -1);
12591 restcoef += gcd;
12592 }
12593 else
12594 restcoef = ((SCIP_Longint)(vals[candpos] + feastol)) % gcd;
12595 assert(restcoef >= 1);
12596 assert(restcoef < gcd);
12597
12598 if( hasrhs )
12599 {
12600 if( rest > 0 )
12601 {
12602 /* replace old with new right hand side */
12603 SCIP_CALL( chgRhs(scip, cons, rhs - rest) );
12604 ++(*nchgsides);
12605 }
12606
12607 /* calculate new coefficient */
12608 if( restcoef > rest )
12609 newcoef = vals[candpos] - restcoef + gcd;
12610 else
12611 newcoef = vals[candpos] - restcoef;
12612 }
12613 else
12614 {
12615 if( rest > 0 )
12616 {
12617 /* replace old with new left hand side */
12618 SCIP_CALL( chgLhs(scip, cons, lhs - rest + gcd) );
12619 ++(*nchgsides);
12620 }
12621
12622 /* calculate new coefficient */
12623 if( rest == 0 || restcoef < rest )
12624 newcoef = vals[candpos] - restcoef;
12625 else
12626 newcoef = vals[candpos] - restcoef + gcd;
12627 }
12628 assert(SCIPisZero(scip, newcoef) || SCIPcalcGreComDiv(gcd, (SCIP_Longint)(REALABS(newcoef) + feastol)) == gcd);
12629
12630 SCIPdebugMsg(scip, "gcd = %" SCIP_LONGINT_FORMAT ", rest = %" SCIP_LONGINT_FORMAT ", restcoef = %" SCIP_LONGINT_FORMAT "; changing coef of variable <%s> to %g and %s by %" SCIP_LONGINT_FORMAT "\n", gcd, rest, restcoef, SCIPvarGetName(vars[candpos]), newcoef, hasrhs ? "reduced rhs" : "increased lhs", hasrhs ? rest : (rest > 0 ? gcd - rest : 0));
12631
12632 if( SCIPisZero(scip, newcoef) )
12633 {
12634 /* delete redundant coefficient */
12635 SCIP_CALL( delCoefPos(scip, cons, candpos) );
12636 }
12637 else
12638 {
12639 /* replace old with new coefficient */
12640 SCIP_CALL( chgCoefPos(scip, cons, candpos, newcoef) );
12641 }
12642 ++(*nchgcoefs);
12643
12644 /* now constraint can be normalized, might be directly done by dividing it by the gcd */
12645 SCIP_CALL( normalizeCons(scip, cons, infeasible) );
12646 assert(vars == consdata->vars);
12647 assert(vals == consdata->vals);
12648
12649 if( *infeasible )
12650 return SCIP_OKAY;
12651
12652 SCIPdebugPrintCons(scip, cons, NULL);
12653
12654 rhs = consdata->rhs;
12655 lhs = consdata->lhs;
12656 assert(!hasrhs || !SCIPisNegative(scip, rhs));
12657 assert(!haslhs || !SCIPisNegative(scip, lhs));
12658
12659 nvars = consdata->nvars;
12660
12661 SCIPdebugMsg(scip, "we did %d coefficient changes and %d side changes on constraint %s when applying one round of the gcd algorithm\n", *nchgcoefs - oldnchgcoefs, *nchgsides - oldnchgsides, SCIPconsGetName(cons));
12662 }
12663 while( nvars >= 2 );
12664
12665 return SCIP_OKAY;
12666 }
12667
12668
12669 /** tries to aggregate an (in)equality and an equality in order to decrease the number of variables in the (in)equality:
12670 * cons0 := a * cons0 + b * cons1,
12671 * where a = val1[v] and b = -val0[v] for common variable v which removes most variable weight;
12672 * for numerical stability, we will only accept integral a and b;
12673 * the variable weight is a weighted sum over all included variables, where each binary variable weighs BINWEIGHT,
12674 * each integer or implicit integer variable weighs INTWEIGHT and each continuous variable weighs CONTWEIGHT
12675 */
12676 static
aggregateConstraints(SCIP * scip,SCIP_CONS * cons0,SCIP_CONS * cons1,int * commonidx0,int * commonidx1,int * diffidx0minus1,int * diffidx1minus0,int nvarscommon,int commonidxweight,int diffidx0minus1weight,int diffidx1minus0weight,SCIP_Real maxaggrnormscale,int * nchgcoefs,SCIP_Bool * aggregated,SCIP_Bool * infeasible)12677 SCIP_RETCODE aggregateConstraints(
12678 SCIP* scip, /**< SCIP data structure */
12679 SCIP_CONS* cons0, /**< (in)equality to modify */
12680 SCIP_CONS* cons1, /**< equality to use for aggregation of cons0 */
12681 int* commonidx0, /**< array with indices of variables in cons0, that appear also in cons1 */
12682 int* commonidx1, /**< array with indices of variables in cons1, that appear also in cons0 */
12683 int* diffidx0minus1, /**< array with indices of variables in cons0, that don't appear in cons1 */
12684 int* diffidx1minus0, /**< array with indices of variables in cons1, that don't appear in cons0 */
12685 int nvarscommon, /**< number of variables, that appear in both constraints */
12686 int commonidxweight, /**< variable weight sum of common variables */
12687 int diffidx0minus1weight, /**< variable weight sum of variables in cons0, that don't appear in cons1 */
12688 int diffidx1minus0weight, /**< variable weight sum of variables in cons1, that don't appear in cons0 */
12689 SCIP_Real maxaggrnormscale, /**< maximal allowed relative gain in maximum norm for constraint aggregation */
12690 int* nchgcoefs, /**< pointer to count the number of changed coefficients */
12691 SCIP_Bool* aggregated, /**< pointer to store whether an aggregation was made */
12692 SCIP_Bool* infeasible /**< pointer to store whether infeasibility was detected */
12693 )
12694 {
12695 SCIP_CONSDATA* consdata0;
12696 SCIP_CONSDATA* consdata1;
12697 SCIP_Real a;
12698 SCIP_Real b;
12699 SCIP_Real aggrcoef;
12700 SCIP_Real scalarsum;
12701 SCIP_Real bestscalarsum;
12702 SCIP_Bool betterscalarsum;
12703 SCIP_Bool commonvarlindependent; /* indicates whether coefficient vector of common variables in linearly dependent */
12704 int varweight;
12705 int nvars;
12706 int bestvarweight;
12707 int bestnvars;
12708 int bestv;
12709 int v;
12710 int i;
12711
12712 assert(scip != NULL);
12713 assert(cons0 != NULL);
12714 assert(cons1 != NULL);
12715 assert(commonidx0 != NULL);
12716 assert(commonidx1 != NULL);
12717 assert(diffidx0minus1 != NULL);
12718 assert(diffidx1minus0 != NULL);
12719 assert(nvarscommon >= 1);
12720 assert(commonidxweight >= nvarscommon);
12721 assert(nchgcoefs != NULL);
12722 assert(aggregated != NULL);
12723
12724 assert(SCIPconsIsActive(cons0));
12725 assert(SCIPconsIsActive(cons1));
12726
12727 *infeasible = FALSE;
12728
12729 SCIPdebugMsg(scip, "try aggregation of <%s> and <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
12730
12731 /* cons0 is an (in)equality */
12732 consdata0 = SCIPconsGetData(cons0);
12733 assert(consdata0 != NULL);
12734 assert(consdata0->nvars >= 1);
12735 assert(SCIPisLE(scip, consdata0->lhs, consdata0->rhs));
12736 assert(diffidx0minus1weight >= consdata0->nvars - nvarscommon);
12737
12738 /* cons1 is an equality */
12739 consdata1 = SCIPconsGetData(cons1);
12740 assert(consdata1 != NULL);
12741 assert(consdata1->nvars >= 1);
12742 assert(SCIPisEQ(scip, consdata1->lhs, consdata1->rhs));
12743 assert(diffidx1minus0weight >= consdata1->nvars - nvarscommon);
12744
12745 *aggregated = FALSE;
12746
12747 /* search for the best common variable such that
12748 * val1[var] * consdata0 - val0[var] * consdata1
12749 * has least weighted number of variables
12750 */
12751 bestvarweight = commonidxweight + diffidx0minus1weight;
12752 bestnvars = consdata0->nvars;
12753 bestv = -1;
12754 bestscalarsum = 0.0;
12755 commonvarlindependent = TRUE;
12756 for( v = 0; v < nvarscommon; ++v )
12757 {
12758 assert(consdata0->vars[commonidx0[v]] == consdata1->vars[commonidx1[v]]);
12759 a = consdata1->vals[commonidx1[v]];
12760 b = -consdata0->vals[commonidx0[v]];
12761
12762 /* only try aggregation, if coefficients are integral (numerical stability) */
12763 if( SCIPisIntegral(scip, a) && SCIPisIntegral(scip, b) )
12764 {
12765 /* count the number of variables in the potential new constraint a * consdata0 + b * consdata1 */
12766 varweight = diffidx0minus1weight + diffidx1minus0weight;
12767 nvars = consdata0->nvars + consdata1->nvars - 2*nvarscommon;
12768 scalarsum = REALABS(a) + REALABS(b);
12769 betterscalarsum = (scalarsum < bestscalarsum);
12770 for( i = 0; i < nvarscommon
12771 && (varweight < bestvarweight || (varweight == bestvarweight && betterscalarsum)); ++i )
12772 {
12773 aggrcoef = a * consdata0->vals[commonidx0[i]] + b * consdata1->vals[commonidx1[i]];
12774 if( !SCIPisZero(scip, aggrcoef) )
12775 {
12776 varweight += getVarWeight(consdata0->vars[commonidx0[i]]);
12777 nvars++;
12778 }
12779 }
12780 if( varweight < bestvarweight || (varweight == bestvarweight && betterscalarsum) )
12781 {
12782 bestv = v;
12783 bestvarweight = varweight;
12784 bestnvars = nvars;
12785 bestscalarsum = scalarsum;
12786 }
12787 }
12788
12789 /* update commonvarlindependent flag, if still TRUE:
12790 * v's common coefficient in cons1 / v's common coefficient in cons0 should be constant, i.e., equal 0's common coefficient in cons1 / 0's common coefficient in cons0
12791 */
12792 if( commonvarlindependent && v > 0 )
12793 commonvarlindependent = SCIPisEQ(scip,
12794 consdata1->vals[commonidx1[v]] * consdata0->vals[commonidx0[0]],
12795 consdata1->vals[commonidx1[0]] * consdata0->vals[commonidx0[v]]);
12796 }
12797
12798 /* if better aggregation was found, create new constraint and delete old one */
12799 if( (bestv != -1 || commonvarlindependent) && SCIPconsGetNUpgradeLocks(cons0) == 0 )
12800 {
12801 SCIP_CONS* newcons;
12802 SCIP_CONSDATA* newconsdata;
12803 SCIP_VAR** newvars;
12804 SCIP_Real* newvals;
12805 SCIP_Real newlhs;
12806 SCIP_Real newrhs;
12807 int newnvars;
12808
12809 if( bestv != -1 )
12810 {
12811 /* choose multipliers such that the multiplier for the (in)equality cons0 is positive */
12812 if( consdata1->vals[commonidx1[bestv]] > 0.0 )
12813 {
12814 a = consdata1->vals[commonidx1[bestv]];
12815 b = -consdata0->vals[commonidx0[bestv]];
12816 }
12817 else
12818 {
12819 a = -consdata1->vals[commonidx1[bestv]];
12820 b = consdata0->vals[commonidx0[bestv]];
12821 }
12822 assert(SCIPisIntegral(scip, a));
12823 assert(SCIPisPositive(scip, a));
12824 assert(SCIPisIntegral(scip, b));
12825 assert(!SCIPisZero(scip, b));
12826 }
12827 else
12828 {
12829 assert(commonvarlindependent);
12830 if( consdata1->vals[commonidx1[0]] > 0.0 )
12831 {
12832 a = consdata1->vals[commonidx1[0]];
12833 b = -consdata0->vals[commonidx0[0]];
12834 }
12835 else
12836 {
12837 a = -consdata1->vals[commonidx1[0]];
12838 b = consdata0->vals[commonidx0[0]];
12839 }
12840 assert(SCIPisPositive(scip, a));
12841 assert(!SCIPisZero(scip, b));
12842
12843 /* if a/b is integral, then we can easily choose integer multipliers */
12844 if( SCIPisIntegral(scip, a/b) )
12845 {
12846 if( a/b > 0 )
12847 {
12848 a /= b;
12849 b = 1.0;
12850 }
12851 else
12852 {
12853 a /= -b;
12854 b = -1.0;
12855 }
12856 }
12857
12858 /* setup best* variables that were not setup above because we are in the commonvarlindependent case */
12859 SCIPdebug( bestvarweight = diffidx0minus1weight + diffidx1minus0weight; )
12860 bestnvars = consdata0->nvars + consdata1->nvars - 2*nvarscommon;
12861 }
12862
12863 SCIPdebugMsg(scip, "aggregate linear constraints <%s> := %.15g*<%s> + %.15g*<%s> -> nvars: %d -> %d, weight: %d -> %d\n",
12864 SCIPconsGetName(cons0), a, SCIPconsGetName(cons0), b, SCIPconsGetName(cons1),
12865 consdata0->nvars, bestnvars, commonidxweight + diffidx0minus1weight, bestvarweight);
12866 SCIPdebugPrintCons(scip, cons0, NULL);
12867 SCIPdebugPrintCons(scip, cons1, NULL);
12868
12869 /* get temporary memory for creating the new linear constraint */
12870 SCIP_CALL( SCIPallocBufferArray(scip, &newvars, bestnvars) );
12871 SCIP_CALL( SCIPallocBufferArray(scip, &newvals, bestnvars) );
12872
12873 /* calculate the common coefficients, if we have not recognized linear dependency */
12874 newnvars = 0;
12875 if( !commonvarlindependent )
12876 {
12877 for( i = 0; i < nvarscommon; ++i )
12878 {
12879 assert(0 <= commonidx0[i] && commonidx0[i] < consdata0->nvars);
12880 assert(0 <= commonidx1[i] && commonidx1[i] < consdata1->nvars);
12881
12882 aggrcoef = a * consdata0->vals[commonidx0[i]] + b * consdata1->vals[commonidx1[i]];
12883 if( !SCIPisZero(scip, aggrcoef) )
12884 {
12885 assert(newnvars < bestnvars);
12886 newvars[newnvars] = consdata0->vars[commonidx0[i]];
12887 newvals[newnvars] = aggrcoef;
12888 newnvars++;
12889 }
12890 }
12891 }
12892 else
12893 {
12894 /* if we recognized linear dependency of the common coefficients, then the aggregation coefficient should be 0.0 for every common variable */
12895 #ifndef NDEBUG
12896 for( i = 0; i < nvarscommon; ++i )
12897 {
12898 assert(0 <= commonidx0[i] && commonidx0[i] < consdata0->nvars);
12899 assert(0 <= commonidx1[i] && commonidx1[i] < consdata1->nvars);
12900
12901 aggrcoef = a * consdata0->vals[commonidx0[i]] + b * consdata1->vals[commonidx1[i]];
12902 assert(SCIPisZero(scip, aggrcoef));
12903 }
12904 #endif
12905 }
12906
12907 /* calculate the coefficients appearing in cons0 but not in cons1 */
12908 for( i = 0; i < consdata0->nvars - nvarscommon; ++i )
12909 {
12910 assert(0 <= diffidx0minus1[i] && diffidx0minus1[i] < consdata0->nvars);
12911
12912 aggrcoef = a * consdata0->vals[diffidx0minus1[i]];
12913 assert(!SCIPisZero(scip, aggrcoef));
12914 assert(newnvars < bestnvars);
12915 newvars[newnvars] = consdata0->vars[diffidx0minus1[i]];
12916 newvals[newnvars] = aggrcoef;
12917 newnvars++;
12918 }
12919
12920 /* calculate the coefficients appearing in cons1 but not in cons0 */
12921 for( i = 0; i < consdata1->nvars - nvarscommon; ++i )
12922 {
12923 assert(0 <= diffidx1minus0[i] && diffidx1minus0[i] < consdata1->nvars);
12924
12925 aggrcoef = b * consdata1->vals[diffidx1minus0[i]];
12926 assert(!SCIPisZero(scip, aggrcoef));
12927 assert(newnvars < bestnvars);
12928 newvars[newnvars] = consdata1->vars[diffidx1minus0[i]];
12929 newvals[newnvars] = aggrcoef;
12930 newnvars++;
12931 }
12932 assert(newnvars == bestnvars);
12933
12934 /* calculate the new left and right hand side of the (in)equality */
12935 assert(!SCIPisInfinity(scip, -consdata1->lhs));
12936 assert(!SCIPisInfinity(scip, consdata1->rhs));
12937 if( SCIPisInfinity(scip, -consdata0->lhs) )
12938 newlhs = -SCIPinfinity(scip);
12939 else
12940 newlhs = a * consdata0->lhs + b * consdata1->lhs;
12941 if( SCIPisInfinity(scip, consdata0->rhs) )
12942 newrhs = SCIPinfinity(scip);
12943 else
12944 newrhs = a * consdata0->rhs + b * consdata1->rhs;
12945
12946 /* create the new linear constraint */
12947 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, SCIPconsGetName(cons0), newnvars, newvars, newvals, newlhs, newrhs,
12948 SCIPconsIsInitial(cons0), SCIPconsIsSeparated(cons0), SCIPconsIsEnforced(cons0),
12949 SCIPconsIsChecked(cons0), SCIPconsIsPropagated(cons0),
12950 SCIPconsIsLocal(cons0), SCIPconsIsModifiable(cons0),
12951 SCIPconsIsDynamic(cons0), SCIPconsIsRemovable(cons0), SCIPconsIsStickingAtNode(cons0)) );
12952
12953 newconsdata = SCIPconsGetData(newcons);
12954 assert(newconsdata != NULL);
12955
12956 /* copy the upgraded flag from the old cons0 to the new constraint */
12957 newconsdata->upgraded = consdata0->upgraded;
12958
12959 /* normalize the new constraint */
12960 SCIP_CALL( normalizeCons(scip, newcons, infeasible) );
12961
12962 if( *infeasible )
12963 goto TERMINATE;
12964
12965 /* check, if we really want to use the new constraint instead of the old one:
12966 * use the new one, if the maximum norm doesn't grow too much
12967 */
12968 if( consdataGetMaxAbsval(SCIPconsGetData(newcons)) <= maxaggrnormscale * consdataGetMaxAbsval(consdata0) )
12969 {
12970 SCIPdebugMsg(scip, " -> aggregated to <%s>\n", SCIPconsGetName(newcons));
12971 SCIPdebugPrintCons(scip, newcons, NULL);
12972
12973 /* update the statistics: we changed all coefficients */
12974 if( !consdata0->upgraded )
12975 (*nchgcoefs) += consdata0->nvars + consdata1->nvars - nvarscommon;
12976 *aggregated = TRUE;
12977
12978 /* delete the old constraint, and add the new linear constraint to the problem */
12979 SCIP_CALL( SCIPdelCons(scip, cons0) );
12980 SCIP_CALL( SCIPaddCons(scip, newcons) );
12981 }
12982
12983 TERMINATE:
12984 /* release the new constraint */
12985 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
12986
12987 /* free temporary memory */
12988 SCIPfreeBufferArray(scip, &newvals);
12989 SCIPfreeBufferArray(scip, &newvars);
12990 }
12991
12992 return SCIP_OKAY;
12993 }
12994
12995 /** gets the key of the given element */
12996 static
SCIP_DECL_HASHGETKEY(hashGetKeyLinearcons)12997 SCIP_DECL_HASHGETKEY(hashGetKeyLinearcons)
12998 { /*lint --e{715}*/
12999 /* the key is the element itself */
13000 return elem;
13001 }
13002
13003 /** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables and the
13004 * coefficients are either equal or negated
13005 */
13006 static
SCIP_DECL_HASHKEYEQ(hashKeyEqLinearcons)13007 SCIP_DECL_HASHKEYEQ(hashKeyEqLinearcons)
13008 {
13009 SCIP* scip;
13010 SCIP_CONSDATA* consdata1;
13011 SCIP_CONSDATA* consdata2;
13012 SCIP_Real cons1scale;
13013 SCIP_Real cons2scale;
13014 int i;
13015
13016 assert(key1 != NULL);
13017 assert(key2 != NULL);
13018 consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
13019 consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
13020 assert(consdata1->indexsorted);
13021 assert(consdata2->indexsorted);
13022
13023 scip = (SCIP*)userptr;
13024 assert(scip != NULL);
13025
13026 /* if it is the same constraint we dont need to check anything */
13027 if( key1 == key2 )
13028 return TRUE;
13029
13030 /* checks trivial case */
13031 if( consdata1->nvars != consdata2->nvars )
13032 return FALSE;
13033
13034 /* tests if variables are equal */
13035 for( i = 0; i < consdata1->nvars; ++i )
13036 {
13037 if( consdata1->vars[i] != consdata2->vars[i] )
13038 {
13039 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
13040 SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
13041 return FALSE;
13042 }
13043 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
13044 }
13045
13046 /* compute scale before comparing coefficients of constraints */
13047 cons1scale = COPYSIGN(1.0/consdata1->maxabsval, consdata1->vals[0]);
13048 cons2scale = COPYSIGN(1.0/consdata2->maxabsval, consdata2->vals[0]);
13049
13050 /* tests if coefficients are equal with the computed scale */
13051 for( i = 0; i < consdata1->nvars; ++i )
13052 {
13053 SCIP_Real val1;
13054 SCIP_Real val2;
13055
13056 val1 = consdata1->vals[i] * cons1scale;
13057 val2 = consdata2->vals[i] * cons2scale;
13058
13059 if( !SCIPisEQ(scip, val1, val2) )
13060 return FALSE;
13061 }
13062
13063 return TRUE;
13064 }
13065
13066 /** returns the hash value of the key */
13067 static
SCIP_DECL_HASHKEYVAL(hashKeyValLinearcons)13068 SCIP_DECL_HASHKEYVAL(hashKeyValLinearcons)
13069 {
13070 SCIP_CONSDATA* consdata;
13071 int minidx;
13072 int mididx;
13073 int maxidx;
13074 SCIP_Real scale;
13075 #ifndef NDEBUG
13076 SCIP* scip;
13077
13078 scip = (SCIP*)userptr;
13079 assert(scip != NULL);
13080 #endif
13081
13082 assert(key != NULL);
13083 consdata = SCIPconsGetData((SCIP_CONS*)key);
13084 assert(consdata != NULL);
13085 assert(consdata->nvars > 0);
13086
13087 assert(consdata->indexsorted);
13088
13089 minidx = SCIPvarGetIndex(consdata->vars[0]);
13090 mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
13091 maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
13092 scale = COPYSIGN(1.0/consdata->maxabsval, consdata->vals[0]);
13093
13094 /* using only the variable indices as hash, since the values are compared by epsilon */
13095 return SCIPhashSeven(consdata->nvars, minidx, SCIPrealHashCode(consdata->vals[0] * scale),
13096 mididx, SCIPrealHashCode(consdata->vals[consdata->nvars / 2] * scale),
13097 maxidx, SCIPrealHashCode(consdata->vals[consdata->nvars - 1] * scale));
13098 }
13099
13100 /** returns the key for deciding which of two parallel constraints should be kept (smaller key should be kept);
13101 * prefers non-upgraded constraints and as second criterion the constraint with the smallest position
13102 */
13103 static
getParallelConsKey(SCIP_CONS * cons)13104 unsigned int getParallelConsKey(
13105 SCIP_CONS* cons /**< linear constraint */
13106 )
13107 {
13108 SCIP_CONSDATA* consdata;
13109
13110 assert(cons != NULL);
13111
13112 consdata = SCIPconsGetData(cons);
13113 assert(consdata != NULL);
13114
13115 return (((unsigned int)consdata->upgraded)<<31) + (unsigned int)SCIPconsGetPos(cons); /*lint !e571*/
13116 }
13117
13118 /** updates the hashtable such that out of all constraints in the hashtable that are detected
13119 * to be parallel to *querycons, only one is kept in the hashtable and stored into *querycons,
13120 * and all others are removed from the hashtable and stored in the given array
13121 */
13122 static
retrieveParallelConstraints(SCIP_HASHTABLE * hashtable,SCIP_CONS ** querycons,SCIP_CONS ** parallelconss,int * nparallelconss)13123 SCIP_RETCODE retrieveParallelConstraints(
13124 SCIP_HASHTABLE* hashtable, /**< hashtable containing linear constraints */
13125 SCIP_CONS** querycons, /**< pointer to linear constraint used to look for duplicates in the hash table;
13126 * upon return will contain the constraint that should be kept */
13127 SCIP_CONS** parallelconss, /**< array to return constraints that are parallel to the given;
13128 * these constraints where removed from the hashtable */
13129 int* nparallelconss /**< pointer to return number of parallel constraints */
13130 )
13131 {
13132 SCIP_CONS* parallelcons;
13133 unsigned int querykey;
13134
13135 *nparallelconss = 0;
13136 querykey = getParallelConsKey(*querycons);
13137
13138 while( (parallelcons = (SCIP_CONS*)SCIPhashtableRetrieve(hashtable, (void*)(*querycons))) != NULL )
13139 {
13140 unsigned int conskey = getParallelConsKey(parallelcons);
13141
13142 if( conskey < querykey )
13143 {
13144 parallelconss[(*nparallelconss)++] = *querycons;
13145 *querycons = parallelcons;
13146 querykey = conskey;
13147 }
13148 else
13149 {
13150 parallelconss[(*nparallelconss)++] = parallelcons;
13151 }
13152
13153 /* if the constraint that just came out of the hash table is the one that is kept,
13154 * we do not need to look into the hashtable again, since the invariant is that
13155 * in the hashtable only pair-wise non-parallel constraints are contained.
13156 * For the original querycons, however, multiple constraints that compare equal (=parallel)
13157 * could be contained due to non-transitivity of the equality comparison.
13158 * Also we can return immediately, since parallelcons is already contained in the
13159 * hashtable and we do not need to remove and reinsert it.
13160 */
13161 if( *querycons == parallelcons )
13162 return SCIP_OKAY;
13163
13164 /* remove parallelcons from the hashtable, since it will be replaced by querycons */
13165 SCIP_CALL( SCIPhashtableRemove(hashtable, (void*) parallelcons) );
13166 }
13167
13168 /* in debug mode we make sure, that the hashtable cannot contain a constraint that
13169 * comnpares equal to querycons at this point
13170 */
13171 #ifndef NDEBUG
13172 SCIP_CALL_ABORT( SCIPhashtableSafeInsert(hashtable, *querycons) );
13173 #else
13174 SCIP_CALL( SCIPhashtableInsert(hashtable, *querycons) );
13175 #endif
13176
13177 return SCIP_OKAY;
13178 }
13179
13180 /** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
13181 * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
13182 */
13183 static
detectRedundantConstraints(SCIP * scip,BMS_BLKMEM * blkmem,SCIP_CONS ** conss,int nconss,int * firstchange,SCIP_Bool * cutoff,int * ndelconss,int * nchgsides)13184 SCIP_RETCODE detectRedundantConstraints(
13185 SCIP* scip, /**< SCIP data structure */
13186 BMS_BLKMEM* blkmem, /**< block memory */
13187 SCIP_CONS** conss, /**< constraint set */
13188 int nconss, /**< number of constraints in constraint set */
13189 int* firstchange, /**< pointer to store first changed constraint */
13190 SCIP_Bool* cutoff, /**< pointer to store TRUE, if a cutoff was found */
13191 int* ndelconss, /**< pointer to count number of deleted constraints */
13192 int* nchgsides /**< pointer to count number of changed left/right hand sides */
13193 )
13194 {
13195 SCIP_HASHTABLE* hashtable;
13196 SCIP_CONS** parallelconss;
13197 int nparallelconss;
13198 int hashtablesize;
13199 int c;
13200
13201 assert(scip != NULL);
13202 assert(blkmem != NULL);
13203 assert(conss != NULL);
13204 assert(firstchange != NULL);
13205 assert(cutoff != NULL);
13206 assert(ndelconss != NULL);
13207 assert(nchgsides != NULL);
13208
13209 /* create a hash table for the constraint set */
13210 hashtablesize = nconss;
13211 SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
13212 hashGetKeyLinearcons, hashKeyEqLinearcons, hashKeyValLinearcons, (void*) scip) );
13213
13214 SCIP_CALL( SCIPallocBufferArray(scip, ¶llelconss, nconss) );
13215
13216 /* check all constraints in the given set for redundancy */
13217 for( c = 0; c < nconss; ++c )
13218 {
13219 SCIP_CONS* cons0;
13220 SCIP_CONSDATA* consdata0;
13221
13222 cons0 = conss[c];
13223
13224 if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
13225 continue;
13226
13227 /* check for interuption */
13228 if( c % 1000 == 0 && SCIPisStopped(scip) )
13229 break;
13230
13231 /* sorts the constraint */
13232 consdata0 = SCIPconsGetData(cons0);
13233 assert(consdata0 != NULL);
13234 SCIP_CALL( consdataSort(scip, consdata0) );
13235 assert(consdata0->indexsorted);
13236
13237 /* get constraints from current hash table with same variables as cons0 and with coefficients equal
13238 * to the ones of cons0 when both are scaled such that maxabsval is 1.0 and the coefficient of the
13239 * first variable is positive
13240 * Also inserts cons0 into the hashtable.
13241 */
13242 SCIP_CALL( retrieveParallelConstraints(hashtable, &cons0, parallelconss, &nparallelconss) );
13243
13244 if( nparallelconss != 0 )
13245 {
13246 SCIP_Real lhs;
13247 SCIP_Real rhs;
13248
13249 int i;
13250
13251 /* cons0 may have been changed in retrieveParallelConstraints() */
13252 consdata0 = SCIPconsGetData(cons0);
13253
13254 lhs = consdata0->lhs;
13255 rhs = consdata0->rhs;
13256
13257 for( i = 0; i < nparallelconss; ++i )
13258 {
13259 SCIP_CONS* consdel;
13260 SCIP_CONSDATA* consdatadel;
13261 SCIP_Real scale;
13262
13263 consdel = parallelconss[i];
13264 consdatadel = SCIPconsGetData(consdel);
13265
13266 assert(SCIPconsIsActive(consdel));
13267 assert(!SCIPconsIsModifiable(consdel));
13268
13269 /* constraint found: create a new constraint with same coefficients and best left and right hand side;
13270 * delete old constraints afterwards
13271 */
13272 assert(consdatadel != NULL);
13273 assert(consdata0->nvars >= 1 && consdata0->nvars == consdatadel->nvars);
13274
13275 assert(consdatadel->indexsorted);
13276 assert(consdata0->vars[0] == consdatadel->vars[0]);
13277
13278 scale = consdata0->vals[0] / consdatadel->vals[0];
13279 assert(scale != 0.0);
13280
13281 /* in debug mode, check that all coefficients are equal with respect to epsilon
13282 * if the constraints are in equilibrium scale
13283 */
13284 #ifndef NDEBUG
13285 {
13286 int k;
13287 SCIP_Real scale0 = 1.0 / consdata0->maxabsval;
13288 SCIP_Real scaledel = COPYSIGN(1.0 / consdatadel->maxabsval, scale);
13289
13290 for( k = 0; k < consdata0->nvars; ++k )
13291 {
13292 assert(SCIPisEQ(scip, scale0 * consdata0->vals[k], scaledel * consdatadel->vals[k]));
13293 }
13294 }
13295 #endif
13296
13297 if( scale > 0.0 )
13298 {
13299 /* the coefficients of both constraints are parallel with a positive scale */
13300 SCIPdebugMsg(scip, "aggregate linear constraints <%s> and <%s> with equal coefficients into single ranged row\n",
13301 SCIPconsGetName(cons0), SCIPconsGetName(consdel));
13302 SCIPdebugPrintCons(scip, cons0, NULL);
13303 SCIPdebugPrintCons(scip, consdel, NULL);
13304
13305 if( ! SCIPisInfinity(scip, -consdatadel->lhs) )
13306 lhs = MAX(scale * consdatadel->lhs, lhs);
13307
13308 if( ! SCIPisInfinity(scip, consdatadel->rhs) )
13309 rhs = MIN(scale * consdatadel->rhs, rhs);
13310 }
13311 else
13312 {
13313 /* the coefficients of both rows are negations */
13314 SCIPdebugMsg(scip, "aggregate linear constraints <%s> and <%s> with negated coefficients into single ranged row\n",
13315 SCIPconsGetName(cons0), SCIPconsGetName(consdel));
13316 SCIPdebugPrintCons(scip, cons0, NULL);
13317 SCIPdebugPrintCons(scip, consdel, NULL);
13318
13319 if( ! SCIPisInfinity(scip, consdatadel->rhs) )
13320 lhs = MAX(scale * consdatadel->rhs, lhs);
13321
13322 if( ! SCIPisInfinity(scip, -consdatadel->lhs) )
13323 rhs = MIN(scale * consdatadel->lhs, rhs);
13324 }
13325
13326 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
13327 SCIP_CALL( SCIPupdateConsFlags(scip, cons0, consdel) );
13328
13329 /* delete consdel */
13330 assert( ! consdata0->upgraded || consdatadel->upgraded );
13331 SCIP_CALL( SCIPdelCons(scip, consdel) );
13332 if( !consdatadel->upgraded )
13333 (*ndelconss)++;
13334 }
13335
13336 if( SCIPisFeasLT(scip, rhs, lhs) )
13337 {
13338 SCIPdebugMsg(scip, "aggregated linear constraint <%s> is infeasible\n", SCIPconsGetName(cons0));
13339 *cutoff = TRUE;
13340 break;
13341 }
13342
13343 /* ensure that lhs <= rhs holds without tolerances as we only allow such rows to enter the LP */
13344 if( lhs > rhs )
13345 {
13346 rhs = (lhs + rhs)/2;
13347 lhs = rhs;
13348 }
13349
13350 /* update lhs and rhs of cons0 */
13351 SCIP_CALL( chgLhs(scip, cons0, lhs) );
13352 SCIP_CALL( chgRhs(scip, cons0, rhs) );
13353
13354 /* update the first changed constraint to begin the next aggregation round with */
13355 if( consdata0->changed && SCIPconsGetPos(cons0) < *firstchange )
13356 *firstchange = SCIPconsGetPos(cons0);
13357
13358 assert(SCIPconsIsActive(cons0));
13359 }
13360 }
13361 #ifdef SCIP_MORE_DEBUG
13362 SCIPinfoMessage(scip, NULL, "linear pairwise comparison hashtable statistics:\n");
13363 SCIPhashtablePrintStatistics(hashtable, SCIPgetMessagehdlr(scip));
13364 #endif
13365
13366 SCIPfreeBufferArray(scip, ¶llelconss);
13367
13368 /* free hash table */
13369 SCIPhashtableFree(&hashtable);
13370
13371 return SCIP_OKAY;
13372 }
13373
13374 /** compares constraint with all prior constraints for possible redundancy or aggregation,
13375 * and removes or changes constraint accordingly
13376 */
13377 static
preprocessConstraintPairs(SCIP * scip,SCIP_CONS ** conss,int firstchange,int chkind,SCIP_Real maxaggrnormscale,SCIP_Bool * cutoff,int * ndelconss,int * nchgsides,int * nchgcoefs)13378 SCIP_RETCODE preprocessConstraintPairs(
13379 SCIP* scip, /**< SCIP data structure */
13380 SCIP_CONS** conss, /**< constraint set */
13381 int firstchange, /**< first constraint that changed since last pair preprocessing round */
13382 int chkind, /**< index of constraint to check against all prior indices upto startind */
13383 SCIP_Real maxaggrnormscale, /**< maximal allowed relative gain in maximum norm for constraint aggregation */
13384 SCIP_Bool* cutoff, /**< pointer to store TRUE, if a cutoff was found */
13385 int* ndelconss, /**< pointer to count number of deleted constraints */
13386 int* nchgsides, /**< pointer to count number of changed left/right hand sides */
13387 int* nchgcoefs /**< pointer to count number of changed coefficients */
13388 )
13389 {
13390 SCIP_CONS* cons0;
13391 SCIP_CONSDATA* consdata0;
13392 int* commonidx0;
13393 int* commonidx1;
13394 int* diffidx0minus1;
13395 int* diffidx1minus0;
13396 uint64_t possignature0;
13397 uint64_t negsignature0;
13398 SCIP_Bool cons0changed;
13399 SCIP_Bool cons0isequality;
13400 int diffidx1minus0size;
13401 int c;
13402 SCIP_Real cons0lhs;
13403 SCIP_Real cons0rhs;
13404 SCIP_Bool cons0upgraded;
13405
13406 assert(scip != NULL);
13407 assert(conss != NULL);
13408 assert(firstchange <= chkind);
13409 assert(cutoff != NULL);
13410 assert(ndelconss != NULL);
13411 assert(nchgsides != NULL);
13412 assert(nchgcoefs != NULL);
13413
13414 /* get the constraint to be checked against all prior constraints */
13415 cons0 = conss[chkind];
13416 assert(cons0 != NULL);
13417 assert(SCIPconsIsActive(cons0));
13418 assert(!SCIPconsIsModifiable(cons0));
13419
13420 consdata0 = SCIPconsGetData(cons0);
13421 assert(consdata0 != NULL);
13422 assert(consdata0->nvars >= 1);
13423 cons0isequality = SCIPisEQ(scip, consdata0->lhs, consdata0->rhs);
13424
13425 /* sort the constraint */
13426 SCIP_CALL( consdataSort(scip, consdata0) );
13427
13428 /* calculate bit signatures of cons0 for potentially positive and negative coefficients */
13429 consdataCalcSignatures(consdata0);
13430 possignature0 = consdata0->possignature;
13431 negsignature0 = consdata0->negsignature;
13432
13433 /* get temporary memory for indices of common variables */
13434 SCIP_CALL( SCIPallocBufferArray(scip, &commonidx0, consdata0->nvars) );
13435 SCIP_CALL( SCIPallocBufferArray(scip, &commonidx1, consdata0->nvars) );
13436 SCIP_CALL( SCIPallocBufferArray(scip, &diffidx0minus1, consdata0->nvars) );
13437 SCIP_CALL( SCIPallocBufferArray(scip, &diffidx1minus0, consdata0->nvars) );
13438 diffidx1minus0size = consdata0->nvars;
13439
13440 cons0lhs = consdata0->lhs;
13441 cons0rhs = consdata0->rhs;
13442 cons0upgraded = consdata0->upgraded;
13443
13444 /* check constraint against all prior constraints */
13445 cons0changed = consdata0->changed;
13446 consdata0->changed = FALSE;
13447 for( c = (cons0changed ? 0 : firstchange); c < chkind && !(*cutoff) && conss[chkind] != NULL; ++c )
13448 {
13449 SCIP_CONS* cons1;
13450 SCIP_CONSDATA* consdata1;
13451 uint64_t possignature1;
13452 uint64_t negsignature1;
13453 SCIP_Bool cons0dominateslhs;
13454 SCIP_Bool cons1dominateslhs;
13455 SCIP_Bool cons0dominatesrhs;
13456 SCIP_Bool cons1dominatesrhs;
13457 SCIP_Bool cons1isequality;
13458 SCIP_Bool coefsequal;
13459 SCIP_Bool coefsnegated;
13460 SCIP_Bool tryaggregation;
13461 int nvarscommon;
13462 int nvars0minus1;
13463 int nvars1minus0;
13464 int commonidxweight;
13465 int diffidx0minus1weight;
13466 int diffidx1minus0weight;
13467 int v0;
13468 int v1;
13469
13470 assert(cons0lhs == consdata0->lhs); /*lint !e777*/
13471 assert(cons0rhs == consdata0->rhs); /*lint !e777*/
13472 assert(cons0upgraded == consdata0->upgraded);
13473
13474 cons1 = conss[c];
13475
13476 /* cons1 has become inactive during presolving of constraint pairs */
13477 if( cons1 == NULL )
13478 continue;
13479
13480 assert(SCIPconsIsActive(cons0) && !SCIPconsIsModifiable(cons0));
13481 assert(SCIPconsIsActive(cons1) && !SCIPconsIsModifiable(cons1));
13482
13483 consdata1 = SCIPconsGetData(cons1);
13484 assert(consdata1 != NULL);
13485
13486 /* SCIPdebugMsg(scip, "preprocess linear constraint pair <%s>[chgd:%d, upgd:%d] and <%s>[chgd:%d, upgd:%d]\n",
13487 SCIPconsGetName(cons0), cons0changed, cons0upgraded,
13488 SCIPconsGetName(cons1), consdata1->changed, consdata1->upgraded); */
13489
13490 /* if both constraints didn't change since last pair processing, we can ignore the pair */
13491 if( !cons0changed && !consdata1->changed )
13492 continue;
13493
13494 /* if both constraints are already upgraded, skip the pair;
13495 * because changes on these constraints cannot be applied to the instance anymore */
13496 if( cons0upgraded && consdata1->upgraded )
13497 continue;
13498
13499 assert(consdata1->nvars >= 1);
13500
13501 /* sort the constraint */
13502 SCIP_CALL( consdataSort(scip, consdata1) );
13503
13504 /* calculate bit signatures of cons1 for potentially positive and negative coefficients */
13505 consdataCalcSignatures(consdata1);
13506 possignature1 = consdata1->possignature;
13507 negsignature1 = consdata1->negsignature;
13508
13509 /* the signatures give a quick test to check for domination and equality of coefficients */
13510 coefsequal = (possignature0 == possignature1) && (negsignature0 == negsignature1);
13511 coefsnegated = (possignature0 == negsignature1) && (negsignature0 == possignature1);
13512 cons0dominateslhs = SCIPisGE(scip, cons0lhs, consdata1->lhs)
13513 && ((possignature0 | possignature1) == possignature1) /* possignature0 <= possignature1 (as bit vector) */
13514 && ((negsignature0 | negsignature1) == negsignature0); /* negsignature0 >= negsignature1 (as bit vector) */
13515 cons1dominateslhs = SCIPisGE(scip, consdata1->lhs, cons0lhs)
13516 && ((possignature0 | possignature1) == possignature0) /* possignature0 >= possignature1 (as bit vector) */
13517 && ((negsignature0 | negsignature1) == negsignature1); /* negsignature0 <= negsignature1 (as bit vector) */
13518 cons0dominatesrhs = SCIPisLE(scip, cons0rhs, consdata1->rhs)
13519 && ((possignature0 | possignature1) == possignature0) /* possignature0 >= possignature1 (as bit vector) */
13520 && ((negsignature0 | negsignature1) == negsignature1); /* negsignature0 <= negsignature1 (as bit vector) */
13521 cons1dominatesrhs = SCIPisLE(scip, consdata1->rhs, cons0rhs)
13522 && ((possignature0 | possignature1) == possignature1) /* possignature0 <= possignature1 (as bit vector) */
13523 && ((negsignature0 | negsignature1) == negsignature0); /* negsignature0 >= negsignature1 (as bit vector) */
13524 cons1isequality = SCIPisEQ(scip, consdata1->lhs, consdata1->rhs);
13525 tryaggregation = (cons0isequality || cons1isequality) && (maxaggrnormscale > 0.0);
13526 if( !cons0dominateslhs && !cons1dominateslhs && !cons0dominatesrhs && !cons1dominatesrhs
13527 && !coefsequal && !coefsnegated && !tryaggregation )
13528 continue;
13529
13530 /* make sure, we have enough memory for the index set of V_1 \ V_0 */
13531 if( tryaggregation && consdata1->nvars > diffidx1minus0size )
13532 {
13533 SCIP_CALL( SCIPreallocBufferArray(scip, &diffidx1minus0, consdata1->nvars) );
13534 diffidx1minus0size = consdata1->nvars;
13535 }
13536
13537 /* check consdata0 against consdata1:
13538 * - if lhs0 >= lhs1 and for each variable v and each solution value x_v val0[v]*x_v <= val1[v]*x_v,
13539 * consdata0 dominates consdata1 w.r.t. left hand side
13540 * - if rhs0 <= rhs1 and for each variable v and each solution value x_v val0[v]*x_v >= val1[v]*x_v,
13541 * consdata0 dominates consdata1 w.r.t. right hand side
13542 * - if val0[v] == -val1[v] for all variables v, the two inequalities can be replaced by a single
13543 * ranged row (or equality)
13544 * - if at least one constraint is an equality, count the weighted number of common variables W_c
13545 * and the weighted number of variable in the difference sets W_0 = w(V_0 \ V_1), W_1 = w(V_1 \ V_0),
13546 * where the weight of each variable depends on its type, such that aggregations in order to remove the
13547 * number of continuous and integer variables are preferred:
13548 * - if W_c > W_1, try to aggregate consdata0 := a * consdata0 + b * consdata1 in order to decrease the
13549 * variable weight in consdata0, where a = +/- val1[v] and b = -/+ val0[v] for common v which leads to
13550 * the smallest weight; for numerical stability, we will only accept integral a and b; the sign of a has
13551 * to be positive to not switch the sense of the (in)equality cons0
13552 * - if W_c > W_0, try to aggregate consdata1 := a * consdata1 + b * consdata0 in order to decrease the
13553 * variable weight in consdata1, where a = +/- val0[v] and b = -/+ val1[v] for common v which leads to
13554 * the smallest weight; for numerical stability, we will only accept integral a and b; the sign of a has
13555 * to be positive to not switch the sense of the (in)equality cons1
13556 */
13557
13558 /* check consdata0 against consdata1 for redundancy, or ranged row accumulation */
13559 nvarscommon = 0;
13560 commonidxweight = 0;
13561 nvars0minus1 = 0;
13562 diffidx0minus1weight = 0;
13563 nvars1minus0 = 0;
13564 diffidx1minus0weight = 0;
13565 v0 = 0;
13566 v1 = 0;
13567 while( (v0 < consdata0->nvars || v1 < consdata1->nvars)
13568 && (cons0dominateslhs || cons1dominateslhs || cons0dominatesrhs || cons1dominatesrhs
13569 || coefsequal || coefsnegated || tryaggregation) )
13570 {
13571 SCIP_VAR* var;
13572 SCIP_Real val0;
13573 SCIP_Real val1;
13574 int varcmp;
13575
13576 /* test, if variable appears in only one or in both constraints */
13577 if( v0 < consdata0->nvars && v1 < consdata1->nvars )
13578 varcmp = SCIPvarCompare(consdata0->vars[v0], consdata1->vars[v1]);
13579 else if( v0 < consdata0->nvars )
13580 varcmp = -1;
13581 else
13582 varcmp = +1;
13583
13584 switch( varcmp )
13585 {
13586 case -1:
13587 /* variable doesn't appear in consdata1 */
13588 var = consdata0->vars[v0];
13589 val0 = consdata0->vals[v0];
13590 val1 = 0.0;
13591 if( tryaggregation )
13592 {
13593 diffidx0minus1[nvars0minus1] = v0;
13594 nvars0minus1++;
13595 diffidx0minus1weight += getVarWeight(var);
13596 }
13597 v0++;
13598 coefsequal = FALSE;
13599 coefsnegated = FALSE;
13600 break;
13601
13602 case +1:
13603 /* variable doesn't appear in consdata0 */
13604 var = consdata1->vars[v1];
13605 val0 = 0.0;
13606 val1 = consdata1->vals[v1];
13607 if( tryaggregation )
13608 {
13609 diffidx1minus0[nvars1minus0] = v1;
13610 nvars1minus0++;
13611 diffidx1minus0weight += getVarWeight(var);
13612 }
13613 v1++;
13614 coefsequal = FALSE;
13615 coefsnegated = FALSE;
13616 break;
13617
13618 case 0:
13619 /* variable appears in both constraints */
13620 assert(consdata0->vars[v0] == consdata1->vars[v1]);
13621 var = consdata0->vars[v0];
13622 val0 = consdata0->vals[v0];
13623 val1 = consdata1->vals[v1];
13624 if( tryaggregation )
13625 {
13626 commonidx0[nvarscommon] = v0;
13627 commonidx1[nvarscommon] = v1;
13628 nvarscommon++;
13629 commonidxweight += getVarWeight(var);
13630 }
13631 v0++;
13632 v1++;
13633 coefsequal = coefsequal && (SCIPisEQ(scip, val0, val1));
13634 coefsnegated = coefsnegated && (SCIPisEQ(scip, val0, -val1));
13635 break;
13636
13637 default:
13638 SCIPerrorMessage("invalid comparison result\n");
13639 SCIPABORT();
13640 var = NULL;
13641 val0 = 0.0;
13642 val1 = 0.0;
13643 }
13644 assert(var != NULL);
13645
13646 /* update domination criteria w.r.t. the coefficient and the variable's bounds */
13647 if( SCIPisGT(scip, val0, val1) )
13648 {
13649 if( SCIPisNegative(scip, SCIPvarGetLbGlobal(var)) )
13650 {
13651 cons0dominatesrhs = FALSE;
13652 cons1dominateslhs = FALSE;
13653 }
13654 if( SCIPisPositive(scip, SCIPvarGetUbGlobal(var)) )
13655 {
13656 cons0dominateslhs = FALSE;
13657 cons1dominatesrhs = FALSE;
13658 }
13659 }
13660 else if( SCIPisLT(scip, val0, val1) )
13661 {
13662 if( SCIPisNegative(scip, SCIPvarGetLbGlobal(var)) )
13663 {
13664 cons0dominateslhs = FALSE;
13665 cons1dominatesrhs = FALSE;
13666 }
13667 if( SCIPisPositive(scip, SCIPvarGetUbGlobal(var)) )
13668 {
13669 cons0dominatesrhs = FALSE;
13670 cons1dominateslhs = FALSE;
13671 }
13672 }
13673 }
13674
13675 /* check for disaggregated ranged rows */
13676 if( coefsequal || coefsnegated )
13677 {
13678 SCIP_CONS* consstay;
13679 SCIP_CONS* consdel;
13680 #ifndef NDEBUG
13681 SCIP_CONSDATA* consdatastay;
13682 #endif
13683 SCIP_CONSDATA* consdatadel;
13684 SCIP_Real lhs;
13685 SCIP_Real rhs;
13686 int consinddel;
13687
13688 /* the coefficients in both rows are either equal or negated: create a new constraint with same coefficients and
13689 * best left and right hand sides; delete the old constraints afterwards
13690 */
13691 SCIPdebugMsg(scip, "aggregate linear constraints <%s> and <%s> with %s coefficients into single ranged row\n",
13692 SCIPconsGetName(cons0), SCIPconsGetName(cons1), coefsequal ? "equal" : "negated");
13693 SCIPdebugPrintCons(scip, cons0, NULL);
13694 SCIPdebugPrintCons(scip, cons1, NULL);
13695
13696 if( coefsequal )
13697 {
13698 /* the coefficients of both rows are equal */
13699 lhs = MAX(consdata0->lhs, consdata1->lhs);
13700 rhs = MIN(consdata0->rhs, consdata1->rhs);
13701 }
13702 else
13703 {
13704 /* the coefficients of both rows are negations */
13705 lhs = MAX(consdata0->lhs, -consdata1->rhs);
13706 rhs = MIN(consdata0->rhs, -consdata1->lhs);
13707 }
13708 if( SCIPisFeasLT(scip, rhs, lhs) )
13709 {
13710 SCIPdebugMsg(scip, "aggregated linear constraint <%s> is infeasible\n", SCIPconsGetName(cons0));
13711 *cutoff = TRUE;
13712 break;
13713 }
13714
13715 /* check which constraint has to stay;
13716 * changes applied to an upgraded constraint will not be considered in the instance */
13717 if( consdata0->upgraded )
13718 {
13719 assert(!consdata1->upgraded);
13720 consstay = cons1;
13721 #ifndef NDEBUG
13722 consdatastay = consdata1;
13723 #endif
13724
13725 consdel = cons0;
13726 consdatadel = consdata0;
13727 consinddel = chkind;
13728 }
13729 else
13730 {
13731 consstay = cons0;
13732 #ifndef NDEBUG
13733 consdatastay = consdata0;
13734 #endif
13735
13736 consdel = cons1;
13737 consdatadel = consdata1;
13738 consinddel = c;
13739 }
13740
13741 /* update the sides of consstay */
13742 SCIP_CALL( chgLhs(scip, consstay, lhs) );
13743 SCIP_CALL( chgRhs(scip, consstay, rhs) );
13744 if( !consdata0->upgraded )
13745 {
13746 assert(consstay == cons0);
13747 cons0lhs = consdata0->lhs;
13748 cons0rhs = consdata0->rhs;
13749 }
13750
13751 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
13752 SCIP_CALL( SCIPupdateConsFlags(scip, consstay, consdel) );
13753
13754 assert( !consdatastay->upgraded );
13755 /* delete consdel */
13756 SCIP_CALL( SCIPdelCons(scip, consdel) );
13757 conss[consinddel] = NULL;
13758 if( !consdatadel->upgraded )
13759 (*ndelconss)++;
13760 continue;
13761 }
13762
13763 /* check for domination: remove dominated sides, but don't touch equalities as long as they are not totally
13764 * redundant
13765 */
13766 if( cons1dominateslhs && (!cons0isequality || cons1dominatesrhs || SCIPisInfinity(scip, consdata0->rhs) ) )
13767 {
13768 /* left hand side is dominated by consdata1: delete left hand side of consdata0 */
13769 SCIPdebugMsg(scip, "left hand side of linear constraint <%s> is dominated by <%s>:\n",
13770 SCIPconsGetName(cons0), SCIPconsGetName(cons1));
13771 SCIPdebugPrintCons(scip, cons0, NULL);
13772 SCIPdebugPrintCons(scip, cons1, NULL);
13773
13774 /* check for infeasibility */
13775 if( SCIPisFeasGT(scip, consdata1->lhs, consdata0->rhs) )
13776 {
13777 SCIPdebugMsg(scip, "linear constraints <%s> and <%s> are infeasible\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
13778 *cutoff = TRUE;
13779 break;
13780 }
13781
13782 /* remove redundant left hand side */
13783 if( !SCIPisInfinity(scip, -consdata0->lhs) )
13784 {
13785 SCIP_CALL( chgLhs(scip, cons0, -SCIPinfinity(scip)) );
13786 cons0lhs = consdata0->lhs;
13787 cons0isequality = FALSE;
13788 if( !consdata0->upgraded )
13789 {
13790 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
13791 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
13792
13793 (*nchgsides)++;
13794 }
13795 }
13796 }
13797 else if( cons0dominateslhs && (!cons1isequality || cons0dominatesrhs || SCIPisInfinity(scip, consdata1->rhs)) )
13798 {
13799 /* left hand side is dominated by consdata0: delete left hand side of consdata1 */
13800 SCIPdebugMsg(scip, "left hand side of linear constraint <%s> is dominated by <%s>:\n",
13801 SCIPconsGetName(cons1), SCIPconsGetName(cons0));
13802 SCIPdebugPrintCons(scip, cons1, NULL);
13803 SCIPdebugPrintCons(scip, cons0, NULL);
13804
13805 /* check for infeasibility */
13806 if( SCIPisFeasGT(scip, consdata0->lhs, consdata1->rhs) )
13807 {
13808 SCIPdebugMsg(scip, "linear constraints <%s> and <%s> are infeasible\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
13809 *cutoff = TRUE;
13810 break;
13811 }
13812
13813 /* remove redundant left hand side */
13814 if( !SCIPisInfinity(scip, -consdata1->lhs) )
13815 {
13816 SCIP_CALL( chgLhs(scip, cons1, -SCIPinfinity(scip)) );
13817 cons1isequality = FALSE;
13818 if( !consdata1->upgraded )
13819 {
13820 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
13821 SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
13822
13823 (*nchgsides)++;
13824 }
13825 }
13826 }
13827 if( cons1dominatesrhs && (!cons0isequality || cons1dominateslhs || SCIPisInfinity(scip, -consdata0->lhs)) )
13828 {
13829 /* right hand side is dominated by consdata1: delete right hand side of consdata0 */
13830 SCIPdebugMsg(scip, "right hand side of linear constraint <%s> is dominated by <%s>:\n",
13831 SCIPconsGetName(cons0), SCIPconsGetName(cons1));
13832 SCIPdebugPrintCons(scip, cons0, NULL);
13833 SCIPdebugPrintCons(scip, cons1, NULL);
13834
13835 /* check for infeasibility */
13836 if( SCIPisFeasLT(scip, consdata1->rhs, consdata0->lhs) )
13837 {
13838 SCIPdebugMsg(scip, "linear constraints <%s> and <%s> are infeasible\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
13839 *cutoff = TRUE;
13840 break;
13841 }
13842
13843 /* remove redundant right hand side */
13844 if( !SCIPisInfinity(scip, consdata0->rhs) )
13845 {
13846 SCIP_CALL( chgRhs(scip, cons0, SCIPinfinity(scip)) );
13847 cons0rhs = consdata0->rhs;
13848 cons0isequality = FALSE;
13849 if( !consdata0->upgraded )
13850 {
13851 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
13852 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
13853
13854 (*nchgsides)++;
13855 }
13856 }
13857 }
13858 else if( cons0dominatesrhs && (!cons1isequality || cons0dominateslhs || SCIPisInfinity(scip, -consdata1->lhs)) )
13859 {
13860 /* right hand side is dominated by consdata0: delete right hand side of consdata1 */
13861 SCIPdebugMsg(scip, "right hand side of linear constraint <%s> is dominated by <%s>:\n",
13862 SCIPconsGetName(cons1), SCIPconsGetName(cons0));
13863 SCIPdebugPrintCons(scip, cons1, NULL);
13864 SCIPdebugPrintCons(scip, cons0, NULL);
13865
13866 /* check for infeasibility */
13867 if( SCIPisFeasLT(scip, consdata0->rhs, consdata1->lhs) )
13868 {
13869 SCIPdebugMsg(scip, "linear constraints <%s> and <%s> are infeasible\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
13870 *cutoff = TRUE;
13871 break;
13872 }
13873
13874 /* remove redundant right hand side */
13875 if( !SCIPisInfinity(scip, consdata1->rhs) )
13876 {
13877 SCIP_CALL( chgRhs(scip, cons1, SCIPinfinity(scip)) );
13878 cons1isequality = FALSE;
13879 if( !consdata1->upgraded )
13880 {
13881 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
13882 SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
13883
13884 (*nchgsides)++;
13885 }
13886 }
13887 }
13888
13889 /* check for now redundant constraints */
13890 if( SCIPisInfinity(scip, -consdata0->lhs) && SCIPisInfinity(scip, consdata0->rhs) )
13891 {
13892 /* consdata0 became redundant */
13893 SCIPdebugMsg(scip, "linear constraint <%s> is redundant\n", SCIPconsGetName(cons0));
13894 SCIP_CALL( SCIPdelCons(scip, cons0) );
13895 conss[chkind] = NULL;
13896 if( !consdata0->upgraded )
13897 {
13898 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
13899 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
13900
13901 (*ndelconss)++;
13902 }
13903 continue;
13904 }
13905 if( SCIPisInfinity(scip, -consdata1->lhs) && SCIPisInfinity(scip, consdata1->rhs) )
13906 {
13907 /* consdata1 became redundant */
13908 SCIPdebugMsg(scip, "linear constraint <%s> is redundant\n", SCIPconsGetName(cons1));
13909 SCIP_CALL( SCIPdelCons(scip, cons1) );
13910 conss[c] = NULL;
13911 if( !consdata1->upgraded )
13912 {
13913 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
13914 SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
13915
13916 (*ndelconss)++;
13917 }
13918 continue;
13919 }
13920
13921 /* check, if we want to aggregate an (in)equality with an equality:
13922 * consdata0 := a * consdata0 + b * consdata1 or consdata1 := a * consdata1 + b * consdata0
13923 */
13924 if( tryaggregation )
13925 {
13926 SCIP_Bool aggregated;
13927
13928 assert(consdata0->nvars == nvarscommon + nvars0minus1);
13929 assert(consdata1->nvars == nvarscommon + nvars1minus0);
13930
13931 aggregated = FALSE;
13932 if( cons1isequality && !consdata0->upgraded && commonidxweight > diffidx1minus0weight )
13933 {
13934 /* W_c > W_1: try to aggregate consdata0 := a * consdata0 + b * consdata1 */
13935 SCIP_CALL( aggregateConstraints(scip, cons0, cons1, commonidx0, commonidx1, diffidx0minus1, diffidx1minus0,
13936 nvarscommon, commonidxweight, diffidx0minus1weight, diffidx1minus0weight, maxaggrnormscale,
13937 nchgcoefs, &aggregated, cutoff) );
13938
13939 if( *cutoff )
13940 break;
13941
13942 /* update array of active constraints */
13943 if( aggregated )
13944 {
13945 assert(!SCIPconsIsActive(cons0));
13946 assert(SCIPconsIsActive(cons1));
13947 conss[chkind] = NULL;
13948 }
13949 }
13950 if( !aggregated && cons0isequality && !consdata1->upgraded && commonidxweight > diffidx0minus1weight )
13951 {
13952 /* W_c > W_0: try to aggregate consdata1 := a * consdata1 + b * consdata0 */
13953 SCIP_CALL( aggregateConstraints(scip, cons1, cons0, commonidx1, commonidx0, diffidx1minus0, diffidx0minus1,
13954 nvarscommon, commonidxweight, diffidx1minus0weight, diffidx0minus1weight, maxaggrnormscale,
13955 nchgcoefs, &aggregated, cutoff) );
13956
13957 if( *cutoff )
13958 break;
13959
13960 /* update array of active constraints */
13961 if( aggregated )
13962 {
13963 assert(!SCIPconsIsActive(cons1));
13964 assert(SCIPconsIsActive(cons0));
13965 conss[c] = NULL;
13966 }
13967 }
13968 }
13969 }
13970
13971 /* free temporary memory */
13972 SCIPfreeBufferArray(scip, &diffidx1minus0);
13973 SCIPfreeBufferArray(scip, &diffidx0minus1);
13974 SCIPfreeBufferArray(scip, &commonidx1);
13975 SCIPfreeBufferArray(scip, &commonidx0);
13976
13977 return SCIP_OKAY;
13978 }
13979
13980 /** do stuffing presolving on a single constraint */
13981 static
presolStuffing(SCIP * scip,SCIP_CONS * cons,SCIP_Bool singletonstuffing,SCIP_Bool singlevarstuffing,SCIP_Bool * cutoff,int * nfixedvars,int * nchgbds)13982 SCIP_RETCODE presolStuffing(
13983 SCIP* scip, /**< SCIP data structure */
13984 SCIP_CONS* cons, /**< linear constraint */
13985 SCIP_Bool singletonstuffing, /**< should stuffing of singleton continuous variables be performed? */
13986 SCIP_Bool singlevarstuffing, /**< should single variable stuffing be performed, which tries to fulfill
13987 * constraints using the cheapest variable? */
13988 SCIP_Bool* cutoff, /**< pointer to store TRUE, if a cutoff was found */
13989 int* nfixedvars, /**< pointer to count the total number of fixed variables */
13990 int* nchgbds /**< pointer to count the total number of tightened bounds */
13991 )
13992 {
13993 SCIP_CONSDATA* consdata;
13994 SCIP_Real* ratios;
13995 int* varpos;
13996 SCIP_Bool* swapped;
13997 SCIP_VAR** vars;
13998 SCIP_Real* vals;
13999 SCIP_VAR* var;
14000 SCIP_Real lb;
14001 SCIP_Real ub;
14002 SCIP_Real minactivity;
14003 SCIP_Real maxactivity;
14004 SCIP_Real maxcondactivity;
14005 SCIP_Real mincondactivity;
14006 SCIP_Real rhs;
14007 SCIP_Real val;
14008 SCIP_Real obj;
14009 SCIP_Real factor;
14010 SCIP_Bool minactisrelax;
14011 SCIP_Bool maxactisrelax;
14012 SCIP_Bool isminsettoinfinity;
14013 SCIP_Bool ismaxsettoinfinity;
14014 SCIP_Bool tryfixing;
14015 int nsingletons;
14016 int idx;
14017 int v;
14018 int nvars;
14019
14020 assert(scip != NULL);
14021 assert(cons != NULL);
14022 assert(nfixedvars != NULL);
14023
14024 consdata = SCIPconsGetData(cons);
14025
14026 /* we only want to run for inequalities */
14027 if( !SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, -consdata->lhs) )
14028 return SCIP_OKAY;
14029
14030 if( singlevarstuffing )
14031 {
14032 consdataGetActivityBounds(scip, consdata, FALSE, &minactivity, &maxactivity, &minactisrelax, &maxactisrelax,
14033 &isminsettoinfinity, &ismaxsettoinfinity);
14034 }
14035 else
14036 {
14037 minactivity = SCIP_INVALID;
14038 maxactivity = SCIP_INVALID;
14039 isminsettoinfinity = FALSE;
14040 ismaxsettoinfinity = FALSE;
14041 }
14042
14043 /* we want to have a <= constraint, if the rhs is infinite, we implicitly multiply the constraint by -1,
14044 * the new maxactivity is minus the old minactivity then
14045 */
14046 if( SCIPisInfinity(scip, consdata->rhs) )
14047 {
14048 rhs = -consdata->lhs;
14049 factor = -1.0;
14050 maxactivity = -minactivity;
14051 ismaxsettoinfinity = isminsettoinfinity;
14052 }
14053 else
14054 {
14055 assert(SCIPisInfinity(scip, -consdata->lhs));
14056 rhs = consdata->rhs;
14057 factor = 1.0;
14058 }
14059
14060 nvars = consdata->nvars;
14061 vars = consdata->vars;
14062 vals = consdata->vals;
14063
14064 /* check for continuous singletons */
14065 if( singletonstuffing )
14066 {
14067 for( v = 0; v < nvars; ++v )
14068 {
14069 var = vars[v];
14070
14071 if( (SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) + SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL)) == 1
14072 && SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS )
14073 break;
14074 }
14075 }
14076 else
14077 /* we don't want to go into the next block */
14078 v = nvars;
14079
14080 /* a singleton was found -> perform singleton variable stuffing */
14081 if( v < nvars )
14082 {
14083 assert(singletonstuffing);
14084
14085 SCIP_CALL( SCIPallocBufferArray(scip, &varpos, nvars) );
14086 SCIP_CALL( SCIPallocBufferArray(scip, &ratios, nvars) );
14087 SCIP_CALL( SCIPallocBufferArray(scip, &swapped, nvars) );
14088
14089 tryfixing = TRUE;
14090 nsingletons = 0;
14091 mincondactivity = 0.0;
14092 maxcondactivity = 0.0;
14093
14094 for( v = 0; v < nvars; ++v )
14095 {
14096 var = vars[v];
14097 lb = SCIPvarGetLbGlobal(var);
14098 ub = SCIPvarGetUbGlobal(var);
14099 obj = SCIPvarGetObj(var);
14100 val = factor * vals[v];
14101
14102 assert(!SCIPisZero(scip, val));
14103
14104 /* the variable is a singleton and continuous */
14105 if( (SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) + SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL)) == 1
14106 && SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS )
14107 {
14108 if( SCIPisNegative(scip, obj) && val > 0 )
14109 {
14110 /* case 1: obj < 0 and coef > 0 */
14111 if( SCIPisInfinity(scip, -lb) )
14112 {
14113 tryfixing = FALSE;
14114 break;
14115 }
14116
14117 maxcondactivity += val * lb;
14118 mincondactivity += val * lb;
14119 swapped[v] = FALSE;
14120 ratios[nsingletons] = obj / val;
14121 varpos[nsingletons] = v;
14122 nsingletons++;
14123 }
14124 else if( SCIPisPositive(scip, obj) && val < 0 )
14125 {
14126 /* case 2: obj > 0 and coef < 0 */
14127 if( SCIPisInfinity(scip, ub) )
14128 {
14129 tryfixing = FALSE;
14130 break;
14131 }
14132 /* multiply column by (-1) to become case 1.
14133 * now bounds are swapped: ub := -lb, lb := -ub
14134 */
14135
14136 maxcondactivity += val * ub;
14137 mincondactivity += val * ub;
14138 swapped[v] = TRUE;
14139 ratios[nsingletons] = obj / val;
14140 varpos[nsingletons] = v;
14141 nsingletons++;
14142 }
14143 else if( val > 0 )
14144 {
14145 /* case 3: obj >= 0 and coef >= 0 is handled by duality fixing.
14146 * we only consider the lower bound for the constants
14147 */
14148 assert(!SCIPisNegative(scip, obj));
14149
14150 if( SCIPisInfinity(scip, -lb) )
14151 {
14152 /* maybe unbounded */
14153 tryfixing = FALSE;
14154 break;
14155 }
14156
14157 maxcondactivity += val * lb;
14158 mincondactivity += val * lb;
14159 }
14160 else
14161 {
14162 /* case 4: obj <= 0 and coef <= 0 is also handled by duality fixing.
14163 * we only consider the upper bound for the constants
14164 */
14165 assert(!SCIPisPositive(scip, obj));
14166 assert(val < 0);
14167
14168 if( SCIPisInfinity(scip, ub) )
14169 {
14170 /* maybe unbounded */
14171 tryfixing = FALSE;
14172 break;
14173 }
14174
14175 maxcondactivity += val * ub;
14176 mincondactivity += val * ub;
14177 }
14178 }
14179 else
14180 {
14181 /* consider contribution of discrete variables, non-singleton
14182 * continuous variables and variables with more than one lock
14183 */
14184 if( SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub) )
14185 {
14186 tryfixing = FALSE;
14187 break;
14188 }
14189
14190 if( val > 0 )
14191 {
14192 maxcondactivity += val * ub;
14193 mincondactivity += val * lb;
14194 }
14195 else
14196 {
14197 maxcondactivity += val * lb;
14198 mincondactivity += val * ub;
14199 }
14200 }
14201 }
14202 if( tryfixing && nsingletons > 0 && (SCIPisGT(scip, rhs, maxcondactivity) || SCIPisLE(scip, rhs, mincondactivity)) )
14203 {
14204 SCIP_Real delta;
14205 SCIP_Bool tightened;
14206 #ifdef SCIP_DEBUG
14207 int oldnfixedvars = *nfixedvars;
14208 int oldnchgbds = *nchgbds;
14209 #endif
14210
14211 SCIPsortRealInt(ratios, varpos, nsingletons);
14212
14213 /* verify which singleton continuous variables can be fixed */
14214 for( v = 0; v < nsingletons; ++v )
14215 {
14216 idx = varpos[v];
14217 var = vars[idx];
14218 val = factor * vals[idx];
14219 lb = SCIPvarGetLbGlobal(var);
14220 ub = SCIPvarGetUbGlobal(var);
14221
14222 assert(val > 0 || SCIPisPositive(scip, SCIPvarGetObj(var)));
14223 assert((val < 0) == swapped[idx]);
14224 val = REALABS(val);
14225
14226 /* stop fixing if variable bounds are not finite */
14227 if( SCIPisInfinity(scip, -lb) || SCIPisInfinity(scip, ub) )
14228 break;
14229
14230 assert((SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL)
14231 + SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL)) == 1);
14232 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS);
14233
14234 /* calculate the change in the row activities if this variable changes
14235 * its value from its worst to its best bound
14236 */
14237 if( swapped[idx] )
14238 delta = -(lb - ub) * val;
14239 else
14240 delta = (ub - lb) * val;
14241
14242 assert(!SCIPisNegative(scip, delta));
14243
14244 if( SCIPisLE(scip, delta, rhs - maxcondactivity) )
14245 {
14246 if( swapped[idx] )
14247 {
14248 SCIPdebugMsg(scip, "fix <%s> to its lower bound %g\n", SCIPvarGetName(var), lb);
14249 SCIP_CALL( SCIPfixVar(scip, var, lb, cutoff, &tightened) );
14250 }
14251 else
14252 {
14253 SCIPdebugMsg(scip, "fix <%s> to its upper bound %g\n", SCIPvarGetName(var), ub);
14254 SCIP_CALL( SCIPfixVar(scip, var, ub, cutoff, &tightened) );
14255 }
14256
14257 if( *cutoff )
14258 break;
14259 if( tightened )
14260 {
14261 (*nfixedvars)++;
14262 }
14263 }
14264 /* @note: we could in theory tighten the bound of the first singleton variable which does not fall into the above case,
14265 * since it cannot be fully fixed. However, this is not needed and should be done by activity-based bound tightening
14266 * anyway after all other continuous singleton columns were fixed; doing it here may introduce numerical
14267 * troubles in case of large bounds.
14268 */
14269 else if( SCIPisLE(scip, rhs, mincondactivity) )
14270 {
14271 if( swapped[idx] )
14272 {
14273 SCIPdebugMsg(scip, "fix <%s> to its upper bound %g\n", SCIPvarGetName(var), ub);
14274 SCIP_CALL( SCIPfixVar(scip, var, ub, cutoff, &tightened) );
14275 }
14276 else
14277 {
14278 SCIPdebugMsg(scip, "fix <%s> to its lower bound %g\n", SCIPvarGetName(var), lb);
14279 SCIP_CALL( SCIPfixVar(scip, var, lb, cutoff, &tightened) );
14280 }
14281
14282 if( *cutoff )
14283 break;
14284 if( tightened )
14285 {
14286 (*nfixedvars)++;
14287 }
14288 }
14289
14290 maxcondactivity += delta;
14291 mincondactivity += delta;
14292 }
14293
14294 #ifdef SCIP_DEBUG
14295 if( *nfixedvars - oldnfixedvars > 0 || *nchgbds - oldnchgbds > 0 )
14296 {
14297 SCIPdebugMsg(scip, "### stuffing fixed %d variables and changed %d bounds\n", *nfixedvars - oldnfixedvars, *nchgbds - oldnchgbds);
14298 }
14299 #endif
14300 }
14301
14302 SCIPfreeBufferArray(scip, &swapped);
14303 SCIPfreeBufferArray(scip, &ratios);
14304 SCIPfreeBufferArray(scip, &varpos);
14305 }
14306
14307 /* perform single-variable stuffing:
14308 * for a linear inequality
14309 * a_1 x_1 + a_2 x_2 + ... + a_n x_n <= b
14310 * with a_i > 0 and objective coefficients c_i < 0,
14311 * setting all variables to their upper bound (giving us the maximal activity of the constraint) is worst w.r.t.
14312 * feasibility of the constraint. On the other hand, this gives the best objective function contribution of the
14313 * variables contained in the constraint. The maximal activity should be larger than the rhs, otherwise the constraint
14314 * is redundant.
14315 * Now we are searching for a variable x_k with maximal ratio c_k / a_k (note that all these ratios are negative), so
14316 * that by reducing the value of this variable we reduce the activity of the constraint while having the smallest
14317 * objective deterioration per activity unit. If x_k has no downlocks, is continuous, and can be reduced enough to
14318 * render the constraint feasible, and ALL other variables have only the one uplock installed by the current constraint,
14319 * we can reduce the upper bound of x_k such that the maxactivity equals the rhs and fix all other variables to their
14320 * upper bound.
14321 * Note that the others variables may have downlocks from other constraints, which we do not need to care
14322 * about since we are setting them to the highest possible value. Also, they may be integer or binary, because the
14323 * computed ratio is still a lower bound on the change in the objective caused by reducing those variable to reach
14324 * constraint feasibility. On the other hand, uplocks on x_k from other constraint do no interfer with the method.
14325 * With a slight adjustment, the procedure even works for integral x_k. If (maxactivity - rhs)/val is integral,
14326 * the variable gets an integral value in order to fulfill the constraint tightly, and we can just apply the procedure.
14327 * If (maxactivity - rhs)/val is fractional, we need to check, if overfulfilling the constraint by setting x_k to
14328 * ceil((maxactivity - rhs)/val) is still better than setting x_k to ceil((maxactivity - rhs)/val) - 1 and
14329 * filling the remaining gap in the constraint with the next-best variable. For this, we check that
14330 * c_k * ceil((maxactivity - rhs)/val) is still better than
14331 * c_k * floor((maxactivity - rhs)/val) + c_j * ((maxactivity - rhs) - (floor((maxactivity - rhs)/val) * val))/a_j.
14332 * In this case, the upper bound of x_k is decreased to ub_k - ceil(maxactivity - rhs).
14333 * If there are variables with a_i < 0 and c_i > 0, they are negated to obtain the above form, variables with same
14334 * sign of coefficients in constraint and objective prevent the use of this method.
14335 */
14336 if( singlevarstuffing && !ismaxsettoinfinity )
14337 {
14338 SCIP_Real bestratio = -SCIPinfinity(scip);
14339 SCIP_Real secondbestratio = -SCIPinfinity(scip);
14340 SCIP_Real ratio;
14341 int bestindex = -1;
14342 int bestuplocks = 0;
14343 int bestdownlocks = 1;
14344 int downlocks;
14345 int uplocks;
14346 SCIPdebug( int oldnfixedvars = *nfixedvars; )
14347 SCIPdebug( int oldnchgbds = *nchgbds; )
14348
14349 /* loop over all variables to identify the best and second-best ratio */
14350 for( v = 0; v < nvars; ++v )
14351 {
14352 var = vars[v];
14353 obj = SCIPvarGetObj(var);
14354 val = factor * vals[v];
14355
14356 assert(!SCIPisZero(scip, val));
14357
14358 ratio = obj / val;
14359
14360 /* if both objective and constraint push the variable to the same direction, we can do nothing here */
14361 if( !SCIPisNegative(scip, ratio) )
14362 {
14363 bestindex = -1;
14364 break;
14365 }
14366
14367 if( val > 0 )
14368 {
14369 downlocks = SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL);
14370 uplocks = SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL);
14371 }
14372 else
14373 {
14374 downlocks = SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL);
14375 uplocks = SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL);
14376 }
14377
14378 /* better ratio, update best candidate
14379 * @todo use some tolerance
14380 * @todo check size of domain and updated ratio for integer variables already?
14381 */
14382 if( ratio > bestratio || ((ratio == bestratio) && downlocks == 0 && (bestdownlocks > 0 /*lint !e777*/
14383 || (SCIPvarGetType(vars[bestindex]) != SCIP_VARTYPE_CONTINUOUS
14384 && SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS))) )
14385 {
14386 /* best index becomes second-best*/
14387 if( bestindex != -1 )
14388 {
14389 /* second-best index must not have more than 1 uplock */
14390 if( bestuplocks > 1 )
14391 {
14392 bestindex = -1;
14393 break;
14394 }
14395 else
14396 {
14397 secondbestratio = bestratio;
14398 }
14399 }
14400 bestdownlocks = downlocks;
14401 bestuplocks = uplocks;
14402 bestratio = ratio;
14403 bestindex = v;
14404
14405 /* if this variable is the best in the end, we cannot do reductions since it has a downlocks,
14406 * if it is not the best, it has too many uplocks -> not applicable
14407 */
14408 if( bestdownlocks > 0 && bestuplocks > 1 )
14409 {
14410 bestindex = -1;
14411 break;
14412 }
14413 }
14414 else
14415 {
14416 /* non-best index must not have more than 1 uplock */
14417 if( uplocks > 1 )
14418 {
14419 bestindex = -1;
14420 break;
14421 }
14422 /* update second-best ratio */
14423 if( ratio > secondbestratio )
14424 {
14425 secondbestratio = ratio;
14426 }
14427 }
14428 }
14429
14430 /* check if we can apply single variable stuffing */
14431 if( bestindex != -1 && bestdownlocks == 0 )
14432 {
14433 SCIP_Bool tightened = FALSE;
14434 SCIP_Real bounddelta;
14435
14436 var = vars[bestindex];
14437 obj = SCIPvarGetObj(var);
14438 val = factor * vals[bestindex];
14439 lb = SCIPvarGetLbGlobal(var);
14440 ub = SCIPvarGetUbGlobal(var);
14441 tryfixing = TRUE;
14442
14443 if( val < 0 )
14444 {
14445 assert(!SCIPisNegative(scip, obj));
14446
14447 /* the best variable is integer, and we need to overfulfill the constraint when using just the variable */
14448 if( SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS && !SCIPisIntegral(scip, (maxactivity - rhs)/-val) )
14449 {
14450 SCIP_Real bestvarfloor = SCIPfloor(scip, (maxactivity - rhs)/-val);
14451 SCIP_Real activitydelta = (maxactivity - rhs) - (bestvarfloor * -val);
14452 assert(SCIPisPositive(scip, activitydelta));
14453
14454 tryfixing = SCIPisLE(scip, obj, -activitydelta * secondbestratio);
14455
14456 bounddelta = SCIPceil(scip, (maxactivity - rhs)/-val);
14457 assert(SCIPisPositive(scip, bounddelta));
14458 }
14459 else
14460 bounddelta = (maxactivity - rhs)/-val;
14461
14462 tryfixing = tryfixing && SCIPisLE(scip, bounddelta, ub - lb);
14463
14464 if( tryfixing )
14465 {
14466 assert(SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == 0);
14467
14468 if( SCIPisEQ(scip, lb + bounddelta, ub) )
14469 {
14470 SCIPdebugMsg(scip, "fix var <%s> to %g\n", SCIPvarGetName(var), lb + bounddelta);
14471 SCIP_CALL( SCIPfixVar(scip, var, lb + bounddelta, cutoff, &tightened) );
14472 }
14473 else
14474 {
14475 SCIPdebugMsg(scip, "tighten the lower bound of <%s> from %g to %g (ub=%g)\n", SCIPvarGetName(var), lb, lb + bounddelta, ub);
14476 SCIP_CALL( SCIPtightenVarLb(scip, var, lb + bounddelta, FALSE, cutoff, &tightened) );
14477 }
14478 }
14479 }
14480 else
14481 {
14482 assert(!SCIPisPositive(scip, obj));
14483
14484 /* the best variable is integer, and we need to overfulfill the constraint when using just the variable */
14485 if( SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS && !SCIPisIntegral(scip, (maxactivity - rhs)/val))
14486 {
14487 SCIP_Real bestvarfloor = SCIPfloor(scip, (maxactivity - rhs)/val);
14488 SCIP_Real activitydelta = (maxactivity - rhs) - (bestvarfloor * val);
14489 assert(SCIPisPositive(scip, activitydelta));
14490
14491 tryfixing = SCIPisLE(scip, -obj, activitydelta * secondbestratio);
14492
14493 bounddelta = SCIPceil(scip, (maxactivity - rhs)/val);
14494 assert(SCIPisPositive(scip, bounddelta));
14495 }
14496 else
14497 bounddelta = (maxactivity - rhs)/val;
14498
14499 tryfixing = tryfixing && SCIPisLE(scip, bounddelta, ub - lb);
14500
14501 if( tryfixing )
14502 {
14503 assert(SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == 0);
14504
14505 if( SCIPisEQ(scip, ub - bounddelta, lb) )
14506 {
14507 SCIPdebugMsg(scip, "fix var <%s> to %g\n", SCIPvarGetName(var), ub - bounddelta);
14508 SCIP_CALL( SCIPfixVar(scip, var, ub - bounddelta, cutoff, &tightened) );
14509 }
14510 else
14511 {
14512 SCIPdebugMsg(scip, "tighten the upper bound of <%s> from %g to %g (lb=%g)\n", SCIPvarGetName(var), ub, ub - bounddelta, lb);
14513 SCIP_CALL( SCIPtightenVarUb(scip, var, ub - bounddelta, FALSE, cutoff, &tightened) );
14514 }
14515 }
14516 }
14517
14518 if( *cutoff )
14519 return SCIP_OKAY;
14520 if( tightened )
14521 {
14522 if( SCIPisEQ(scip, SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var)) )
14523 ++(*nfixedvars);
14524 else
14525 ++(*nchgbds);
14526
14527 SCIPdebugMsg(scip, "cons <%s>: %g <=\n", SCIPconsGetName(cons), factor > 0 ? consdata->lhs : -consdata->rhs);
14528 for( v = 0; v < nvars; ++v )
14529 {
14530 SCIPdebugMsg(scip, "%+g <%s>([%g,%g],%g,[%d,%d],%s)\n", factor * vals[v], SCIPvarGetName(vars[v]),
14531 SCIPvarGetLbGlobal(vars[v]), SCIPvarGetUbGlobal(vars[v]), SCIPvarGetObj(vars[v]),
14532 SCIPvarGetNLocksDownType(vars[v], SCIP_LOCKTYPE_MODEL),
14533 SCIPvarGetNLocksUpType(vars[v], SCIP_LOCKTYPE_MODEL),
14534 SCIPvarGetType(vars[v]) == SCIP_VARTYPE_CONTINUOUS ? "C" : "I");
14535 }
14536 SCIPdebugMsg(scip, "<= %g\n", factor > 0 ? consdata->rhs : -consdata->lhs);
14537
14538 for( v = 0; v < nvars; ++v )
14539 {
14540 if( v == bestindex )
14541 continue;
14542
14543 if( factor * vals[v] < 0 )
14544 {
14545 assert(SCIPvarGetNLocksDownType(vars[v], SCIP_LOCKTYPE_MODEL) == 1);
14546 SCIPdebugMsg(scip, "fix <%s> to its lower bound (%g)\n",
14547 SCIPvarGetName(vars[v]), SCIPvarGetLbGlobal(vars[v]));
14548 SCIP_CALL( SCIPfixVar(scip, vars[v], SCIPvarGetLbGlobal(vars[v]), cutoff, &tightened) );
14549 }
14550 else
14551 {
14552 assert(SCIPvarGetNLocksUpType(vars[v], SCIP_LOCKTYPE_MODEL) == 1);
14553 SCIPdebugMsg(scip, "fix <%s> to its upper bound (%g)\n",
14554 SCIPvarGetName(vars[v]), SCIPvarGetUbGlobal(vars[v]));
14555 SCIP_CALL( SCIPfixVar(scip, vars[v], SCIPvarGetUbGlobal(vars[v]), cutoff, &tightened) );
14556 }
14557
14558 if( *cutoff )
14559 return SCIP_OKAY;
14560 if( tightened )
14561 ++(*nfixedvars);
14562 }
14563 SCIPdebug( SCIPdebugMsg(scip, "### new stuffing fixed %d vars, tightened %d bounds\n", *nfixedvars - oldnfixedvars, *nchgbds - oldnchgbds); )
14564 }
14565 }
14566 }
14567
14568 return SCIP_OKAY;
14569 }
14570
14571 /** applies full dual presolving on variables that only appear in linear constraints */
14572 static
fullDualPresolve(SCIP * scip,SCIP_CONS ** conss,int nconss,SCIP_Bool * cutoff,int * nchgbds)14573 SCIP_RETCODE fullDualPresolve(
14574 SCIP* scip, /**< SCIP data structure */
14575 SCIP_CONS** conss, /**< constraint set */
14576 int nconss, /**< number of constraints */
14577 SCIP_Bool* cutoff, /**< pointer to store TRUE, if a cutoff was found */
14578 int* nchgbds /**< pointer to count the number of bound changes */
14579 )
14580 {
14581 SCIP_Real* redlb;
14582 SCIP_Real* redub;
14583 int* nlocksdown;
14584 int* nlocksup;
14585 SCIP_Bool* isimplint;
14586 SCIP_VAR** origvars;
14587 SCIP_VAR** vars;
14588 SCIP_VAR** conscontvars;
14589 int nvars;
14590 int nbinvars;
14591 int nintvars;
14592 int ncontvars;
14593 int v;
14594 int c;
14595
14596 /* we calculate redundancy bounds with the following meaning:
14597 * redlb[v] == k : if x_v >= k, we can always round x_v down to x_v == k without violating any constraint
14598 * redub[v] == k : if x_v <= k, we can always round x_v up to x_v == k without violating any constraint
14599 * then:
14600 * c_v >= 0 : x_v <= redlb[v] is feasible due to optimality
14601 * c_v <= 0 : x_v >= redub[v] is feasible due to optimality
14602 */
14603
14604 /* Additionally, we detect continuous variables that are implicitly integral.
14605 * A continuous variable j is implicit integral if it only has only +/-1 coefficients,
14606 * and all constraints (including the bounds as trivial constraints) in which:
14607 * c_j > 0: the variable is down-locked,
14608 * c_j < 0: the variable is up-locked,
14609 * c_j = 0: the variable appears
14610 * have, apart from j, only integer variables with integral coefficients and integral sides.
14611 * This is because then, the value of the variable is either determined by one of its bounds or
14612 * by one of these constraints, and in all cases, the value of the variable is integral.
14613 */
14614
14615 assert(scip != NULL);
14616 assert(nconss == 0 || conss != NULL);
14617 assert(nchgbds != NULL);
14618 assert(!SCIPinProbing(scip));
14619
14620 /* get active variables */
14621 nvars = SCIPgetNVars(scip);
14622 origvars = SCIPgetVars(scip);
14623
14624 /* if the problem is a pure binary program, nothing can be achieved by full dual presolve */
14625 nbinvars = SCIPgetNBinVars(scip);
14626 if( nbinvars == nvars )
14627 return SCIP_OKAY;
14628
14629 /* get number of continuous variables */
14630 ncontvars = SCIPgetNContVars(scip);
14631 nintvars = nvars - ncontvars;
14632
14633 /* copy the variable array since this array might change during the curse of this algorithm */
14634 nvars = nvars - nbinvars;
14635 SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, &(origvars[nbinvars]), nvars) );
14636
14637 /* allocate temporary memory */
14638 SCIP_CALL( SCIPallocBufferArray(scip, &redlb, nvars) );
14639 SCIP_CALL( SCIPallocBufferArray(scip, &redub, nvars) );
14640 SCIP_CALL( SCIPallocBufferArray(scip, &nlocksdown, nvars) );
14641 SCIP_CALL( SCIPallocBufferArray(scip, &nlocksup, nvars) );
14642 SCIP_CALL( SCIPallocBufferArray(scip, &isimplint, ncontvars) );
14643 SCIP_CALL( SCIPallocBufferArray(scip, &conscontvars, ncontvars) );
14644
14645 /* initialize redundancy bounds */
14646 for( v = 0; v < nvars; ++v )
14647 {
14648 assert(SCIPvarGetType(vars[v]) != SCIP_VARTYPE_BINARY);
14649 redlb[v] = SCIPvarGetLbGlobal(vars[v]);
14650 redub[v] = SCIPvarGetUbGlobal(vars[v]);
14651 }
14652 BMSclearMemoryArray(nlocksdown, nvars);
14653 BMSclearMemoryArray(nlocksup, nvars);
14654
14655 /* Initialize isimplint array: variable may be implied integer if rounded to their best bound they are integral.
14656 * We better not use SCIPisFeasIntegral() in these checks.
14657 */
14658 for( v = 0; v < ncontvars; v++ )
14659 {
14660 SCIP_VAR* var;
14661 SCIP_Real obj;
14662 SCIP_Real lb;
14663 SCIP_Real ub;
14664
14665 var = vars[v + nintvars - nbinvars];
14666 lb = SCIPvarGetLbGlobal(var);
14667 ub = SCIPvarGetUbGlobal(var);
14668
14669 obj = SCIPvarGetObj(var);
14670 if( SCIPisZero(scip, obj) )
14671 isimplint[v] = (SCIPisInfinity(scip, -lb) || SCIPisIntegral(scip, lb)) && (SCIPisInfinity(scip, ub) || SCIPisIntegral(scip, ub));
14672 else
14673 {
14674 if( SCIPisPositive(scip, obj) )
14675 isimplint[v] = (SCIPisInfinity(scip, -lb) || SCIPisIntegral(scip, lb));
14676 else
14677 {
14678 assert(SCIPisNegative(scip, obj));
14679 isimplint[v] = (SCIPisInfinity(scip, ub) || SCIPisIntegral(scip, ub));
14680 }
14681 }
14682 }
14683
14684 /* scan all constraints */
14685 for( c = 0; c < nconss; ++c )
14686 {
14687 /* we only need to consider constraints that have been locked (i.e., checked constraints or constraints that are
14688 * part of checked disjunctions)
14689 */
14690 if( SCIPconsIsLocked(conss[c]) )
14691 {
14692 SCIP_CONSDATA* consdata;
14693 SCIP_Bool lhsexists;
14694 SCIP_Bool rhsexists;
14695 SCIP_Bool hasimpliedpotential;
14696 SCIP_Bool integralcoefs;
14697 int nlockspos;
14698 int contvarpos;
14699 int nconscontvars;
14700 int i;
14701
14702 consdata = SCIPconsGetData(conss[c]);
14703 assert(consdata != NULL);
14704
14705 /* get number of times the constraint was locked */
14706 nlockspos = SCIPconsGetNLocksPos(conss[c]);
14707
14708 /* we do not want to include constraints with locked negation (this would be too weird) */
14709 if( SCIPconsGetNLocksNeg(conss[c]) > 0 )
14710 {
14711 /* mark all continuous variables as not being implicit integral */
14712 for( i = 0; i < consdata->nvars; ++i )
14713 {
14714 SCIP_VAR* var;
14715
14716 var = consdata->vars[i];
14717 if( SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS )
14718 {
14719 int contv;
14720 contv = SCIPvarGetProbindex(var) - nintvars;
14721 assert(0 <= contv && contv < ncontvars); /* variable should be active due to applyFixings() */
14722 isimplint[contv] = FALSE;
14723 }
14724 }
14725 continue;
14726 }
14727
14728 /* check for existing sides */
14729 lhsexists = !SCIPisInfinity(scip, -consdata->lhs);
14730 rhsexists = !SCIPisInfinity(scip, consdata->rhs);
14731
14732 /* count locks and update redundancy bounds */
14733 contvarpos = -1;
14734 nconscontvars = 0;
14735 hasimpliedpotential = FALSE;
14736 integralcoefs = !SCIPconsIsModifiable(conss[c]);
14737
14738 for( i = 0; i < consdata->nvars; ++i )
14739 {
14740 SCIP_VAR* var;
14741 SCIP_Real val;
14742 SCIP_Real minresactivity;
14743 SCIP_Real maxresactivity;
14744 SCIP_Real newredlb;
14745 SCIP_Real newredub;
14746 SCIP_Bool minisrelax;
14747 SCIP_Bool maxisrelax;
14748 SCIP_Bool isminsettoinfinity;
14749 SCIP_Bool ismaxsettoinfinity;
14750 int arrayindex;
14751
14752 var = consdata->vars[i];
14753 val = consdata->vals[i];
14754
14755 /* check if still all integer variables have integral coefficients */
14756 if( SCIPvarIsIntegral(var) )
14757 integralcoefs = integralcoefs && SCIPisIntegral(scip, val);
14758
14759 /* we do not need to process binary variables */
14760 if( SCIPvarIsBinary(var) )
14761 continue;
14762
14763 if( SCIPconsIsModifiable(conss[c]) )
14764 {
14765 minresactivity = -SCIPinfinity(scip);
14766 maxresactivity = SCIPinfinity(scip);
14767 isminsettoinfinity = TRUE;
14768 ismaxsettoinfinity = TRUE;
14769 }
14770 else
14771 {
14772 /* calculate residual activity bounds if variable would be fixed to zero */
14773 consdataGetGlbActivityResiduals(scip, consdata, var, val, FALSE, &minresactivity, &maxresactivity,
14774 &minisrelax, &maxisrelax, &isminsettoinfinity, &ismaxsettoinfinity);
14775
14776 /* We called consdataGetGlbActivityResiduals() saying that we do not need a good relaxation,
14777 * so whenever we have a relaxed activity, it should be relaxed to +/- infinity.
14778 * This is needed, because we do not want to rely on relaxed finite resactivities.
14779 */
14780 assert((!minisrelax || isminsettoinfinity) && (!maxisrelax || ismaxsettoinfinity));
14781
14782 /* check minresactivity for reliability */
14783 if( !isminsettoinfinity && SCIPisUpdateUnreliable(scip, minresactivity, consdata->lastglbminactivity) )
14784 consdataGetReliableResidualActivity(scip, consdata, var, &minresactivity, TRUE, TRUE);
14785
14786 /* check maxresactivity for reliability */
14787 if( !ismaxsettoinfinity && SCIPisUpdateUnreliable(scip, maxresactivity, consdata->lastglbmaxactivity) )
14788 consdataGetReliableResidualActivity(scip, consdata, var, &maxresactivity, FALSE, TRUE);
14789 }
14790
14791 arrayindex = SCIPvarGetProbindex(var) - nbinvars;
14792
14793 assert(0 <= arrayindex && arrayindex < nvars); /* variable should be active due to applyFixings() */
14794
14795 newredlb = redlb[arrayindex];
14796 newredub = redub[arrayindex];
14797 if( val > 0.0 )
14798 {
14799 if( lhsexists )
14800 {
14801 /* lhs <= d*x + a*y, d > 0 -> redundant in y if x >= (lhs - min{a*y})/d */
14802 nlocksdown[arrayindex] += nlockspos;
14803 newredlb = (isminsettoinfinity ? SCIPinfinity(scip) : (consdata->lhs - minresactivity)/val);
14804 }
14805 if( rhsexists )
14806 {
14807 /* d*x + a*y <= rhs, d > 0 -> redundant in y if x <= (rhs - max{a*y})/d */
14808 nlocksup[arrayindex] += nlockspos;
14809 newredub = (ismaxsettoinfinity ? -SCIPinfinity(scip) : (consdata->rhs - maxresactivity)/val);
14810 }
14811 }
14812 else
14813 {
14814 if( lhsexists )
14815 {
14816 /* lhs <= d*x + a*y, d < 0 -> redundant in y if x <= (lhs - min{a*y})/d */
14817 nlocksup[arrayindex] += nlockspos;
14818 newredub = (isminsettoinfinity ? -SCIPinfinity(scip) : (consdata->lhs - minresactivity)/val);
14819 }
14820 if( rhsexists )
14821 {
14822 /* d*x + a*y <= rhs, d < 0 -> redundant in y if x >= (rhs - max{a*y})/d */
14823 nlocksdown[arrayindex] += nlockspos;
14824 newredlb = (ismaxsettoinfinity ? SCIPinfinity(scip) : (consdata->rhs - maxresactivity)/val);
14825 }
14826 }
14827
14828 /* if the variable is integer, we have to round the value to the next integral value */
14829 if( SCIPvarIsIntegral(var) )
14830 {
14831 if( !SCIPisInfinity(scip, newredlb) )
14832 newredlb = SCIPceil(scip, newredlb);
14833 if( !SCIPisInfinity(scip, -newredub) )
14834 newredub = SCIPfloor(scip, newredub);
14835 }
14836
14837 /* update redundancy bounds */
14838 redlb[arrayindex] = MAX(redlb[arrayindex], newredlb);
14839 redub[arrayindex] = MIN(redub[arrayindex], newredub);
14840
14841 /* collect the continuous variables of the constraint */
14842 if( SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS )
14843 {
14844 int contv;
14845
14846 assert(nconscontvars < ncontvars);
14847 contvarpos = i;
14848 conscontvars[nconscontvars] = var;
14849 nconscontvars++;
14850
14851 contv = SCIPvarGetProbindex(var) - nintvars;
14852 assert(0 <= contv && contv < ncontvars);
14853 hasimpliedpotential = hasimpliedpotential || isimplint[contv];
14854 }
14855 }
14856
14857 /* update implied integer status of continuous variables */
14858 if( hasimpliedpotential )
14859 {
14860 if( nconscontvars > 1 || !integralcoefs )
14861 {
14862 /* there is more than one continuous variable or the integer variables have fractional coefficients:
14863 * none of the continuous variables is implied integer
14864 */
14865 for( i = 0; i < nconscontvars; i++ )
14866 {
14867 int contv;
14868 contv = SCIPvarGetProbindex(conscontvars[i]) - nintvars;
14869 assert(0 <= contv && contv < ncontvars);
14870 isimplint[contv] = FALSE;
14871 }
14872 }
14873 else
14874 {
14875 SCIP_VAR* var;
14876 SCIP_Real val;
14877 SCIP_Real absval;
14878 int contv;
14879
14880 /* there is exactly one continuous variable and the integer variables have integral coefficients:
14881 * this is the interesting case, and we have to check whether the coefficient is +/-1 and the corresponding
14882 * side(s) of the constraint is integral
14883 */
14884 assert(nconscontvars == 1);
14885 assert(0 <= contvarpos && contvarpos < consdata->nvars);
14886 var = consdata->vars[contvarpos];
14887 val = consdata->vals[contvarpos];
14888 contv = SCIPvarGetProbindex(var) - nintvars;
14889 assert(0 <= contv && contv < ncontvars);
14890 assert(isimplint[contv]);
14891
14892 absval = REALABS(val);
14893 if( !SCIPisEQ(scip, absval, 1.0) )
14894 isimplint[contv] = FALSE;
14895 else
14896 {
14897 SCIP_Real obj;
14898
14899 obj = SCIPvarGetObj(var);
14900 if( obj * val >= 0.0 && lhsexists )
14901 {
14902 /* the variable may be blocked by the constraint's left hand side */
14903 isimplint[contv] = isimplint[contv] && SCIPisIntegral(scip, consdata->lhs);
14904 }
14905 if( obj * val <= 0.0 && rhsexists )
14906 {
14907 /* the variable may be blocked by the constraint's left hand side */
14908 isimplint[contv] = isimplint[contv] && SCIPisIntegral(scip, consdata->rhs);
14909 }
14910 }
14911 }
14912 }
14913 }
14914 }
14915
14916 /* check if any bounds can be tightened due to optimality */
14917 for( v = 0; v < nvars; ++v )
14918 {
14919 SCIP_VAR* var;
14920 SCIP_Real obj;
14921 SCIP_Bool infeasible;
14922 SCIP_Bool tightened;
14923
14924 assert(SCIPvarGetType(vars[v]) != SCIP_VARTYPE_BINARY);
14925 assert(SCIPvarGetNLocksDownType(vars[v], SCIP_LOCKTYPE_MODEL) >= nlocksdown[v]);
14926 assert(SCIPvarGetNLocksUpType(vars[v], SCIP_LOCKTYPE_MODEL) >= nlocksup[v]);
14927
14928 var = vars[v];
14929 obj = SCIPvarGetObj(var);
14930 if( obj >= 0.0 )
14931 {
14932 /* making the variable as small as possible does not increase the objective:
14933 * check if all down locks of the variables are due to linear constraints;
14934 * if largest bound to make constraints redundant is -infinity, we better do nothing for numerical reasons
14935 */
14936 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == nlocksdown[v]
14937 && !SCIPisInfinity(scip, -redlb[v])
14938 && redlb[v] < SCIPvarGetUbGlobal(var) )
14939 {
14940 SCIP_Real ub;
14941
14942 /* if x_v >= redlb[v], we can always round x_v down to x_v == redlb[v] without violating any constraint
14943 * -> tighten upper bound to x_v <= redlb[v]
14944 */
14945 SCIPdebugMsg(scip, "variable <%s> only locked down in linear constraints: dual presolve <%s>[%.15g,%.15g] <= %.15g\n",
14946 SCIPvarGetName(var), SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var),
14947 redlb[v]);
14948 SCIP_CALL( SCIPtightenVarUb(scip, var, redlb[v], FALSE, &infeasible, &tightened) );
14949 assert(!infeasible);
14950
14951 ub = SCIPvarGetUbGlobal(var);
14952 redub[v] = MIN(redub[v], ub);
14953 if( tightened )
14954 (*nchgbds)++;
14955 }
14956 }
14957 if( obj <= 0.0 )
14958 {
14959 /* making the variable as large as possible does not increase the objective:
14960 * check if all up locks of the variables are due to linear constraints;
14961 * if smallest bound to make constraints redundant is +infinity, we better do nothing for numerical reasons
14962 */
14963 if( SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == nlocksup[v]
14964 && !SCIPisInfinity(scip, redub[v])
14965 && redub[v] > SCIPvarGetLbGlobal(var) )
14966 {
14967 SCIP_Real lb;
14968
14969 /* if x_v <= redub[v], we can always round x_v up to x_v == redub[v] without violating any constraint
14970 * -> tighten lower bound to x_v >= redub[v]
14971 */
14972 SCIPdebugMsg(scip, "variable <%s> only locked up in linear constraints: dual presolve <%s>[%.15g,%.15g] >= %.15g\n",
14973 SCIPvarGetName(var), SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var),
14974 redub[v]);
14975 SCIP_CALL( SCIPtightenVarLb(scip, var, redub[v], FALSE, &infeasible, &tightened) );
14976 assert(!infeasible);
14977
14978 lb = SCIPvarGetLbGlobal(var);
14979 redlb[v] = MAX(redlb[v], lb);
14980 if( tightened )
14981 (*nchgbds)++;
14982 }
14983 }
14984 }
14985
14986 /* upgrade continuous variables to implied integers */
14987 for( v = nintvars - nbinvars; v < nvars; ++v )
14988 {
14989 SCIP_VAR* var;
14990 SCIP_Bool infeasible;
14991
14992 var = vars[v];
14993 assert(var != NULL);
14994
14995 assert(SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS);
14996 assert(SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) >= nlocksdown[v]);
14997 assert(SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) >= nlocksup[v]);
14998 assert(0 <= v - nintvars + nbinvars && v - nintvars + nbinvars < ncontvars);
14999
15000 /* we can only conclude implied integrality if the variable appears in no other constraint */
15001 if( isimplint[v - nintvars + nbinvars]
15002 && SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == nlocksdown[v]
15003 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == nlocksup[v] )
15004 {
15005 /* since we locally copied the variable array we can change the variable type immediately */
15006 SCIP_CALL( SCIPchgVarType(scip, var, SCIP_VARTYPE_IMPLINT, &infeasible) );
15007
15008 if( infeasible )
15009 {
15010 SCIPdebugMsg(scip, "infeasible upgrade of variable <%s> to integral type, domain is empty\n", SCIPvarGetName(var));
15011 *cutoff = TRUE;
15012
15013 break;
15014 }
15015
15016 SCIPdebugMsg(scip, "dual presolve: converting continuous variable <%s>[%g,%g] to implicit integer\n",
15017 SCIPvarGetName(var), SCIPvarGetLbGlobal(var), SCIPvarGetUbGlobal(var));
15018 }
15019 }
15020
15021 /* free temporary memory */
15022 SCIPfreeBufferArray(scip, &conscontvars);
15023 SCIPfreeBufferArray(scip, &isimplint);
15024 SCIPfreeBufferArray(scip, &nlocksup);
15025 SCIPfreeBufferArray(scip, &nlocksdown);
15026 SCIPfreeBufferArray(scip, &redub);
15027 SCIPfreeBufferArray(scip, &redlb);
15028
15029 SCIPfreeBufferArray(scip, &vars);
15030
15031 return SCIP_OKAY;
15032 }
15033
15034 /** helper function to enforce constraints */
15035 static
enforceConstraint(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_CONS ** conss,int nconss,int nusefulconss,SCIP_SOL * sol,SCIP_RESULT * result)15036 SCIP_RETCODE enforceConstraint(
15037 SCIP* scip, /**< SCIP data structure */
15038 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
15039 SCIP_CONS** conss, /**< constraints to process */
15040 int nconss, /**< number of constraints */
15041 int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
15042 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
15043 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
15044 )
15045 {
15046 SCIP_CONSHDLRDATA* conshdlrdata;
15047 SCIP_Bool checkrelmaxabs;
15048 SCIP_Bool violated;
15049 SCIP_Bool cutoff = FALSE;
15050 int c;
15051
15052 assert(scip != NULL);
15053 assert(conshdlr != NULL);
15054 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
15055 assert(result != NULL);
15056
15057 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15058 assert(conshdlrdata != NULL);
15059
15060 checkrelmaxabs = conshdlrdata->checkrelmaxabs;
15061
15062 SCIPdebugMsg(scip, "Enforcement method of linear constraints for %s solution\n", sol == NULL ? "LP" : "relaxation");
15063
15064 /* check for violated constraints
15065 * LP is processed at current node -> we can add violated linear constraints to the SCIP_LP
15066 */
15067 *result = SCIP_FEASIBLE;
15068
15069 /* check all useful linear constraints for feasibility */
15070 for( c = 0; c < nusefulconss; ++c )
15071 {
15072 SCIP_CALL( checkCons(scip, conss[c], sol, FALSE, checkrelmaxabs, &violated) );
15073
15074 if( violated )
15075 {
15076 /* insert LP row as cut */
15077 SCIP_CALL( addRelaxation(scip, conss[c], &cutoff) );
15078 if ( cutoff )
15079 *result = SCIP_CUTOFF;
15080 else
15081 *result = SCIP_SEPARATED;
15082 }
15083 }
15084
15085 /* check all obsolete linear constraints for feasibility */
15086 for( c = nusefulconss; c < nconss && *result == SCIP_FEASIBLE; ++c )
15087 {
15088 SCIP_CALL( checkCons(scip, conss[c], sol, FALSE, checkrelmaxabs, &violated) );
15089
15090 if( violated )
15091 {
15092 /* insert LP row as cut */
15093 SCIP_CALL( addRelaxation(scip, conss[c], &cutoff) );
15094 if ( cutoff )
15095 *result = SCIP_CUTOFF;
15096 else
15097 *result = SCIP_SEPARATED;
15098 }
15099 }
15100
15101 SCIPdebugMsg(scip, "-> constraints checked, %s\n", *result == SCIP_FEASIBLE ? "all constraints feasible" : "infeasibility detected");
15102
15103 return SCIP_OKAY;
15104 }
15105
15106 /*
15107 * Callback methods of constraint handler
15108 */
15109
15110 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
15111 static
SCIP_DECL_CONSHDLRCOPY(conshdlrCopyLinear)15112 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyLinear)
15113 { /*lint --e{715}*/
15114 assert(scip != NULL);
15115 assert(conshdlr != NULL);
15116 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
15117
15118 /* call inclusion method of constraint handler */
15119 SCIP_CALL( SCIPincludeConshdlrLinear(scip) );
15120
15121 *valid = TRUE;
15122
15123 return SCIP_OKAY;
15124 }
15125
15126 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
15127 static
SCIP_DECL_CONSFREE(consFreeLinear)15128 SCIP_DECL_CONSFREE(consFreeLinear)
15129 { /*lint --e{715}*/
15130 SCIP_CONSHDLRDATA* conshdlrdata;
15131
15132 assert(scip != NULL);
15133 assert(conshdlr != NULL);
15134 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
15135
15136 /* free constraint handler data */
15137 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15138 assert(conshdlrdata != NULL);
15139
15140 conshdlrdataFree(scip, &conshdlrdata);
15141
15142 SCIPconshdlrSetData(conshdlr, NULL);
15143
15144 return SCIP_OKAY;
15145 }
15146
15147
15148 /** initialization method of constraint handler (called after problem was transformed) */
15149 static
SCIP_DECL_CONSINIT(consInitLinear)15150 SCIP_DECL_CONSINIT(consInitLinear)
15151 {
15152 SCIP_CONSHDLRDATA* conshdlrdata;
15153 int c;
15154
15155 assert(scip != NULL);
15156
15157 /* check for event handler */
15158 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15159 assert(conshdlrdata != NULL);
15160 assert(conshdlrdata->eventhdlr != NULL);
15161 assert(nconss == 0 || conss != NULL);
15162
15163 /* catch events for the constraints */
15164 for( c = 0; c < nconss; ++c )
15165 {
15166 /* catch all events */
15167 SCIP_CALL( consCatchAllEvents(scip, conss[c], conshdlrdata->eventhdlr) );
15168 }
15169
15170 return SCIP_OKAY;
15171 }
15172
15173
15174 /** deinitialization method of constraint handler (called before transformed problem is freed) */
15175 static
SCIP_DECL_CONSEXIT(consExitLinear)15176 SCIP_DECL_CONSEXIT(consExitLinear)
15177 {
15178 SCIP_CONSHDLRDATA* conshdlrdata;
15179 int c;
15180
15181 assert(scip != NULL);
15182
15183 /* check for event handler */
15184 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15185 assert(conshdlrdata != NULL);
15186 assert(conshdlrdata->eventhdlr != NULL);
15187
15188 /* drop events for the constraints */
15189 for( c = nconss - 1; c >= 0; --c )
15190 {
15191 SCIP_CONSDATA* consdata;
15192
15193 consdata = SCIPconsGetData(conss[c]);
15194 assert(consdata != NULL);
15195
15196 if( consdata->eventdata != NULL )
15197 {
15198 /* drop all events */
15199 SCIP_CALL( consDropAllEvents(scip, conss[c], conshdlrdata->eventhdlr) );
15200 assert(consdata->eventdata == NULL);
15201 }
15202 }
15203
15204 return SCIP_OKAY;
15205 }
15206
15207 /** is constraint ranged row, i.e., -inf < lhs < rhs < inf? */
15208 static
isRangedRow(SCIP * scip,SCIP_Real lhs,SCIP_Real rhs)15209 SCIP_Bool isRangedRow(
15210 SCIP* scip, /**< SCIP data structure */
15211 SCIP_Real lhs, /**< left hand side */
15212 SCIP_Real rhs /**< right hand side */
15213 )
15214 {
15215 assert(scip != NULL);
15216
15217 return !(SCIPisEQ(scip, lhs, rhs) || SCIPisInfinity(scip, -lhs) || SCIPisInfinity(scip, rhs) );
15218 }
15219
15220 /** is constraint ranged row, i.e., -inf < lhs < rhs < inf? */
15221 static
isFiniteNonnegativeIntegral(SCIP * scip,SCIP_Real x)15222 SCIP_Bool isFiniteNonnegativeIntegral(
15223 SCIP* scip, /**< SCIP data structure */
15224 SCIP_Real x /**< value */
15225 )
15226 {
15227 assert(scip != NULL);
15228
15229 return (!SCIPisInfinity(scip, x) && !SCIPisNegative(scip, x) && SCIPisIntegral(scip, x));
15230 }
15231
15232 /** performs linear constraint type classification as used for MIPLIB
15233 *
15234 * iterates through all linear constraints and stores relevant statistics in the linear constraint statistics \p linconsstats.
15235 *
15236 * @note only constraints are iterated that belong to the linear constraint handler. If the problem has been presolved already,
15237 * constraints that were upgraded to more special types such as, e.g., varbound constraints, will not be shown correctly anymore.
15238 * Similarly, if specialized constraints were created through the API, these are currently not present.
15239 */
SCIPclassifyConstraintTypesLinear(SCIP * scip,SCIP_LINCONSSTATS * linconsstats)15240 SCIP_RETCODE SCIPclassifyConstraintTypesLinear(
15241 SCIP* scip, /**< SCIP data structure */
15242 SCIP_LINCONSSTATS* linconsstats /**< linear constraint type classification */
15243 )
15244 {
15245 int c;
15246 SCIP_CONSHDLR* conshdlr;
15247 SCIP_CONS** conss;
15248 int nconss;
15249
15250 assert(scip != NULL);
15251 assert(linconsstats != NULL);
15252 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
15253 assert(conshdlr != NULL);
15254
15255 if( SCIPgetStage(scip) == SCIP_STAGE_PROBLEM )
15256 {
15257 conss = SCIPgetConss(scip);
15258 nconss = SCIPgetNConss(scip);
15259 }
15260 else
15261 {
15262 conss = SCIPconshdlrGetConss(conshdlr);
15263 nconss = SCIPconshdlrGetNConss(conshdlr);
15264 }
15265
15266 /* reset linear constraint type classification */
15267 SCIPlinConsStatsReset(linconsstats);
15268
15269 /* loop through all constraints */
15270 for( c = 0; c < nconss; c++ )
15271 {
15272 SCIP_CONS* cons;
15273 SCIP_CONSDATA* consdata;
15274 SCIP_Real lhs;
15275 SCIP_Real rhs;
15276 int i;
15277
15278 /* get constraint */
15279 cons = conss[c];
15280 assert(cons != NULL);
15281
15282 /* skip constraints that are not handled by the constraint handler */
15283 if( SCIPconsGetHdlr(cons) != conshdlr )
15284 continue;
15285
15286 /* get constraint data */
15287 consdata = SCIPconsGetData(cons);
15288 assert(consdata != NULL);
15289 rhs = consdata->rhs;
15290 lhs = consdata->lhs;
15291
15292 /* merge multiples and delete variables with zero coefficient */
15293 SCIP_CALL( mergeMultiples(scip, cons) );
15294 for( i = 0; i < consdata->nvars; i++ )
15295 {
15296 assert(!SCIPisZero(scip, consdata->vals[i]));
15297 }
15298
15299 /* is constraint of type SCIP_CONSTYPE_EMPTY? */
15300 if( consdata->nvars == 0 )
15301 {
15302 SCIPdebugMsg(scip, "classified as EMPTY: ");
15303 SCIPdebugPrintCons(scip, cons, NULL);
15304 SCIPlinConsStatsIncTypeCount(linconsstats, SCIP_LINCONSTYPE_EMPTY, 1);
15305
15306 continue;
15307 }
15308
15309 /* is constraint of type SCIP_CONSTYPE_FREE? */
15310 if( SCIPisInfinity(scip, rhs) && SCIPisInfinity(scip, -lhs) )
15311 {
15312 SCIPdebugMsg(scip, "classified as FREE: ");
15313 SCIPdebugPrintCons(scip, cons, NULL);
15314 SCIPlinConsStatsIncTypeCount(linconsstats, SCIP_LINCONSTYPE_FREE, 1);
15315
15316 continue;
15317 }
15318
15319 /* is constraint of type SCIP_CONSTYPE_SINGLETON? */
15320 if( consdata->nvars == 1 )
15321 {
15322 SCIPdebugMsg(scip, "classified as SINGLETON: ");
15323 SCIPdebugPrintCons(scip, cons, NULL);
15324 SCIPlinConsStatsIncTypeCount(linconsstats, SCIP_LINCONSTYPE_SINGLETON, isRangedRow(scip, lhs, rhs) ? 2 : 1);
15325
15326 continue;
15327 }
15328
15329 /* is constraint of type SCIP_CONSTYPE_AGGREGATION? */
15330 if( consdata->nvars == 2 && SCIPisEQ(scip, lhs, rhs) )
15331 {
15332 SCIPdebugMsg(scip, "classified as AGGREGATION: ");
15333 SCIPdebugPrintCons(scip, cons, NULL);
15334 SCIPlinConsStatsIncTypeCount(linconsstats, SCIP_LINCONSTYPE_AGGREGATION, 1);
15335
15336 continue;
15337 }
15338
15339 /* is constraint of type SCIP_CONSTYPE_{VARBOUND,PRECEDENCE}? */
15340 if( consdata->nvars == 2 )
15341 {
15342 SCIP_LINCONSTYPE constype;
15343
15344 /* precedence constraints have the same coefficient, but with opposite sign for the same variable type */
15345 if( SCIPisEQ(scip, consdata->vals[0], -consdata->vals[1])
15346 && SCIPvarGetType(consdata->vars[0]) == SCIPvarGetType(consdata->vars[1]))
15347 {
15348 constype = SCIP_LINCONSTYPE_PRECEDENCE;
15349 SCIPdebugMsg(scip, "classified as PRECEDENCE: ");
15350 }
15351 else
15352 {
15353 constype = SCIP_LINCONSTYPE_VARBOUND;
15354 SCIPdebugMsg(scip, "classified as VARBOUND: ");
15355 }
15356 SCIPdebugPrintCons(scip, cons, NULL);
15357
15358 SCIPlinConsStatsIncTypeCount(linconsstats, constype, isRangedRow(scip, lhs, rhs) ? 2 : 1);
15359
15360 continue;
15361 }
15362
15363 /* is constraint of type SCIP_CONSTYPE_{SETPARTITION, SETPACKING, SETCOVERING, CARDINALITY, INVKNAPSACK}? */
15364 {
15365 SCIP_Real scale;
15366 SCIP_Real b;
15367 SCIP_Bool unmatched;
15368 int nnegbinvars;
15369
15370 unmatched = FALSE;
15371 nnegbinvars = 0;
15372
15373 scale = REALABS(consdata->vals[0]);
15374
15375 /* scan through variables and detect if all variables are binary and have a coefficient +/-1 */
15376 for( i = 0; i < consdata->nvars && !unmatched; i++ )
15377 {
15378 unmatched = unmatched || SCIPvarGetType(consdata->vars[i]) == SCIP_VARTYPE_CONTINUOUS;
15379 unmatched = unmatched || SCIPisLE(scip, SCIPvarGetLbGlobal(consdata->vars[i]), -1.0);
15380 unmatched = unmatched || SCIPisGE(scip, SCIPvarGetUbGlobal(consdata->vars[i]), 2.0);
15381 unmatched = unmatched || !SCIPisEQ(scip, REALABS(consdata->vals[i]), scale);
15382
15383 if( consdata->vals[i] < 0.0 )
15384 nnegbinvars++;
15385 }
15386
15387 if( !unmatched )
15388 {
15389 if( SCIPisEQ(scip, lhs, rhs) )
15390 {
15391 b = rhs/scale + nnegbinvars;
15392 if( SCIPisEQ(scip, 1.0, b) )
15393 {
15394 SCIPdebugMsg(scip, "classified as SETPARTITION: ");
15395 SCIPdebugPrintCons(scip, cons, NULL);
15396 SCIPlinConsStatsIncTypeCount(linconsstats, SCIP_LINCONSTYPE_SETPARTITION, 1);
15397
15398 continue;
15399 }
15400 else if( SCIPisIntegral(scip, b) && !SCIPisNegative(scip, b) )
15401 {
15402 SCIPdebugMsg(scip, "classified as CARDINALITY: ");
15403 SCIPdebugPrintCons(scip, cons, NULL);
15404 SCIPlinConsStatsIncTypeCount(linconsstats, SCIP_LINCONSTYPE_CARDINALITY, 1);
15405
15406 continue;
15407 }
15408 }
15409
15410 /* compute right hand side divided by scale */
15411 if( !SCIPisInfinity(scip, rhs) )
15412 b = rhs/scale + nnegbinvars;
15413 else
15414 b = SCIPinfinity(scip);
15415
15416 if( SCIPisEQ(scip, 1.0, b) )
15417 {
15418 SCIPdebugMsg(scip, "classified as SETPACKING: ");
15419 SCIPdebugPrintCons(scip, cons, NULL);
15420 SCIPlinConsStatsIncTypeCount(linconsstats, SCIP_LINCONSTYPE_SETPACKING, 1);
15421
15422 /* relax right hand side to prevent further classifications */
15423 rhs = SCIPinfinity(scip);
15424 }
15425 else if( !SCIPisInfinity(scip, b) && SCIPisIntegral(scip, b) && !SCIPisNegative(scip, b) )
15426 {
15427 SCIPdebugMsg(scip, "classified as INVKNAPSACK: ");
15428 SCIPdebugPrintCons(scip, cons, NULL);
15429
15430 SCIPlinConsStatsIncTypeCount(linconsstats, SCIP_LINCONSTYPE_INVKNAPSACK, 1);;
15431
15432 /* relax right hand side to prevent further classifications */
15433 rhs = SCIPinfinity(scip);
15434 }
15435
15436 if( !SCIPisInfinity(scip, lhs) )
15437 b = lhs/scale + nnegbinvars;
15438 else
15439 b = SCIPinfinity(scip);
15440
15441 if( SCIPisEQ(scip, 1.0, b) )
15442 {
15443 SCIPdebugMsg(scip, "classified as SETCOVERING: ");
15444 SCIPdebugPrintCons(scip, cons, NULL);
15445 SCIPlinConsStatsIncTypeCount(linconsstats, SCIP_LINCONSTYPE_SETCOVERING, 1);
15446
15447 /* relax left hand side to prevent further classifications */
15448 lhs = -SCIPinfinity(scip);
15449 }
15450
15451 /* if both sides are infinite at this point, no further classification is necessary for this constraint */
15452 if( SCIPisInfinity(scip, -lhs) && SCIPisInfinity(scip, rhs) )
15453 continue;
15454 }
15455 }
15456
15457 /* is constraint of type SCIP_CONSTYPE_{EQKNAPSACK, BINPACKING, KNAPSACK}? */
15458 /* @todo If coefficients or rhs are not integral, we currently do not check
15459 * if the constraint could be scaled (finitely), such that they are.
15460 */
15461 {
15462 SCIP_Real b;
15463 SCIP_Bool unmatched;
15464
15465 b = rhs;
15466 unmatched = FALSE;
15467 for( i = 0; i < consdata->nvars && !unmatched; i++ )
15468 {
15469 unmatched = unmatched || SCIPvarGetType(consdata->vars[i]) == SCIP_VARTYPE_CONTINUOUS;
15470 unmatched = unmatched || SCIPisLE(scip, SCIPvarGetLbGlobal(consdata->vars[i]), -1.0);
15471 unmatched = unmatched || SCIPisGE(scip, SCIPvarGetUbGlobal(consdata->vars[i]), 2.0);
15472 unmatched = unmatched || !SCIPisIntegral(scip, consdata->vals[i]);
15473
15474 if( SCIPisNegative(scip, consdata->vals[i]) )
15475 b -= consdata->vals[i];
15476 }
15477 unmatched = unmatched || !isFiniteNonnegativeIntegral(scip, b);
15478
15479 if( !unmatched )
15480 {
15481 if( SCIPisEQ(scip, lhs, rhs) )
15482 {
15483 SCIPdebugMsg(scip, "classified as EQKNAPSACK: ");
15484 SCIPdebugPrintCons(scip, cons, NULL);
15485
15486 SCIPlinConsStatsIncTypeCount(linconsstats, SCIP_LINCONSTYPE_EQKNAPSACK, 1);
15487
15488 continue;
15489 }
15490 else
15491 {
15492 SCIP_Bool matched;
15493
15494 matched = FALSE;
15495 for( i = 0; i < consdata->nvars && !matched; i++ )
15496 {
15497 matched = matched || SCIPisEQ(scip, b, REALABS(consdata->vals[i]));
15498 }
15499
15500 SCIPdebugMsg(scip, "classified as %s: ", matched ? "BINPACKING" : "KNAPSACK");
15501 SCIPdebugPrintCons(scip, cons, NULL);
15502 SCIPlinConsStatsIncTypeCount(linconsstats, matched ? SCIP_LINCONSTYPE_BINPACKING : SCIP_LINCONSTYPE_KNAPSACK, 1);
15503 }
15504
15505 /* check if finite left hand side allows for a second classification, relax already used right hand side */
15506 if( SCIPisInfinity(scip, -lhs) )
15507 continue;
15508 else
15509 rhs = SCIPinfinity(scip);
15510 }
15511 }
15512
15513 /* is constraint of type SCIP_CONSTYPE_{INTKNAPSACK}? */
15514 {
15515 SCIP_Real b;
15516 SCIP_Bool unmatched;
15517
15518 unmatched = FALSE;
15519
15520 b = rhs;
15521 unmatched = unmatched || !isFiniteNonnegativeIntegral(scip, b);
15522
15523 for( i = 0; i < consdata->nvars && !unmatched; i++ )
15524 {
15525 unmatched = unmatched || SCIPvarGetType(consdata->vars[i]) == SCIP_VARTYPE_CONTINUOUS;
15526 unmatched = unmatched || SCIPisNegative(scip, SCIPvarGetLbGlobal(consdata->vars[i]));
15527 unmatched = unmatched || !SCIPisIntegral(scip, consdata->vals[i]);
15528 unmatched = unmatched || SCIPisNegative(scip, consdata->vals[i]);
15529 }
15530
15531 if( !unmatched )
15532 {
15533 SCIPdebugMsg(scip, "classified as INTKNAPSACK: ");
15534 SCIPdebugPrintCons(scip, cons, NULL);
15535 SCIPlinConsStatsIncTypeCount(linconsstats, SCIP_LINCONSTYPE_INTKNAPSACK, 1);
15536
15537 /* check if finite left hand side allows for a second classification, relax already used right hand side */
15538 if( SCIPisInfinity(scip, -lhs) )
15539 continue;
15540 else
15541 rhs = SCIPinfinity(scip);
15542 }
15543 }
15544
15545 /* is constraint of type SCIP_CONSTYPE_{MIXEDBINARY}? */
15546 {
15547 SCIP_Bool unmatched;
15548
15549 unmatched = FALSE;
15550 for( i = 0; i < consdata->nvars && !unmatched; i++ )
15551 {
15552 if( SCIPvarGetType(consdata->vars[i]) != SCIP_VARTYPE_CONTINUOUS
15553 && (SCIPisLE(scip, SCIPvarGetLbGlobal(consdata->vars[i]), -1.0)
15554 || SCIPisGE(scip, SCIPvarGetUbGlobal(consdata->vars[i]), 2.0)) )
15555 unmatched = TRUE;
15556 }
15557
15558 if( !unmatched )
15559 {
15560 SCIPdebugMsg(scip, "classified as MIXEDBINARY (%d): ", isRangedRow(scip, lhs, rhs) ? 2 : 1);
15561 SCIPdebugPrintCons(scip, cons, NULL);
15562 SCIPlinConsStatsIncTypeCount(linconsstats, SCIP_LINCONSTYPE_MIXEDBINARY, isRangedRow(scip, lhs, rhs) ? 2 : 1);
15563
15564 continue;
15565 }
15566 }
15567
15568 /* no special structure detected */
15569 SCIPdebugMsg(scip, "classified as GENERAL: ");
15570 SCIPdebugPrintCons(scip, cons, NULL);
15571 SCIPlinConsStatsIncTypeCount(linconsstats, SCIP_LINCONSTYPE_GENERAL, isRangedRow(scip, lhs, rhs) ? 2 : 1);
15572 }
15573
15574 return SCIP_OKAY;
15575 }
15576
15577
15578 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
15579 static
SCIP_DECL_CONSEXITPRE(consExitpreLinear)15580 SCIP_DECL_CONSEXITPRE(consExitpreLinear)
15581 { /*lint --e{715}*/
15582 int c;
15583 #ifdef SCIP_STATISTIC
15584 SCIP_CONSHDLRDATA* conshdlrdata;
15585 int ngoodconss;
15586 int nallconss;
15587 #endif
15588
15589 /* delete all linear constraints that were upgraded to a more specific constraint type;
15590 * make sure, only active variables remain in the remaining constraints
15591 */
15592 assert(scip != NULL);
15593
15594 #ifdef SCIP_STATISTIC
15595 /* count number of well behaved linear constraints */
15596 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15597 assert(conshdlrdata != NULL);
15598
15599 ngoodconss = 0;
15600 nallconss = 0;
15601
15602 for( c = 0; c < nconss; ++c )
15603 {
15604 SCIP_CONSDATA* consdata;
15605
15606 if( SCIPconsIsDeleted(conss[c]) )
15607 continue;
15608
15609 consdata = SCIPconsGetData(conss[c]);
15610 assert(consdata != NULL);
15611
15612 if( consdata->upgraded )
15613 continue;
15614
15615 nallconss++;
15616
15617 consdataRecomputeMaxActivityDelta(scip, consdata);
15618
15619 if( SCIPisLT(scip, consdata->maxactdelta, conshdlrdata->maxeasyactivitydelta) )
15620 ngoodconss++;
15621 }
15622 if( nallconss )
15623 {
15624 SCIPstatisticMessage("below threshold: %d / %d ratio= %g\n", ngoodconss, nallconss, (100.0 * ngoodconss / nallconss));
15625 }
15626 #endif
15627
15628 for( c = 0; c < nconss; ++c )
15629 {
15630 SCIP_CONSDATA* consdata;
15631
15632 if( SCIPconsIsDeleted(conss[c]) )
15633 continue;
15634
15635 consdata = SCIPconsGetData(conss[c]);
15636 assert(consdata != NULL);
15637
15638 if( consdata->upgraded )
15639 {
15640 /* this is no problem reduction, because the upgraded constraint was added to the problem before, and the
15641 * (redundant) linear constraint was only kept in order to support presolving the the linear constraint handler
15642 */
15643 SCIP_CALL( SCIPdelCons(scip, conss[c]) );
15644 }
15645 else
15646 {
15647 /* since we are not allowed to detect infeasibility in the exitpre stage, we dont give an infeasible pointer */
15648 SCIP_CALL( applyFixings(scip, conss[c], NULL) );
15649 }
15650 }
15651
15652 return SCIP_OKAY;
15653 }
15654
15655
15656 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
15657 static
SCIP_DECL_CONSEXITSOL(consExitsolLinear)15658 SCIP_DECL_CONSEXITSOL(consExitsolLinear)
15659 { /*lint --e{715}*/
15660 int c;
15661
15662 assert(scip != NULL);
15663
15664 /* release the rows of all constraints */
15665 for( c = 0; c < nconss; ++c )
15666 {
15667 SCIP_CONSDATA* consdata;
15668
15669 consdata = SCIPconsGetData(conss[c]);
15670 assert(consdata != NULL);
15671
15672 if( consdata->row != NULL )
15673 {
15674 SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
15675 }
15676 }
15677
15678 /* if this is a restart, convert cutpool rows into linear constraints */
15679 if( restart )
15680 {
15681 int ncutsadded;
15682
15683 ncutsadded = 0;
15684
15685 /* create out of all active cuts in cutpool linear constraints */
15686 SCIP_CALL( SCIPconvertCutsToConss(scip, NULL, NULL, TRUE, &ncutsadded) );
15687
15688 if( ncutsadded > 0 )
15689 {
15690 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL,
15691 "(restart) converted %d cuts from the global cut pool into linear constraints\n", ncutsadded);
15692 /* an extra blank line should be printed separately since the buffer message handler only handles up to one
15693 * line correctly
15694 */
15695 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "\n");
15696 }
15697 }
15698
15699 return SCIP_OKAY;
15700 }
15701
15702
15703 /** constraint deactivation notification method of constraint handler */
15704 static
SCIP_DECL_CONSDEACTIVE(consDeactiveLinear)15705 SCIP_DECL_CONSDEACTIVE(consDeactiveLinear)
15706 { /*lint --e{715}*/
15707 assert( cons != NULL );
15708
15709 if( SCIPconsIsDeleted(cons) )
15710 {
15711 SCIP_CONSHDLRDATA* conshdlrdata;
15712 SCIP_CONSDATA* consdata;
15713
15714 assert(scip != NULL);
15715 assert(conshdlr != NULL);
15716 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
15717
15718 /* get constraint data */
15719 consdata = SCIPconsGetData(cons);
15720 assert(consdata != NULL);
15721
15722 /* check for event handler */
15723 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15724 assert(conshdlrdata != NULL);
15725 assert(conshdlrdata->eventhdlr != NULL);
15726
15727 /* free event data */
15728 if( consdata->eventdata != NULL )
15729 {
15730 /* drop bound change events of variables */
15731 SCIP_CALL( consDropAllEvents(scip, cons, conshdlrdata->eventhdlr) );
15732 }
15733 assert(consdata->eventdata == NULL);
15734 }
15735
15736 return SCIP_OKAY;
15737 }
15738
15739
15740 /** frees specific constraint data */
15741 static
SCIP_DECL_CONSDELETE(consDeleteLinear)15742 SCIP_DECL_CONSDELETE(consDeleteLinear)
15743 { /*lint --e{715}*/
15744 assert(scip != NULL);
15745 assert(conshdlr != NULL);
15746 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
15747
15748 if( (*consdata)->eventdata != NULL )
15749 {
15750 SCIP_CONSHDLRDATA* conshdlrdata;
15751
15752 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15753 assert(conshdlrdata != NULL);
15754
15755 /* drop all events */
15756 SCIP_CALL( consDropAllEvents(scip, cons, conshdlrdata->eventhdlr) );
15757 assert((*consdata)->eventdata == NULL);
15758 }
15759
15760 /* free linear constraint */
15761 SCIP_CALL( consdataFree(scip, consdata) );
15762
15763 return SCIP_OKAY;
15764 }
15765
15766
15767 /** transforms constraint data into data belonging to the transformed problem */
15768 static
SCIP_DECL_CONSTRANS(consTransLinear)15769 SCIP_DECL_CONSTRANS(consTransLinear)
15770 { /*lint --e{715}*/
15771 SCIP_CONSDATA* sourcedata;
15772 SCIP_CONSDATA* targetdata;
15773
15774 /*debugMsg(scip, "Trans method of linear constraints\n");*/
15775
15776 assert(scip != NULL);
15777 assert(conshdlr != NULL);
15778 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
15779 assert(SCIPgetStage(scip) == SCIP_STAGE_TRANSFORMING);
15780 assert(sourcecons != NULL);
15781 assert(targetcons != NULL);
15782
15783 sourcedata = SCIPconsGetData(sourcecons);
15784 assert(sourcedata != NULL);
15785 assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */
15786
15787 /* create linear constraint data for target constraint */
15788 SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->nvars, sourcedata->vars, sourcedata->vals, sourcedata->lhs, sourcedata->rhs) );
15789
15790 #ifndef NDEBUG
15791 /* if this is a checked or enforced constraints, then there must be no relaxation-only variables */
15792 if( SCIPconsIsEnforced(sourcecons) || SCIPconsIsChecked(sourcecons) )
15793 {
15794 int n;
15795 for(n = targetdata->nvars - 1; n >= 0; --n )
15796 assert(!SCIPvarIsRelaxationOnly(targetdata->vars[n]));
15797 }
15798 #endif
15799
15800 /* create target constraint */
15801 SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
15802 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
15803 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
15804 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
15805 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
15806
15807 return SCIP_OKAY;
15808 }
15809
15810
15811 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
15812 static
SCIP_DECL_CONSINITLP(consInitlpLinear)15813 SCIP_DECL_CONSINITLP(consInitlpLinear)
15814 { /*lint --e{715}*/
15815 int c;
15816
15817 assert(scip != NULL);
15818 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
15819
15820 *infeasible = FALSE;
15821
15822 for( c = 0; c < nconss && !(*infeasible); ++c )
15823 {
15824 assert(SCIPconsIsInitial(conss[c]));
15825 SCIP_CALL( addRelaxation(scip, conss[c], infeasible) );
15826 }
15827
15828 return SCIP_OKAY;
15829 }
15830
15831
15832 /** separation method of constraint handler for LP solutions */
15833 static
SCIP_DECL_CONSSEPALP(consSepalpLinear)15834 SCIP_DECL_CONSSEPALP(consSepalpLinear)
15835 { /*lint --e{715}*/
15836 SCIP_CONSHDLRDATA* conshdlrdata;
15837 SCIP_Real loclowerbound;
15838 SCIP_Real glblowerbound;
15839 SCIP_Real cutoffbound;
15840 SCIP_Real maxbound;
15841 SCIP_Bool separatecards;
15842 SCIP_Bool cutoff;
15843 int c;
15844 int depth;
15845 int nrounds;
15846 int maxsepacuts;
15847 int ncuts;
15848
15849 assert(scip != NULL);
15850 assert(conshdlr != NULL);
15851 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
15852 assert(result != NULL);
15853
15854 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15855 assert(conshdlrdata != NULL);
15856 depth = SCIPgetDepth(scip);
15857 nrounds = SCIPgetNSepaRounds(scip);
15858
15859 /*debugMsg(scip, "Sepa method of linear constraints\n");*/
15860
15861 *result = SCIP_DIDNOTRUN;
15862
15863 /* only call the separator a given number of times at each node */
15864 if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
15865 || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
15866 return SCIP_OKAY;
15867
15868 /* get the maximal number of cuts allowed in a separation round */
15869 maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
15870
15871 /* check if we want to produce knapsack cardinality cuts at this node */
15872 loclowerbound = SCIPgetLocalLowerbound(scip);
15873 glblowerbound = SCIPgetLowerbound(scip);
15874 cutoffbound = SCIPgetCutoffbound(scip);
15875 maxbound = glblowerbound + conshdlrdata->maxcardbounddist * (cutoffbound - glblowerbound);
15876 separatecards = SCIPisLE(scip, loclowerbound, maxbound);
15877 separatecards = separatecards && (SCIPgetNLPBranchCands(scip) > 0);
15878
15879 *result = SCIP_DIDNOTFIND;
15880 ncuts = 0;
15881 cutoff = FALSE;
15882
15883 /* check all useful linear constraints for feasibility */
15884 for( c = 0; c < nusefulconss && ncuts < maxsepacuts && !cutoff; ++c )
15885 {
15886 /*debugMsg(scip, "separating linear constraint <%s>\n", SCIPconsGetName(conss[c]));*/
15887 SCIP_CALL( separateCons(scip, conss[c], conshdlrdata, NULL, separatecards, conshdlrdata->separateall, &ncuts, &cutoff) );
15888 }
15889
15890 /* adjust return value */
15891 if( cutoff )
15892 *result = SCIP_CUTOFF;
15893 else if( ncuts > 0 )
15894 *result = SCIP_SEPARATED;
15895
15896 /* combine linear constraints to get more cuts */
15897 /**@todo further cuts of linear constraints */
15898
15899 return SCIP_OKAY;
15900 }
15901
15902
15903 /** separation method of constraint handler for arbitrary primal solutions */
15904 static
SCIP_DECL_CONSSEPASOL(consSepasolLinear)15905 SCIP_DECL_CONSSEPASOL(consSepasolLinear)
15906 { /*lint --e{715}*/
15907 SCIP_CONSHDLRDATA* conshdlrdata;
15908 int c;
15909 int depth;
15910 int nrounds;
15911 int maxsepacuts;
15912 int ncuts;
15913 SCIP_Bool cutoff;
15914
15915 assert(scip != NULL);
15916 assert(conshdlr != NULL);
15917 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
15918 assert(result != NULL);
15919
15920 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15921 assert(conshdlrdata != NULL);
15922 depth = SCIPgetDepth(scip);
15923 nrounds = SCIPgetNSepaRounds(scip);
15924
15925 /*debugMsg(scip, "Sepa method of linear constraints\n");*/
15926
15927 *result = SCIP_DIDNOTRUN;
15928
15929 /* only call the separator a given number of times at each node */
15930 if( (depth == 0 && conshdlrdata->maxroundsroot >= 0 && nrounds >= conshdlrdata->maxroundsroot)
15931 || (depth > 0 && conshdlrdata->maxrounds >= 0 && nrounds >= conshdlrdata->maxrounds) )
15932 return SCIP_OKAY;
15933
15934 /* get the maximal number of cuts allowed in a separation round */
15935 maxsepacuts = (depth == 0 ? conshdlrdata->maxsepacutsroot : conshdlrdata->maxsepacuts);
15936
15937 *result = SCIP_DIDNOTFIND;
15938 ncuts = 0;
15939 cutoff = FALSE;
15940
15941 /* check all useful linear constraints for feasibility */
15942 for( c = 0; c < nusefulconss && ncuts < maxsepacuts && !cutoff; ++c )
15943 {
15944 /*debugMsg(scip, "separating linear constraint <%s>\n", SCIPconsGetName(conss[c]));*/
15945 SCIP_CALL( separateCons(scip, conss[c], conshdlrdata, sol, TRUE, conshdlrdata->separateall, &ncuts, &cutoff) );
15946 }
15947
15948 /* adjust return value */
15949 if( cutoff )
15950 *result = SCIP_CUTOFF;
15951 else if( ncuts > 0 )
15952 *result = SCIP_SEPARATED;
15953
15954 /* combine linear constraints to get more cuts */
15955 /**@todo further cuts of linear constraints */
15956
15957 return SCIP_OKAY;
15958 }
15959
15960
15961 /** constraint enforcing method of constraint handler for LP solutions */
15962 static
SCIP_DECL_CONSENFOLP(consEnfolpLinear)15963 SCIP_DECL_CONSENFOLP(consEnfolpLinear)
15964 { /*lint --e{715}*/
15965 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
15966
15967 return SCIP_OKAY;
15968 }
15969
15970 /** constraint enforcing method of constraint handler for relaxation solutions */
15971 static
SCIP_DECL_CONSENFORELAX(consEnforelaxLinear)15972 SCIP_DECL_CONSENFORELAX(consEnforelaxLinear)
15973 { /*lint --e{715}*/
15974 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) );
15975
15976 return SCIP_OKAY;
15977 }
15978
15979 /** constraint enforcing method of constraint handler for pseudo solutions */
15980 static
SCIP_DECL_CONSENFOPS(consEnfopsLinear)15981 SCIP_DECL_CONSENFOPS(consEnfopsLinear)
15982 { /*lint --e{715}*/
15983 SCIP_CONSHDLRDATA* conshdlrdata;
15984 SCIP_Bool checkrelmaxabs;
15985 SCIP_Bool violated;
15986 int c;
15987
15988 assert(scip != NULL);
15989 assert(conshdlr != NULL);
15990 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
15991 assert(result != NULL);
15992
15993 conshdlrdata = SCIPconshdlrGetData(conshdlr);
15994 assert(conshdlrdata != NULL);
15995
15996 checkrelmaxabs = conshdlrdata->checkrelmaxabs;
15997
15998 SCIPdebugMsg(scip, "Enfops method of linear constraints\n");
15999
16000 /* if the solution is infeasible anyway due to objective value, skip the enforcement */
16001 if( objinfeasible )
16002 {
16003 SCIPdebugMsg(scip, "-> pseudo solution is objective infeasible, return.\n");
16004
16005 *result = SCIP_DIDNOTRUN;
16006 return SCIP_OKAY;
16007 }
16008
16009 /* check all linear constraints for feasibility */
16010 violated = FALSE;
16011 for( c = 0; c < nconss && !violated; ++c )
16012 {
16013 SCIP_CALL( checkCons(scip, conss[c], NULL, TRUE, checkrelmaxabs, &violated) );
16014 }
16015
16016 if( violated )
16017 *result = SCIP_INFEASIBLE;
16018 else
16019 *result = SCIP_FEASIBLE;
16020
16021 SCIPdebugMsg(scip, "-> constraints checked, %s\n", *result == SCIP_FEASIBLE ? "all constraints feasible" : "infeasibility detected");
16022
16023 return SCIP_OKAY;
16024 }
16025
16026
16027 /** feasibility check method of constraint handler for integral solutions */
16028 static
SCIP_DECL_CONSCHECK(consCheckLinear)16029 SCIP_DECL_CONSCHECK(consCheckLinear)
16030 { /*lint --e{715}*/
16031 SCIP_CONSHDLRDATA* conshdlrdata;
16032 SCIP_Bool checkrelmaxabs;
16033 int c;
16034
16035 assert(scip != NULL);
16036 assert(conshdlr != NULL);
16037 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
16038 assert(result != NULL);
16039
16040 *result = SCIP_FEASIBLE;
16041
16042 conshdlrdata = SCIPconshdlrGetData(conshdlr);
16043 assert(conshdlrdata != NULL);
16044
16045 checkrelmaxabs = conshdlrdata->checkrelmaxabs;
16046
16047 /*debugMsg(scip, "Check method of linear constraints\n");*/
16048
16049 /* check all linear constraints for feasibility */
16050 for( c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c )
16051 {
16052 SCIP_Bool violated = FALSE;
16053 SCIP_CALL( checkCons(scip, conss[c], sol, checklprows, checkrelmaxabs, &violated) );
16054
16055 if( violated )
16056 {
16057 *result = SCIP_INFEASIBLE;
16058
16059 if( printreason )
16060 {
16061 SCIP_CONSDATA* consdata;
16062 SCIP_Real activity;
16063
16064 consdata = SCIPconsGetData(conss[c]);
16065 assert( consdata != NULL);
16066
16067 activity = consdataGetActivity(scip, consdata, sol);
16068
16069 SCIP_CALL( consPrintConsSol(scip, conss[c], sol, NULL ) );
16070 SCIPinfoMessage(scip, NULL, ";\n");
16071
16072 if( activity == SCIP_INVALID ) /*lint !e777*/
16073 SCIPinfoMessage(scip, NULL, "activity invalid due to positive and negative infinity contributions\n");
16074 else if( SCIPisFeasLT(scip, activity, consdata->lhs) )
16075 SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", consdata->lhs - activity);
16076 else if( SCIPisFeasGT(scip, activity, consdata->rhs) )
16077 SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", activity - consdata->rhs);
16078 }
16079 }
16080 }
16081
16082 return SCIP_OKAY;
16083 }
16084
16085
16086 /** domain propagation method of constraint handler */
16087 static
SCIP_DECL_CONSPROP(consPropLinear)16088 SCIP_DECL_CONSPROP(consPropLinear)
16089 { /*lint --e{715}*/
16090 SCIP_CONSHDLRDATA* conshdlrdata;
16091 SCIP_Bool rangedrowpropagation = FALSE;
16092 SCIP_Bool tightenbounds;
16093 SCIP_Bool cutoff;
16094
16095 int nchgbds;
16096 int i;
16097
16098 assert(scip != NULL);
16099 assert(conshdlr != NULL);
16100 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
16101 assert(result != NULL);
16102
16103 conshdlrdata = SCIPconshdlrGetData(conshdlr);
16104 assert(conshdlrdata != NULL);
16105
16106 /*debugMsg(scip, "Prop method of linear constraints\n");*/
16107
16108 /* check, if we want to tighten variable's bounds (in probing, we always want to tighten the bounds) */
16109 if( SCIPinProbing(scip) )
16110 tightenbounds = TRUE;
16111 else
16112 {
16113 int depth;
16114 int propfreq;
16115 int tightenboundsfreq;
16116 int rangedrowfreq;
16117
16118 depth = SCIPgetDepth(scip);
16119 propfreq = SCIPconshdlrGetPropFreq(conshdlr);
16120 tightenboundsfreq = propfreq * conshdlrdata->tightenboundsfreq;
16121 tightenbounds = (conshdlrdata->tightenboundsfreq >= 0)
16122 && ((tightenboundsfreq == 0 && depth == 0) || (tightenboundsfreq >= 1 && (depth % tightenboundsfreq == 0)));
16123
16124 /* check if we want to do ranged row propagation */
16125 rangedrowpropagation = conshdlrdata->rangedrowpropagation;
16126 rangedrowpropagation = rangedrowpropagation && !SCIPinRepropagation(scip);
16127 rangedrowpropagation = rangedrowpropagation && (depth <= conshdlrdata->rangedrowmaxdepth);
16128 rangedrowfreq = propfreq * conshdlrdata->rangedrowfreq;
16129 rangedrowpropagation = rangedrowpropagation && (conshdlrdata->rangedrowfreq >= 0)
16130 && ((rangedrowfreq == 0 && depth == 0) || (rangedrowfreq >= 1 && (depth % rangedrowfreq == 0)));
16131 }
16132
16133 cutoff = FALSE;
16134 nchgbds = 0;
16135
16136 /* process constraints marked for propagation */
16137 for( i = 0; i < nmarkedconss && !cutoff; i++ )
16138 {
16139 SCIP_CALL( SCIPunmarkConsPropagate(scip, conss[i]) );
16140 SCIP_CALL( propagateCons(scip, conss[i], tightenbounds, rangedrowpropagation,
16141 conshdlrdata->maxeasyactivitydelta, conshdlrdata->sortvars, &cutoff, &nchgbds) );
16142 }
16143
16144 /* adjust result code */
16145 if( cutoff )
16146 *result = SCIP_CUTOFF;
16147 else if( nchgbds > 0 )
16148 *result = SCIP_REDUCEDDOM;
16149 else
16150 *result = SCIP_DIDNOTFIND;
16151
16152 return SCIP_OKAY;
16153 }
16154
16155
16156 #define MAXCONSPRESOLROUNDS 10
16157 /** presolving method of constraint handler */
16158 static
SCIP_DECL_CONSPRESOL(consPresolLinear)16159 SCIP_DECL_CONSPRESOL(consPresolLinear)
16160 { /*lint --e{715}*/
16161 SCIP_CONSHDLRDATA* conshdlrdata;
16162 SCIP_CONS* cons;
16163 SCIP_CONSDATA* consdata;
16164 SCIP_Real minactivity;
16165 SCIP_Real maxactivity;
16166 SCIP_Bool minactisrelax;
16167 SCIP_Bool maxactisrelax;
16168 SCIP_Bool isminsettoinfinity;
16169 SCIP_Bool ismaxsettoinfinity;
16170 SCIP_Bool cutoff;
16171 int oldnfixedvars;
16172 int oldnaggrvars;
16173 int oldnchgbds;
16174 int oldndelconss;
16175 int oldnupgdconss;
16176 int oldnchgcoefs;
16177 int oldnchgsides;
16178 int firstchange;
16179 int firstupgradetry;
16180 int c;
16181
16182 assert(scip != NULL);
16183 assert(conshdlr != NULL);
16184 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
16185 assert(result != NULL);
16186
16187 /*debugMsg(scip, "Presol method of linear constraints\n");*/
16188
16189 /* remember old preprocessing counters */
16190 cutoff = FALSE;
16191 oldnfixedvars = *nfixedvars;
16192 oldnaggrvars = *naggrvars;
16193 oldnchgbds = *nchgbds;
16194 oldndelconss = *ndelconss;
16195 oldnupgdconss = *nupgdconss;
16196 oldnchgcoefs = *nchgcoefs;
16197 oldnchgsides = *nchgsides;
16198
16199 /* get constraint handler data */
16200 conshdlrdata = SCIPconshdlrGetData(conshdlr);
16201 assert(conshdlrdata != NULL);
16202
16203 /* process single constraints */
16204 firstchange = INT_MAX;
16205 firstupgradetry = INT_MAX;
16206 for( c = 0; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
16207 {
16208 int npresolrounds;
16209 SCIP_Bool infeasible;
16210
16211 infeasible = FALSE;
16212
16213 cons = conss[c];
16214 assert(SCIPconsIsActive(cons));
16215 consdata = SCIPconsGetData(cons);
16216 assert(consdata != NULL);
16217
16218 /* ensure that rhs >= lhs is satisfied without numerical tolerance */
16219 if( SCIPisEQ(scip, consdata->rhs, consdata->lhs) )
16220 {
16221 consdata->lhs = consdata->rhs;
16222 assert(consdata->row == NULL);
16223 }
16224
16225 if( consdata->eventdata == NULL )
16226 {
16227 /* catch bound change events of variables */
16228 SCIP_CALL( consCatchAllEvents(scip, cons, conshdlrdata->eventhdlr) );
16229 assert(consdata->eventdata != NULL);
16230 }
16231
16232 /* constraint should not be already presolved in the initial round */
16233 assert(SCIPgetNRuns(scip) > 0 || nrounds > 0 || SCIPconsIsMarkedPropagate(cons));
16234 assert(SCIPgetNRuns(scip) > 0 || nrounds > 0 || consdata->boundstightened == 0);
16235 assert(SCIPgetNRuns(scip) > 0 || nrounds > 0 || !consdata->presolved);
16236 assert(!SCIPconsIsMarkedPropagate(cons) || !consdata->presolved);
16237
16238 /* incorporate fixings and aggregations in constraint */
16239 SCIP_CALL( applyFixings(scip, cons, &infeasible) );
16240
16241 if( infeasible )
16242 {
16243 SCIPdebugMsg(scip, " -> infeasible fixing\n");
16244 cutoff = TRUE;
16245 break;
16246 }
16247
16248 assert(consdata->removedfixings);
16249
16250 /* we can only presolve linear constraints, that are not modifiable */
16251 if( SCIPconsIsModifiable(cons) )
16252 continue;
16253
16254 /* remember the first changed constraint to begin the next aggregation round with */
16255 if( firstchange == INT_MAX && consdata->changed )
16256 firstchange = c;
16257
16258 /* remember the first constraint that was not yet tried to be upgraded, to begin the next upgrading round with */
16259 if( firstupgradetry == INT_MAX && !consdata->upgradetried )
16260 firstupgradetry = c;
16261
16262 /* check, if constraint is already preprocessed */
16263 if( consdata->presolved )
16264 continue;
16265
16266 assert(SCIPconsIsActive(cons));
16267
16268 SCIPdebugMsg(scip, "presolving linear constraint <%s>\n", SCIPconsGetName(cons));
16269 SCIPdebugPrintCons(scip, cons, NULL);
16270
16271 /* apply presolving as long as possible on the single constraint (however, abort after a certain number of rounds
16272 * to avoid nearly infinite cycling due to very small bound changes)
16273 */
16274 npresolrounds = 0;
16275 while( !consdata->presolved && npresolrounds < MAXCONSPRESOLROUNDS && !SCIPisStopped(scip) )
16276 {
16277 assert(!cutoff);
16278 npresolrounds++;
16279
16280 /* mark constraint being presolved and propagated */
16281 consdata->presolved = TRUE;
16282 SCIP_CALL( SCIPunmarkConsPropagate(scip, cons) );
16283
16284 /* normalize constraint */
16285 SCIP_CALL( normalizeCons(scip, cons, &infeasible) );
16286
16287 if( infeasible )
16288 {
16289 SCIPdebugMsg(scip, " -> infeasible normalization\n");
16290 cutoff = TRUE;
16291 break;
16292 }
16293
16294 /* tighten left and right hand side due to integrality */
16295 SCIP_CALL( tightenSides(scip, cons, nchgsides, &infeasible) );
16296
16297 if( infeasible )
16298 {
16299 SCIPdebugMsg(scip, " -> infeasibility detected during tightening sides\n");
16300 cutoff = TRUE;
16301 break;
16302 }
16303
16304 /* check bounds */
16305 if( SCIPisFeasGT(scip, consdata->lhs, consdata->rhs) )
16306 {
16307 SCIPdebugMsg(scip, "linear constraint <%s> is infeasible: sides=[%.15g,%.15g]\n",
16308 SCIPconsGetName(cons), consdata->lhs, consdata->rhs);
16309 cutoff = TRUE;
16310 break;
16311 }
16312
16313 /* tighten variable's bounds */
16314 SCIP_CALL( tightenBounds(scip, cons, conshdlrdata->maxeasyactivitydelta, conshdlrdata->sortvars, &cutoff, nchgbds) );
16315 if( cutoff )
16316 break;
16317
16318 /* check for fixed variables */
16319 SCIP_CALL( fixVariables(scip, cons, &cutoff, nfixedvars) );
16320 if( cutoff )
16321 break;
16322
16323 /* check constraint for infeasibility and redundancy */
16324 consdataGetActivityBounds(scip, consdata, TRUE, &minactivity, &maxactivity, &minactisrelax, &maxactisrelax,
16325 &isminsettoinfinity, &ismaxsettoinfinity);
16326 if( SCIPisFeasGT(scip, minactivity, consdata->rhs) || SCIPisFeasLT(scip, maxactivity, consdata->lhs) )
16327 {
16328 SCIPdebugMsg(scip, "linear constraint <%s> is infeasible: activitybounds=[%.15g,%.15g], sides=[%.15g,%.15g]\n",
16329 SCIPconsGetName(cons), minactivity, maxactivity, consdata->lhs, consdata->rhs);
16330 cutoff = TRUE;
16331 break;
16332 }
16333 else if( SCIPisFeasGE(scip, minactivity, consdata->lhs) && SCIPisFeasLE(scip, maxactivity, consdata->rhs) )
16334 {
16335 SCIPdebugMsg(scip, "linear constraint <%s> is redundant: activitybounds=[%.15g,%.15g], sides=[%.15g,%.15g]\n",
16336 SCIPconsGetName(cons), minactivity, maxactivity, consdata->lhs, consdata->rhs);
16337 SCIP_CALL( SCIPdelCons(scip, cons) );
16338 assert(!SCIPconsIsActive(cons));
16339
16340 if( !consdata->upgraded )
16341 (*ndelconss)++;
16342 break;
16343 }
16344 else if( !SCIPisInfinity(scip, -consdata->lhs) && SCIPisFeasGE(scip, minactivity, consdata->lhs) )
16345 {
16346 SCIPdebugMsg(scip, "linear constraint <%s> left hand side is redundant: activitybounds=[%.15g,%.15g], sides=[%.15g,%.15g]\n",
16347 SCIPconsGetName(cons), minactivity, maxactivity, consdata->lhs, consdata->rhs);
16348 SCIP_CALL( chgLhs(scip, cons, -SCIPinfinity(scip)) );
16349 if( !consdata->upgraded )
16350 (*nchgsides)++;
16351 }
16352 else if( !SCIPisInfinity(scip, consdata->rhs) && SCIPisFeasLE(scip, maxactivity, consdata->rhs) )
16353 {
16354 SCIPdebugMsg(scip, "linear constraint <%s> right hand side is redundant: activitybounds=[%.15g,%.15g], sides=[%.15g,%.15g]\n",
16355 SCIPconsGetName(cons), minactivity, maxactivity, consdata->lhs, consdata->rhs);
16356 SCIP_CALL( chgRhs(scip, cons, SCIPinfinity(scip)) );
16357 if( !consdata->upgraded )
16358 (*nchgsides)++;
16359 }
16360 assert(consdata->nvars >= 1); /* otherwise, it should be redundant or infeasible */
16361
16362 /* handle empty constraint */
16363 if( consdata->nvars == 0 )
16364 {
16365 if( SCIPisFeasGT(scip, consdata->lhs, consdata->rhs) )
16366 {
16367 SCIPdebugMsg(scip, "empty linear constraint <%s> is infeasible: sides=[%.15g,%.15g]\n",
16368 SCIPconsGetName(cons), consdata->lhs, consdata->rhs);
16369 cutoff = TRUE;
16370 }
16371 else
16372 {
16373 SCIPdebugMsg(scip, "empty linear constraint <%s> is redundant: sides=[%.15g,%.15g]\n",
16374 SCIPconsGetName(cons), consdata->lhs, consdata->rhs);
16375 SCIP_CALL( SCIPdelCons(scip, cons) );
16376 assert(!SCIPconsIsActive(cons));
16377
16378 if( !consdata->upgraded )
16379 (*ndelconss)++;
16380 }
16381 break;
16382 }
16383
16384 /* reduce big-M coefficients, that make the constraint redundant if the variable is on a bound */
16385 SCIP_CALL( consdataTightenCoefs(scip, cons, nchgcoefs, nchgsides) );
16386
16387 /* try to simplify inequalities */
16388 if( conshdlrdata->simplifyinequalities )
16389 {
16390 SCIP_CALL( simplifyInequalities(scip, cons, nchgcoefs, nchgsides, &cutoff) );
16391
16392 if( cutoff )
16393 break;
16394 }
16395
16396 /* aggregation variable in equations */
16397 if( conshdlrdata->aggregatevariables )
16398 {
16399 SCIP_CALL( aggregateVariables(scip, cons, &cutoff, nfixedvars, naggrvars) );
16400 if( cutoff )
16401 break;
16402 }
16403 }
16404
16405 if( !cutoff && !SCIPisStopped(scip) )
16406 {
16407 /* perform ranged row propagation */
16408 if( conshdlrdata->rangedrowpropagation )
16409 {
16410 int lastnfixedvars;
16411
16412 lastnfixedvars = *nfixedvars;
16413
16414 SCIP_CALL( rangedRowPropagation(scip, cons, &cutoff, nfixedvars, nchgbds, naddconss) );
16415 if( !cutoff )
16416 {
16417 if( lastnfixedvars < *nfixedvars )
16418 {
16419 SCIP_CALL( applyFixings(scip, cons, &cutoff) );
16420 }
16421 }
16422 }
16423
16424 /* extract cliques from constraint */
16425 if( conshdlrdata->extractcliques && !cutoff && SCIPconsIsActive(cons) )
16426 {
16427 SCIP_CALL( extractCliques(scip, cons, conshdlrdata->maxeasyactivitydelta, conshdlrdata->sortvars,
16428 nfixedvars, nchgbds, &cutoff) );
16429
16430 /* check if the constraint got redundant or infeasible */
16431 if( !cutoff && SCIPconsIsActive(cons) && consdata->nvars == 0 )
16432 {
16433 if( SCIPisFeasGT(scip, consdata->lhs, consdata->rhs) )
16434 {
16435 SCIPdebugMsg(scip, "empty linear constraint <%s> is infeasible: sides=[%.15g,%.15g]\n",
16436 SCIPconsGetName(cons), consdata->lhs, consdata->rhs);
16437 cutoff = TRUE;
16438 }
16439 else
16440 {
16441 SCIPdebugMsg(scip, "empty linear constraint <%s> is redundant: sides=[%.15g,%.15g]\n",
16442 SCIPconsGetName(cons), consdata->lhs, consdata->rhs);
16443 SCIP_CALL( SCIPdelCons(scip, cons) );
16444 assert(!SCIPconsIsActive(cons));
16445
16446 if( !consdata->upgraded )
16447 (*ndelconss)++;
16448 }
16449 }
16450 }
16451
16452 /* convert special equalities */
16453 if( !cutoff && SCIPconsIsActive(cons) )
16454 {
16455 SCIP_CALL( convertEquality(scip, cons, conshdlrdata, &cutoff, nfixedvars, naggrvars, ndelconss) );
16456 }
16457
16458 /* apply dual presolving for variables that appear in only one constraint */
16459 if( !cutoff && SCIPconsIsActive(cons) && conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip) )
16460 {
16461 SCIP_CALL( dualPresolve(scip, conshdlrdata, cons, &cutoff, nfixedvars, naggrvars, ndelconss) );
16462 }
16463
16464 /* check if an inequality is parallel to the objective function */
16465 if( !cutoff && SCIPconsIsActive(cons) )
16466 {
16467 SCIP_CALL( checkParallelObjective(scip, cons, conshdlrdata) );
16468 }
16469
16470 /* remember the first changed constraint to begin the next aggregation round with */
16471 if( firstchange == INT_MAX && consdata->changed )
16472 firstchange = c;
16473
16474 /* remember the first constraint that was not yet tried to be upgraded, to begin the next upgrading round with */
16475 if( firstupgradetry == INT_MAX && !consdata->upgradetried )
16476 firstupgradetry = c;
16477 }
16478
16479 /* singleton column stuffing */
16480 if( !cutoff && SCIPconsIsActive(cons) && SCIPconsIsChecked(cons) &&
16481 (conshdlrdata->singletonstuffing || conshdlrdata->singlevarstuffing) && SCIPallowStrongDualReds(scip) )
16482 {
16483 SCIP_CALL( presolStuffing(scip, cons, conshdlrdata->singletonstuffing,
16484 conshdlrdata->singlevarstuffing, &cutoff, nfixedvars, nchgbds) );
16485
16486 /* handle empty constraint */
16487 if( consdata->nvars == 0 )
16488 {
16489 if( SCIPisFeasGT(scip, consdata->lhs, consdata->rhs) )
16490 {
16491 SCIPdebugMsg(scip, "empty linear constraint <%s> is infeasible: sides=[%.15g,%.15g]\n",
16492 SCIPconsGetName(cons), consdata->lhs, consdata->rhs);
16493 cutoff = TRUE;
16494 }
16495 else
16496 {
16497 SCIPdebugMsg(scip, "empty linear constraint <%s> is redundant: sides=[%.15g,%.15g]\n",
16498 SCIPconsGetName(cons), consdata->lhs, consdata->rhs);
16499 SCIP_CALL( SCIPdelCons(scip, cons) );
16500 assert(!SCIPconsIsActive(cons));
16501
16502 if( !consdata->upgraded )
16503 (*ndelconss)++;
16504 }
16505 break;
16506 }
16507 }
16508 }
16509
16510 /* process pairs of constraints: check them for redundancy and try to aggregate them;
16511 * only apply this expensive procedure in exhaustive presolving timing
16512 */
16513 if( !cutoff && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && (conshdlrdata->presolusehashing || conshdlrdata->presolpairwise) && !SCIPisStopped(scip) )
16514 {
16515 assert(firstchange >= 0);
16516
16517 if( firstchange < nconss && conshdlrdata->presolusehashing )
16518 {
16519 /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
16520 SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &firstchange, &cutoff,
16521 ndelconss, nchgsides) );
16522 }
16523
16524 if( firstchange < nconss && conshdlrdata->presolpairwise )
16525 {
16526 SCIP_CONS** usefulconss;
16527 int nusefulconss;
16528 int firstchangenew;
16529 SCIP_Longint npaircomparisons;
16530
16531 npaircomparisons = 0;
16532 oldndelconss = *ndelconss;
16533 oldnchgsides = *nchgsides;
16534 oldnchgcoefs = *nchgcoefs;
16535
16536 /* allocate temporary memory */
16537 SCIP_CALL( SCIPallocBufferArray(scip, &usefulconss, nconss) );
16538
16539 nusefulconss = 0;
16540 firstchangenew = -1;
16541 for( c = 0; c < nconss; ++c )
16542 {
16543 /* update firstchange */
16544 if( c == firstchange )
16545 firstchangenew = nusefulconss;
16546
16547 /* ignore inactive and modifiable constraints */
16548 if( !SCIPconsIsActive(conss[c]) || SCIPconsIsModifiable(conss[c]) )
16549 continue;
16550
16551 usefulconss[nusefulconss] = conss[c];
16552 ++nusefulconss;
16553 }
16554 firstchange = firstchangenew;
16555 assert(firstchangenew >= 0 && firstchangenew <= nusefulconss);
16556
16557 for( c = firstchange; c < nusefulconss && !cutoff && !SCIPisStopped(scip); ++c )
16558 {
16559 /* constraint has become inactive or modifiable during pairwise presolving */
16560 if( usefulconss[c] == NULL )
16561 continue;
16562
16563 npaircomparisons += (SCIPconsGetData(conss[c])->changed) ? c : (c - firstchange); /*lint !e776*/
16564
16565 assert(SCIPconsIsActive(usefulconss[c]) && !SCIPconsIsModifiable(usefulconss[c]));
16566 SCIP_CALL( preprocessConstraintPairs(scip, usefulconss, firstchange, c, conshdlrdata->maxaggrnormscale,
16567 &cutoff, ndelconss, nchgsides, nchgcoefs) );
16568
16569 if( npaircomparisons > conshdlrdata->nmincomparisons )
16570 {
16571 assert(npaircomparisons > 0);
16572 if( ((*ndelconss - oldndelconss) + (*nchgsides - oldnchgsides)/2.0 + (*nchgcoefs - oldnchgcoefs)/10.0) / ((SCIP_Real) npaircomparisons) < conshdlrdata->mingainpernmincomp )
16573 break;
16574 oldndelconss = *ndelconss;
16575 oldnchgsides = *nchgsides;
16576 oldnchgcoefs = *nchgcoefs;
16577 npaircomparisons = 0;
16578 }
16579 }
16580 /* free temporary memory */
16581 SCIPfreeBufferArray(scip, &usefulconss);
16582 }
16583 }
16584
16585 /* before upgrading, check whether we can apply some additional dual presolving, because a variable only appears
16586 * in linear constraints and we therefore have full information about it
16587 */
16588 if( !cutoff && firstupgradetry < nconss
16589 && *nfixedvars == oldnfixedvars && *naggrvars == oldnaggrvars && *nchgbds == oldnchgbds && *ndelconss == oldndelconss
16590 && *nupgdconss == oldnupgdconss && *nchgcoefs == oldnchgcoefs && *nchgsides == oldnchgsides
16591 )
16592 {
16593 if( conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip) && !SCIPisStopped(scip) )
16594 {
16595 SCIP_CALL( fullDualPresolve(scip, conss, nconss, &cutoff, nchgbds) );
16596 }
16597 }
16598
16599 /* try to upgrade constraints into a more specific constraint type;
16600 * only upgrade constraints, if no reductions were found in this round (otherwise, the linear constraint handler
16601 * may find additional reductions before giving control away to other (less intelligent?) constraint handlers)
16602 */
16603 if( !cutoff && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && SCIPisPresolveFinished(scip) )
16604 {
16605 for( c = firstupgradetry; c < nconss && !SCIPisStopped(scip); ++c )
16606 {
16607 cons = conss[c];
16608
16609 /* don't upgrade modifiable constraints */
16610 if( SCIPconsIsModifiable(cons) )
16611 continue;
16612
16613 consdata = SCIPconsGetData(cons);
16614 assert(consdata != NULL);
16615
16616 /* only upgrade completely presolved constraints, that changed since the last upgrading call */
16617 if( consdata->upgradetried )
16618 continue;
16619 /* @todo force that upgrade will be performed later? */
16620 if( !consdata->presolved )
16621 continue;
16622
16623 consdata->upgradetried = TRUE;
16624 if( SCIPconsIsActive(cons) )
16625 {
16626 SCIP_CONS* upgdcons;
16627
16628 SCIP_CALL( SCIPupgradeConsLinear(scip, cons, &upgdcons) );
16629 if( upgdcons != NULL )
16630 {
16631 /* add the upgraded constraint to the problem */
16632 SCIP_CALL( SCIPaddCons(scip, upgdcons) );
16633 SCIP_CALL( SCIPreleaseCons(scip, &upgdcons) );
16634 (*nupgdconss)++;
16635
16636 /* mark the linear constraint being upgraded and to be removed after presolving;
16637 * don't delete it directly, because it may help to preprocess other linear constraints
16638 */
16639 assert(!consdata->upgraded);
16640 consdata->upgraded = TRUE;
16641
16642 /* delete upgraded inequalities immediately;
16643 * delete upgraded equalities, if we don't need it anymore for aggregation and redundancy checking
16644 */
16645 if( SCIPisLT(scip, consdata->lhs, consdata->rhs)
16646 || !conshdlrdata->presolpairwise
16647 || (conshdlrdata->maxaggrnormscale == 0.0) )
16648 {
16649 SCIP_CALL( SCIPdelCons(scip, cons) );
16650 }
16651 }
16652 }
16653 }
16654 }
16655
16656 /* return the correct result code */
16657 if( cutoff )
16658 *result = SCIP_CUTOFF;
16659 else if( *nfixedvars > oldnfixedvars || *naggrvars > oldnaggrvars || *nchgbds > oldnchgbds || *ndelconss > oldndelconss
16660 || *nupgdconss > oldnupgdconss || *nchgcoefs > oldnchgcoefs || *nchgsides > oldnchgsides )
16661 *result = SCIP_SUCCESS;
16662 else
16663 *result = SCIP_DIDNOTFIND;
16664
16665 return SCIP_OKAY;
16666 }
16667
16668
16669 /** propagation conflict resolving method of constraint handler */
16670 static
SCIP_DECL_CONSRESPROP(consRespropLinear)16671 SCIP_DECL_CONSRESPROP(consRespropLinear)
16672 { /*lint --e{715}*/
16673 assert(scip != NULL);
16674 assert(cons != NULL);
16675 assert(result != NULL);
16676
16677 SCIP_CALL( resolvePropagation(scip, cons, infervar, intToInferInfo(inferinfo), boundtype, bdchgidx, result) );
16678
16679 return SCIP_OKAY;
16680 }
16681
16682
16683 /** variable rounding lock method of constraint handler */
16684 static
SCIP_DECL_CONSLOCK(consLockLinear)16685 SCIP_DECL_CONSLOCK(consLockLinear)
16686 { /*lint --e{715}*/
16687 SCIP_CONSDATA* consdata;
16688 SCIP_Bool haslhs;
16689 SCIP_Bool hasrhs;
16690 int i;
16691
16692 assert(scip != NULL);
16693 assert(cons != NULL);
16694 consdata = SCIPconsGetData(cons);
16695 assert(consdata != NULL);
16696
16697 haslhs = !SCIPisInfinity(scip, -consdata->lhs);
16698 hasrhs = !SCIPisInfinity(scip, consdata->rhs);
16699
16700 /* update rounding locks of every single variable */
16701 for( i = 0; i < consdata->nvars; ++i )
16702 {
16703 if( SCIPisPositive(scip, consdata->vals[i]) )
16704 {
16705 if( haslhs )
16706 {
16707 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlockspos, nlocksneg) );
16708 }
16709 if( hasrhs )
16710 {
16711 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlocksneg, nlockspos) );
16712 }
16713 }
16714 else
16715 {
16716 if( haslhs )
16717 {
16718 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlocksneg, nlockspos) );
16719 }
16720 if( hasrhs )
16721 {
16722 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlockspos, nlocksneg) );
16723 }
16724 }
16725 }
16726
16727 return SCIP_OKAY;
16728 }
16729
16730
16731 /** variable deletion method of constraint handler */
16732 static
SCIP_DECL_CONSDELVARS(consDelvarsLinear)16733 SCIP_DECL_CONSDELVARS(consDelvarsLinear)
16734 {
16735 assert(scip != NULL);
16736 assert(conshdlr != NULL);
16737 assert(conss != NULL || nconss == 0);
16738
16739 if( nconss > 0 )
16740 {
16741 SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) );
16742 }
16743
16744 return SCIP_OKAY;
16745 }
16746
16747 /** constraint display method of constraint handler */
16748 static
SCIP_DECL_CONSPRINT(consPrintLinear)16749 SCIP_DECL_CONSPRINT(consPrintLinear)
16750 { /*lint --e{715}*/
16751 assert(scip != NULL);
16752 assert(conshdlr != NULL);
16753 assert(cons != NULL);
16754
16755 SCIP_CALL( consdataPrint(scip, SCIPconsGetData(cons), file) );
16756
16757 return SCIP_OKAY;
16758 }
16759
16760 /** constraint copying method of constraint handler */
16761 static
SCIP_DECL_CONSCOPY(consCopyLinear)16762 SCIP_DECL_CONSCOPY(consCopyLinear)
16763 { /*lint --e{715}*/
16764 SCIP_VAR** sourcevars;
16765 SCIP_Real* sourcecoefs;
16766 const char* consname;
16767 int nvars;
16768
16769 assert(scip != NULL);
16770 assert(sourcescip != NULL);
16771 assert(sourcecons != NULL);
16772
16773 /* get variables and coefficients of the source constraint */
16774 sourcevars = SCIPgetVarsLinear(sourcescip, sourcecons);
16775 sourcecoefs = SCIPgetValsLinear(sourcescip, sourcecons);
16776 nvars = SCIPgetNVarsLinear(sourcescip, sourcecons);
16777
16778 if( name != NULL )
16779 consname = name;
16780 else
16781 consname = SCIPconsGetName(sourcecons);
16782
16783 SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, sourcecoefs,
16784 SCIPgetLhsLinear(sourcescip, sourcecons), SCIPgetRhsLinear(sourcescip, sourcecons), varmap, consmap,
16785 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
16786 assert(cons != NULL || *valid == FALSE);
16787
16788 /* @todo should also the checkabsolute flag of the constraint be copied? */
16789
16790 return SCIP_OKAY;
16791 }
16792
16793 /** find operators '<=', '==', '>=', [free] in input string and return those places
16794 *
16795 * There should only be one operator, except for ranged rows for which exactly two operators '<=' must be present.
16796 */
16797 static
findOperators(const char * str,char ** firstoperator,char ** secondoperator,SCIP_Bool * success)16798 void findOperators(
16799 const char* str, /**< null terminated input string */
16800 char** firstoperator, /**< pointer to store the string starting at the first operator */
16801 char** secondoperator, /**< pointer to store the string starting at the second operator */
16802 SCIP_Bool* success /**< pointer to store if the line contains a valid operator order */
16803 )
16804 {
16805 char* curr;
16806
16807 assert(str != NULL);
16808 assert(firstoperator != NULL);
16809 assert(secondoperator != NULL);
16810
16811 *firstoperator = NULL;
16812 *secondoperator = NULL;
16813
16814 curr = (char*)str;
16815 *success = TRUE;
16816
16817 /* loop over the input string to find all operators */
16818 while( *curr && *success )
16819 {
16820 SCIP_Bool found = FALSE;
16821 int increment = 1;
16822
16823 /* try if we found a possible operator */
16824 switch( *curr )
16825 {
16826 case '<':
16827 case '=':
16828 case '>':
16829
16830 /* check if the two characters curr[0,1] form an operator together */
16831 if( curr[1] == '=' )
16832 {
16833 found = TRUE;
16834
16835 /* update increment to continue after this operator */
16836 increment = 2;
16837 }
16838 break;
16839 case '[':
16840 if( strncmp(curr, "[free]", 6) == 0 )
16841 {
16842 found = TRUE;
16843
16844 /* update increment to continue after this operator */
16845 increment = 6;
16846 }
16847 break;
16848 default:
16849 break;
16850 }
16851
16852 /* assign the found operator to the first or second pointer and check for violations of the linear constraint grammar */
16853 if( found )
16854 {
16855 if( *firstoperator == NULL )
16856 {
16857 *firstoperator = curr;
16858 }
16859 else
16860 {
16861 if( *secondoperator != NULL )
16862 {
16863 SCIPerrorMessage("Found more than two operators in line %s\n", str);
16864 *success = FALSE;
16865 }
16866 else if( strncmp(*firstoperator, "<=", 2) != 0 )
16867 {
16868 SCIPerrorMessage("Two operators in line that is not a ranged row: %s", str);
16869 *success = FALSE;
16870 }
16871 else if( strncmp(curr, "<=", 2) != 0 )
16872 {
16873 SCIPerrorMessage("Bad second operator, expected ranged row specification: %s", str);
16874 *success = FALSE;
16875 }
16876
16877 *secondoperator = curr;
16878 }
16879 }
16880
16881 curr += increment;
16882 }
16883
16884 /* check if we did find at least one operator */
16885 if( *success )
16886 {
16887 if( *firstoperator == NULL )
16888 {
16889 SCIPerrorMessage("Could not find any operator in line %s\n", str);
16890 *success = FALSE;
16891 }
16892 }
16893 }
16894
16895 /** constraint parsing method of constraint handler */
16896 static
SCIP_DECL_CONSPARSE(consParseLinear)16897 SCIP_DECL_CONSPARSE(consParseLinear)
16898 { /*lint --e{715}*/
16899 SCIP_VAR** vars;
16900 SCIP_Real* coefs;
16901 int nvars;
16902 int coefssize;
16903 int requsize;
16904 SCIP_Real lhs;
16905 SCIP_Real rhs;
16906 char* endptr;
16907 char* firstop;
16908 char* secondop;
16909 SCIP_Bool operatorsuccess;
16910 char* lhsstrptr;
16911 char* rhsstrptr;
16912 char* varstrptr;
16913
16914 assert(scip != NULL);
16915 assert(success != NULL);
16916 assert(str != NULL);
16917 assert(name != NULL);
16918 assert(cons != NULL);
16919
16920 /* set left and right hand side to their default values */
16921 lhs = -SCIPinfinity(scip);
16922 rhs = SCIPinfinity(scip);
16923
16924 (*success) = FALSE;
16925
16926 /* return of string empty */
16927 if( !*str )
16928 return SCIP_OKAY;
16929
16930 /* ignore whitespace */
16931 while( isspace((unsigned char)*str) )
16932 ++str;
16933
16934 /* find operators in the line first, all other remaining parsing depends on occurence of the operators '<=', '>=', '==',
16935 * and the special word [free]
16936 */
16937 findOperators(str, &firstop, &secondop, &operatorsuccess);
16938
16939 /* if the grammar is not valid for parsing a linear constraint, return */
16940 if( ! operatorsuccess )
16941 return SCIP_OKAY;
16942
16943 varstrptr = (char *)str;
16944 lhsstrptr = rhsstrptr = NULL;
16945 assert(firstop != NULL);
16946
16947 /* assign the strings for parsing the left hand side, right hand side, and the linear variable sum */
16948 switch( *firstop )
16949 {
16950 case '<':
16951 assert(firstop[1] == '=');
16952 /* we have ranged row lhs <= a_1 x_1 + ... + a_n x_n <= rhs */
16953 if( secondop != NULL )
16954 {
16955 assert(secondop[0] == '<' && secondop[1] == '=');
16956 lhsstrptr = (char *)str;
16957 varstrptr = firstop + 2;
16958 rhsstrptr = secondop + 2;
16959 }
16960 else
16961 {
16962 /* we have an inequality with infinite left hand side a_1 x_1 + ... + a_n x_n <= rhs */
16963 lhsstrptr = NULL;
16964 varstrptr = (char *)str;
16965 rhsstrptr = firstop + 2;
16966 }
16967 break;
16968 case '>':
16969 assert(firstop[1] == '=');
16970 assert(secondop == NULL);
16971 /* we have a_1 x_1 + ... + a_n x_n >= lhs */
16972 lhsstrptr = firstop + 2;
16973 break;
16974 case '=':
16975 assert(firstop[1] == '=');
16976 assert(secondop == NULL);
16977 /* we have a_1 x_1 + ... + a_n x_n == lhs (rhs) */
16978 rhsstrptr = firstop + 2;
16979 lhsstrptr = firstop + 2;
16980 break;
16981 case '[':
16982 assert(strncmp(firstop, "[free]", 6) == 0);
16983 assert(secondop == NULL);
16984 /* nothing to assign in case of a free a_1 x_1 + ... + a_n x_n [free] */
16985 break;
16986 default:
16987 /* it should not be possible that a different character appears in that position */
16988 SCIPerrorMessage("Parsing has wrong operator character '%c', should be one of <=>[", *firstop);
16989 return SCIP_READERROR;
16990 }
16991
16992 /* parse left hand side, if necessary */
16993 if( lhsstrptr != NULL )
16994 {
16995 if( ! SCIPparseReal(scip, lhsstrptr, &lhs, &endptr) )
16996 {
16997 SCIPerrorMessage("error parsing left hand side number from <%s>\n", lhsstrptr);
16998 return SCIP_OKAY;
16999 }
17000
17001 /* in case of an equation, assign the left also to the right hand side */
17002 if( rhsstrptr == lhsstrptr )
17003 rhs = lhs;
17004 }
17005
17006 /* parse right hand side, if different from left hand side */
17007 if( rhsstrptr != NULL && rhsstrptr != lhsstrptr )
17008 {
17009 if( ! SCIPparseReal(scip, rhsstrptr, &rhs, &endptr) )
17010 {
17011 SCIPerrorMessage("error parsing right hand side number from <%s>\n", lhsstrptr);
17012 return SCIP_OKAY;
17013 }
17014 }
17015
17016 /* initialize buffers for storing the variables and coefficients */
17017 coefssize = 100;
17018 SCIP_CALL( SCIPallocBufferArray(scip, &vars, coefssize) );
17019 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, coefssize) );
17020
17021 assert(varstrptr != NULL);
17022
17023 /* parse linear sum to get variables and coefficients */
17024 SCIP_CALL( SCIPparseVarsLinearsum(scip, varstrptr, vars, coefs, &nvars, coefssize, &requsize, &endptr, success) );
17025
17026 if( *success && requsize > coefssize )
17027 {
17028 /* realloc buffers and try again */
17029 coefssize = requsize;
17030 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, coefssize) );
17031 SCIP_CALL( SCIPreallocBufferArray(scip, &coefs, coefssize) );
17032
17033 SCIP_CALL( SCIPparseVarsLinearsum(scip, varstrptr, vars, coefs, &nvars, coefssize, &requsize, &endptr, success) );
17034 assert(!*success || requsize <= coefssize); /* if successful, then should have had enough space now */
17035 }
17036
17037 if( !*success )
17038 {
17039 SCIPerrorMessage("no luck in parsing linear sum '%s'\n", varstrptr);
17040 }
17041 else
17042 {
17043 SCIP_CALL( SCIPcreateConsLinear(scip, cons, name, nvars, vars, coefs, lhs, rhs,
17044 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
17045 }
17046
17047 SCIPfreeBufferArray(scip, &coefs);
17048 SCIPfreeBufferArray(scip, &vars);
17049
17050 return SCIP_OKAY;
17051 }
17052
17053
17054 /** constraint method of constraint handler which returns the variables (if possible) */
17055 static
SCIP_DECL_CONSGETVARS(consGetVarsLinear)17056 SCIP_DECL_CONSGETVARS(consGetVarsLinear)
17057 { /*lint --e{715}*/
17058 SCIP_CONSDATA* consdata;
17059
17060 consdata = SCIPconsGetData(cons);
17061 assert(consdata != NULL);
17062
17063 if( varssize < consdata->nvars )
17064 (*success) = FALSE;
17065 else
17066 {
17067 assert(vars != NULL);
17068
17069 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
17070 (*success) = TRUE;
17071 }
17072
17073 return SCIP_OKAY;
17074 }
17075
17076 /**! [Callback for the number of variables]*/
17077 /** constraint method of constraint handler which returns the number of variables (if possible) */
17078 static
SCIP_DECL_CONSGETNVARS(consGetNVarsLinear)17079 SCIP_DECL_CONSGETNVARS(consGetNVarsLinear)
17080 { /*lint --e{715}*/
17081 SCIP_CONSDATA* consdata;
17082
17083 consdata = SCIPconsGetData(cons);
17084 assert(consdata != NULL);
17085
17086 (*nvars) = consdata->nvars;
17087 (*success) = TRUE;
17088
17089 return SCIP_OKAY;
17090 }
17091 /**! [Callback for the number of variables]*/
17092
17093 /*
17094 * Callback methods of event handler
17095 */
17096
17097 /** execution method of event handler */
17098 static
SCIP_DECL_EVENTEXEC(eventExecLinear)17099 SCIP_DECL_EVENTEXEC(eventExecLinear)
17100 { /*lint --e{715}*/
17101 SCIP_CONS* cons;
17102 SCIP_CONSDATA* consdata;
17103 SCIP_VAR* var;
17104 SCIP_EVENTTYPE eventtype;
17105
17106 assert(scip != NULL);
17107 assert(eventhdlr != NULL);
17108 assert(eventdata != NULL);
17109 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
17110 assert(event != NULL);
17111
17112 cons = eventdata->cons;
17113 assert(cons != NULL);
17114 consdata = SCIPconsGetData(cons);
17115 assert(consdata != NULL);
17116
17117 /* we can skip events droped for deleted constraints */
17118 if( SCIPconsIsDeleted(cons) )
17119 return SCIP_OKAY;
17120
17121 eventtype = SCIPeventGetType(event);
17122 var = SCIPeventGetVar(event);
17123
17124 if( (eventtype & SCIP_EVENTTYPE_BOUNDCHANGED) != 0 )
17125 {
17126 SCIP_Real oldbound;
17127 SCIP_Real newbound;
17128 SCIP_Real val;
17129 int varpos;
17130
17131 varpos = eventdata->varpos;
17132 assert(0 <= varpos && varpos < consdata->nvars);
17133 oldbound = SCIPeventGetOldbound(event);
17134 newbound = SCIPeventGetNewbound(event);
17135 assert(var != NULL);
17136 assert(consdata->vars[varpos] == var);
17137 val = consdata->vals[varpos];
17138
17139 /* we only need to update the activities if the constraint is active,
17140 * otherwise we mark them to be invalid
17141 */
17142 if( SCIPconsIsActive(cons) )
17143 {
17144 /* update the activity values */
17145 if( (eventtype & SCIP_EVENTTYPE_LBCHANGED) != 0 )
17146 consdataUpdateActivitiesLb(scip, consdata, var, oldbound, newbound, val, TRUE);
17147 else
17148 {
17149 assert((eventtype & SCIP_EVENTTYPE_UBCHANGED) != 0);
17150 consdataUpdateActivitiesUb(scip, consdata, var, oldbound, newbound, val, TRUE);
17151 }
17152 }
17153 else
17154 consdataInvalidateActivities(consdata);
17155
17156 consdata->presolved = FALSE;
17157 consdata->rangedrowpropagated = 0;
17158
17159 /* bound change can turn the constraint infeasible or redundant only if it was a tightening */
17160 if( (eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED) != 0 )
17161 {
17162 SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
17163
17164 /* reset maximal activity delta, so that it will be recalculated on the next real propagation */
17165 if( consdata->maxactdeltavar == var )
17166 {
17167 consdata->maxactdelta = SCIP_INVALID;
17168 consdata->maxactdeltavar = NULL;
17169 }
17170
17171 /* check whether bound tightening might now be successful */
17172 if( consdata->boundstightened > 0)
17173 {
17174 switch( eventtype )
17175 {
17176 case SCIP_EVENTTYPE_LBTIGHTENED:
17177 if( (val > 0.0 ? !SCIPisInfinity(scip, consdata->rhs) : !SCIPisInfinity(scip, -consdata->lhs)) )
17178 consdata->boundstightened = 0;
17179 break;
17180 case SCIP_EVENTTYPE_UBTIGHTENED:
17181 if( (val > 0.0 ? !SCIPisInfinity(scip, -consdata->lhs) : !SCIPisInfinity(scip, consdata->rhs)) )
17182 consdata->boundstightened = 0;
17183 break;
17184 default:
17185 SCIPerrorMessage("invalid event type %ld\n", eventtype);
17186 return SCIP_INVALIDDATA;
17187 }
17188 }
17189 }
17190 /* update maximal activity delta if a bound was relaxed */
17191 else if( !SCIPisInfinity(scip, consdata->maxactdelta) )
17192 {
17193 SCIP_Real lb;
17194 SCIP_Real ub;
17195 SCIP_Real domain;
17196 SCIP_Real delta;
17197
17198 assert((eventtype & SCIP_EVENTTYPE_BOUNDRELAXED) != 0);
17199
17200 lb = SCIPvarGetLbLocal(var);
17201 ub = SCIPvarGetUbLocal(var);
17202
17203 domain = ub - lb;
17204 delta = REALABS(val) * domain;
17205
17206 if( delta > consdata->maxactdelta )
17207 {
17208 consdata->maxactdelta = delta;
17209 consdata->maxactdeltavar = var;
17210 }
17211 }
17212 }
17213 else if( (eventtype & SCIP_EVENTTYPE_VARFIXED) != 0 )
17214 {
17215 /* we want to remove the fixed variable */
17216 consdata->presolved = FALSE;
17217 consdata->removedfixings = FALSE;
17218 consdata->rangedrowpropagated = 0;
17219
17220 /* reset maximal activity delta, so that it will be recalculated on the next real propagation */
17221 if( consdata->maxactdeltavar == var )
17222 {
17223 consdata->maxactdelta = SCIP_INVALID;
17224 consdata->maxactdeltavar = NULL;
17225 }
17226 }
17227 else if( (eventtype & SCIP_EVENTTYPE_VARUNLOCKED) != 0 )
17228 {
17229 /* there is only one lock left: we may multi-aggregate the variable as slack of an equation */
17230 assert(SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) <= 1);
17231 assert(SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) <= 1);
17232 consdata->presolved = FALSE;
17233 }
17234 else if( (eventtype & SCIP_EVENTTYPE_GBDCHANGED) != 0 )
17235 {
17236 SCIP_Real oldbound;
17237 SCIP_Real newbound;
17238 SCIP_Real val;
17239 int varpos;
17240
17241 varpos = eventdata->varpos;
17242 assert(0 <= varpos && varpos < consdata->nvars);
17243 oldbound = SCIPeventGetOldbound(event);
17244 newbound = SCIPeventGetNewbound(event);
17245 assert(var != NULL);
17246 assert(consdata->vars[varpos] == var);
17247 val = consdata->vals[varpos];
17248
17249 consdata->rangedrowpropagated = 0;
17250
17251 /* update the activity values */
17252 if( (eventtype & SCIP_EVENTTYPE_GLBCHANGED) != 0 )
17253 consdataUpdateActivitiesGlbLb(scip, consdata, oldbound, newbound, val, TRUE);
17254 else
17255 {
17256 assert((eventtype & SCIP_EVENTTYPE_GUBCHANGED) != 0);
17257 consdataUpdateActivitiesGlbUb(scip, consdata, oldbound, newbound, val, TRUE);
17258 }
17259
17260 /* if the variable is binary but not fixed it had to become binary due to this global change */
17261 if( SCIPvarIsBinary(var) && SCIPisGT(scip, SCIPvarGetUbGlobal(var), SCIPvarGetLbGlobal(var)) )
17262 {
17263 if( SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE )
17264 consdata->indexsorted = FALSE;
17265 else
17266 consdata->coefsorted = FALSE;
17267 }
17268 }
17269 else if( (eventtype & SCIP_EVENTTYPE_TYPECHANGED) != 0 )
17270 {
17271 assert(SCIPgetStage(scip) < SCIP_STAGE_PRESOLVED);
17272
17273 /* for presolving it only matters if a variable type changed from continuous to some kind of integer */
17274 consdata->presolved = (consdata->presolved && SCIPeventGetOldtype(event) < SCIP_VARTYPE_CONTINUOUS);
17275
17276 /* the ordering is preserved if the type changes from something different to binary to binary but SCIPvarIsBinary() is true */
17277 consdata->indexsorted = (consdata->indexsorted && SCIPeventGetNewtype(event) == SCIP_VARTYPE_BINARY && SCIPvarIsBinary(var));
17278 }
17279 else
17280 {
17281 assert((eventtype & SCIP_EVENTTYPE_VARDELETED) != 0);
17282 consdata->varsdeleted = TRUE;
17283 }
17284
17285 return SCIP_OKAY;
17286 }
17287
17288
17289 /*
17290 * Callback methods of conflict handler
17291 */
17292
17293 /** conflict processing method of conflict handler (called when conflict was found) */
17294 static
SCIP_DECL_CONFLICTEXEC(conflictExecLinear)17295 SCIP_DECL_CONFLICTEXEC(conflictExecLinear)
17296 { /*lint --e{715}*/
17297 SCIP_VAR** vars;
17298 SCIP_Real* vals;
17299 SCIP_Real lhs;
17300 int i;
17301
17302 assert(scip != NULL);
17303 assert(conflicthdlr != NULL);
17304 assert(strcmp(SCIPconflicthdlrGetName(conflicthdlr), CONFLICTHDLR_NAME) == 0);
17305 assert(bdchginfos != NULL || nbdchginfos == 0);
17306 assert(result != NULL);
17307
17308 /* don't process already resolved conflicts */
17309 if( resolved )
17310 {
17311 *result = SCIP_DIDNOTRUN;
17312 return SCIP_OKAY;
17313 }
17314
17315 *result = SCIP_DIDNOTFIND;
17316
17317 /* create array of variables and coefficients: sum_{i \in P} x_i - sum_{i \in N} x_i >= 1 - |N| */
17318 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nbdchginfos) );
17319 SCIP_CALL( SCIPallocBufferArray(scip, &vals, nbdchginfos) );
17320 lhs = 1.0;
17321 for( i = 0; i < nbdchginfos; ++i )
17322 {
17323 assert(bdchginfos != NULL);
17324
17325 vars[i] = SCIPbdchginfoGetVar(bdchginfos[i]);
17326
17327 /* we can only treat binary variables */
17328 /**@todo extend linear conflict constraints to some non-binary cases */
17329 if( !SCIPvarIsBinary(vars[i]) )
17330 break;
17331
17332 /* check whether the variable is fixed to zero (P) or one (N) in the conflict set */
17333 if( SCIPbdchginfoGetNewbound(bdchginfos[i]) < 0.5 )
17334 vals[i] = 1.0;
17335 else
17336 {
17337 vals[i] = -1.0;
17338 lhs -= 1.0;
17339 }
17340 }
17341
17342 if( i == nbdchginfos )
17343 {
17344 SCIP_CONS* cons;
17345 SCIP_CONS* upgdcons;
17346 char consname[SCIP_MAXSTRLEN];
17347
17348 /* create a constraint out of the conflict set */
17349 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "cf%" SCIP_LONGINT_FORMAT, SCIPgetNConflictConssApplied(scip));
17350 SCIP_CALL( SCIPcreateConsLinear(scip, &cons, consname, nbdchginfos, vars, vals, lhs, SCIPinfinity(scip),
17351 FALSE, separate, FALSE, FALSE, TRUE, local, FALSE, dynamic, removable, FALSE) );
17352
17353 /* try to automatically convert a linear constraint into a more specific and more specialized constraint */
17354 SCIP_CALL( SCIPupgradeConsLinear(scip, cons, &upgdcons) );
17355 if( upgdcons != NULL )
17356 {
17357 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
17358 cons = upgdcons;
17359 }
17360
17361 /* add conflict to SCIP */
17362 SCIP_CALL( SCIPaddConflict(scip, node, cons, validnode, conftype, cutoffinvolved) );
17363
17364 *result = SCIP_CONSADDED;
17365 }
17366
17367 /* free temporary memory */
17368 SCIPfreeBufferArray(scip, &vals);
17369 SCIPfreeBufferArray(scip, &vars);
17370
17371 return SCIP_OKAY;
17372 }
17373
17374
17375 /*
17376 * Quadratic constraint upgrading
17377 */
17378
17379
17380 /** upgrades quadratic constraints with only and at least one linear variables into a linear constraint
17381 */
17382 static
SCIP_DECL_QUADCONSUPGD(upgradeConsQuadratic)17383 SCIP_DECL_QUADCONSUPGD(upgradeConsQuadratic)
17384 { /*lint --e{715}*/
17385 SCIP_CONSDATA* upgdconsdata;
17386
17387 assert(scip != NULL);
17388 assert(cons != NULL);
17389 assert(nupgdconss != NULL);
17390 assert(upgdconss != NULL);
17391
17392 *nupgdconss = 0;
17393
17394 SCIPdebugMsg(scip, "upgradeConsQuadratic called for constraint <%s>\n", SCIPconsGetName(cons));
17395 SCIPdebugPrintCons(scip, cons, NULL);
17396
17397 if( SCIPgetNQuadVarTermsQuadratic(scip, cons) > 0 )
17398 return SCIP_OKAY;
17399 if( SCIPgetNLinearVarsQuadratic(scip, cons) == 0 )
17400 return SCIP_OKAY;
17401
17402 if( upgdconsssize < 1 )
17403 {
17404 /* signal that we need more memory */
17405 *nupgdconss = -1;
17406 return SCIP_OKAY;
17407 }
17408
17409 *nupgdconss = 1;
17410 SCIP_CALL( SCIPcreateConsLinear(scip, &upgdconss[0], SCIPconsGetName(cons),
17411 SCIPgetNLinearVarsQuadratic(scip, cons),
17412 SCIPgetLinearVarsQuadratic(scip, cons),
17413 SCIPgetCoefsLinearVarsQuadratic(scip, cons),
17414 SCIPgetLhsQuadratic(scip, cons), SCIPgetRhsQuadratic(scip, cons),
17415 SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
17416 SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons),
17417 SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons),
17418 SCIPconsIsStickingAtNode(cons)) );
17419
17420 upgdconsdata = SCIPconsGetData(upgdconss[0]);
17421 assert(upgdconsdata != NULL);
17422
17423 /* check violation of this linear constraint with absolute tolerances, to be consistent with the original quadratic constraint */
17424 upgdconsdata->checkabsolute = TRUE;
17425
17426 SCIPdebugMsg(scip, "created linear constraint:\n");
17427 SCIPdebugPrintCons(scip, upgdconss[0], NULL);
17428
17429 return SCIP_OKAY;
17430 }
17431
17432 /** tries to upgrade a nonlinear constraint into a linear constraint */
17433 static
SCIP_DECL_NONLINCONSUPGD(upgradeConsNonlinear)17434 SCIP_DECL_NONLINCONSUPGD(upgradeConsNonlinear)
17435 {
17436 SCIP_CONSDATA* upgdconsdata;
17437
17438 assert(nupgdconss != NULL);
17439 assert(upgdconss != NULL);
17440
17441 *nupgdconss = 0;
17442
17443 /* no interest in nonlinear constraints */
17444 if( SCIPgetExprgraphNodeNonlinear(scip, cons) != NULL )
17445 return SCIP_OKAY;
17446
17447 /* no interest in constant constraints */
17448 if( SCIPgetNLinearVarsNonlinear(scip, cons) == 0 )
17449 return SCIP_OKAY;
17450
17451 if( upgdconsssize < 1 )
17452 {
17453 /* request larger upgdconss array */
17454 *nupgdconss = -1;
17455 return SCIP_OKAY;
17456 }
17457
17458 *nupgdconss = 1;
17459 SCIP_CALL( SCIPcreateConsLinear(scip, &upgdconss[0], SCIPconsGetName(cons),
17460 SCIPgetNLinearVarsNonlinear(scip, cons), SCIPgetLinearVarsNonlinear(scip, cons), SCIPgetLinearCoefsNonlinear(scip, cons),
17461 SCIPgetLhsNonlinear(scip, cons), SCIPgetRhsNonlinear(scip, cons),
17462 SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
17463 SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons),
17464 SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons),
17465 SCIPconsIsStickingAtNode(cons)) );
17466
17467 upgdconsdata = SCIPconsGetData(upgdconss[0]);
17468 assert(upgdconsdata != NULL);
17469
17470 /* check violation of this linear constraint with absolute tolerances, to be consistent with the original nonlinear constraint */
17471 upgdconsdata->checkabsolute = TRUE;
17472
17473 SCIPdebugMsg(scip, "created linear constraint:\n");
17474 SCIPdebugPrintCons(scip, upgdconss[0], NULL);
17475
17476 return SCIP_OKAY;
17477 }
17478
17479 /*
17480 * constraint specific interface methods
17481 */
17482
17483 /** creates the handler for linear constraints and includes it in SCIP */
SCIPincludeConshdlrLinear(SCIP * scip)17484 SCIP_RETCODE SCIPincludeConshdlrLinear(
17485 SCIP* scip /**< SCIP data structure */
17486 )
17487 {
17488 SCIP_CONSHDLRDATA* conshdlrdata;
17489 SCIP_CONSHDLR* conshdlr;
17490 SCIP_EVENTHDLR* eventhdlr;
17491 SCIP_CONFLICTHDLR* conflicthdlr;
17492
17493 assert(scip != NULL);
17494
17495 /* create event handler for bound change events */
17496 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC,
17497 eventExecLinear, NULL) );
17498
17499 /* create conflict handler for linear constraints */
17500 SCIP_CALL( SCIPincludeConflicthdlrBasic(scip, &conflicthdlr, CONFLICTHDLR_NAME, CONFLICTHDLR_DESC, CONFLICTHDLR_PRIORITY,
17501 conflictExecLinear, NULL) );
17502
17503 /* create constraint handler data */
17504 SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
17505
17506 /* include constraint handler */
17507 SCIP_CALL( SCIPincludeConshdlrBasic(scip, &conshdlr, CONSHDLR_NAME, CONSHDLR_DESC,
17508 CONSHDLR_ENFOPRIORITY, CONSHDLR_CHECKPRIORITY, CONSHDLR_EAGERFREQ, CONSHDLR_NEEDSCONS,
17509 consEnfolpLinear, consEnfopsLinear, consCheckLinear, consLockLinear,
17510 conshdlrdata) );
17511
17512 assert(conshdlr != NULL);
17513
17514 /* set non-fundamental callbacks via specific setter functions */
17515 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyLinear, consCopyLinear) );
17516 SCIP_CALL( SCIPsetConshdlrDeactive(scip, conshdlr, consDeactiveLinear) );
17517 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteLinear) );
17518 SCIP_CALL( SCIPsetConshdlrDelvars(scip, conshdlr, consDelvarsLinear) );
17519 SCIP_CALL( SCIPsetConshdlrExit(scip, conshdlr, consExitLinear) );
17520 SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreLinear) );
17521 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolLinear) );
17522 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeLinear) );
17523 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsLinear) );
17524 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsLinear) );
17525 SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitLinear) );
17526 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpLinear) );
17527 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseLinear) );
17528 SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolLinear, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
17529 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintLinear) );
17530 SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropLinear, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
17531 CONSHDLR_PROP_TIMING) );
17532 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropLinear) );
17533 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpLinear, consSepasolLinear, CONSHDLR_SEPAFREQ,
17534 CONSHDLR_SEPAPRIORITY, CONSHDLR_DELAYSEPA) );
17535 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransLinear) );
17536 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxLinear) );
17537
17538 if( SCIPfindConshdlr(scip, "quadratic") != NULL )
17539 {
17540 /* include function that upgrades quadratic constraint to linear constraints */
17541 SCIP_CALL( SCIPincludeQuadconsUpgrade(scip, upgradeConsQuadratic, QUADCONSUPGD_PRIORITY, TRUE, CONSHDLR_NAME) );
17542 }
17543
17544 if( SCIPfindConshdlr(scip, "nonlinear") != NULL )
17545 {
17546 /* include the linear constraint upgrade in the nonlinear constraint handler */
17547 SCIP_CALL( SCIPincludeNonlinconsUpgrade(scip, upgradeConsNonlinear, NULL, NONLINCONSUPGD_PRIORITY, TRUE, CONSHDLR_NAME) );
17548 }
17549
17550 /* add linear constraint handler parameters */
17551 SCIP_CALL( SCIPaddIntParam(scip,
17552 "constraints/" CONSHDLR_NAME "/tightenboundsfreq",
17553 "multiplier on propagation frequency, how often the bounds are tightened (-1: never, 0: only at root)",
17554 &conshdlrdata->tightenboundsfreq, TRUE, DEFAULT_TIGHTENBOUNDSFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
17555 SCIP_CALL( SCIPaddIntParam(scip,
17556 "constraints/" CONSHDLR_NAME "/maxrounds",
17557 "maximal number of separation rounds per node (-1: unlimited)",
17558 &conshdlrdata->maxrounds, FALSE, DEFAULT_MAXROUNDS, -1, INT_MAX, NULL, NULL) );
17559 SCIP_CALL( SCIPaddIntParam(scip,
17560 "constraints/" CONSHDLR_NAME "/maxroundsroot",
17561 "maximal number of separation rounds per node in the root node (-1: unlimited)",
17562 &conshdlrdata->maxroundsroot, FALSE, DEFAULT_MAXROUNDSROOT, -1, INT_MAX, NULL, NULL) );
17563 SCIP_CALL( SCIPaddIntParam(scip,
17564 "constraints/" CONSHDLR_NAME "/maxsepacuts",
17565 "maximal number of cuts separated per separation round",
17566 &conshdlrdata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, 0, INT_MAX, NULL, NULL) );
17567 SCIP_CALL( SCIPaddIntParam(scip,
17568 "constraints/" CONSHDLR_NAME "/maxsepacutsroot",
17569 "maximal number of cuts separated per separation round in the root node",
17570 &conshdlrdata->maxsepacutsroot, FALSE, DEFAULT_MAXSEPACUTSROOT, 0, INT_MAX, NULL, NULL) );
17571 SCIP_CALL( SCIPaddBoolParam(scip,
17572 "constraints/" CONSHDLR_NAME "/presolpairwise",
17573 "should pairwise constraint comparison be performed in presolving?",
17574 &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
17575 SCIP_CALL( SCIPaddBoolParam(scip,
17576 "constraints/" CONSHDLR_NAME "/presolusehashing",
17577 "should hash table be used for detecting redundant constraints in advance",
17578 &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
17579 SCIP_CALL( SCIPaddIntParam(scip,
17580 "constraints/" CONSHDLR_NAME "/nmincomparisons",
17581 "number for minimal pairwise presolve comparisons",
17582 &conshdlrdata->nmincomparisons, TRUE, DEFAULT_NMINCOMPARISONS, 1, INT_MAX, NULL, NULL) );
17583 SCIP_CALL( SCIPaddRealParam(scip,
17584 "constraints/" CONSHDLR_NAME "/mingainpernmincomparisons",
17585 "minimal gain per minimal pairwise presolve comparisons to repeat pairwise comparison round",
17586 &conshdlrdata->mingainpernmincomp, TRUE, DEFAULT_MINGAINPERNMINCOMP, 0.0, 1.0, NULL, NULL) );
17587 SCIP_CALL( SCIPaddRealParam(scip,
17588 "constraints/" CONSHDLR_NAME "/maxaggrnormscale",
17589 "maximal allowed relative gain in maximum norm for constraint aggregation (0.0: disable constraint aggregation)",
17590 &conshdlrdata->maxaggrnormscale, TRUE, DEFAULT_MAXAGGRNORMSCALE, 0.0, SCIP_REAL_MAX, NULL, NULL) );
17591 SCIP_CALL( SCIPaddRealParam(scip,
17592 "constraints/" CONSHDLR_NAME "/maxeasyactivitydelta",
17593 "maximum activity delta to run easy propagation on linear constraint (faster, but numerically less stable)",
17594 &conshdlrdata->maxeasyactivitydelta, TRUE, DEFAULT_MAXEASYACTIVITYDELTA, 0.0, SCIP_REAL_MAX, NULL, NULL) );
17595 SCIP_CALL( SCIPaddRealParam(scip,
17596 "constraints/" CONSHDLR_NAME "/maxcardbounddist",
17597 "maximal relative distance from current node's dual bound to primal bound compared to best node's dual bound for separating knapsack cardinality cuts",
17598 &conshdlrdata->maxcardbounddist, TRUE, DEFAULT_MAXCARDBOUNDDIST, 0.0, 1.0, NULL, NULL) );
17599 SCIP_CALL( SCIPaddBoolParam(scip,
17600 "constraints/" CONSHDLR_NAME "/separateall",
17601 "should all constraints be subject to cardinality cut generation instead of only the ones with non-zero dual value?",
17602 &conshdlrdata->separateall, FALSE, DEFAULT_SEPARATEALL, NULL, NULL) );
17603 SCIP_CALL( SCIPaddBoolParam(scip,
17604 "constraints/" CONSHDLR_NAME "/aggregatevariables",
17605 "should presolving search for aggregations in equations",
17606 &conshdlrdata->aggregatevariables, TRUE, DEFAULT_AGGREGATEVARIABLES, NULL, NULL) );
17607 SCIP_CALL( SCIPaddBoolParam(scip,
17608 "constraints/" CONSHDLR_NAME "/simplifyinequalities",
17609 "should presolving try to simplify inequalities",
17610 &conshdlrdata->simplifyinequalities, TRUE, DEFAULT_SIMPLIFYINEQUALITIES, NULL, NULL) );
17611 SCIP_CALL( SCIPaddBoolParam(scip,
17612 "constraints/" CONSHDLR_NAME "/dualpresolving",
17613 "should dual presolving steps be performed?",
17614 &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
17615 SCIP_CALL( SCIPaddBoolParam(scip,
17616 "constraints/" CONSHDLR_NAME "/singletonstuffing",
17617 "should stuffing of singleton continuous variables be performed?",
17618 &conshdlrdata->singletonstuffing, TRUE, DEFAULT_SINGLETONSTUFFING, NULL, NULL) );
17619 SCIP_CALL( SCIPaddBoolParam(scip,
17620 "constraints/" CONSHDLR_NAME "/singlevarstuffing",
17621 "should single variable stuffing be performed, which tries to fulfill constraints using the cheapest variable?",
17622 &conshdlrdata->singlevarstuffing, TRUE, DEFAULT_SINGLEVARSTUFFING, NULL, NULL) );
17623 SCIP_CALL( SCIPaddBoolParam(scip,
17624 "constraints/" CONSHDLR_NAME "/sortvars", "apply binaries sorting in decr. order of coeff abs value?",
17625 &conshdlrdata->sortvars, TRUE, DEFAULT_SORTVARS, NULL, NULL) );
17626 SCIP_CALL( SCIPaddBoolParam(scip,
17627 "constraints/" CONSHDLR_NAME "/checkrelmaxabs",
17628 "should the violation for a constraint with side 0.0 be checked relative to 1.0 (FALSE) or to the maximum absolute value in the activity (TRUE)?",
17629 &conshdlrdata->checkrelmaxabs, TRUE, DEFAULT_CHECKRELMAXABS, NULL, NULL) );
17630 SCIP_CALL( SCIPaddBoolParam(scip,
17631 "constraints/" CONSHDLR_NAME "/detectcutoffbound",
17632 "should presolving try to detect constraints parallel to the objective function defining an upper bound and prevent these constraints from entering the LP?",
17633 &conshdlrdata->detectcutoffbound, TRUE, DEFAULT_DETECTCUTOFFBOUND, NULL, NULL) );
17634 SCIP_CALL( SCIPaddBoolParam(scip,
17635 "constraints/" CONSHDLR_NAME "/detectlowerbound",
17636 "should presolving try to detect constraints parallel to the objective function defining a lower bound and prevent these constraints from entering the LP?",
17637 &conshdlrdata->detectlowerbound, TRUE, DEFAULT_DETECTLOWERBOUND, NULL, NULL) );
17638 SCIP_CALL( SCIPaddBoolParam(scip,
17639 "constraints/" CONSHDLR_NAME "/detectpartialobjective",
17640 "should presolving try to detect subsets of constraints parallel to the objective function?",
17641 &conshdlrdata->detectpartialobjective, TRUE, DEFAULT_DETECTPARTIALOBJECTIVE, NULL, NULL) );
17642 SCIP_CALL( SCIPaddBoolParam(scip,
17643 "constraints/" CONSHDLR_NAME "/rangedrowpropagation",
17644 "should presolving and propagation try to improve bounds, detect infeasibility, and extract sub-constraints from ranged rows and equations?",
17645 &conshdlrdata->rangedrowpropagation, TRUE, DEFAULT_RANGEDROWPROPAGATION, NULL, NULL) );
17646 SCIP_CALL( SCIPaddBoolParam(scip,
17647 "constraints/" CONSHDLR_NAME "/rangedrowartcons",
17648 "should presolving and propagation extract sub-constraints from ranged rows and equations?",
17649 &conshdlrdata->rangedrowartcons, TRUE, DEFAULT_RANGEDROWARTCONS, NULL, NULL) );
17650 SCIP_CALL( SCIPaddIntParam(scip,
17651 "constraints/" CONSHDLR_NAME "/rangedrowmaxdepth",
17652 "maximum depth to apply ranged row propagation",
17653 &conshdlrdata->rangedrowmaxdepth, TRUE, DEFAULT_RANGEDROWMAXDEPTH, 0, INT_MAX, NULL, NULL) );
17654 SCIP_CALL( SCIPaddIntParam(scip,
17655 "constraints/" CONSHDLR_NAME "/rangedrowfreq",
17656 "frequency for applying ranged row propagation",
17657 &conshdlrdata->rangedrowfreq, TRUE, DEFAULT_RANGEDROWFREQ, 1, SCIP_MAXTREEDEPTH, NULL, NULL) );
17658 SCIP_CALL( SCIPaddBoolParam(scip,
17659 "constraints/" CONSHDLR_NAME "/multaggrremove",
17660 "should multi-aggregations only be performed if the constraint can be removed afterwards?",
17661 &conshdlrdata->multaggrremove, TRUE, DEFAULT_MULTAGGRREMOVE, NULL, NULL) );
17662 SCIP_CALL( SCIPaddRealParam(scip,
17663 "constraints/" CONSHDLR_NAME "/maxmultaggrquot",
17664 "maximum coefficient dynamism (ie. maxabsval / minabsval) for primal multiaggregation",
17665 &conshdlrdata->maxmultaggrquot, TRUE, DEFAULT_MAXMULTAGGRQUOT, 1.0, SCIP_REAL_MAX, NULL, NULL) );
17666 SCIP_CALL( SCIPaddRealParam(scip,
17667 "constraints/" CONSHDLR_NAME "/maxdualmultaggrquot",
17668 "maximum coefficient dynamism (ie. maxabsval / minabsval) for dual multiaggregation",
17669 &conshdlrdata->maxdualmultaggrquot, TRUE, DEFAULT_MAXDUALMULTAGGRQUOT, 1.0, SCIP_REAL_MAX, NULL, NULL) );
17670 SCIP_CALL( SCIPaddBoolParam(scip,
17671 "constraints/" CONSHDLR_NAME "/extractcliques",
17672 "should Cliques be extracted?",
17673 &conshdlrdata->extractcliques, TRUE, DEFAULT_EXTRACTCLIQUES, NULL, NULL) );
17674
17675 return SCIP_OKAY;
17676 }
17677
17678 /** includes a linear constraint update method into the linear constraint handler */
SCIPincludeLinconsUpgrade(SCIP * scip,SCIP_DECL_LINCONSUPGD ((* linconsupgd)),int priority,const char * conshdlrname)17679 SCIP_RETCODE SCIPincludeLinconsUpgrade(
17680 SCIP* scip, /**< SCIP data structure */
17681 SCIP_DECL_LINCONSUPGD((*linconsupgd)), /**< method to call for upgrading linear constraint */
17682 int priority, /**< priority of upgrading method */
17683 const char* conshdlrname /**< name of the constraint handler */
17684 )
17685 {
17686 SCIP_CONSHDLR* conshdlr;
17687 SCIP_CONSHDLRDATA* conshdlrdata;
17688 SCIP_LINCONSUPGRADE* linconsupgrade;
17689 char paramname[SCIP_MAXSTRLEN];
17690 char paramdesc[SCIP_MAXSTRLEN];
17691
17692 assert(scip != NULL);
17693 assert(linconsupgd != NULL);
17694 assert(conshdlrname != NULL );
17695
17696 /* find the linear constraint handler */
17697 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
17698 if( conshdlr == NULL )
17699 {
17700 SCIPerrorMessage("linear constraint handler not found\n");
17701 return SCIP_PLUGINNOTFOUND;
17702 }
17703
17704 conshdlrdata = SCIPconshdlrGetData(conshdlr);
17705 assert(conshdlrdata != NULL);
17706
17707 /* check if linear constraint update method already exists in constraint handler data */
17708 if( !conshdlrdataHasUpgrade(scip, conshdlrdata, linconsupgd, conshdlrname) )
17709 {
17710 /* create a linear constraint upgrade data object */
17711 SCIP_CALL( linconsupgradeCreate(scip, &linconsupgrade, linconsupgd, priority) );
17712
17713 /* insert linear constraint update method into constraint handler data */
17714 SCIP_CALL( conshdlrdataIncludeUpgrade(scip, conshdlrdata, linconsupgrade) );
17715
17716 /* adds parameter to turn on and off the upgrading step */
17717 (void) SCIPsnprintf(paramname, SCIP_MAXSTRLEN, "constraints/linear/upgrade/%s", conshdlrname);
17718 (void) SCIPsnprintf(paramdesc, SCIP_MAXSTRLEN, "enable linear upgrading for constraint handler <%s>", conshdlrname);
17719 SCIP_CALL( SCIPaddBoolParam(scip,
17720 paramname, paramdesc,
17721 &linconsupgrade->active, FALSE, TRUE, NULL, NULL) );
17722 }
17723
17724 return SCIP_OKAY;
17725 }
17726
17727 /** creates and captures a linear constraint
17728 *
17729 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
17730 */
SCIPcreateConsLinear(SCIP * scip,SCIP_CONS ** cons,const char * name,int nvars,SCIP_VAR ** vars,SCIP_Real * vals,SCIP_Real lhs,SCIP_Real rhs,SCIP_Bool initial,SCIP_Bool separate,SCIP_Bool enforce,SCIP_Bool check,SCIP_Bool propagate,SCIP_Bool local,SCIP_Bool modifiable,SCIP_Bool dynamic,SCIP_Bool removable,SCIP_Bool stickingatnode)17731 SCIP_RETCODE SCIPcreateConsLinear(
17732 SCIP* scip, /**< SCIP data structure */
17733 SCIP_CONS** cons, /**< pointer to hold the created constraint */
17734 const char* name, /**< name of constraint */
17735 int nvars, /**< number of nonzeros in the constraint */
17736 SCIP_VAR** vars, /**< array with variables of constraint entries */
17737 SCIP_Real* vals, /**< array with coefficients of constraint entries */
17738 SCIP_Real lhs, /**< left hand side of constraint */
17739 SCIP_Real rhs, /**< right hand side of constraint */
17740 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
17741 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
17742 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
17743 * Usually set to TRUE. */
17744 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
17745 * TRUE for model constraints, FALSE for additional, redundant constraints. */
17746 SCIP_Bool check, /**< should the constraint be checked for feasibility?
17747 * TRUE for model constraints, FALSE for additional, redundant constraints. */
17748 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
17749 * Usually set to TRUE. */
17750 SCIP_Bool local, /**< is constraint only valid locally?
17751 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
17752 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
17753 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
17754 * adds coefficients to this constraint. */
17755 SCIP_Bool dynamic, /**< is constraint subject to aging?
17756 * Usually set to FALSE. Set to TRUE for own cuts which
17757 * are separated as constraints. */
17758 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
17759 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
17760 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
17761 * if it may be moved to a more global node?
17762 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
17763 )
17764 {
17765 SCIP_CONSHDLR* conshdlr;
17766 SCIP_CONSDATA* consdata;
17767
17768 assert(scip != NULL);
17769 assert(cons != NULL);
17770
17771 /* find the linear constraint handler */
17772 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
17773 if( conshdlr == NULL )
17774 {
17775 SCIPerrorMessage("linear constraint handler not found\n");
17776 return SCIP_PLUGINNOTFOUND;
17777 }
17778
17779 /* for the solving process we need linear rows, containing only active variables; therefore when creating a linear
17780 * constraint after presolving we have to ensure that it holds active variables
17781 */
17782 if( SCIPgetStage(scip) >= SCIP_STAGE_EXITPRESOLVE && nvars > 0 )
17783 {
17784 SCIP_VAR** consvars;
17785 SCIP_Real* consvals;
17786 SCIP_Real constant = 0.0;
17787 int nconsvars;
17788 int requiredsize;
17789
17790 nconsvars = nvars;
17791 SCIP_CALL( SCIPduplicateBufferArray(scip, &consvars, vars, nconsvars) );
17792 SCIP_CALL( SCIPduplicateBufferArray(scip, &consvals, vals, nconsvars) );
17793
17794 /* get active variables for new constraint */
17795 SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, nconsvars, &constant, &requiredsize, TRUE) );
17796
17797 /* if space was not enough we need to resize the buffers */
17798 if( requiredsize > nconsvars )
17799 {
17800 SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, requiredsize) );
17801 SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, requiredsize) );
17802
17803 SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize, TRUE) );
17804 assert(requiredsize <= nconsvars);
17805 }
17806
17807 /* adjust sides and check that we do not subtract infinity values */
17808 if( SCIPisInfinity(scip, REALABS(constant)) )
17809 {
17810 if( constant < 0.0 )
17811 {
17812 if( SCIPisInfinity(scip, lhs) )
17813 {
17814 SCIPfreeBufferArray(scip, &consvals);
17815 SCIPfreeBufferArray(scip, &consvars);
17816
17817 SCIPerrorMessage("try to generate inconsistent constraint <%s>, active variables leads to a infinite constant constradict the infinite left hand side of the constraint\n", name);
17818
17819 SCIPABORT();
17820 return SCIP_INVALIDDATA; /*lint !e527*/
17821 }
17822 if( SCIPisInfinity(scip, rhs) )
17823 {
17824 SCIPfreeBufferArray(scip, &consvals);
17825 SCIPfreeBufferArray(scip, &consvars);
17826
17827 SCIPerrorMessage("try to generate inconsistent constraint <%s>, active variables leads to a infinite constant constradict the infinite right hand side of the constraint\n", name);
17828
17829 SCIPABORT();
17830 return SCIP_INVALIDDATA; /*lint !e527*/
17831 }
17832
17833 lhs = -SCIPinfinity(scip);
17834 rhs = -SCIPinfinity(scip);
17835 }
17836 else
17837 {
17838 if( SCIPisInfinity(scip, -lhs) )
17839 {
17840 SCIPfreeBufferArray(scip, &consvals);
17841 SCIPfreeBufferArray(scip, &consvars);
17842
17843 SCIPerrorMessage("try to generate inconsistent constraint <%s>, active variables leads to a infinite constant constradict the infinite left hand side of the constraint\n", name);
17844
17845 SCIPABORT();
17846 return SCIP_INVALIDDATA; /*lint !e527*/
17847 }
17848 if( SCIPisInfinity(scip, -rhs) )
17849 {
17850 SCIPfreeBufferArray(scip, &consvals);
17851 SCIPfreeBufferArray(scip, &consvars);
17852
17853 SCIPerrorMessage("try to generate inconsistent constraint <%s>, active variables leads to a infinite constant constradict the infinite right hand side of the constraint\n", name);
17854
17855 SCIPABORT();
17856 return SCIP_INVALIDDATA; /*lint !e527*/
17857 }
17858
17859 lhs = SCIPinfinity(scip);
17860 rhs = SCIPinfinity(scip);
17861 }
17862 }
17863 else
17864 {
17865 if( !SCIPisInfinity(scip, REALABS(lhs)) )
17866 lhs -= constant;
17867 if( !SCIPisInfinity(scip, REALABS(rhs)) )
17868 rhs -= constant;
17869
17870 if( SCIPisInfinity(scip, -lhs) )
17871 lhs = -SCIPinfinity(scip);
17872 else if( SCIPisInfinity(scip, lhs) )
17873 lhs = SCIPinfinity(scip);
17874
17875 if( SCIPisInfinity(scip, rhs) )
17876 rhs = SCIPinfinity(scip);
17877 else if( SCIPisInfinity(scip, -rhs) )
17878 rhs = -SCIPinfinity(scip);
17879 }
17880
17881 /* create constraint data */
17882 SCIP_CALL( consdataCreate(scip, &consdata, nconsvars, consvars, consvals, lhs, rhs) );
17883 assert(consdata != NULL);
17884
17885 SCIPfreeBufferArray(scip, &consvals);
17886 SCIPfreeBufferArray(scip, &consvars);
17887 }
17888 else
17889 {
17890 /* create constraint data */
17891 SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, vals, lhs, rhs) );
17892 assert(consdata != NULL);
17893 }
17894
17895 #ifndef NDEBUG
17896 /* if this is a checked or enforced constraints, then there must be no relaxation-only variables */
17897 if( check || enforce )
17898 {
17899 int n;
17900 for(n = consdata->nvars - 1; n >= 0; --n )
17901 assert(!SCIPvarIsRelaxationOnly(consdata->vars[n]));
17902 }
17903 #endif
17904
17905 /* create constraint */
17906 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
17907 local, modifiable, dynamic, removable, stickingatnode) );
17908
17909 return SCIP_OKAY;
17910 }
17911
17912 /** creates and captures a linear constraint
17913 * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
17914 * method SCIPcreateConsLinear(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
17915 *
17916 * @see SCIPcreateConsLinear() for information about the basic constraint flag configuration
17917 *
17918 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
17919 */
SCIPcreateConsBasicLinear(SCIP * scip,SCIP_CONS ** cons,const char * name,int nvars,SCIP_VAR ** vars,SCIP_Real * vals,SCIP_Real lhs,SCIP_Real rhs)17920 SCIP_RETCODE SCIPcreateConsBasicLinear(
17921 SCIP* scip, /**< SCIP data structure */
17922 SCIP_CONS** cons, /**< pointer to hold the created constraint */
17923 const char* name, /**< name of constraint */
17924 int nvars, /**< number of nonzeros in the constraint */
17925 SCIP_VAR** vars, /**< array with variables of constraint entries */
17926 SCIP_Real* vals, /**< array with coefficients of constraint entries */
17927 SCIP_Real lhs, /**< left hand side of constraint */
17928 SCIP_Real rhs /**< right hand side of constraint */
17929 )
17930 {
17931 assert(scip != NULL);
17932
17933 SCIP_CALL( SCIPcreateConsLinear(scip, cons, name, nvars, vars, vals, lhs, rhs,
17934 TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
17935
17936 return SCIP_OKAY;
17937 }
17938
17939 /** creates by copying and captures a linear constraint */
SCIPcopyConsLinear(SCIP * scip,SCIP_CONS ** cons,SCIP * sourcescip,const char * name,int nvars,SCIP_VAR ** sourcevars,SCIP_Real * sourcecoefs,SCIP_Real lhs,SCIP_Real rhs,SCIP_HASHMAP * varmap,SCIP_HASHMAP * consmap,SCIP_Bool initial,SCIP_Bool separate,SCIP_Bool enforce,SCIP_Bool check,SCIP_Bool propagate,SCIP_Bool local,SCIP_Bool modifiable,SCIP_Bool dynamic,SCIP_Bool removable,SCIP_Bool stickingatnode,SCIP_Bool global,SCIP_Bool * valid)17940 SCIP_RETCODE SCIPcopyConsLinear(
17941 SCIP* scip, /**< target SCIP data structure */
17942 SCIP_CONS** cons, /**< pointer to store the created target constraint */
17943 SCIP* sourcescip, /**< source SCIP data structure */
17944 const char* name, /**< name of constraint */
17945 int nvars, /**< number of variables in source variable array */
17946 SCIP_VAR** sourcevars, /**< source variables of the linear constraints */
17947 SCIP_Real* sourcecoefs, /**< coefficient array of the linear constraint, or NULL if all coefficients are one */
17948 SCIP_Real lhs, /**< left hand side of the linear constraint */
17949 SCIP_Real rhs, /**< right hand side of the linear constraint */
17950 SCIP_HASHMAP* varmap, /**< a SCIP_HASHMAP mapping variables of the source SCIP to corresponding
17951 * variables of the target SCIP */
17952 SCIP_HASHMAP* consmap, /**< a hashmap to store the mapping of source constraints to the corresponding
17953 * target constraints */
17954 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP? */
17955 SCIP_Bool separate, /**< should the constraint be separated during LP processing? */
17956 SCIP_Bool enforce, /**< should the constraint be enforced during node processing? */
17957 SCIP_Bool check, /**< should the constraint be checked for feasibility? */
17958 SCIP_Bool propagate, /**< should the constraint be propagated during node processing? */
17959 SCIP_Bool local, /**< is constraint only valid locally? */
17960 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)? */
17961 SCIP_Bool dynamic, /**< is constraint subject to aging? */
17962 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup? */
17963 SCIP_Bool stickingatnode, /**< should the constraint always be kept at the node where it was added, even
17964 * if it may be moved to a more global node? */
17965 SCIP_Bool global, /**< create a global or a local copy? */
17966 SCIP_Bool* valid /**< pointer to store if the copying was valid */
17967 )
17968 {
17969 SCIP_VAR** vars;
17970 SCIP_Real* coefs;
17971
17972 SCIP_Real constant;
17973 int requiredsize;
17974 int v;
17975 SCIP_Bool success;
17976
17977 if( SCIPisGT(scip, lhs, rhs) )
17978 {
17979 *valid = FALSE;
17980 return SCIP_OKAY;
17981 }
17982
17983 (*valid) = TRUE;
17984
17985 if( nvars == 0 )
17986 {
17987 SCIP_CALL( SCIPcreateConsLinear(scip, cons, name, 0, NULL, NULL, lhs, rhs,
17988 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
17989 return SCIP_OKAY;
17990 }
17991
17992 /* duplicate variable array */
17993 SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, sourcevars, nvars) );
17994
17995 /* duplicate coefficient array */
17996 if( sourcecoefs != NULL )
17997 {
17998 SCIP_CALL( SCIPduplicateBufferArray(scip, &coefs, sourcecoefs, nvars) );
17999 }
18000 else
18001 {
18002 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
18003 for( v = 0; v < nvars; ++v )
18004 coefs[v] = 1.0;
18005 }
18006
18007 constant = 0.0;
18008
18009 /* transform source variable to active variables of the source SCIP since only these can be mapped to variables of
18010 * the target SCIP
18011 */
18012 if( !SCIPvarIsOriginal(vars[0]) )
18013 {
18014 SCIP_CALL( SCIPgetProbvarLinearSum(sourcescip, vars, coefs, &nvars, nvars, &constant, &requiredsize, TRUE) );
18015
18016 if( requiredsize > nvars )
18017 {
18018 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, requiredsize) );
18019 SCIP_CALL( SCIPreallocBufferArray(scip, &coefs, requiredsize) );
18020
18021 SCIP_CALL( SCIPgetProbvarLinearSum(sourcescip, vars, coefs, &nvars, requiredsize, &constant, &requiredsize, TRUE) );
18022 assert(requiredsize <= nvars);
18023 }
18024 }
18025 else
18026 {
18027 for( v = 0; v < nvars; ++v )
18028 {
18029 assert(SCIPvarIsOriginal(vars[v]));
18030 SCIP_CALL( SCIPvarGetOrigvarSum(&vars[v], &coefs[v], &constant) );
18031 assert(vars[v] != NULL);
18032 }
18033 }
18034
18035 success = TRUE;
18036 /* map variables of the source constraint to variables of the target SCIP */
18037 for( v = 0; v < nvars && success; ++v )
18038 {
18039 SCIP_VAR* var;
18040 var = vars[v];
18041
18042 /* if this is a checked or enforced constraints, then there must be no relaxation-only variables */
18043 assert(!SCIPvarIsRelaxationOnly(var) || (!check && !enforce));
18044
18045 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, var, &vars[v], varmap, consmap, global, &success) );
18046 assert(!(success) || vars[v] != NULL);
18047 }
18048
18049 /* only create the target constraint, if all variables could be copied */
18050 if( success )
18051 {
18052 if( !SCIPisInfinity(scip, -lhs) )
18053 lhs -= constant;
18054
18055 if( !SCIPisInfinity(scip, rhs) )
18056 rhs -= constant;
18057
18058 SCIP_CALL( SCIPcreateConsLinear(scip, cons, name, nvars, vars, coefs, lhs, rhs,
18059 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
18060 }
18061 else
18062 *valid = FALSE;
18063
18064 /* free buffer array */
18065 SCIPfreeBufferArray(scip, &coefs);
18066 SCIPfreeBufferArray(scip, &vars);
18067
18068 return SCIP_OKAY;
18069 }
18070
18071 /** adds coefficient to linear constraint (if it is not zero) */
SCIPaddCoefLinear(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * var,SCIP_Real val)18072 SCIP_RETCODE SCIPaddCoefLinear(
18073 SCIP* scip, /**< SCIP data structure */
18074 SCIP_CONS* cons, /**< constraint data */
18075 SCIP_VAR* var, /**< variable of constraint entry */
18076 SCIP_Real val /**< coefficient of constraint entry */
18077 )
18078 {
18079 assert(scip != NULL);
18080 assert(cons != NULL);
18081 assert(var != NULL);
18082
18083 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
18084 {
18085 SCIPerrorMessage("constraint is not linear\n");
18086 return SCIP_INVALIDDATA;
18087 }
18088
18089 /* for the solving process we need linear rows, containing only active variables; therefore when creating a linear
18090 * constraint after presolving we have to ensure that it holds active variables
18091 */
18092 if( SCIPgetStage(scip) >= SCIP_STAGE_EXITPRESOLVE )
18093 {
18094 SCIP_CONSDATA* consdata;
18095 SCIP_VAR** consvars;
18096 SCIP_Real* consvals;
18097 SCIP_Real constant = 0.0;
18098 SCIP_Real rhs;
18099 SCIP_Real lhs;
18100 int nconsvars;
18101 int requiredsize;
18102 int v;
18103
18104 nconsvars = 1;
18105 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nconsvars) );
18106 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, nconsvars) );
18107 consvars[0] = var;
18108 consvals[0] = val;
18109
18110 /* get active variables for new constraint */
18111 SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, nconsvars, &constant, &requiredsize, TRUE) );
18112
18113 /* if space was not enough we need to resize the buffers */
18114 if( requiredsize > nconsvars )
18115 {
18116 SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, requiredsize) );
18117 SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, requiredsize) );
18118
18119 SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize, TRUE) );
18120 assert(requiredsize <= nconsvars);
18121 }
18122
18123 consdata = SCIPconsGetData(cons);
18124 assert(consdata != NULL);
18125
18126 lhs = consdata->lhs;
18127 rhs = consdata->rhs;
18128
18129 /* adjust sides and check that we do not subtract infinity values */
18130 /* constant is infinite */
18131 if( SCIPisInfinity(scip, REALABS(constant)) )
18132 {
18133 if( constant < 0.0 )
18134 {
18135 if( SCIPisInfinity(scip, lhs) )
18136 {
18137 SCIPfreeBufferArray(scip, &consvals);
18138 SCIPfreeBufferArray(scip, &consvars);
18139
18140 SCIPerrorMessage("adding variable <%s> leads to inconsistent constraint <%s>, active variables leads to a infinite constant constradict the infinite left hand side of the constraint\n", SCIPvarGetName(var), SCIPconsGetName(cons));
18141
18142 SCIPABORT();
18143 return SCIP_INVALIDDATA; /*lint !e527*/
18144 }
18145 if( SCIPisInfinity(scip, rhs) )
18146 {
18147 SCIPfreeBufferArray(scip, &consvals);
18148 SCIPfreeBufferArray(scip, &consvars);
18149
18150 SCIPerrorMessage("adding variable <%s> leads to inconsistent constraint <%s>, active variables leads to a infinite constant constradict the infinite right hand side of the constraint\n", SCIPvarGetName(var), SCIPconsGetName(cons));
18151
18152 SCIPABORT();
18153 return SCIP_INVALIDDATA; /*lint !e527*/
18154 }
18155
18156 lhs = -SCIPinfinity(scip);
18157 rhs = -SCIPinfinity(scip);
18158 }
18159 else
18160 {
18161 if( SCIPisInfinity(scip, -lhs) )
18162 {
18163 SCIPfreeBufferArray(scip, &consvals);
18164 SCIPfreeBufferArray(scip, &consvars);
18165
18166 SCIPerrorMessage("adding variable <%s> leads to inconsistent constraint <%s>, active variables leads to a infinite constant constradict the infinite left hand side of the constraint\n", SCIPvarGetName(var), SCIPconsGetName(cons));
18167
18168 SCIPABORT();
18169 return SCIP_INVALIDDATA; /*lint !e527*/
18170 }
18171 if( SCIPisInfinity(scip, -rhs) )
18172 {
18173 SCIPfreeBufferArray(scip, &consvals);
18174 SCIPfreeBufferArray(scip, &consvars);
18175
18176 SCIPerrorMessage("adding variable <%s> leads to inconsistent constraint <%s>, active variables leads to a infinite constant constradict the infinite right hand side of the constraint\n", SCIPvarGetName(var), SCIPconsGetName(cons));
18177
18178 SCIPABORT();
18179 return SCIP_INVALIDDATA; /*lint !e527*/
18180 }
18181
18182 lhs = SCIPinfinity(scip);
18183 rhs = SCIPinfinity(scip);
18184 }
18185 }
18186 /* constant is not infinite */
18187 else
18188 {
18189 if( !SCIPisInfinity(scip, REALABS(lhs)) )
18190 lhs -= constant;
18191 if( !SCIPisInfinity(scip, REALABS(rhs)) )
18192 rhs -= constant;
18193
18194 if( SCIPisInfinity(scip, -lhs) )
18195 lhs = -SCIPinfinity(scip);
18196 else if( SCIPisInfinity(scip, lhs) )
18197 lhs = SCIPinfinity(scip);
18198
18199 if( SCIPisInfinity(scip, rhs) )
18200 rhs = SCIPinfinity(scip);
18201 else if( SCIPisInfinity(scip, -rhs) )
18202 rhs = -SCIPinfinity(scip);
18203 }
18204
18205 /* add all active variables to constraint */
18206 for( v = nconsvars - 1; v >= 0; --v )
18207 {
18208 SCIP_CALL( addCoef(scip, cons, consvars[v], consvals[v]) );
18209 }
18210
18211 /* update left and right hand sides */
18212 SCIP_CALL( chgLhs(scip, cons, lhs));
18213 SCIP_CALL( chgRhs(scip, cons, rhs));
18214
18215 SCIPfreeBufferArray(scip, &consvals);
18216 SCIPfreeBufferArray(scip, &consvars);
18217 }
18218 else
18219 {
18220 SCIP_CALL( addCoef(scip, cons, var, val) );
18221 }
18222
18223 return SCIP_OKAY;
18224 }
18225
18226 /** changes coefficient of variable in linear constraint; deletes the variable if coefficient is zero; adds variable if
18227 * not yet contained in the constraint
18228 *
18229 * @note This method may only be called during problem creation stage for an original constraint and variable.
18230 *
18231 * @note This method requires linear time to search for occurences of the variable in the constraint data.
18232 */
SCIPchgCoefLinear(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * var,SCIP_Real val)18233 SCIP_RETCODE SCIPchgCoefLinear(
18234 SCIP* scip, /**< SCIP data structure */
18235 SCIP_CONS* cons, /**< constraint data */
18236 SCIP_VAR* var, /**< variable of constraint entry */
18237 SCIP_Real val /**< new coefficient of constraint entry */
18238 )
18239 {
18240 SCIP_CONSDATA* consdata;
18241 SCIP_VAR** vars;
18242 SCIP_Bool found;
18243 int i;
18244
18245 assert(scip != NULL);
18246 assert(cons != NULL);
18247 assert(var != NULL);
18248
18249 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
18250 {
18251 SCIPerrorMessage("constraint is not linear\n");
18252 return SCIP_INVALIDDATA;
18253 }
18254
18255 if( SCIPgetStage(scip) > SCIP_STAGE_PROBLEM || !SCIPconsIsOriginal(cons) || !SCIPvarIsOriginal(var) )
18256 {
18257 SCIPerrorMessage("method may only be called during problem creation stage for original constraints and variables\n");
18258 return SCIP_INVALIDDATA;
18259 }
18260
18261 consdata = SCIPconsGetData(cons);
18262 assert(consdata != NULL);
18263
18264 vars = consdata->vars;
18265 found = FALSE;
18266 i = 0;
18267 while( i < consdata->nvars )
18268 {
18269 if( vars[i] == var )
18270 {
18271 if( found || SCIPisZero(scip, val) )
18272 {
18273 SCIP_CALL( delCoefPos(scip, cons, i) );
18274
18275 /* decrease i by one since otherwise we would skip the coefficient which has been switched to position i */
18276 i--;
18277 }
18278 else
18279 {
18280 SCIP_CALL( chgCoefPos(scip, cons, i, val) );
18281 }
18282 found = TRUE;
18283 }
18284 i++;
18285 }
18286
18287 if( !found && !SCIPisZero(scip, val) )
18288 {
18289 SCIP_CALL( SCIPaddCoefLinear(scip, cons, var, val) );
18290 }
18291
18292 return SCIP_OKAY;
18293 }
18294
18295 /** deletes variable from linear constraint
18296 *
18297 * @note This method may only be called during problem creation stage for an original constraint and variable.
18298 *
18299 * @note This method requires linear time to search for occurences of the variable in the constraint data.
18300 */
SCIPdelCoefLinear(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * var)18301 SCIP_RETCODE SCIPdelCoefLinear(
18302 SCIP* scip, /**< SCIP data structure */
18303 SCIP_CONS* cons, /**< constraint data */
18304 SCIP_VAR* var /**< variable of constraint entry */
18305 )
18306 {
18307 assert(scip != NULL);
18308 assert(cons != NULL);
18309 assert(var != NULL);
18310
18311 SCIP_CALL( SCIPchgCoefLinear(scip, cons, var, 0.0) );
18312
18313 return SCIP_OKAY;
18314 }
18315
18316 /** gets left hand side of linear constraint */
SCIPgetLhsLinear(SCIP * scip,SCIP_CONS * cons)18317 SCIP_Real SCIPgetLhsLinear(
18318 SCIP* scip, /**< SCIP data structure */
18319 SCIP_CONS* cons /**< constraint data */
18320 )
18321 {
18322 SCIP_CONSDATA* consdata;
18323
18324 assert(scip != NULL);
18325 assert(cons != NULL);
18326
18327 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
18328 {
18329 SCIPerrorMessage("constraint is not linear\n");
18330 SCIPABORT();
18331 return SCIP_INVALID; /*lint !e527*/
18332 }
18333
18334 consdata = SCIPconsGetData(cons);
18335 assert(consdata != NULL);
18336
18337 return consdata->lhs;
18338 }
18339
18340 /** gets right hand side of linear constraint */
SCIPgetRhsLinear(SCIP * scip,SCIP_CONS * cons)18341 SCIP_Real SCIPgetRhsLinear(
18342 SCIP* scip, /**< SCIP data structure */
18343 SCIP_CONS* cons /**< constraint data */
18344 )
18345 {
18346 SCIP_CONSDATA* consdata;
18347
18348 assert(scip != NULL);
18349 assert(cons != NULL);
18350
18351 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
18352 {
18353 SCIPerrorMessage("constraint is not linear\n");
18354 SCIPABORT();
18355 return SCIP_INVALID; /*lint !e527*/
18356 }
18357
18358 consdata = SCIPconsGetData(cons);
18359 assert(consdata != NULL);
18360
18361 return consdata->rhs;
18362 }
18363
18364 /** changes left hand side of linear constraint */
SCIPchgLhsLinear(SCIP * scip,SCIP_CONS * cons,SCIP_Real lhs)18365 SCIP_RETCODE SCIPchgLhsLinear(
18366 SCIP* scip, /**< SCIP data structure */
18367 SCIP_CONS* cons, /**< constraint data */
18368 SCIP_Real lhs /**< new left hand side */
18369 )
18370 {
18371 assert(scip != NULL);
18372 assert(cons != NULL);
18373
18374 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
18375 {
18376 SCIPerrorMessage("constraint is not linear\n");
18377 return SCIP_INVALIDDATA;
18378 }
18379
18380 SCIP_CALL( chgLhs(scip, cons, lhs) );
18381
18382 return SCIP_OKAY;
18383 }
18384
18385 /** changes right hand side of linear constraint */
SCIPchgRhsLinear(SCIP * scip,SCIP_CONS * cons,SCIP_Real rhs)18386 SCIP_RETCODE SCIPchgRhsLinear(
18387 SCIP* scip, /**< SCIP data structure */
18388 SCIP_CONS* cons, /**< constraint data */
18389 SCIP_Real rhs /**< new right hand side */
18390 )
18391 {
18392 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
18393 {
18394 SCIPerrorMessage("constraint is not linear\n");
18395 return SCIP_INVALIDDATA;
18396 }
18397
18398 SCIP_CALL( chgRhs(scip, cons, rhs) );
18399
18400 return SCIP_OKAY;
18401 }
18402
18403 /** gets the number of variables in the linear constraint */
SCIPgetNVarsLinear(SCIP * scip,SCIP_CONS * cons)18404 int SCIPgetNVarsLinear(
18405 SCIP* scip, /**< SCIP data structure */
18406 SCIP_CONS* cons /**< constraint data */
18407 )
18408 {
18409 SCIP_CONSDATA* consdata;
18410
18411 assert(scip != NULL);
18412 assert(cons != NULL);
18413
18414 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
18415 {
18416 SCIPerrorMessage("constraint is not linear\n");
18417 SCIPABORT();
18418 return -1; /*lint !e527*/
18419 }
18420
18421 consdata = SCIPconsGetData(cons);
18422 assert(consdata != NULL);
18423
18424 return consdata->nvars;
18425 }
18426
18427 /** gets the array of variables in the linear constraint; the user must not modify this array! */
SCIPgetVarsLinear(SCIP * scip,SCIP_CONS * cons)18428 SCIP_VAR** SCIPgetVarsLinear(
18429 SCIP* scip, /**< SCIP data structure */
18430 SCIP_CONS* cons /**< constraint data */
18431 )
18432 {
18433 SCIP_CONSDATA* consdata;
18434
18435 assert(scip != NULL);
18436 assert(cons != NULL);
18437
18438 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
18439 {
18440 SCIPerrorMessage("constraint is not linear\n");
18441 SCIPABORT();
18442 return NULL; /*lint !e527*/
18443 }
18444
18445 consdata = SCIPconsGetData(cons);
18446 assert(consdata != NULL);
18447
18448 return consdata->vars;
18449 }
18450
18451 /** gets the array of coefficient values in the linear constraint; the user must not modify this array! */
SCIPgetValsLinear(SCIP * scip,SCIP_CONS * cons)18452 SCIP_Real* SCIPgetValsLinear(
18453 SCIP* scip, /**< SCIP data structure */
18454 SCIP_CONS* cons /**< constraint data */
18455 )
18456 {
18457 SCIP_CONSDATA* consdata;
18458
18459 assert(scip != NULL);
18460 assert(cons != NULL);
18461
18462 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
18463 {
18464 SCIPerrorMessage("constraint is not linear\n");
18465 SCIPABORT();
18466 return NULL; /*lint !e527*/
18467 }
18468
18469 consdata = SCIPconsGetData(cons);
18470 assert(consdata != NULL);
18471
18472 return consdata->vals;
18473 }
18474
18475 /** gets the activity of the linear constraint in the given solution
18476 *
18477 * @note if the solution contains values at infinity, this method will return SCIP_INVALID in case the activity
18478 * comprises positive and negative infinity contributions
18479 */
SCIPgetActivityLinear(SCIP * scip,SCIP_CONS * cons,SCIP_SOL * sol)18480 SCIP_Real SCIPgetActivityLinear(
18481 SCIP* scip, /**< SCIP data structure */
18482 SCIP_CONS* cons, /**< constraint data */
18483 SCIP_SOL* sol /**< solution, or NULL to use current node's solution */
18484 )
18485 {
18486 SCIP_CONSDATA* consdata;
18487
18488 assert(scip != NULL);
18489 assert(cons != NULL);
18490
18491 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
18492 {
18493 SCIPerrorMessage("constraint is not linear\n");
18494 SCIPABORT();
18495 return SCIP_INVALID; /*lint !e527*/
18496 }
18497
18498 consdata = SCIPconsGetData(cons);
18499 assert(consdata != NULL);
18500
18501 if( consdata->row != NULL )
18502 return SCIPgetRowSolActivity(scip, consdata->row, sol);
18503 else
18504 return consdataGetActivity(scip, consdata, sol);
18505 }
18506
18507 /** gets the feasibility of the linear constraint in the given solution */
SCIPgetFeasibilityLinear(SCIP * scip,SCIP_CONS * cons,SCIP_SOL * sol)18508 SCIP_Real SCIPgetFeasibilityLinear(
18509 SCIP* scip, /**< SCIP data structure */
18510 SCIP_CONS* cons, /**< constraint data */
18511 SCIP_SOL* sol /**< solution, or NULL to use current node's solution */
18512 )
18513 {
18514 SCIP_CONSDATA* consdata;
18515
18516 assert(scip != NULL);
18517 assert(cons != NULL);
18518
18519 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
18520 {
18521 SCIPerrorMessage("constraint is not linear\n");
18522 SCIPABORT();
18523 return SCIP_INVALID; /*lint !e527*/
18524 }
18525
18526 consdata = SCIPconsGetData(cons);
18527 assert(consdata != NULL);
18528
18529 if( consdata->row != NULL )
18530 return SCIPgetRowSolFeasibility(scip, consdata->row, sol);
18531 else
18532 return consdataGetFeasibility(scip, consdata, sol);
18533 }
18534
18535 /** gets the dual solution of the linear constraint in the current LP */
SCIPgetDualsolLinear(SCIP * scip,SCIP_CONS * cons)18536 SCIP_Real SCIPgetDualsolLinear(
18537 SCIP* scip, /**< SCIP data structure */
18538 SCIP_CONS* cons /**< constraint data */
18539 )
18540 {
18541 SCIP_CONSDATA* consdata;
18542
18543 assert(scip != NULL);
18544 assert(cons != NULL);
18545 assert(!SCIPconsIsOriginal(cons)); /* original constraints would always return 0 */
18546
18547 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
18548 {
18549 SCIPerrorMessage("constraint is not linear\n");
18550 SCIPABORT();
18551 return SCIP_INVALID; /*lint !e527*/
18552 }
18553
18554 consdata = SCIPconsGetData(cons);
18555 assert(consdata != NULL);
18556
18557 if( consdata->row != NULL )
18558 return SCIProwGetDualsol(consdata->row);
18559 else
18560 return 0.0;
18561 }
18562
18563 /** gets the dual Farkas value of the linear constraint in the current infeasible LP */
SCIPgetDualfarkasLinear(SCIP * scip,SCIP_CONS * cons)18564 SCIP_Real SCIPgetDualfarkasLinear(
18565 SCIP* scip, /**< SCIP data structure */
18566 SCIP_CONS* cons /**< constraint data */
18567 )
18568 {
18569 SCIP_CONSDATA* consdata;
18570
18571 assert(scip != NULL);
18572 assert(cons != NULL);
18573 assert(!SCIPconsIsOriginal(cons)); /* original constraints would always return 0 */
18574
18575 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
18576 {
18577 SCIPerrorMessage("constraint is not linear\n");
18578 SCIPABORT();
18579 return SCIP_INVALID; /*lint !e527*/
18580 }
18581
18582 consdata = SCIPconsGetData(cons);
18583 assert(consdata != NULL);
18584
18585 if( consdata->row != NULL )
18586 return SCIProwGetDualfarkas(consdata->row);
18587 else
18588 return 0.0;
18589 }
18590
18591 /** returns the linear relaxation of the given linear constraint; may return NULL if no LP row was yet created;
18592 * the user must not modify the row!
18593 */
SCIPgetRowLinear(SCIP * scip,SCIP_CONS * cons)18594 SCIP_ROW* SCIPgetRowLinear(
18595 SCIP* scip, /**< SCIP data structure */
18596 SCIP_CONS* cons /**< constraint data */
18597 )
18598 {
18599 SCIP_CONSDATA* consdata;
18600
18601 assert(scip != NULL);
18602 assert(cons != NULL);
18603
18604 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
18605 {
18606 SCIPerrorMessage("constraint is not linear\n");
18607 SCIPABORT();
18608 return NULL; /*lint !e527*/
18609 }
18610
18611 consdata = SCIPconsGetData(cons);
18612 assert(consdata != NULL);
18613
18614 return consdata->row;
18615 }
18616
18617 /** tries to automatically convert a linear constraint into a more specific and more specialized constraint */
SCIPupgradeConsLinear(SCIP * scip,SCIP_CONS * cons,SCIP_CONS ** upgdcons)18618 SCIP_RETCODE SCIPupgradeConsLinear(
18619 SCIP* scip, /**< SCIP data structure */
18620 SCIP_CONS* cons, /**< source constraint to try to convert */
18621 SCIP_CONS** upgdcons /**< pointer to store upgraded constraint, or NULL if not successful */
18622 )
18623 {
18624 SCIP_CONSHDLR* conshdlr;
18625 SCIP_CONSHDLRDATA* conshdlrdata;
18626 SCIP_CONSDATA* consdata;
18627 SCIP_VAR* var;
18628 SCIP_Real val;
18629 SCIP_Real lb;
18630 SCIP_Real ub;
18631 SCIP_Real poscoeffsum;
18632 SCIP_Real negcoeffsum;
18633 SCIP_Bool infeasible;
18634 SCIP_Bool integral;
18635 int nchgsides = 0;
18636 int nposbin;
18637 int nnegbin;
18638 int nposint;
18639 int nnegint;
18640 int nposimpl;
18641 int nnegimpl;
18642 int nposimplbin;
18643 int nnegimplbin;
18644 int nposcont;
18645 int nnegcont;
18646 int ncoeffspone;
18647 int ncoeffsnone;
18648 int ncoeffspint;
18649 int ncoeffsnint;
18650 int ncoeffspfrac;
18651 int ncoeffsnfrac;
18652 int i;
18653
18654 assert(scip != NULL);
18655 assert(cons != NULL);
18656 assert(upgdcons != NULL);
18657
18658 *upgdcons = NULL;
18659
18660 /* we cannot upgrade a modifiable linear constraint, since we don't know what additional coefficients to expect */
18661 if( SCIPconsIsModifiable(cons) )
18662 return SCIP_OKAY;
18663
18664 /* check for upgradability */
18665 if( SCIPconsGetNUpgradeLocks(cons) > 0 )
18666 return SCIP_OKAY;
18667
18668 /* get the constraint handler and check, if it's really a linear constraint */
18669 conshdlr = SCIPconsGetHdlr(cons);
18670 if( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
18671 {
18672 SCIPerrorMessage("constraint is not linear\n");
18673 return SCIP_INVALIDDATA;
18674 }
18675
18676 /* get constraint handler data and constraint data */
18677 conshdlrdata = SCIPconshdlrGetData(conshdlr);
18678 assert(conshdlrdata != NULL);
18679 consdata = SCIPconsGetData(cons);
18680 assert(consdata != NULL);
18681
18682 /* check, if the constraint was already upgraded and will be deleted anyway after preprocessing */
18683 if( consdata->upgraded )
18684 return SCIP_OKAY;
18685
18686 /* check, if the constraint is already stored as LP row */
18687 if( consdata->row != NULL )
18688 {
18689 if( SCIProwIsInLP(consdata->row) )
18690 {
18691 SCIPerrorMessage("cannot upgrade linear constraint that is already stored as row in the LP\n");
18692 return SCIP_INVALIDDATA;
18693 }
18694 else
18695 {
18696 SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
18697 }
18698 }
18699
18700 /* normalize constraint */
18701 SCIP_CALL( normalizeCons(scip, cons, &infeasible) );
18702
18703 /* normalizeCons() can only detect infeasibility when scaling with the gcd. in that case, the scaling was
18704 * skipped and we hope that the infeasibility gets detected later again.
18705 *
18706 * TODO: do we want to try to upgrade the constraint anyway?
18707 *
18708 * TODO: this needs to be fixed on master by changing the API and passing a pointer to whether the constraint is
18709 * proven to be infeasible.
18710 */
18711 if( infeasible ) /*lint !e774*/
18712 return SCIP_OKAY;
18713
18714 /* tighten sides */
18715 SCIP_CALL( tightenSides(scip, cons, &nchgsides, &infeasible) );
18716
18717 if( infeasible ) /*lint !e774*/
18718 return SCIP_OKAY;
18719
18720 /*
18721 * calculate some statistics on linear constraint
18722 */
18723
18724 nposbin = 0;
18725 nnegbin = 0;
18726 nposint = 0;
18727 nnegint = 0;
18728 nposimpl = 0;
18729 nnegimpl = 0;
18730 nposimplbin = 0;
18731 nnegimplbin = 0;
18732 nposcont = 0;
18733 nnegcont = 0;
18734 ncoeffspone = 0;
18735 ncoeffsnone = 0;
18736 ncoeffspint = 0;
18737 ncoeffsnint = 0;
18738 ncoeffspfrac = 0;
18739 ncoeffsnfrac = 0;
18740 integral = TRUE;
18741 poscoeffsum = 0.0;
18742 negcoeffsum = 0.0;
18743
18744 for( i = 0; i < consdata->nvars; ++i )
18745 {
18746 var = consdata->vars[i];
18747 val = consdata->vals[i];
18748 lb = SCIPvarGetLbLocal(var);
18749 ub = SCIPvarGetUbLocal(var);
18750 assert(!SCIPisZero(scip, val));
18751
18752 switch( SCIPvarGetType(var) )
18753 {
18754 case SCIP_VARTYPE_BINARY:
18755 if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
18756 integral = integral && SCIPisIntegral(scip, val);
18757 if( val >= 0.0 )
18758 nposbin++;
18759 else
18760 nnegbin++;
18761 break;
18762 case SCIP_VARTYPE_INTEGER:
18763 if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
18764 integral = integral && SCIPisIntegral(scip, val);
18765 if( val >= 0.0 )
18766 nposint++;
18767 else
18768 nnegint++;
18769 break;
18770 case SCIP_VARTYPE_IMPLINT:
18771 if( SCIPvarIsBinary(var) )
18772 {
18773 if( val >= 0.0 )
18774 nposimplbin++;
18775 else
18776 nnegimplbin++;
18777 }
18778 if( !SCIPisZero(scip, lb) || !SCIPisZero(scip, ub) )
18779 integral = integral && SCIPisIntegral(scip, val);
18780 if( val >= 0.0 )
18781 nposimpl++;
18782 else
18783 nnegimpl++;
18784 break;
18785 case SCIP_VARTYPE_CONTINUOUS:
18786 integral = integral && SCIPisEQ(scip, lb, ub) && SCIPisIntegral(scip, val * lb);
18787 if( val >= 0.0 )
18788 nposcont++;
18789 else
18790 nnegcont++;
18791 break;
18792 default:
18793 SCIPerrorMessage("unknown variable type\n");
18794 return SCIP_INVALIDDATA;
18795 }
18796 if( SCIPisEQ(scip, val, 1.0) )
18797 ncoeffspone++;
18798 else if( SCIPisEQ(scip, val, -1.0) )
18799 ncoeffsnone++;
18800 else if( SCIPisIntegral(scip, val) )
18801 {
18802 if( SCIPisPositive(scip, val) )
18803 ncoeffspint++;
18804 else
18805 ncoeffsnint++;
18806 }
18807 else
18808 {
18809 if( SCIPisPositive(scip, val) )
18810 ncoeffspfrac++;
18811 else
18812 ncoeffsnfrac++;
18813 }
18814 if( SCIPisPositive(scip, val) )
18815 poscoeffsum += val;
18816 else
18817 negcoeffsum += val;
18818 }
18819
18820 /*
18821 * call the upgrading methods
18822 */
18823
18824 SCIPdebugMsg(scip, "upgrading linear constraint <%s> (%d upgrade methods):\n",
18825 SCIPconsGetName(cons), conshdlrdata->nlinconsupgrades);
18826 SCIPdebugMsg(scip, " +bin=%d -bin=%d +int=%d -int=%d +impl=%d -impl=%d +cont=%d -cont=%d +1=%d -1=%d +I=%d -I=%d +F=%d -F=%d possum=%.15g negsum=%.15g integral=%u\n",
18827 nposbin, nnegbin, nposint, nnegint, nposimpl, nnegimpl, nposcont, nnegcont,
18828 ncoeffspone, ncoeffsnone, ncoeffspint, ncoeffsnint, ncoeffspfrac, ncoeffsnfrac,
18829 poscoeffsum, negcoeffsum, integral);
18830
18831 /* try all upgrading methods in priority order in case the upgrading step is enable */
18832 for( i = 0; i < conshdlrdata->nlinconsupgrades && *upgdcons == NULL; ++i )
18833 {
18834 if( conshdlrdata->linconsupgrades[i]->active )
18835 {
18836 SCIP_CALL( conshdlrdata->linconsupgrades[i]->linconsupgd(scip, cons, consdata->nvars,
18837 consdata->vars, consdata->vals, consdata->lhs, consdata->rhs,
18838 nposbin, nnegbin, nposint, nnegint, nposimpl, nnegimpl, nposimplbin, nnegimplbin, nposcont, nnegcont,
18839 ncoeffspone, ncoeffsnone, ncoeffspint, ncoeffsnint, ncoeffspfrac, ncoeffsnfrac,
18840 poscoeffsum, negcoeffsum, integral,
18841 upgdcons) );
18842 }
18843 }
18844
18845 #ifdef SCIP_DEBUG
18846 if( *upgdcons != NULL )
18847 {
18848 SCIPdebugPrintCons(scip, cons, NULL);
18849 SCIPdebugMsg(scip, " -> upgraded to constraint type <%s>\n", SCIPconshdlrGetName(SCIPconsGetHdlr(*upgdcons)));
18850 SCIPdebugPrintCons(scip, *upgdcons, NULL);
18851 }
18852 #endif
18853
18854 return SCIP_OKAY; /*lint !e438*/
18855 }
18856
18857 /** cleans up (multi-)aggregations and fixings from linear constraints */
SCIPcleanupConssLinear(SCIP * scip,SCIP_Bool onlychecked,SCIP_Bool * infeasible)18858 SCIP_RETCODE SCIPcleanupConssLinear(
18859 SCIP* scip, /**< SCIP data structure */
18860 SCIP_Bool onlychecked, /**< should only checked constraints be cleaned up? */
18861 SCIP_Bool* infeasible /**< pointer to return whether the problem was detected to be infeasible */
18862 )
18863 {
18864 SCIP_CONSHDLR* conshdlr;
18865 SCIP_CONS** conss;
18866 int nconss;
18867 int i;
18868
18869 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
18870 if( conshdlr == NULL )
18871 return SCIP_OKAY;
18872
18873 assert(infeasible != NULL);
18874 *infeasible = FALSE;
18875
18876 nconss = onlychecked ? SCIPconshdlrGetNCheckConss(conshdlr) : SCIPconshdlrGetNActiveConss(conshdlr);
18877 conss = onlychecked ? SCIPconshdlrGetCheckConss(conshdlr) : SCIPconshdlrGetConss(conshdlr);
18878
18879 for( i = 0; i < nconss; ++i )
18880 {
18881 SCIP_CALL( applyFixings(scip, conss[i], infeasible) );
18882
18883 if( *infeasible )
18884 break;
18885 }
18886
18887 return SCIP_OKAY;
18888 }
18889