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_setppc.c
17 * @ingroup DEFPLUGINS_CONS
18 * @brief Constraint handler for the set partitioning / packing / covering constraints \f$1^T x\ \{=, \le, \ge\}\ 1\f$.
19 * @author Tobias Achterberg
20 * @author Michael Winkler
21 */
22
23 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
24
25 #include "blockmemshell/memory.h"
26 #include "scip/cons_linear.h"
27 #include "scip/cons_quadratic.h"
28 #include "scip/cons_setppc.h"
29 #include "scip/pub_conflict.h"
30 #include "scip/pub_cons.h"
31 #include "scip/pub_event.h"
32 #include "scip/pub_lp.h"
33 #include "scip/pub_message.h"
34 #include "scip/pub_misc.h"
35 #include "scip/pub_misc_sort.h"
36 #include "scip/pub_var.h"
37 #include "scip/scip_conflict.h"
38 #include "scip/scip_cons.h"
39 #include "scip/scip_cut.h"
40 #include "scip/scip_event.h"
41 #include "scip/scip_general.h"
42 #include "scip/scip_lp.h"
43 #include "scip/scip_mem.h"
44 #include "scip/scip_message.h"
45 #include "scip/scip_numerics.h"
46 #include "scip/scip_param.h"
47 #include "scip/scip_prob.h"
48 #include "scip/scip_probing.h"
49 #include "scip/scip_randnumgen.h"
50 #include "scip/scip_sol.h"
51 #include "scip/scip_solvingstats.h"
52 #include "scip/scip_var.h"
53 #include <ctype.h>
54 #include <string.h>
55
56
57 #define CONSHDLR_NAME "setppc"
58 #define CONSHDLR_DESC "set partitioning / packing / covering constraints"
59 #define CONSHDLR_SEPAPRIORITY +700000 /**< priority of the constraint handler for separation */
60 #define CONSHDLR_ENFOPRIORITY -700000 /**< priority of the constraint handler for constraint enforcing */
61 #define CONSHDLR_CHECKPRIORITY -700000 /**< priority of the constraint handler for checking feasibility */
62 #define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
63 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
64 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
65 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
66 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
67 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
68 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
69 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
70
71 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
72 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
73
74 #define LINCONSUPGD_PRIORITY +700000 /**< priority of the constraint handler for upgrading of linear constraints */
75 #define QUADCONSUPGD_PRIORITY +700000 /**< priority of the constraint handler for upgrading of linear constraints */
76
77 #define EVENTHDLR_NAME "setppc"
78 #define EVENTHDLR_DESC "bound change event handler for set partitioning / packing / covering constraints"
79
80 #define CONFLICTHDLR_NAME "setppc"
81 #define CONFLICTHDLR_DESC "conflict handler creating set covering constraints"
82 #define CONFLICTHDLR_PRIORITY LINCONSUPGD_PRIORITY
83
84 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
85
86 #define HASHSIZE_SETPPCCONS 500 /**< minimal size of hash table in setppc constraint tables */
87 #define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
88 #define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */
89 #define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise comparison round */
90
91 #define DEFAULT_RANDSEED 3
92
93 /*#define VARUSES*/ /* activate variable usage counting, that is necessary for LP and pseudo branching */
94 /*#define BRANCHLP*/ /* BRANCHLP is only useful if the ENFOPRIORITY is set to a positive value */
95 #ifdef BRANCHLP
96 #define MINBRANCHWEIGHT 0.3 /**< minimum weight of both sets in binary set branching */
97 #define MAXBRANCHWEIGHT 0.7 /**< maximum weight of both sets in binary set branching */
98 #endif
99 #define DEFAULT_NPSEUDOBRANCHES 2 /**< number of children created in pseudo branching (0: disable branching) */
100 #define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving steps be performed? */
101
102 #define DEFAULT_CLIQUELIFTING FALSE /**< should we try to lift variables into other clique constraints, fix
103 * variables, aggregate them, and also shrink the amount of variables in
104 * clique constraints
105 */
106 #define DEFAULT_ADDVARIABLESASCLIQUES FALSE/**< should we try to generate extra clique constraint out of all binary
107 * variables to hopefully fasten the detection of redundant clique
108 * constraints */
109 #define DEFAULT_CLIQUESHRINKING TRUE /**< should we try to shrink the number of variables in a clique constraints, by
110 * replacing more than one variable by only one
111 */
112
113 /* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */
114
115 /*
116 * Data structures
117 */
118
119 /** constraint handler data */
120 struct SCIP_ConshdlrData
121 {
122 SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
123 SCIP_CONSHDLR* conshdlrlinear; /**< pointer to linear constraint handler or NULL if not included */
124 #ifdef VARUSES
125 SCIP_INTARRAY* varuses; /**< number of times a var is used in the active setppc constraints */
126 #endif
127 SCIP_Longint nsetpart; /**< number of set partitioning constraints in transformed problem */
128 int npseudobranches; /**< number of children created in pseudo branching (0 to disable branching) */
129 int noldfixedvars; /**< number of fixed variables after last clique lifting run */
130 int noldimpls; /**< number of implication before last clique lifting run */
131 int noldcliques; /**< number of cliques before last clique lifting run */
132 int noldupgrs; /**< number of setppc constraints since the last clique lifting run */
133 int nclqpresolve; /**< number of setppc clique lifting runs */
134 SCIP_Bool updatedsetppctype; /**< remember whether we upgraded a constraint type */
135 SCIP_Bool cliquelifting; /**< should we perform the clique lifting procedure */
136 SCIP_Bool enablecliquelifting;/**< check whether we have enough changes to run the lifting procedure again */
137 SCIP_Bool cliqueshrinking; /**< should we try to shrink the number of variables in a clique
138 * constraints, by replacing more than one variable by only one
139 */
140 SCIP_Bool addvariablesascliques;/**< should we try to generate extra clique constraint out of all binary
141 * variables to hopefully fasten the detection of redundant clique
142 * constraints */
143 SCIP_RANDNUMGEN* randnumgen; /**< random number generator */
144 SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
145 SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance */
146 SCIP_Bool dualpresolving; /**< should dual presolving steps be performed? */
147 };
148
149 /** constraint data for set partitioning / packing / covering constraints */
150 struct SCIP_ConsData
151 {
152 uint64_t signature; /**< bit signature of vars array */
153 SCIP_ROW* row; /**< LP row, if constraint is already stored in LP row format */
154 SCIP_VAR** vars; /**< variables of the constraint */
155 int varssize; /**< size of vars array */
156 int nvars; /**< number of variables in the constraint */
157 int nfixedzeros; /**< current number of variables fixed to zero in the constraint */
158 int nfixedones; /**< current number of variables fixed to one in the constraint */
159 unsigned int setppctype:2; /**< type of constraint: set partitioning, packing or covering */
160 unsigned int sorted:1; /**< are the constraint's variables sorted? */
161 unsigned int cliqueadded:1; /**< was the set partitioning / packing constraint already added as clique? */
162 unsigned int validsignature:1; /**< is the bit signature valid? */
163 unsigned int changed:1; /**< was constraint changed since last redundancy round in preprocessing? */
164 unsigned int varsdeleted:1; /**< were variables deleted after last cleanup? */
165 unsigned int merged:1; /**< are the constraint's equal/negated variables already merged? */
166 unsigned int presolpropagated:1; /**< was the constraint already propagated in presolving w.r.t. the current domains? */
167 unsigned int existmultaggr:1; /**< does this constraint contain aggregations */
168 unsigned int catchevents:1; /**< are events installed for this constraint? */
169 };
170
171
172
173
174 /*
175 * Local methods
176 */
177
178 /** compares two active constraints of type set partitioning or set packing such that a "-1" is return if
179 * 1. the first constraint is a set partitioning constraint and the second is a set packing or
180 * 2. both constraints are set partitioning constraints and the second has more! variables than the first or
181 * 3. both constraints are set packing constraints and the second has less! variables than the first
182 * a "0" is return if
183 * 1. both constraint are of the same type and have the amount of variables or
184 * and a "1" is returned otherwise
185 */
186 static
setppcCompare(SCIP_CONS * const cons1,SCIP_CONS * const cons2)187 int setppcCompare(
188 SCIP_CONS*const cons1, /**< first problem variable */
189 SCIP_CONS*const cons2 /**< second problem variable */
190 )
191 {
192 SCIP_CONSDATA* consdata1;
193 SCIP_CONSDATA* consdata2;
194
195 assert(cons1 != NULL);
196 assert(cons2 != NULL);
197 assert(SCIPconsIsActive(cons1));
198 assert(SCIPconsIsActive(cons2));
199
200 /* the partitioning type should be the smallest value and the packing the second smallest */
201 assert(SCIP_SETPPCTYPE_PARTITIONING < SCIP_SETPPCTYPE_PACKING); /*lint !e506*/
202
203 consdata1 = SCIPconsGetData(cons1);
204 assert(consdata1 != NULL);
205 assert(consdata1->setppctype != SCIP_SETPPCTYPE_COVERING); /*lint !e641*/
206 consdata2 = SCIPconsGetData(cons2);
207 assert(consdata2 != NULL);
208 assert(consdata2->setppctype != SCIP_SETPPCTYPE_COVERING); /*lint !e641*/
209
210 if( consdata1->setppctype < consdata2->setppctype ||
211 (consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata1->nvars < consdata2->nvars) || /*lint !e641*/
212 (consdata2->setppctype == SCIP_SETPPCTYPE_PACKING && consdata1->nvars > consdata2->nvars) ) /*lint !e641*/
213 return -1;
214 else if( (consdata1->setppctype == consdata2->setppctype && consdata1->nvars == consdata2->nvars) ) /*lint !e641*/
215 return 0;
216 else
217 {
218 assert(consdata1->setppctype > consdata2->setppctype || (consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata1->setppctype == consdata2->setppctype && consdata1->nvars > consdata2->nvars) || (consdata1->setppctype == SCIP_SETPPCTYPE_PACKING && consdata1->setppctype == consdata2->setppctype && consdata1->nvars < consdata2->nvars)); /*lint !e641*/
219 return +1;
220 }
221 }
222
223 /** sort constraints first after type (partitioning before packing before covering) and second after number of
224 * variables such that the partitioning constraints have increasing number of variables and the packing constraints
225 * have decreasing number of variables */
226 static
SCIP_DECL_SORTPTRCOMP(setppcConssSort)227 SCIP_DECL_SORTPTRCOMP(setppcConssSort)
228 {
229 return setppcCompare((SCIP_CONS*)elem1, (SCIP_CONS*)elem2);
230 }
231
232 /** compares two setppc constraints such that a "-1" is return if the first constraint is active and
233 * 1. the second constraint is deleted
234 * 2. the first constraint is a set partitioning constraint and the second is a set packing or
235 * 3. both constraints are set partitioning constraints and the second has more! variables than the first or
236 * 4. both constraints are set packing constraints and the second has less! variables than the first
237 * a "0" is return if
238 * 1. both constraint are set-covering constraints
239 * 2. both constraint are of the same type and have the amount of variables or
240 * and a "1" is returned otherwise
241 */
242 static
setppcCompare2(SCIP_CONS * const cons1,SCIP_CONS * const cons2)243 int setppcCompare2(
244 SCIP_CONS*const cons1, /**< first problem variable */
245 SCIP_CONS*const cons2 /**< second problem variable */
246 )
247 {
248 SCIP_CONSDATA* consdata1;
249 SCIP_CONSDATA* consdata2;
250
251 assert(cons1 != NULL);
252 assert(cons2 != NULL);
253
254 if( SCIPconsIsDeleted(cons1) )
255 {
256 if( SCIPconsIsDeleted(cons2) )
257 return 0;
258 else
259 return +1;
260 }
261 else if( SCIPconsIsDeleted(cons2) )
262 return -1;
263
264 consdata1 = SCIPconsGetData(cons1);
265 assert(consdata1 != NULL);
266 consdata2 = SCIPconsGetData(cons2);
267 assert(consdata2 != NULL);
268
269 /* the partitioning type should be the smallest value and the packing the second smallest */
270 assert(SCIP_SETPPCTYPE_PARTITIONING < SCIP_SETPPCTYPE_PACKING && SCIP_SETPPCTYPE_PACKING < SCIP_SETPPCTYPE_COVERING); /*lint !e506*/
271
272 if( consdata1->setppctype < consdata2->setppctype ||
273 ((SCIP_SETPPCTYPE)consdata1->setppctype != SCIP_SETPPCTYPE_COVERING &&
274 (((SCIP_SETPPCTYPE)consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata1->nvars < consdata2->nvars) ||
275 ((SCIP_SETPPCTYPE)consdata2->setppctype == SCIP_SETPPCTYPE_PACKING && consdata1->nvars > consdata2->nvars))) )
276 return -1;
277 else if( ((SCIP_SETPPCTYPE)consdata2->setppctype == SCIP_SETPPCTYPE_COVERING || (consdata1->setppctype == consdata2->setppctype && consdata1->nvars == consdata2->nvars)) )
278 return 0;
279 else
280 {
281 assert(consdata1->setppctype > consdata2->setppctype || ((consdata1->setppctype == consdata2->setppctype) &&
282 ((consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata1->nvars > consdata2->nvars)
283 || (consdata1->setppctype == SCIP_SETPPCTYPE_PACKING && consdata1->nvars < consdata2->nvars)))); /*lint !e641*/
284 return +1;
285 }
286 }
287
288 /** sort constraints first after type (partitioning before packing before covering) and second after number of
289 * variables such that the partitioning constraints have increasing number of variables and the packing constraints
290 * have decreasing number of variables */
291 static
SCIP_DECL_SORTPTRCOMP(setppcConssSort2)292 SCIP_DECL_SORTPTRCOMP(setppcConssSort2)
293 {
294 return setppcCompare2((SCIP_CONS*)elem1, (SCIP_CONS*)elem2);
295 }
296
297
298 /** installs rounding locks for the given variable in the given setppc constraint */
299 static
lockRounding(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * var)300 SCIP_RETCODE lockRounding(
301 SCIP* scip, /**< SCIP data structure */
302 SCIP_CONS* cons, /**< setppc constraint */
303 SCIP_VAR* var /**< variable of constraint entry */
304 )
305 {
306 SCIP_CONSDATA* consdata;
307
308 consdata = SCIPconsGetData(cons);
309 assert(consdata != NULL);
310
311 switch( consdata->setppctype )
312 {
313 case SCIP_SETPPCTYPE_PARTITIONING:
314 SCIP_CALL( SCIPlockVarCons(scip, var, cons, TRUE, TRUE) );
315 break;
316 case SCIP_SETPPCTYPE_PACKING:
317 SCIP_CALL( SCIPlockVarCons(scip, var, cons, FALSE, TRUE) );
318 break;
319 case SCIP_SETPPCTYPE_COVERING:
320 SCIP_CALL( SCIPlockVarCons(scip, var, cons, TRUE, FALSE) );
321 break;
322 default:
323 SCIPerrorMessage("unknown setppc type\n");
324 return SCIP_INVALIDDATA;
325 }
326
327 return SCIP_OKAY;
328 }
329
330 /** removes rounding locks for the given variable in the given setppc constraint */
331 static
unlockRounding(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * var)332 SCIP_RETCODE unlockRounding(
333 SCIP* scip, /**< SCIP data structure */
334 SCIP_CONS* cons, /**< setppc constraint */
335 SCIP_VAR* var /**< variable of constraint entry */
336 )
337 {
338 SCIP_CONSDATA* consdata;
339
340 consdata = SCIPconsGetData(cons);
341 assert(consdata != NULL);
342
343 switch( consdata->setppctype )
344 {
345 case SCIP_SETPPCTYPE_PARTITIONING:
346 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, TRUE) );
347 break;
348 case SCIP_SETPPCTYPE_PACKING:
349 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, FALSE, TRUE) );
350 break;
351 case SCIP_SETPPCTYPE_COVERING:
352 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, FALSE) );
353 break;
354 default:
355 SCIPerrorMessage("unknown setppc type\n");
356 return SCIP_INVALIDDATA;
357 }
358
359 return SCIP_OKAY;
360 }
361
362 /** creates constraint handler data for set partitioning / packing / covering constraint handler */
363 static
conshdlrdataCreate(SCIP * scip,SCIP_CONSHDLRDATA ** conshdlrdata,SCIP_EVENTHDLR * eventhdlr)364 SCIP_RETCODE conshdlrdataCreate(
365 SCIP* scip, /**< SCIP data structure */
366 SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
367 SCIP_EVENTHDLR* eventhdlr /**< event handler */
368 )
369 {
370 assert(scip != NULL);
371 assert(conshdlrdata != NULL);
372 assert(eventhdlr != NULL);
373
374 SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
375 #ifdef VARUSES
376 SCIP_CALL( SCIPcreateIntarray(scip, &(*conshdlrdata)->varuses) );
377 #endif
378 (*conshdlrdata)->npseudobranches = DEFAULT_NPSEUDOBRANCHES;
379
380 /* set event handler for bound change events */
381 (*conshdlrdata)->eventhdlr = eventhdlr;
382 (*conshdlrdata)->nsetpart = 0;
383
384 /* create a random number generator */
385 SCIP_CALL( SCIPcreateRandom(scip, &(*conshdlrdata)->randnumgen,
386 DEFAULT_RANDSEED, TRUE) );
387
388 return SCIP_OKAY;
389 }
390
391 /** frees constraint handler data for set partitioning / packing / covering constraint handler */
392 static
conshdlrdataFree(SCIP * scip,SCIP_CONSHDLRDATA ** conshdlrdata)393 SCIP_RETCODE conshdlrdataFree(
394 SCIP* scip, /**< SCIP data structure */
395 SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
396 )
397 {
398 assert(conshdlrdata != NULL);
399 assert(*conshdlrdata != NULL);
400
401 #ifdef VARUSES
402 SCIP_CALL( SCIPfreeIntarray(scip, &(*conshdlrdata)->varuses) );
403 #endif
404
405 /* free random number generator */
406 SCIPfreeRandom(scip, &(*conshdlrdata)->randnumgen);
407
408 SCIPfreeBlockMemory(scip, conshdlrdata);
409
410 return SCIP_OKAY;
411 }
412
413 #ifdef VARUSES
414 /** adds the given value to the usage counter of the given variable */
415 static
conshdlrdataAddVaruses(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_VAR * var,int addval)416 SCIP_RETCODE conshdlrdataAddVaruses(
417 SCIP* scip, /**< SCIP data structure */
418 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
419 SCIP_VAR* var, /**< variable to increase usage counter for */
420 int addval /**< value to add to the usage counter */
421 )
422 {
423 SCIP_INTARRAY* varuses;
424
425 assert(conshdlrdata != NULL);
426 assert(var != NULL);
427
428 varuses = conshdlrdata->varuses;
429 assert(varuses != NULL);
430
431 /* if the variable is the negation of a problem variable, count the varuses in the problem variable */
432 if( SCIPvarIsNegated(var) )
433 {
434 SCIP_VAR* negvar;
435 int varindex;
436
437 /* move the varuses value of the negated variable to the active problem variable */
438 varindex = SCIPvarGetIndex(var);
439 addval += SCIPgetIntarrayVal(scip, varuses, varindex);
440 SCIP_CALL( SCIPsetIntarrayVal(scip, varuses, varindex, 0) );
441 SCIP_CALL( SCIPgetNegatedVar(scip, var, &negvar) );
442 var = negvar;
443 }
444
445 /* increase varuses counter */
446 SCIP_CALL( SCIPincIntarrayVal(scip, varuses, SCIPvarGetIndex(var), addval) );
447
448 SCIPdebugMsg(scip, "added %d to varuses of <%s>: %d\n",
449 addval, SCIPvarGetName(var), SCIPgetIntarrayVal(scip, varuses, SCIPvarGetIndex(var)));
450
451 return SCIP_OKAY;
452 }
453
454 /** increases the usage counter of the given variable */
455 static
conshdlrdataIncVaruses(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_VAR * var)456 SCIP_RETCODE conshdlrdataIncVaruses(
457 SCIP* scip, /**< SCIP data structure */
458 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
459 SCIP_VAR* var /**< variable to increase usage counter for */
460 )
461 {
462 assert(conshdlrdata != NULL);
463
464 SCIPdebugMsg(scip, "increasing varuses of <%s>: %d\n",
465 SCIPvarGetName(var), SCIPgetIntarrayVal(scip, conshdlrdata->varuses, SCIPvarGetIndex(var)));
466
467 SCIP_CALL( conshdlrdataAddVaruses(scip, conshdlrdata, var, +1) );
468
469 return SCIP_OKAY;
470 }
471
472 /** decreases the usage counter of the given variable */
473 static
conshdlrdataDecVaruses(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_VAR * var)474 SCIP_RETCODE conshdlrdataDecVaruses(
475 SCIP* scip, /**< SCIP data structure */
476 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
477 SCIP_VAR* var /**< variable to increase usage counter for */
478 )
479 {
480 assert(conshdlrdata != NULL);
481
482 SCIPdebugMsg(scip, "decreasing varuses of <%s>: %d\n",
483 SCIPvarGetName(var), SCIPgetIntarrayVal(scip, conshdlrdata->varuses, SCIPvarGetIndex(var)));
484
485 SCIP_CALL( conshdlrdataAddVaruses(scip, conshdlrdata, var, -1) );
486
487 return SCIP_OKAY;
488 }
489
490 /** increases the usage counter of all variable in the constraint */
491 static
consdataIncVaruses(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_CONSDATA * consdata)492 SCIP_RETCODE consdataIncVaruses(
493 SCIP* scip, /**< SCIP data structure */
494 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
495 SCIP_CONSDATA* consdata /**< setppc constraint data */
496 )
497 {
498 int v;
499
500 assert(consdata != NULL);
501
502 for( v = 0; v < consdata->nvars; ++v )
503 {
504 SCIP_CALL( conshdlrdataIncVaruses(scip, conshdlrdata, consdata->vars[v]) );
505 }
506
507 return SCIP_OKAY;
508 }
509
510 /** decreases the usage counter of all variable in the constraint */
511 static
consdataDecVaruses(SCIP * scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_CONSDATA * consdata)512 SCIP_RETCODE consdataDecVaruses(
513 SCIP* scip, /**< SCIP data structure */
514 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
515 SCIP_CONSDATA* consdata /**< setppc constraint data */
516 )
517 {
518 int v;
519
520 assert(consdata != NULL);
521
522 for( v = 0; v < consdata->nvars; ++v )
523 {
524 SCIP_CALL( conshdlrdataDecVaruses(scip, conshdlrdata, consdata->vars[v]) );
525 }
526
527 return SCIP_OKAY;
528 }
529 #endif
530
531 /** ensures, that the vars array can store at least num entries */
532 static
consdataEnsureVarsSize(SCIP * scip,SCIP_CONSDATA * consdata,int num)533 SCIP_RETCODE consdataEnsureVarsSize(
534 SCIP* scip, /**< SCIP data structure */
535 SCIP_CONSDATA* consdata, /**< setppc constraint data */
536 int num /**< minimum number of entries to store */
537 )
538 {
539 assert(consdata != NULL);
540 assert(consdata->nvars <= consdata->varssize);
541
542 if( num > consdata->varssize )
543 {
544 int newsize;
545
546 newsize = SCIPcalcMemGrowSize(scip, num);
547 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
548 consdata->varssize = newsize;
549 }
550 assert(num <= consdata->varssize);
551
552 return SCIP_OKAY;
553 }
554
555 /** creates a set partitioning / packing / covering constraint data object */
556 static
consdataCreate(SCIP * scip,SCIP_CONSDATA ** consdata,int nvars,SCIP_VAR ** vars,SCIP_SETPPCTYPE setppctype)557 SCIP_RETCODE consdataCreate(
558 SCIP* scip, /**< SCIP data structure */
559 SCIP_CONSDATA** consdata, /**< pointer to store the set partitioning / packing / covering constraint */
560 int nvars, /**< number of variables in the constraint */
561 SCIP_VAR** vars, /**< variables of the constraint */
562 SCIP_SETPPCTYPE setppctype /**< type of constraint: set partitioning, packing, or covering constraint */
563 )
564 {
565 assert(consdata != NULL);
566 assert(nvars == 0 || vars != NULL);
567
568 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
569
570 (*consdata)->signature = 0;
571 (*consdata)->row = NULL;
572 (*consdata)->existmultaggr = FALSE;
573 (*consdata)->catchevents = FALSE;
574 (*consdata)->nfixedzeros = 0;
575 (*consdata)->nfixedones = 0;
576
577 if( nvars > 0 )
578 {
579 int v;
580
581 /* @todo the setppc constraint handler does not remove fixed variables from its var array; removing those
582 * variables is only possible if we consider the values of nfixedones and nfixedzeros in all propagation methods
583 */
584 #ifdef SCIP_DISABLED_CODE
585
586 if( SCIPisConsCompressionEnabled(scip) )
587 {
588 SCIP_VAR** varsbuffer;
589 int k;
590
591 /* allocate temporary buffer storage for active variables */
592 SCIP_CALL( SCIPallocBufferArray(scip, &varsbuffer, nvars) );
593
594 k = 0;
595 /* collect fixed variables to compress the required memory */
596 for( v = 0; v < nvars; ++v )
597 {
598 assert(SCIPvarIsBinary(vars[v]));
599
600 /* already fixed variables account as fixed ones or zero, only unfixed are appended */
601 if( SCIPvarGetLbGlobal(vars[v]) > 0.5 )
602 (*consdata)->nfixedones++;
603 else if( SCIPvarGetUbGlobal(vars[v]) < 0.5 )
604 (*consdata)->nfixedzeros++;
605 else
606 varsbuffer[k++] = vars[v];
607 }
608
609 (*consdata)->varssize = k;
610 (*consdata)->nvars = k;
611 /* copy unfixed variables into constraint data */
612 if( k > 0 )
613 {
614 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, varsbuffer, k) );
615 }
616
617 /* free temporary storage */
618 SCIPfreeBufferArray(scip, &varsbuffer);
619 }
620 else
621 #endif
622 {
623 /* for uncompressed copies, simply duplicate the whole array */
624 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
625 (*consdata)->varssize = nvars;
626 (*consdata)->nvars = nvars;
627 }
628
629 if( SCIPisTransformed(scip) )
630 {
631 /* get transformed variables */
632 SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
633
634 /* check for multi-aggregations and capture variables */
635 for( v = 0; v < (*consdata)->nvars; v++ )
636 {
637 SCIP_VAR* var = SCIPvarGetProbvar((*consdata)->vars[v]);
638 assert(var != NULL);
639 (*consdata)->existmultaggr = (*consdata)->existmultaggr || (SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR);
640 SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
641 }
642 }
643 else
644 {
645 /* capture variables */
646 for( v = 0; v < (*consdata)->nvars; v++ )
647 {
648 assert((*consdata)->vars[v] != NULL);
649 SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
650 }
651 }
652 }
653 else
654 {
655 (*consdata)->vars = NULL;
656 (*consdata)->varssize = 0;
657 (*consdata)->nvars = 0;
658 }
659 (*consdata)->setppctype = setppctype; /*lint !e641*/
660 (*consdata)->sorted = (nvars <= 1);
661 (*consdata)->cliqueadded = FALSE;
662 (*consdata)->validsignature = FALSE;
663 (*consdata)->changed = TRUE;
664 (*consdata)->varsdeleted = FALSE;
665 (*consdata)->merged = FALSE;
666 (*consdata)->presolpropagated = FALSE;
667
668 return SCIP_OKAY;
669 }
670
671 /** creates a transformed set partitioning / packing / covering constraint data object */
672 static
consdataCreateTransformed(SCIP * scip,SCIP_CONSDATA ** consdata,int nvars,SCIP_VAR ** vars,SCIP_SETPPCTYPE setppctype)673 SCIP_RETCODE consdataCreateTransformed(
674 SCIP* scip, /**< SCIP data structure */
675 SCIP_CONSDATA** consdata, /**< pointer to store the set partitioning / packing / covering constraint */
676 int nvars, /**< number of variables in the constraint */
677 SCIP_VAR** vars, /**< variables of the constraint */
678 SCIP_SETPPCTYPE setppctype /**< type of constraint: set partitioning, packing, or covering constraint */
679 )
680 {
681 assert(consdata != NULL);
682 assert(nvars == 0 || vars != NULL);
683
684 /* create constraint data */
685 SCIP_CALL( consdataCreate(scip, consdata, nvars, vars, setppctype) );
686
687 /* transform the variables */
688 SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
689
690 return SCIP_OKAY;
691 }
692
693 /** frees a set partitioning / packing / covering constraint data */
694 static
consdataFree(SCIP * scip,SCIP_CONSDATA ** consdata)695 SCIP_RETCODE consdataFree(
696 SCIP* scip, /**< SCIP data structure */
697 SCIP_CONSDATA** consdata /**< pointer to store the set partitioning / packing / covering constraint */
698 )
699 {
700 int v;
701
702 assert(consdata != NULL);
703 assert(*consdata != NULL);
704
705 /* release the row */
706 if( (*consdata)->row != NULL )
707 {
708 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
709 }
710
711 /* release variables */
712 for( v = 0; v < (*consdata)->nvars; v++ )
713 {
714 assert((*consdata)->vars[v] != NULL);
715 SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
716 }
717
718 SCIPfreeBlockMemoryArrayNull(scip, &(*consdata)->vars, (*consdata)->varssize);
719 SCIPfreeBlockMemory(scip, consdata);
720
721 return SCIP_OKAY;
722 }
723
724 /** prints set partitioning / packing / covering constraint to file stream */
725 static
consdataPrint(SCIP * scip,SCIP_CONSDATA * consdata,FILE * file)726 SCIP_RETCODE consdataPrint(
727 SCIP* scip, /**< SCIP data structure */
728 SCIP_CONSDATA* consdata, /**< set partitioning / packing / covering constraint data */
729 FILE* file /**< output file (or NULL for standard output) */
730 )
731 {
732 assert(consdata != NULL);
733
734 /* print coefficients */
735 if( consdata->nvars == 0 )
736 SCIPinfoMessage(scip, file, "0 ");
737
738 /* write linear sum */
739 SCIP_CALL( SCIPwriteVarsLinearsum(scip, file, consdata->vars, NULL, consdata->nvars, TRUE) );
740
741 /* print right hand side */
742 switch( consdata->setppctype )
743 {
744 case SCIP_SETPPCTYPE_PARTITIONING:
745 SCIPinfoMessage(scip, file, " == 1");
746 break;
747 case SCIP_SETPPCTYPE_PACKING:
748 SCIPinfoMessage(scip, file, " <= 1");
749 break;
750 case SCIP_SETPPCTYPE_COVERING:
751 SCIPinfoMessage(scip, file, " >= 1");
752 break;
753 default:
754 SCIPerrorMessage("unknown setppc type\n");
755 return SCIP_ERROR;
756 }
757
758 return SCIP_OKAY;
759 }
760
761 /** returns the bit signature of the given constraint data */
762 static
consdataGetSignature(SCIP_CONSDATA * consdata)763 uint64_t consdataGetSignature(
764 SCIP_CONSDATA* consdata /**< set partitioning / packing / covering constraint data */
765 )
766 {
767 assert(consdata != NULL);
768
769 if( !consdata->validsignature )
770 {
771 int i;
772
773 consdata->signature = 0;
774 for( i = 0; i < consdata->nvars; ++i )
775 consdata->signature |= SCIPhashSignature64(SCIPvarGetIndex(consdata->vars[i]));
776 consdata->validsignature = TRUE;
777 }
778
779 return consdata->signature;
780 }
781
782 /** sorts setppc constraint's variables by non-decreasing variable index */
783 static
consdataSort(SCIP_CONSDATA * consdata)784 void consdataSort(
785 SCIP_CONSDATA* consdata /**< linear constraint data */
786 )
787 {
788 assert(consdata != NULL);
789
790 if( !consdata->sorted )
791 {
792 if( consdata->nvars <= 1 )
793 consdata->sorted = TRUE;
794 else
795 {
796 SCIPsortPtr((void**)consdata->vars, SCIPvarComp, consdata->nvars);
797 consdata->sorted = TRUE;
798 }
799 }
800 assert(consdata->sorted);
801 #ifdef SCIP_DEBUG
802 /* check sorting */
803 {
804 int v;
805
806 for( v = 0; v < consdata->nvars; ++v )
807 {
808 assert(v == consdata->nvars-1 || SCIPvarCompare(consdata->vars[v], consdata->vars[v+1]) <= 0);
809 }
810 }
811 #endif
812 }
813
814 /** changes the type of a setppc constraint */
815 static
setSetppcType(SCIP * scip,SCIP_CONS * cons,SCIP_SETPPCTYPE setppctype)816 SCIP_RETCODE setSetppcType(
817 SCIP* scip, /**< SCIP data structure */
818 SCIP_CONS* cons, /**< setppc constraint */
819 SCIP_SETPPCTYPE setppctype /**< new type of constraint */
820 )
821 {
822 SCIP_CONSHDLR* conshdlr;
823 SCIP_CONSHDLRDATA* conshdlrdata;
824 SCIP_CONSDATA* consdata;
825 SCIP_Bool locked;
826 int i;
827
828 consdata = SCIPconsGetData(cons);
829 assert(consdata != NULL);
830
831 if( (SCIP_SETPPCTYPE)consdata->setppctype == setppctype )
832 return SCIP_OKAY;
833
834 SCIPdebugMsg(scip, " -> converting <%s> into setppc type %d\n", SCIPconsGetName(cons), setppctype);
835
836 /* remove rounding locks */
837 locked = FALSE;
838 for( i = 0; i < NLOCKTYPES && !locked; i++ )
839 locked = SCIPconsIsLockedType(cons, (SCIP_LOCKTYPE) i);
840
841 if( locked )
842 {
843 for( i = 0; i < consdata->nvars; ++i )
844 {
845 SCIP_CALL( unlockRounding(scip, cons, consdata->vars[i]) );
846 }
847 }
848
849 conshdlr = SCIPconsGetHdlr(cons);
850 assert(conshdlr != NULL);
851 conshdlrdata = SCIPconshdlrGetData(conshdlr);
852 assert(conshdlrdata != NULL);
853
854 if( SCIPisTransformed(scip) )
855 {
856 if( setppctype == SCIP_SETPPCTYPE_PARTITIONING )
857 {
858 ++(conshdlrdata->nsetpart);
859 assert(conshdlrdata->nsetpart >= 0);
860 }
861 else if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING )
862 {
863 --(conshdlrdata->nsetpart);
864 assert(conshdlrdata->nsetpart >= 0);
865 }
866 }
867
868 /* change the constraint type */
869 consdata->setppctype = setppctype; /*lint !e641*/
870
871 /* reinstall rounding locks again */
872 if( locked )
873 {
874 for( i = 0; i < consdata->nvars; ++i )
875 {
876 SCIP_CALL( lockRounding(scip, cons, consdata->vars[i]) );
877 }
878 }
879
880 /* remember that we changed a constraint type for clique lifting procedure */
881 if( setppctype != SCIP_SETPPCTYPE_COVERING )
882 conshdlrdata->updatedsetppctype = TRUE;
883
884 return SCIP_OKAY;
885 }
886
887 /** catches events for variable at given position */
888 static
catchEvent(SCIP * scip,SCIP_CONS * cons,SCIP_EVENTHDLR * eventhdlr,int pos)889 SCIP_RETCODE catchEvent(
890 SCIP* scip, /**< SCIP data structure */
891 SCIP_CONS* cons, /**< set partitioning / packing / covering constraint */
892 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
893 int pos /**< array position of variable to catch bound change events for */
894 )
895 {
896 SCIP_CONSDATA* consdata;
897 SCIP_EVENTTYPE eventtype;
898 SCIP_VAR* var;
899
900 consdata = SCIPconsGetData(cons);
901 assert(consdata != NULL);
902 assert(eventhdlr != NULL);
903 assert(0 <= pos && pos < consdata->nvars);
904 assert(consdata->vars != NULL);
905
906 var = consdata->vars[pos];
907 assert(var != NULL);
908
909 /* we are catching the following events:
910 *
911 * - SCIP_EVENTTYPE_BOUNDCHANGED: Is used to count the number of variable fixed locally to zero and one. That helps
912 * to speed up the propagation
913 *
914 * - SCIP_EVENTTYPE_VARDELETED: Is caught to remove a deleted variable from the constraint
915 *
916 * - SCIP_EVENTTYPE_VARFIXED: Is used to get informed if a variable of the constraint was aggregated which means was
917 * detected to be equal or a negated variable of on other variable. in case of a negation
918 * this could lead to a redundant constraint if the (other) active variable is also part
919 * of the constraint.
920 */
921 eventtype = SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARDELETED | SCIP_EVENTTYPE_VARFIXED;
922
923 /* catch bound change events on variable */
924 SCIP_CALL( SCIPcatchVarEvent(scip, var, eventtype, eventhdlr, (SCIP_EVENTDATA*)cons, NULL) );
925
926 /* update the fixed variables counters for this variable */
927 if( SCIPisEQ(scip, SCIPvarGetUbLocal(var), 0.0) )
928 {
929 consdata->nfixedzeros++;
930
931 /* during presolving, we may fix the last unfixed variable or do an aggregation if there are two unfixed variables */
932 if( SCIPconsIsActive(cons) && ((SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE) && (consdata->nfixedzeros >= consdata->nvars - 2)) )
933 {
934 consdata->presolpropagated = FALSE;
935
936 /* during solving, we only propagate again if there is only one unfixed variable left */
937 if( consdata->nfixedzeros >= consdata->nvars - 1 )
938 {
939 SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
940 }
941 }
942 }
943 else if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), 1.0) )
944 {
945 consdata->nfixedones++;
946
947 if( SCIPconsIsActive(cons) )
948 {
949 consdata->presolpropagated = FALSE;
950 SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
951 }
952 }
953
954 return SCIP_OKAY;
955 }
956
957 /** drops events for variable at given position */
958 static
dropEvent(SCIP * scip,SCIP_CONS * cons,SCIP_EVENTHDLR * eventhdlr,int pos)959 SCIP_RETCODE dropEvent(
960 SCIP* scip, /**< SCIP data structure */
961 SCIP_CONS* cons, /**< set partitioning / packing / covering constraint */
962 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
963 int pos /**< array position of variable to catch bound change events for */
964 )
965 {
966 SCIP_CONSDATA* consdata;
967 SCIP_EVENTTYPE eventtype;
968 SCIP_VAR* var;
969
970 consdata = SCIPconsGetData(cons);
971 assert(consdata != NULL);
972 assert(eventhdlr != NULL);
973 assert(0 <= pos && pos < consdata->nvars);
974 assert(consdata->vars != NULL);
975
976 var = consdata->vars[pos];
977 assert(var != NULL);
978
979 eventtype = SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_VARDELETED | SCIP_EVENTTYPE_VARFIXED;
980
981 /* drop events on variable */
982 SCIP_CALL( SCIPdropVarEvent(scip, var, eventtype, eventhdlr, (SCIP_EVENTDATA*)cons, -1) );
983
984 /* update the fixed variables counters for this variable */
985 if( SCIPisEQ(scip, SCIPvarGetUbLocal(var), 0.0) )
986 consdata->nfixedzeros--;
987 else if( SCIPisEQ(scip, SCIPvarGetLbLocal(var), 1.0) )
988 consdata->nfixedones--;
989
990 return SCIP_OKAY;
991 }
992
993 /** catches bound change events for all variables in transformed setppc constraint */
994 static
catchAllEvents(SCIP * scip,SCIP_CONS * cons,SCIP_EVENTHDLR * eventhdlr)995 SCIP_RETCODE catchAllEvents(
996 SCIP* scip, /**< SCIP data structure */
997 SCIP_CONS* cons, /**< set partitioning / packing / covering constraint */
998 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
999 )
1000 {
1001 SCIP_CONSDATA* consdata;
1002 int i;
1003
1004 consdata = SCIPconsGetData(cons);
1005 assert(consdata != NULL);
1006
1007 if( consdata->catchevents == TRUE )
1008 return SCIP_OKAY;
1009
1010 /* catch event for every single variable */
1011 for( i = 0; i < consdata->nvars; ++i )
1012 {
1013 SCIP_CALL( catchEvent(scip, cons, eventhdlr, i) );
1014 }
1015
1016 consdata->catchevents = TRUE;
1017
1018 return SCIP_OKAY;
1019 }
1020
1021 /** drops bound change events for all variables in transformed setppc constraint */
1022 static
dropAllEvents(SCIP * scip,SCIP_CONS * cons,SCIP_EVENTHDLR * eventhdlr)1023 SCIP_RETCODE dropAllEvents(
1024 SCIP* scip, /**< SCIP data structure */
1025 SCIP_CONS* cons, /**< set partitioning / packing / covering constraint */
1026 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
1027 )
1028 {
1029 SCIP_CONSDATA* consdata;
1030 int i;
1031
1032 consdata = SCIPconsGetData(cons);
1033 assert(consdata != NULL);
1034
1035 if( consdata->catchevents == FALSE )
1036 return SCIP_OKAY;
1037
1038 /* drop event of every single variable */
1039 for( i = 0; i < consdata->nvars; ++i )
1040 {
1041 SCIP_CALL( dropEvent(scip, cons, eventhdlr, i) );
1042 }
1043
1044 consdata->catchevents = FALSE;
1045
1046 return SCIP_OKAY;
1047 }
1048
1049 /** adds coefficient in setppc constraint */
1050 static
addCoef(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * var)1051 SCIP_RETCODE addCoef(
1052 SCIP* scip, /**< SCIP data structure */
1053 SCIP_CONS* cons, /**< setppc constraint */
1054 SCIP_VAR* var /**< variable to add to the constraint */
1055 )
1056 {
1057 SCIP_CONSDATA* consdata;
1058 SCIP_Bool transformed;
1059
1060 assert(var != NULL);
1061
1062 consdata = SCIPconsGetData(cons);
1063 assert(consdata != NULL);
1064
1065 /* are we in the transformed problem? */
1066 transformed = SCIPconsIsTransformed(cons);
1067
1068 /* always use transformed variables in transformed constraints */
1069 if( transformed )
1070 {
1071 SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
1072 }
1073 assert(var != NULL);
1074 assert(transformed == SCIPvarIsTransformed(var));
1075
1076 SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1) );
1077 consdata->vars[consdata->nvars] = var;
1078 consdata->nvars++;
1079 if( consdata->validsignature )
1080 consdata->signature |= SCIPhashSignature64(SCIPvarGetIndex(var));
1081 consdata->sorted = (consdata->nvars == 1);
1082 consdata->changed = TRUE;
1083
1084 /* capture the variable */
1085 SCIP_CALL( SCIPcaptureVar(scip, var) );
1086
1087 /* if we are in transformed problem, catch the variable's events */
1088 if( transformed )
1089 {
1090 SCIP_CONSHDLR* conshdlr;
1091 SCIP_CONSHDLRDATA* conshdlrdata;
1092
1093 /* get event handler */
1094 conshdlr = SCIPconsGetHdlr(cons);
1095 assert(conshdlr != NULL);
1096 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1097 assert(conshdlrdata != NULL);
1098 assert(conshdlrdata->eventhdlr != NULL);
1099
1100 /* catch bound change events of variable */
1101 if( consdata->catchevents )
1102 {
1103 SCIP_CALL( catchEvent(scip, cons, conshdlrdata->eventhdlr, consdata->nvars-1) );
1104 }
1105
1106 if( !consdata->existmultaggr && SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
1107 consdata->existmultaggr = TRUE;
1108
1109 #ifdef VARUSES
1110 /* if the constraint is currently active, increase the variable usage counter */
1111 if( SCIPconsIsActive(cons) )
1112 {
1113 SCIP_CALL( conshdlrdataIncVaruses(scip, conshdlrdata, var) );
1114 }
1115 #endif
1116 }
1117
1118 /* install the rounding locks for the new variable */
1119 SCIP_CALL( lockRounding(scip, cons, var) );
1120
1121 /* add the new coefficient to the LP row */
1122 if( consdata->row != NULL )
1123 {
1124 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, 1.0) );
1125 }
1126
1127 consdata->merged = FALSE;
1128 consdata->cliqueadded = FALSE;
1129
1130 return SCIP_OKAY;
1131 }
1132
1133 /** deletes coefficient at given position from setppc constraint data */
1134 static
delCoefPos(SCIP * scip,SCIP_CONS * cons,int pos)1135 SCIP_RETCODE delCoefPos(
1136 SCIP* scip, /**< SCIP data structure */
1137 SCIP_CONS* cons, /**< set partitioning / packing / covering constraint */
1138 int pos /**< position of coefficient to delete */
1139 )
1140 {
1141 SCIP_CONSDATA* consdata;
1142 SCIP_VAR* var;
1143
1144 assert(scip != NULL);
1145 assert(cons != NULL);
1146
1147 consdata = SCIPconsGetData(cons);
1148 assert(consdata != NULL);
1149 assert(0 <= pos && pos < consdata->nvars);
1150
1151 var = consdata->vars[pos];
1152 assert(var != NULL);
1153 assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(var));
1154
1155 /* remove the rounding locks for the deleted variable */
1156 SCIP_CALL( unlockRounding(scip, cons, var) );
1157
1158 /* if we are in transformed problem, delete the event data of the variable */
1159 if( SCIPconsIsTransformed(cons) )
1160 {
1161 SCIP_CONSHDLR* conshdlr;
1162 SCIP_CONSHDLRDATA* conshdlrdata;
1163
1164 /* get event handler */
1165 conshdlr = SCIPconsGetHdlr(cons);
1166 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1167 assert(conshdlrdata != NULL);
1168 assert(conshdlrdata->eventhdlr != NULL);
1169
1170 /* drop bound change events of variable */
1171 if( consdata->catchevents )
1172 {
1173 SCIP_CALL( dropEvent(scip, cons, conshdlrdata->eventhdlr, pos) );
1174 }
1175
1176 /* the last variable of the constraint was deleted; mark it for propagation (so that it can be deleted) */
1177 if( consdata->nvars == 1 )
1178 {
1179 consdata->presolpropagated = FALSE;
1180 }
1181 }
1182
1183 /* delete coefficient from the LP row */
1184 if( consdata->row != NULL )
1185 {
1186 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, -1.0) );
1187 }
1188
1189 /* move the last variable to the free slot */
1190 if( pos != consdata->nvars - 1 )
1191 {
1192 consdata->vars[pos] = consdata->vars[consdata->nvars-1];
1193 consdata->sorted = FALSE;
1194 }
1195 consdata->nvars--;
1196 consdata->validsignature = FALSE;
1197 consdata->changed = TRUE;
1198
1199 /* release variable */
1200 SCIP_CALL( SCIPreleaseVar(scip, &var) );
1201
1202 return SCIP_OKAY;
1203 }
1204
1205 /** in case a part (more than one variable) in the setppc constraint is independent of every else (is locked only by
1206 * this constraint), we can perform dual reductions;
1207 *
1208 * (1) set covering
1209 *
1210 * - fix all independent variables with negative object coefficient to one
1211 * - fix all remaining independent variables to zero
1212 *
1213 * (i) all variables are independent and the constraint is not modifiable
1214 *
1215 * - fix the variable with the smallest object coefficient to one
1216 *
1217 * (ii) a variable x has exactly 0 uplocks and arbitrary downlocks and a variable y has exactly 1 downlock and
1218 * arbitrary uplocks and obj(x) <= obj(y) and obj(y) >= 0
1219 *
1220 * - fix y to 0, because it is dominated by x
1221 *
1222 * (2) set partitioning
1223 *
1224 * (i) all variables are independent and the constraint is not modifiable
1225 *
1226 * - fix the variable with the smallest object coefficient to one
1227 * - fix all remaining independent variables to zero
1228 *
1229 * (ii) a variable x has exactly 1 uplock and arbitrary downlocks and a variable y has exactly 1 downlock and
1230 * arbitrary uplocks and obj(x) <= obj(y)
1231 *
1232 * - fix y to 0, because it is dominated by x
1233 *
1234 * (3) set packing
1235 *
1236 * (i) all variables are independent and the constraint is not modifiable
1237 *
1238 * - fix the variable with the smallest object coefficient to one if the object coefficient is negative or zero
1239 * - fix all remaining independent variables to zero
1240 *
1241 * (ii) a variable x has exactly 1 uplock and arbitrary downlocks and a variable y has exactly 0 downlocks and
1242 * arbitrary uplocks and obj(x) <= obj(y)
1243 *
1244 * - fix y to 0, because it is dominated by x
1245 *
1246 *
1247 * Note: the following dual reduction for set covering and set packing constraints is already performed by the presolver
1248 * "dualfix"
1249 * (1) in case of a set covering constraint the following dual reduction can be performed:
1250 * - if a variable in a set covering constraint is only locked by that constraint and has negative or zero
1251 * objective coefficient than it can be fixed to one
1252 * (2) in case of a set packing constraint the following dual reduction can be performed:
1253 * - if a variable in a set packing constraint is only locked by that constraint and has positive or zero
1254 * objective coefficient than it can be fixed to zero
1255 *
1256 * Note: all dual reduction (ii) could also be performed by the "domcol" presolver, but cause the pairwise comparison of
1257 * columns is only done heuristically (and here it should be even cheaper) we perform them here (too)
1258 *
1259 */
1260 static
dualPresolving(SCIP * scip,SCIP_CONS * cons,int * nfixedvars,int * ndelconss,SCIP_RESULT * result)1261 SCIP_RETCODE dualPresolving(
1262 SCIP* scip, /**< SCIP data structure */
1263 SCIP_CONS* cons, /**< setppc constraint */
1264 int* nfixedvars, /**< pointer to count number of fixings */
1265 int* ndelconss, /**< pointer to count number of deleted constraints */
1266 SCIP_RESULT* result /**< pointer to store the result SCIP_SUCCESS, if presolving was performed */
1267 )
1268 {
1269 SCIP_CONSDATA* consdata;
1270 SCIP_SETPPCTYPE setppctype;
1271 SCIP_VAR** vars;
1272 SCIP_VAR* activevar;
1273 SCIP_VAR* var;
1274 SCIP_Real bestobjval;
1275 SCIP_Real objval;
1276 SCIP_Real fixval;
1277 SCIP_Bool infeasible;
1278 SCIP_Bool fixed;
1279 SCIP_Bool negated;
1280 int noldfixed;
1281 int nposfixings;
1282 int nlockdowns;
1283 int nlockups;
1284 int nvars;
1285 int idx;
1286 int v;
1287
1288 assert(scip != NULL);
1289 assert(cons != NULL);
1290 assert(nfixedvars != NULL);
1291 assert(ndelconss != NULL);
1292 assert(result != NULL);
1293
1294 /* constraints for which the check flag is set to FALSE, did not contribute to the lock numbers; therefore, we cannot
1295 * use the locks to decide for a dual reduction using this constraint; for example after a restart the cuts which are
1296 * added to the problems have the check flag set to FALSE
1297 */
1298 if( !SCIPconsIsChecked(cons) )
1299 return SCIP_OKAY;
1300
1301 assert(SCIPconsIsActive(cons));
1302
1303 consdata = SCIPconsGetData(cons);
1304 assert(consdata != NULL);
1305
1306 /* modifiable non-covering constraints cannot be deleted if one variable is fixed to one, because the propagation for
1307 * newly inserted variables must be considered later
1308 */
1309 if( consdata->nfixedones == 1 && SCIPconsIsModifiable(cons) )
1310 return SCIP_OKAY;
1311
1312 /* all fixed variables should be removed at that point */
1313 assert(consdata->nfixedones == 0);
1314 assert(consdata->nfixedzeros == 0);
1315
1316 nvars = consdata->nvars;
1317
1318 /* we don't want to consider small constraints (note that the constraints can be modifiable, so we can't delete this
1319 * constraint)
1320 */
1321 if( nvars < 2 )
1322 return SCIP_OKAY;
1323
1324 setppctype = (SCIP_SETPPCTYPE)consdata->setppctype;
1325 vars = consdata->vars;
1326 idx = -1;
1327 bestobjval = SCIP_INVALID;
1328
1329 /* collect the rounding locks depending on the setppc type */
1330 switch( setppctype )
1331 {
1332 case SCIP_SETPPCTYPE_PARTITIONING:
1333 nlockdowns = 1;
1334 nlockups = 1;
1335 break;
1336 case SCIP_SETPPCTYPE_PACKING:
1337 nlockdowns = 0;
1338 nlockups = 1;
1339 break;
1340 case SCIP_SETPPCTYPE_COVERING:
1341 nlockdowns = 1;
1342 nlockups = 0;
1343 break;
1344 default:
1345 SCIPerrorMessage("unknown setppc type\n");
1346 SCIPABORT();
1347 return SCIP_INVALIDDATA; /*lint !e527*/
1348 }
1349
1350 nposfixings = 0;
1351
1352 /* check if we can apply the dual reduction; therefore count the number of variables where the setppc has the only
1353 * locks on this constraint
1354 */
1355 for( v = 0; v < nvars; ++v )
1356 {
1357 var = vars[v];
1358 assert(var != NULL);
1359
1360 /* the variable should not be (globally) fixed */
1361 assert(SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5);
1362
1363 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) >= nlockdowns
1364 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == nlockups )
1365 {
1366 activevar = var;
1367 negated = FALSE;
1368
1369 /* get the active variable */
1370 SCIP_CALL( SCIPvarGetProbvarBinary(&activevar, &negated) );
1371 assert(SCIPvarIsActive(activevar));
1372
1373 if( negated )
1374 objval = -SCIPvarGetObj(activevar);
1375 else
1376 objval = SCIPvarGetObj(activevar);
1377
1378 /* check if the current variable has a smaller objective coefficient */
1379 if( idx == -1 || objval < bestobjval )
1380 {
1381 idx = v;
1382 bestobjval = objval;
1383 }
1384 }
1385
1386 /* in case another constraint has also downlocks on that variable we cannot perform a dual reduction on these
1387 * variables
1388 */
1389 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == nlockdowns
1390 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) >= nlockups )
1391 ++nposfixings;
1392 }
1393
1394 if( idx == -1 || nposfixings == 0 )
1395 return SCIP_OKAY;
1396
1397 SCIPdebugMsg(scip, "dual fixing constraint: \n");
1398 SCIPdebug( SCIP_CALL( SCIPprintCons(scip, cons, NULL) ) );
1399 SCIPdebug( SCIPinfoMessage(scip, NULL, "\n") );
1400
1401 assert(idx >= 0 && idx < nvars);
1402 assert(bestobjval < SCIPinfinity(scip));
1403
1404 noldfixed = *nfixedvars;
1405
1406 /* in case of set packing and set partitioning we fix the dominated variables to zero */
1407 if( setppctype != SCIP_SETPPCTYPE_COVERING )
1408 {
1409 /* first part of all variables */
1410 for( v = nvars - 1; v >= 0; --v )
1411 {
1412 if( v == idx )
1413 continue;
1414
1415 var = vars[v];
1416 assert(var != NULL);
1417
1418 /* in case another constraint has also downlocks on that variable we cannot perform a dual reduction on these
1419 * variables
1420 */
1421 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == nlockdowns
1422 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) >= nlockups )
1423 {
1424 activevar = var;
1425 negated = FALSE;
1426
1427 /* get the active variable */
1428 SCIP_CALL( SCIPvarGetProbvarBinary(&activevar, &negated) );
1429 assert(SCIPvarIsActive(activevar));
1430
1431 if( negated )
1432 objval = -SCIPvarGetObj(activevar);
1433 else
1434 objval = SCIPvarGetObj(activevar);
1435
1436 if( objval >= bestobjval )
1437 {
1438 SCIP_CALL( SCIPfixVar(scip, var, 0.0, &infeasible, &fixed) );
1439 assert(!infeasible);
1440 assert(fixed);
1441
1442 SCIPdebugMsg(scip, " -> dual-fixed dominated variable <%s> == 0.0\n", SCIPvarGetName(var));
1443 ++(*nfixedvars);
1444 }
1445 }
1446 }
1447 }
1448 /* if we got a set covering constraint and not all variables are locked from this constraint it might not get
1449 * redundant (which is case if it is not possible to fix at least one variable to one), we fix all redundant
1450 * variables to their best bound
1451 */
1452 else
1453 {
1454 /* first part of all variables */
1455 for( v = nvars - 1; v >= 0; --v )
1456 {
1457 if( v == idx )
1458 continue;
1459
1460 var = vars[v];
1461 assert(var != NULL);
1462
1463 /* in case another constraint has also downlocks on that variable we cannot perform a dual reduction on these
1464 * variables
1465 */
1466 if( SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == nlockdowns
1467 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) >= nlockups )
1468 {
1469 activevar = var;
1470 negated = FALSE;
1471
1472 /* get the active variable */
1473 SCIP_CALL( SCIPvarGetProbvarBinary(&activevar, &negated) );
1474 assert(SCIPvarIsActive(activevar));
1475 assert(negated
1476 || (SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == SCIPvarGetNLocksDownType(activevar, SCIP_LOCKTYPE_MODEL)
1477 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == SCIPvarGetNLocksUpType(activevar, SCIP_LOCKTYPE_MODEL)));
1478 assert(!negated
1479 || (SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == SCIPvarGetNLocksUpType(activevar, SCIP_LOCKTYPE_MODEL)
1480 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == SCIPvarGetNLocksDownType(activevar, SCIP_LOCKTYPE_MODEL)));
1481
1482 if( negated )
1483 objval = -SCIPvarGetObj(activevar);
1484 else
1485 objval = SCIPvarGetObj(activevar);
1486
1487 if( objval > 0.0 )
1488 fixval = 0.0;
1489 else
1490 fixval = 1.0;
1491
1492 /* if variables has a negative objective contribution, and is uplocked by another constraint we cannot fix
1493 * the variables to 1
1494 */
1495 if( (fixval == 1.0 && SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) > nlockups) || objval < bestobjval )
1496 continue;
1497
1498 SCIP_CALL( SCIPfixVar(scip, var, fixval, &infeasible, &fixed) );
1499 assert(!infeasible);
1500 assert(fixed);
1501
1502 SCIPdebugMsg(scip, " -> dual-fixed dominated variable <%s> == %g\n", SCIPvarGetName(var), fixval);
1503 ++(*nfixedvars);
1504 }
1505 }
1506 }
1507
1508 /* if all variables but the domination variable is fixed and the constraint is not modifiable or the constraint is a
1509 * covering constraint and the bestobjval is less than or equal to zero, we can fix the domination variable (with best
1510 * objective coefficient) and the constraint gets redundant
1511 */
1512 if( ((*nfixedvars - noldfixed == nvars - 1) && !SCIPconsIsModifiable(cons)) || (setppctype == SCIP_SETPPCTYPE_COVERING && bestobjval <= 0.0) )
1513 {
1514 /* in case of a set packing constraint with positive objective values, all variables can be fixed to zero; in all
1515 * other cases the variable with the smallest objective values is fixed to one
1516 */
1517 if( (setppctype == SCIP_SETPPCTYPE_PACKING && bestobjval > 0.0
1518 && SCIPvarGetNLocksDownType(vars[idx], SCIP_LOCKTYPE_MODEL) == 0)
1519 || setppctype != SCIP_SETPPCTYPE_PACKING || bestobjval <= 0.0 )
1520 {
1521 if( setppctype == SCIP_SETPPCTYPE_PACKING && bestobjval > 0.0 )
1522 fixval = 0.0;
1523 else
1524 fixval = 1.0;
1525
1526 SCIP_CALL( SCIPfixVar(scip, vars[idx], fixval, &infeasible, &fixed) );
1527 assert(!infeasible);
1528 assert(fixed);
1529
1530 SCIPdebugMsg(scip, " -> dual-fixed best variable <%s> == %g\n", SCIPvarGetName(vars[idx]), fixval);
1531 ++(*nfixedvars);
1532 }
1533
1534 /* check that we really have a non-violated constraint in hand before deleting */
1535 assert((setppctype == SCIP_SETPPCTYPE_PACKING && consdata->nfixedones <= 1) ||
1536 (setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata->nfixedones == 1) ||
1537 (setppctype == SCIP_SETPPCTYPE_COVERING && consdata->nfixedones >= 1));
1538
1539 /* remove constraint since it is redundant */
1540 SCIP_CALL( SCIPdelCons(scip, cons) );
1541 ++(*ndelconss);
1542 }
1543
1544 assert(*nfixedvars >= noldfixed);
1545
1546 /* set result pointer to SCIP_SUCCESS, if variables could be fixed */
1547 if( *nfixedvars != noldfixed )
1548 *result = SCIP_SUCCESS;
1549
1550 return SCIP_OKAY;
1551 }
1552
1553 /** find pairs of negated variables in constraint:
1554 * partitioning/packing: all other variables must be zero, constraint is redundant
1555 * covering: constraint is redundant
1556 *
1557 * find sets of equal variables in constraint:
1558 * partitioning/packing: variable must be zero
1559 * covering: multiple entries of variable can be replaced by single entry
1560 */
1561 static
mergeMultiples(SCIP * scip,SCIP_CONS * cons,int * nfixedvars,int * ndelconss,int * nchgcoefs,SCIP_Bool * cutoff)1562 SCIP_RETCODE mergeMultiples(
1563 SCIP* scip, /**< SCIP data structure */
1564 SCIP_CONS* cons, /**< knapsack constraint */
1565 int* nfixedvars, /**< pointer to store number of fixed variables */
1566 int* ndelconss, /**< pointer to store number of deleted constraints */
1567 int* nchgcoefs, /**< pointer to store number of changed coefficients */
1568 SCIP_Bool* cutoff /**< pointer to store whether a fixing leads to a cutoff */
1569 )
1570 {
1571 SCIP_CONSDATA* consdata;
1572 int v;
1573
1574 assert(scip != NULL);
1575 assert(cons != NULL);
1576 assert(nfixedvars != NULL);
1577 assert(ndelconss != NULL);
1578 assert(nchgcoefs != NULL);
1579 assert(cutoff != NULL);
1580
1581 consdata = SCIPconsGetData(cons);
1582 assert(consdata != NULL);
1583
1584 if( consdata->merged || SCIPconsIsDeleted(cons) )
1585 return SCIP_OKAY;
1586
1587 if( consdata->nvars <= 1 )
1588 {
1589 consdata->merged = TRUE;
1590 return SCIP_OKAY;
1591 }
1592
1593 assert(consdata->vars != NULL || consdata->nvars == 0);
1594
1595 /* sorting array after indices of variables, that's only for faster merging */
1596 SCIPsortPtr((void**)consdata->vars, SCIPvarCompActiveAndNegated, consdata->nvars);
1597 /* setppc sorting now lost */
1598 consdata->sorted = FALSE;
1599
1600 /* loop backwards through the items: deletion only affects rear items */
1601 for( v = consdata->nvars - 1; v > 0; --v )
1602 {
1603 SCIP_VAR* var1;
1604 SCIP_VAR* var2;
1605 SCIP_Bool negated1;
1606 SCIP_Bool negated2;
1607
1608 negated1 = FALSE;
1609 negated2 = FALSE;
1610
1611 var1 = consdata->vars[v];
1612 assert(SCIPvarIsBinary(var1));
1613 assert(SCIPvarIsActive(var1) || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(var1) == SCIP_VARSTATUS_FIXED);
1614 if( SCIPvarGetStatus(var1) == SCIP_VARSTATUS_NEGATED )
1615 {
1616 var1 = SCIPvarGetNegatedVar(var1);
1617 negated1 = TRUE;
1618 }
1619 assert(var1 != NULL);
1620
1621 var2 = consdata->vars[v-1];
1622 assert(SCIPvarIsBinary(var2));
1623 assert(SCIPvarIsActive(var2) || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(var2) == SCIP_VARSTATUS_FIXED);
1624 if( SCIPvarGetStatus(var2) == SCIP_VARSTATUS_NEGATED )
1625 {
1626 var2 = SCIPvarGetNegatedVar(var2);
1627 negated2 = TRUE;
1628 }
1629 assert(var2 != NULL);
1630
1631 if( var1 == var2 )
1632 {
1633 SCIP_Bool infeasible;
1634 SCIP_Bool fixed;
1635
1636 /* one variables is active and the other is the same negated variable */
1637 if( negated1 != negated2 )
1638 {
1639 /* all other variable have to be zero if it's a partitioning or packing constraint */
1640 if( consdata->setppctype != SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
1641 {
1642 int i;
1643
1644 assert(consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING
1645 || consdata->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/
1646
1647 for( i = consdata->nvars - 1; i >= 0; --i )
1648 if( i != v && i != (v-1) )
1649 {
1650 SCIP_CALL( SCIPfixVar(scip, consdata->vars[i], 0.0, &infeasible, &fixed) );
1651 if( infeasible )
1652 {
1653 SCIPdebugMsg(scip, "setppc constraint <%s>: infeasible fixing <%s> == 0\n",
1654 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[i]));
1655 *cutoff = TRUE;
1656 return SCIP_OKAY;
1657 }
1658
1659 if( fixed )
1660 ++(*nfixedvars);
1661 }
1662 }
1663 /* all setppc-type constraints are redundant */
1664 SCIP_CALL( SCIPdelCons(scip, cons) );
1665 ++(*ndelconss);
1666 return SCIP_OKAY;
1667 }
1668 /* both variables are either active or negated */
1669 else
1670 {
1671 /* this variable can be fixed to zero if it's a partitioning or packing constraint */
1672 if( consdata->setppctype != SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
1673 {
1674 assert(consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING
1675 || consdata->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/
1676
1677 SCIP_CALL( SCIPfixVar(scip, var1, negated1 ? 1.0 : 0.0, &infeasible, &fixed) );
1678 if( infeasible )
1679 {
1680 SCIPdebugMsg(scip, "setppc constraint <%s>: infeasible fixing <%s> == %g\n",
1681 SCIPconsGetName(cons), SCIPvarGetName(var1), negated1 ? 1.0 : 0.0);
1682 *cutoff = TRUE;
1683 return SCIP_OKAY;
1684 }
1685
1686 if( fixed )
1687 ++(*nfixedvars);
1688 }
1689 /* multiple entries of variable can be replaced by single entry */
1690 else
1691 {
1692 SCIP_CALL( delCoefPos(scip, cons, v) ); /* only some changed behind position v-1, so it's okay */
1693 ++(*nchgcoefs);
1694 }
1695 }
1696 consdata->changed = TRUE;
1697 }
1698 }
1699 consdata->merged = TRUE;
1700
1701 return SCIP_OKAY;
1702 }
1703
1704 /** deletes all zero-fixed variables and replace aggregated variables */
1705 static
applyFixings(SCIP * scip,SCIP_CONS * cons,int * naddconss,int * ndelconss,int * nfixedvars,SCIP_Bool * cutoff)1706 SCIP_RETCODE applyFixings(
1707 SCIP* scip, /**< SCIP data structure */
1708 SCIP_CONS* cons, /**< set partitioning / packing / covering constraint */
1709 int* naddconss, /**< pointer to count number of added constraints, or NULL indicating we
1710 * can not resolve multi-aggregations
1711 */
1712 int* ndelconss, /**< pointer to count number of deleted constraints, or NULL indicating we
1713 * can not resolve multi-aggregations
1714 */
1715 int* nfixedvars, /**< pointer to store number of fixed variables, or NULL indicating we can
1716 * not resolve multi-aggregations
1717 */
1718 SCIP_Bool* cutoff /**< pointer to store whether a fixing leads to a cutoff, or NULL
1719 * indicating we can not resolve multi-aggregations
1720 */
1721 )
1722 {
1723 SCIP_CONSDATA* consdata;
1724 int v;
1725
1726 assert(scip != NULL);
1727 assert(cons != NULL);
1728
1729 consdata = SCIPconsGetData(cons);
1730 assert(consdata != NULL);
1731
1732 /* all multi-aggregations should be resolved */
1733 consdata->existmultaggr = FALSE;
1734
1735 v = 0;
1736 while( v < consdata->nvars )
1737 {
1738 SCIP_VAR* var;
1739
1740 var = consdata->vars[v];
1741 assert(SCIPvarIsBinary(var));
1742
1743 if( SCIPvarGetUbGlobal(var) < 0.5 )
1744 {
1745 assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(var), 0.0));
1746 SCIP_CALL( delCoefPos(scip, cons, v) );
1747 }
1748 else
1749 {
1750 SCIP_VAR* repvar;
1751 SCIP_Bool negated;
1752
1753 /* get binary representative of variable */
1754 SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
1755
1756 /* resolve multi-aggregation */
1757 if( SCIPvarGetStatus(repvar) == SCIP_VARSTATUS_MULTAGGR || (SCIPvarGetStatus(repvar) == SCIP_VARSTATUS_NEGATED && SCIPvarGetStatus(SCIPvarGetNegatedVar(repvar)) == SCIP_VARSTATUS_MULTAGGR) )
1758 {
1759 SCIP_VAR** consvars;
1760 SCIP_Real* consvals;
1761 SCIP_Real constant = 0.0;
1762 SCIP_Bool easycase;
1763 int nconsvars;
1764 int requiredsize;
1765 int v2;
1766
1767 nconsvars = 1;
1768 SCIP_CALL( SCIPallocBufferArray(scip, &consvars, 1) );
1769 SCIP_CALL( SCIPallocBufferArray(scip, &consvals, 1) );
1770 consvars[0] = repvar;
1771 consvals[0] = 1.0;
1772
1773 /* get active variables for new constraint */
1774 SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, nconsvars, &constant, &requiredsize, TRUE) );
1775 /* if space was not enough we need to resize the buffers */
1776 if( requiredsize > nconsvars )
1777 {
1778 SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, requiredsize) );
1779 SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, requiredsize) );
1780
1781 SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize, TRUE) );
1782 assert(requiredsize <= nconsvars);
1783 }
1784
1785 easycase = FALSE;
1786
1787 if( SCIPisZero(scip, constant) )
1788 {
1789 /* add active representation */
1790 for( v2 = nconsvars - 1; v2 >= 0; --v2 )
1791 {
1792 if( !SCIPvarIsBinary(consvars[v2]) )
1793 break;
1794
1795 if( !SCIPisEQ(scip, consvals[v2], 1.0) )
1796 break;
1797 }
1798
1799 if( v2 < 0 )
1800 easycase = TRUE;
1801 }
1802 else if( SCIPisFeasEQ(scip, constant, 1.0) )
1803 {
1804 /* check for another multi-aggregation */
1805 for( v2 = consdata->nvars - 1; v2 > v; --v2 )
1806 {
1807 if( SCIPvarGetStatus(SCIPvarGetProbvar(consdata->vars[v])) == SCIP_VARSTATUS_MULTAGGR )
1808 break;
1809 }
1810
1811 /* constraint is redundant */
1812 if( v2 == v && nconsvars == 0 )
1813 {
1814 /* we can fix */
1815 if( consdata->nvars > 1 && (SCIP_SETPPCTYPE)consdata->setppctype != SCIP_SETPPCTYPE_COVERING )
1816 {
1817 if( nfixedvars != NULL )
1818 {
1819 SCIP_Bool fixed;
1820
1821 assert(cutoff != NULL);
1822
1823 for( v2 = consdata->nvars - 1; v2 >= 0; --v2 )
1824 {
1825 if( consdata->vars[v2] != var )
1826 {
1827 SCIPdebugMsg(scip, "trying to fix <%s> to 0 due to at least one variable is already fixed to 1\n", SCIPvarGetName(consdata->vars[v2]));
1828
1829 /* fix all remaining variables to zero, constraint is already feasible or infeasible */
1830 SCIP_CALL( SCIPfixVar(scip, consdata->vars[v2], 0.0, cutoff, &fixed) );
1831 if( *cutoff )
1832 {
1833 SCIPdebugMsg(scip, "setppc constraint <%s>: infeasible fixing <%s> == 0\n",
1834 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[v2]));
1835
1836 SCIPfreeBufferArray(scip, &consvals);
1837 SCIPfreeBufferArray(scip, &consvars);
1838
1839 goto TERMINATE;
1840 }
1841
1842 if( fixed )
1843 ++(*nfixedvars);
1844 }
1845 }
1846 }
1847 }
1848
1849 if( ndelconss != NULL && (nfixedvars != NULL || consdata->nvars == 1 || (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_COVERING) )
1850 {
1851 /* delete old constraint */
1852 SCIP_CALL( SCIPdelCons(scip, cons) );
1853 ++(*ndelconss);
1854 }
1855 SCIPfreeBufferArray(scip, &consvals);
1856 SCIPfreeBufferArray(scip, &consvars);
1857
1858 goto TERMINATE;
1859 }
1860 }
1861
1862 /* we can easily add the coefficients and still have a setppc constraint */
1863 if( easycase )
1864 {
1865 /* delete old (multi-aggregated) variable */
1866 SCIP_CALL( delCoefPos(scip, cons, v) );
1867
1868 /* add active representation */
1869 for( v2 = nconsvars - 1; v2 >= 0; --v2 )
1870 {
1871 assert(SCIPvarIsBinary(consvars[v2]));
1872 assert(SCIPvarIsActive(consvars[v2]) || (SCIPvarGetStatus(consvars[v2]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(consvars[v2]))));
1873
1874 SCIP_CALL( addCoef(scip, cons, consvars[v2]) );
1875 }
1876 }
1877 /* we need to degrade this setppc constraint to a linear constraint */
1878 else if( (ndelconss != NULL && naddconss != NULL) || SCIPconsIsAdded(cons) )
1879 {
1880 char name[SCIP_MAXSTRLEN];
1881 SCIP_CONS* newcons;
1882 SCIP_Real lhs;
1883 SCIP_Real rhs;
1884 int size;
1885 int k;
1886
1887 /* it might happen that there are more than one multi-aggregated variable, so we need to get the whole
1888 * probvar sum over all variables
1889 */
1890
1891 size = MAX(nconsvars, 1) + consdata->nvars - 1;
1892
1893 /* memory needed is at least old number of variables - 1 + number of variables in first multi-aggregation */
1894 SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, size) );
1895 SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, size) );
1896
1897 nconsvars = consdata->nvars;
1898
1899 /* add constraint variables to new linear variables */
1900 for( k = consdata->nvars - 1; k >= 0; --k )
1901 {
1902 consvars[k] = consdata->vars[k];
1903 consvals[k] = 1.0;
1904 }
1905
1906 constant = 0.0;
1907
1908 /* get active variables for new constraint */
1909 SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, size, &constant, &requiredsize, TRUE) );
1910
1911 /* if space was not enough (we found another multi-aggregation), we need to resize the buffers */
1912 if( requiredsize > nconsvars )
1913 {
1914 SCIP_CALL( SCIPreallocBufferArray(scip, &consvars, requiredsize) );
1915 SCIP_CALL( SCIPreallocBufferArray(scip, &consvals, requiredsize) );
1916
1917 SCIP_CALL( SCIPgetProbvarLinearSum(scip, consvars, consvals, &nconsvars, requiredsize, &constant, &requiredsize, TRUE) );
1918 assert(requiredsize <= nconsvars);
1919 }
1920
1921 /* compute sides */
1922 if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING )
1923 {
1924 lhs = -SCIPinfinity(scip);
1925 rhs = 1.0 - constant;
1926 }
1927 else if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING )
1928 {
1929 lhs = 1.0 - constant;
1930 rhs = 1.0 - constant;
1931 }
1932 else
1933 {
1934 assert((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_COVERING);
1935 lhs = 1.0 - constant;
1936 rhs = SCIPinfinity(scip);
1937 }
1938
1939 /* create linear constraint */
1940 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s", SCIPconsGetName(cons));
1941 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, nconsvars, consvars, consvals, lhs, rhs,
1942 SCIPconsIsInitial(cons),
1943 SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons), SCIPconsIsChecked(cons),
1944 SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons),
1945 SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );
1946 SCIP_CALL( SCIPaddCons(scip, newcons) );
1947
1948 SCIPdebugMsg(scip, "added linear constraint: ");
1949 SCIPdebugPrintCons(scip, newcons, NULL);
1950 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1951
1952 SCIPfreeBufferArray(scip, &consvals);
1953 SCIPfreeBufferArray(scip, &consvars);
1954
1955 /* delete old constraint */
1956 SCIP_CALL( SCIPdelCons(scip, cons) );
1957 if( ndelconss != NULL && naddconss != NULL )
1958 {
1959 ++(*ndelconss);
1960 ++(*naddconss);
1961 }
1962
1963 goto TERMINATE;
1964 }
1965 /* we need to degrade this setppc constraint to a linear constraint*/
1966 else
1967 {
1968 /* check, if the variable should be replaced with the representative */
1969 if( repvar != var )
1970 {
1971 /* delete old (aggregated) variable */
1972 SCIP_CALL( delCoefPos(scip, cons, v) );
1973
1974 /* add representative instead */
1975 SCIP_CALL( addCoef(scip, cons, repvar) );
1976 }
1977
1978 SCIPwarningMessage(scip, "setppc constraint <%s> has a multi-aggregated variable, which was not resolved and therefore could lead to aborts\n", SCIPconsGetName(cons));
1979 ++v;
1980 }
1981
1982 SCIPfreeBufferArray(scip, &consvals);
1983 SCIPfreeBufferArray(scip, &consvars);
1984 }
1985 else
1986 {
1987 /* check, if the variable should be replaced with the representative */
1988 if( repvar != var )
1989 {
1990 /* delete old (aggregated) variable */
1991 SCIP_CALL( delCoefPos(scip, cons, v) );
1992
1993 /* add representative instead */
1994 SCIP_CALL( addCoef(scip, cons, repvar) );
1995 }
1996 else
1997 ++v;
1998 }
1999 }
2000 }
2001
2002 TERMINATE:
2003 /* all multi-aggregations should be resolved */
2004 consdata->existmultaggr = FALSE;
2005
2006 return SCIP_OKAY;
2007 }
2008
2009 /** analyzes conflicting assignment on given constraint where all of the variables where assigned to zero,
2010 * and adds conflict constraint to problem
2011 */
2012 static
analyzeConflictZero(SCIP * scip,SCIP_CONS * cons)2013 SCIP_RETCODE analyzeConflictZero(
2014 SCIP* scip, /**< SCIP data structure */
2015 SCIP_CONS* cons /**< set partitioning / packing / covering constraint that detected the conflict */
2016 )
2017 {
2018 SCIP_CONSDATA* consdata;
2019 int v;
2020
2021 /* conflict analysis can only be applied in solving stage and if it is applicable */
2022 if( (SCIPgetStage(scip) != SCIP_STAGE_SOLVING && !SCIPinProbing(scip)) || !SCIPisConflictAnalysisApplicable(scip) )
2023 return SCIP_OKAY;
2024
2025 consdata = SCIPconsGetData(cons);
2026 assert(consdata != NULL);
2027 assert(consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING
2028 || consdata->setppctype == SCIP_SETPPCTYPE_COVERING); /*lint !e641*/
2029
2030 /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */
2031 SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) );
2032
2033 for( v = 0; v < consdata->nvars; ++v )
2034 {
2035 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[v]) );
2036 }
2037
2038 /* analyze the conflict */
2039 SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
2040
2041 return SCIP_OKAY;
2042 }
2043
2044 /** analyzes conflicting assignment on given constraint where two of the variables where assigned to one,
2045 * and adds conflict constraint to problem
2046 */
2047 static
analyzeConflictOne(SCIP * scip,SCIP_CONS * cons)2048 SCIP_RETCODE analyzeConflictOne(
2049 SCIP* scip, /**< SCIP data structure */
2050 SCIP_CONS* cons /**< set partitioning / packing / covering constraint that detected the conflict */
2051 )
2052 {
2053 SCIP_CONSDATA* consdata;
2054 int v;
2055 int n;
2056
2057 /* conflict analysis can only be applied in solving stage and if it is applicable */
2058 if( (SCIPgetStage(scip) != SCIP_STAGE_SOLVING && !SCIPinProbing(scip)) || !SCIPisConflictAnalysisApplicable(scip) )
2059 return SCIP_OKAY;
2060
2061 consdata = SCIPconsGetData(cons);
2062 assert(consdata != NULL);
2063 assert(consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING
2064 || consdata->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/
2065
2066 /* initialize conflict analysis, and add the two variables assigned to one to conflict candidate queue */
2067 SCIP_CALL( SCIPinitConflictAnalysis(scip, SCIP_CONFTYPE_PROPAGATION, FALSE) );
2068
2069 n = 0;
2070 for( v = 0; v < consdata->nvars && n < 2; ++v )
2071 {
2072 if( SCIPvarGetLbLocal(consdata->vars[v]) > 0.5 )
2073 {
2074 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[v]) );
2075 n++;
2076 }
2077 }
2078 assert(n == 2);
2079
2080 /* analyze the conflict */
2081 SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
2082
2083 return SCIP_OKAY;
2084 }
2085
2086 /** checks constraint for violation only looking at the fixed variables, applies further fixings if possible */
2087 static
processFixings(SCIP * scip,SCIP_CONS * cons,SCIP_Bool * cutoff,int * nfixedvars,SCIP_Bool * addcut,SCIP_Bool * mustcheck)2088 SCIP_RETCODE processFixings(
2089 SCIP* scip, /**< SCIP data structure */
2090 SCIP_CONS* cons, /**< set partitioning / packing / covering constraint to be processed */
2091 SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
2092 int* nfixedvars, /**< pointer to count number of deleted variables */
2093 SCIP_Bool* addcut, /**< pointer to store whether this constraint must be added as a cut */
2094 SCIP_Bool* mustcheck /**< pointer to store whether this constraint must be checked for feasibility */
2095 )
2096 {
2097 SCIP_CONSDATA* consdata;
2098 #ifndef NDEBUG
2099 int oldnfixedvars;
2100 #endif
2101
2102 assert(cons != NULL);
2103 assert(SCIPconsGetHdlr(cons) != NULL);
2104 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
2105 assert(cutoff != NULL);
2106 assert(nfixedvars != NULL);
2107 assert(addcut != NULL);
2108 assert(mustcheck != NULL);
2109
2110 #ifndef NDEBUG
2111 oldnfixedvars = *nfixedvars;
2112 #endif
2113
2114 consdata = SCIPconsGetData(cons);
2115 assert(consdata != NULL);
2116 assert(consdata->nvars == 0 || consdata->vars != NULL);
2117 assert(0 <= consdata->nfixedzeros && consdata->nfixedzeros <= consdata->nvars);
2118 assert(0 <= consdata->nfixedones && consdata->nfixedones <= consdata->nvars);
2119
2120 *addcut = FALSE;
2121 *mustcheck = TRUE;
2122
2123 /*SCIPdebugMsg(scip, "processing constraint <%s> with respect to fixed variables (%d fixed to 0.0, %d fixed to 1.0)\n",
2124 SCIPconsGetName(cons), consdata->nfixedzeros, consdata->nfixedones);*/
2125
2126 if( consdata->nfixedones == 1 )
2127 {
2128 /* exactly one variable is fixed to 1:
2129 * - a set covering constraint is feasible anyway and can be disabled
2130 * - all other variables in a set partitioning or packing constraint must be zero
2131 */
2132 if( consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
2133 {
2134 SCIPdebugMsg(scip, " -> disabling set covering constraint <%s>\n", SCIPconsGetName(cons));
2135 SCIP_CALL( SCIPdelConsLocal(scip, cons) );
2136 }
2137 else
2138 {
2139 if( consdata->nfixedzeros < consdata->nvars - 1 )
2140 {
2141 SCIP_VAR** vars;
2142 SCIP_VAR* var;
2143 #ifndef NDEBUG
2144 SCIP_Bool fixedonefound;
2145 #endif
2146 SCIP_Bool infeasible;
2147 SCIP_Bool tightened;
2148 int nvars;
2149 int v;
2150 int oneidx = -1;
2151
2152 SCIPdebugMsg(scip, " -> fixing all other variables to zero in set packing/partitioning constraint <%s>\n",
2153 SCIPconsGetName(cons));
2154
2155 /* unfixed variables exist: fix them to zero;
2156 * this could result in additional variables fixed to one due to aggregations; in this case, the
2157 * constraint is infeasible in local bounds
2158 */
2159 vars = consdata->vars;
2160 nvars = consdata->nvars;
2161 #ifndef NDEBUG
2162 fixedonefound = FALSE;
2163 #endif
2164 for( v = 0; v < nvars && consdata->nfixedones == 1; ++v )
2165 {
2166 var = vars[v];
2167 assert(SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) || SCIPisFeasEQ(scip, SCIPvarGetUbLocal(var), 1.0));
2168 if( SCIPvarGetLbLocal(var) < 0.5 )
2169 {
2170 SCIP_CALL( SCIPinferBinvarCons(scip, var, FALSE, cons, oneidx, &infeasible, &tightened) );
2171 assert(!infeasible);
2172
2173 if( tightened )
2174 ++(*nfixedvars);
2175
2176 SCIPdebugMsg(scip, " -> fixed <%s> to zero (tightened=%u)\n", SCIPvarGetName(var), tightened);
2177 }
2178 else
2179 {
2180 #ifndef NDEBUG
2181 fixedonefound = TRUE;
2182 #endif
2183 oneidx = v;
2184 }
2185 }
2186 /* the fixed to one variable must have been found, and at least one variable must have been fixed */
2187 assert(consdata->nfixedones >= 2 || (fixedonefound && *nfixedvars > oldnfixedvars));
2188
2189 SCIP_CALL( SCIPresetConsAge(scip, cons) );
2190 }
2191
2192 /* now all other variables are fixed to zero:
2193 * the constraint is feasible, and if it's not modifiable, it is redundant
2194 */
2195 if( !SCIPconsIsModifiable(cons) && consdata->nfixedones == 1 )
2196 {
2197 SCIPdebugMsg(scip, " -> disabling set packing/partitioning constraint <%s>\n", SCIPconsGetName(cons));
2198 SCIP_CALL( SCIPdelConsLocal(scip, cons) );
2199 }
2200 }
2201 *mustcheck = FALSE;
2202 }
2203
2204 if( consdata->nfixedones >= 2 )
2205 {
2206 /* at least two variables are fixed to 1:
2207 * - a set covering constraint is feasible anyway and can be disabled
2208 * - a set partitioning or packing constraint is infeasible
2209 */
2210 if( consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
2211 {
2212 SCIPdebugMsg(scip, " -> disabling set covering constraint <%s>\n", SCIPconsGetName(cons));
2213 SCIP_CALL( SCIPdelConsLocal(scip, cons) );
2214 }
2215 else
2216 {
2217 SCIPdebugMsg(scip, " -> conflict on set packing/partitioning constraint <%s>\n", SCIPconsGetName(cons));
2218
2219 SCIP_CALL( SCIPresetConsAge(scip, cons) );
2220
2221 /* use conflict analysis to get a conflict constraint out of the conflicting assignment */
2222 SCIP_CALL( analyzeConflictOne(scip, cons) );
2223
2224 *cutoff = TRUE;
2225 }
2226 *mustcheck = FALSE;
2227 }
2228 else if( consdata->nfixedzeros == consdata->nvars )
2229 {
2230 /* all variables are fixed to zero:
2231 * - a set packing constraint is feasible anyway, and if it's unmodifiable, it can be disabled
2232 * - a set partitioning or covering constraint is infeasible, and if it's unmodifiable, the node
2233 * can be cut off -- otherwise, the constraint must be added as a cut and further pricing must
2234 * be performed
2235 */
2236 assert(consdata->nfixedones == 0);
2237
2238 if( consdata->setppctype == SCIP_SETPPCTYPE_PACKING ) /*lint !e641*/
2239 {
2240 if( !SCIPconsIsModifiable(cons) )
2241 {
2242 SCIPdebugMsg(scip, " -> disabling set packing constraint <%s>\n", SCIPconsGetName(cons));
2243 SCIP_CALL( SCIPdelConsLocal(scip, cons) );
2244 }
2245 }
2246 else
2247 {
2248 SCIPdebugMsg(scip, " -> set covering/partitioning constraint <%s> is infeasible\n", SCIPconsGetName(cons));
2249
2250 SCIP_CALL( SCIPresetConsAge(scip, cons) );
2251 if( SCIPconsIsModifiable(cons) )
2252 *addcut = TRUE;
2253 else
2254 {
2255 /* use conflict analysis to get a conflict constraint out of the conflicting assignment */
2256 SCIP_CALL( analyzeConflictZero(scip, cons) );
2257
2258 *cutoff = TRUE;
2259 }
2260 }
2261 *mustcheck = FALSE;
2262 }
2263 else if( consdata->nfixedzeros == consdata->nvars - 1 && consdata->nfixedones == 0 )
2264 {
2265 /* all variables except one are fixed to zero:
2266 * - a set packing constraint is feasible anyway, and if it's unmodifiable, it can be disabled
2267 * - an unmodifiable set partitioning or covering constraint is feasible and can be disabled after the
2268 * remaining variable is fixed to one
2269 * - a modifiable set partitioning or covering constraint must be checked manually
2270 */
2271 if( consdata->setppctype == SCIP_SETPPCTYPE_PACKING ) /*lint !e641*/
2272 {
2273 if( !SCIPconsIsModifiable(cons) )
2274 {
2275 SCIPdebugMsg(scip, " -> disabling set packing constraint <%s>\n", SCIPconsGetName(cons));
2276 SCIP_CALL( SCIPdelConsLocal(scip, cons) );
2277 }
2278 *mustcheck = FALSE;
2279 }
2280 else if( !SCIPconsIsModifiable(cons) )
2281 {
2282 SCIP_VAR** vars;
2283 SCIP_VAR* var;
2284 SCIP_Bool infeasible;
2285 SCIP_Bool tightened;
2286 int nvars;
2287 int v;
2288
2289 /* search the single variable that can be fixed */
2290 vars = consdata->vars;
2291 nvars = consdata->nvars;
2292 for( v = 0; v < nvars; ++v )
2293 {
2294 var = vars[v];
2295 assert(SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)));
2296 assert(SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) || SCIPisFeasEQ(scip, SCIPvarGetUbLocal(var), 1.0));
2297 if( SCIPvarGetUbLocal(var) > 0.5 )
2298 {
2299 SCIPdebugMsg(scip, " -> fixing remaining variable <%s> to one in set covering/partitioning constraint <%s>\n",
2300 SCIPvarGetName(var), SCIPconsGetName(cons));
2301 SCIP_CALL( SCIPinferBinvarCons(scip, var, TRUE, cons, 0, &infeasible, &tightened) );
2302 assert(!infeasible);
2303 assert(tightened);
2304
2305 ++(*nfixedvars);
2306 break;
2307 }
2308 }
2309 assert(v < nvars);
2310 assert(consdata->nfixedzeros == consdata->nvars - 1);
2311 assert(consdata->nfixedones == 1);
2312
2313 SCIP_CALL( SCIPdelConsLocal(scip, cons) );
2314 *mustcheck = FALSE;
2315 }
2316 }
2317 assert(consdata->nfixedzeros + consdata->nfixedones <= consdata->nvars);
2318
2319 return SCIP_OKAY;
2320 }
2321
2322 /** checks constraint for violation, returns TRUE iff constraint is feasible */
2323 static
checkCons(SCIP * scip,SCIP_CONSDATA * consdata,SCIP_SOL * sol)2324 SCIP_Bool checkCons(
2325 SCIP* scip, /**< SCIP data structure */
2326 SCIP_CONSDATA* consdata, /**< set partitioning / packing / covering constraint to be checked */
2327 SCIP_SOL* sol /**< primal CIP solution */
2328 )
2329 {
2330 SCIP_VAR** vars;
2331 SCIP_Real solval;
2332 SCIP_Real sum;
2333 SCIP_Real sumbound;
2334 SCIP_Real absviol;
2335 SCIP_Real relviol;
2336 SCIP_Bool check;
2337 int nvars;
2338 int v;
2339
2340 /* calculate the constraint's activity */
2341 vars = consdata->vars;
2342 nvars = consdata->nvars;
2343 sum = 0.0;
2344 sumbound = ((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_COVERING ? 1.0 : 1.0 + 2*SCIPfeastol(scip));
2345 for( v = 0; v < nvars && sum < sumbound; ++v ) /* if sum >= sumbound, the feasibility is clearly decided */
2346 {
2347 assert(SCIPvarIsBinary(vars[v]));
2348
2349 solval = SCIPgetSolVal(scip, sol, vars[v]);
2350 assert(SCIPisFeasGE(scip, solval, 0.0) && SCIPisFeasLE(scip, solval, 1.0));
2351
2352 sum += solval;
2353 }
2354
2355 absviol = sum - 1.0;
2356 relviol = SCIPrelDiff(sum, 1.0);
2357 switch( consdata->setppctype )
2358 {
2359 case SCIP_SETPPCTYPE_PARTITIONING:
2360 /* in case of partitioning, the violation is equal to the absolute difference between sum and 1 */
2361 absviol = REALABS(absviol);
2362 relviol = REALABS(relviol);
2363 check = SCIPisFeasEQ(scip, sum, 1.0);
2364 break;
2365 case SCIP_SETPPCTYPE_PACKING:
2366 /* in case of packing, the violation is equal to how much sum exceeds 1 */
2367 check = SCIPisFeasLE(scip, sum, 1.0);
2368 break;
2369 case SCIP_SETPPCTYPE_COVERING:
2370 /* in case of covering, the violation is equal to how much 1 exceeds sum */
2371 absviol = -absviol;
2372 relviol = -relviol;
2373 check = SCIPisFeasGE(scip, sum, 1.0);
2374 break;
2375 default:
2376 SCIPerrorMessage("unknown setppc type\n");
2377 SCIPABORT();
2378 return FALSE; /*lint !e527*/
2379 }
2380
2381 if( sol != NULL )
2382 SCIPupdateSolLPConsViolation(scip, sol, absviol, relviol);
2383
2384 return check;
2385 }
2386
2387 /** creates an LP row in a set partitioning / packing / covering constraint data object */
2388 static
createRow(SCIP * scip,SCIP_CONS * cons)2389 SCIP_RETCODE createRow(
2390 SCIP* scip, /**< SCIP data structure */
2391 SCIP_CONS* cons /**< set partitioning / packing / covering constraint */
2392 )
2393 {
2394 SCIP_CONSDATA* consdata;
2395 SCIP_Real lhs;
2396 SCIP_Real rhs;
2397
2398 consdata = SCIPconsGetData(cons);
2399 assert(consdata != NULL);
2400 assert(consdata->row == NULL);
2401
2402 switch( consdata->setppctype )
2403 {
2404 case SCIP_SETPPCTYPE_PARTITIONING:
2405 lhs = 1.0;
2406 rhs = 1.0;
2407 break;
2408 case SCIP_SETPPCTYPE_PACKING:
2409 lhs = -SCIPinfinity(scip);
2410 rhs = 1.0;
2411 break;
2412 case SCIP_SETPPCTYPE_COVERING:
2413 lhs = 1.0;
2414 rhs = SCIPinfinity(scip);
2415 break;
2416 default:
2417 SCIPerrorMessage("unknown setppc type\n");
2418 return SCIP_INVALIDDATA;
2419 }
2420
2421 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->row, cons, SCIPconsGetName(cons), lhs, rhs,
2422 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons), SCIPconsIsRemovable(cons)) );
2423
2424 SCIP_CALL( SCIPaddVarsToRowSameCoef(scip, consdata->row, consdata->nvars, consdata->vars, 1.0) );
2425
2426 return SCIP_OKAY;
2427 }
2428
2429 /** adds setppc constraint as cut to the LP */
2430 static
addCut(SCIP * scip,SCIP_CONS * cons,SCIP_Bool * cutoff)2431 SCIP_RETCODE addCut(
2432 SCIP* scip, /**< SCIP data structure */
2433 SCIP_CONS* cons, /**< setppc constraint */
2434 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
2435 )
2436 {
2437 SCIP_CONSDATA* consdata;
2438
2439 assert( cutoff != NULL );
2440 *cutoff = FALSE;
2441
2442 consdata = SCIPconsGetData(cons);
2443 assert(consdata != NULL);
2444
2445 if( consdata->row == NULL )
2446 {
2447 /* convert set partitioning constraint data into LP row */
2448 SCIP_CALL( createRow(scip, cons) );
2449 }
2450 assert(consdata->row != NULL);
2451
2452 /* insert LP row as cut */
2453 if( !SCIProwIsInLP(consdata->row) )
2454 {
2455 SCIPdebugMsg(scip, "adding constraint <%s> as cut to the LP\n", SCIPconsGetName(cons));
2456 SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, cutoff) );
2457 }
2458
2459 return SCIP_OKAY;
2460 }
2461
2462 /** checks constraint for violation, and adds it as a cut if possible */
2463 static
separateCons(SCIP * scip,SCIP_CONS * cons,SCIP_SOL * sol,SCIP_Bool lpfeas,SCIP_Bool * cutoff,SCIP_Bool * separated,SCIP_Bool * reduceddom)2464 SCIP_RETCODE separateCons(
2465 SCIP* scip, /**< SCIP data structure */
2466 SCIP_CONS* cons, /**< set partitioning / packing / covering constraint to be separated */
2467 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
2468 SCIP_Bool lpfeas, /**< is the given solution feasible for the current LP ? */
2469 SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
2470 SCIP_Bool* separated, /**< pointer to store TRUE, if a cut was found */
2471 SCIP_Bool* reduceddom /**< pointer to store TRUE, if a domain reduction was found */
2472 )
2473 {
2474 SCIP_CONSDATA* consdata;
2475 SCIP_Bool addcut;
2476 SCIP_Bool mustcheck;
2477
2478 assert(cons != NULL);
2479 assert(SCIPconsGetHdlr(cons) != NULL);
2480 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
2481 assert(cutoff != NULL);
2482 assert(separated != NULL);
2483 assert(reduceddom != NULL);
2484
2485 *cutoff = FALSE;
2486
2487 consdata = SCIPconsGetData(cons);
2488 assert(consdata != NULL);
2489 assert(consdata->nvars == 0 || consdata->vars != NULL);
2490 assert(0 <= consdata->nfixedzeros && consdata->nfixedzeros <= consdata->nvars);
2491 assert(0 <= consdata->nfixedones && consdata->nfixedones <= consdata->nvars);
2492
2493 /* skip constraints already in the LP */
2494 if( lpfeas && consdata->row != NULL && SCIProwIsInLP(consdata->row) )
2495 return SCIP_OKAY;
2496
2497 SCIPdebugMsg(scip, "separating constraint <%s>\n", SCIPconsGetName(cons));
2498
2499 /* check constraint for violation only looking at the fixed variables, apply further fixings if possible */
2500 if( lpfeas )
2501 {
2502 int nfixedvars = 0;
2503
2504 SCIP_CALL( processFixings(scip, cons, cutoff, &nfixedvars, &addcut, &mustcheck) );
2505
2506 *reduceddom = (nfixedvars > 0);
2507 }
2508 else
2509 {
2510 mustcheck = TRUE;
2511 addcut = FALSE;
2512 }
2513
2514 if( mustcheck )
2515 {
2516 assert(!addcut);
2517
2518 /* variable's fixings didn't give us any information -> we have to check the constraint */
2519 if( lpfeas && consdata->row != NULL )
2520 {
2521 SCIP_Real feasibility;
2522
2523 assert(!SCIProwIsInLP(consdata->row));
2524 feasibility = SCIPgetRowSolFeasibility(scip, consdata->row, sol);
2525 addcut = SCIPisFeasNegative(scip, feasibility);
2526 }
2527 else
2528 addcut = !checkCons(scip, consdata, sol);
2529
2530 if( !addcut )
2531 {
2532 /* constraint was feasible -> increase age */
2533 SCIP_CALL( SCIPincConsAge(scip, cons) );
2534 }
2535 }
2536
2537 if( addcut )
2538 {
2539 /* insert LP row as cut */
2540 SCIP_CALL( addCut(scip, cons, cutoff) );
2541 SCIP_CALL( SCIPresetConsAge(scip, cons) );
2542 *separated = TRUE;
2543 }
2544
2545 return SCIP_OKAY;
2546 }
2547
2548 /** enforces the pseudo solution on the given constraint */
2549 static
enforcePseudo(SCIP * scip,SCIP_CONS * cons,SCIP_Bool * cutoff,SCIP_Bool * infeasible,SCIP_Bool * reduceddom,SCIP_Bool * solvelp)2550 SCIP_RETCODE enforcePseudo(
2551 SCIP* scip, /**< SCIP data structure */
2552 SCIP_CONS* cons, /**< set partitioning / packing / covering constraint to be separated */
2553 SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
2554 SCIP_Bool* infeasible, /**< pointer to store TRUE, if the constraint was infeasible */
2555 SCIP_Bool* reduceddom, /**< pointer to store TRUE, if a domain reduction was found */
2556 SCIP_Bool* solvelp /**< pointer to store TRUE, if the LP has to be solved */
2557 )
2558 {
2559 SCIP_Bool addcut;
2560 SCIP_Bool mustcheck;
2561 int nfixedvars = 0;
2562
2563 assert(!SCIPhasCurrentNodeLP(scip));
2564 assert(cons != NULL);
2565 assert(SCIPconsGetHdlr(cons) != NULL);
2566 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
2567 assert(cutoff != NULL);
2568 assert(infeasible != NULL);
2569 assert(reduceddom != NULL);
2570 assert(solvelp != NULL);
2571
2572 /* check constraint for violation only looking at the fixed variables, apply further fixings if possible */
2573 SCIP_CALL( processFixings(scip, cons, cutoff, &nfixedvars, &addcut, &mustcheck) );
2574
2575 *reduceddom = (nfixedvars > 0);
2576
2577 if( mustcheck )
2578 {
2579 SCIP_CONSDATA* consdata;
2580
2581 assert(!addcut);
2582
2583 consdata = SCIPconsGetData(cons);
2584 assert(consdata != NULL);
2585
2586 if( checkCons(scip, consdata, NULL) )
2587 {
2588 /* constraint was feasible -> increase age */
2589 SCIP_CALL( SCIPincConsAge(scip, cons) );
2590 }
2591 else
2592 {
2593 /* constraint was infeasible -> reset age */
2594 SCIP_CALL( SCIPresetConsAge(scip, cons) );
2595 *infeasible = TRUE;
2596 }
2597 }
2598
2599 if( addcut )
2600 {
2601 /* a cut must be added to the LP -> we have to solve the LP immediately */
2602 SCIP_CALL( SCIPresetConsAge(scip, cons) );
2603 *solvelp = TRUE;
2604 }
2605
2606 return SCIP_OKAY;
2607 }
2608
2609 /** gets the key of the given element */
2610 static
SCIP_DECL_HASHGETKEY(hashGetKeySetppccons)2611 SCIP_DECL_HASHGETKEY(hashGetKeySetppccons)
2612 { /*lint --e{715}*/
2613 /* the key is the element itself */
2614 return elem;
2615 }
2616
2617 /** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables */
2618 static
SCIP_DECL_HASHKEYEQ(hashKeyEqSetppccons)2619 SCIP_DECL_HASHKEYEQ(hashKeyEqSetppccons)
2620 {
2621 #ifndef NDEBUG
2622 SCIP* scip;
2623 #endif
2624 SCIP_CONSDATA* consdata1;
2625 SCIP_CONSDATA* consdata2;
2626 SCIP_Bool coefsequal;
2627 int i;
2628
2629 consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
2630 consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
2631 assert(consdata1->sorted);
2632 assert(consdata2->sorted);
2633 #ifndef NDEBUG
2634 scip = (SCIP*)userptr;
2635 assert(scip != NULL);
2636 #endif
2637
2638 /* checks trivial case */
2639 if( consdata1->nvars != consdata2->nvars )
2640 return FALSE;
2641
2642 coefsequal = TRUE;
2643
2644 for( i = 0; i < consdata1->nvars; ++i )
2645 {
2646 /* tests if variables are equal */
2647 if( consdata1->vars[i] != consdata2->vars[i] )
2648 {
2649 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
2650 SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
2651 coefsequal = FALSE;
2652 break;
2653 }
2654 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
2655 }
2656
2657 return coefsequal;
2658 }
2659
2660 /** returns the hash value of the key */
2661 static
SCIP_DECL_HASHKEYVAL(hashKeyValSetppccons)2662 SCIP_DECL_HASHKEYVAL(hashKeyValSetppccons)
2663 {
2664 SCIP_CONSDATA* consdata;
2665 int minidx;
2666 int mididx;
2667 int maxidx;
2668 #ifndef NDEBUG
2669 SCIP* scip;
2670
2671 scip = (SCIP*)userptr;
2672 assert(scip != NULL);
2673 #endif
2674
2675 consdata = SCIPconsGetData((SCIP_CONS*)key);
2676 assert(consdata != NULL);
2677 assert(consdata->nvars > 0);
2678
2679 /* sorts the constraints */
2680 consdataSort(consdata);
2681
2682 minidx = SCIPvarGetIndex(consdata->vars[0]);
2683 mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
2684 maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
2685 assert(minidx >= 0 && minidx <= maxidx);
2686
2687 return SCIPhashFour(consdata->nvars, minidx, mididx, maxidx);
2688 }
2689
2690 /** add extra clique-constraints resulting from a given cliquepartition to SCIP */
2691 static
addExtraCliques(SCIP * const scip,SCIP_VAR ** const binvars,int const nbinvars,int * const cliquepartition,int const ncliques,SCIP_CONS ** const usefulconss,int * const nusefulconss,int const nrounds,int * const nfixedvars,int * const naddconss,int * const ndelconss,int * const nchgcoefs,SCIP_Bool * const cutoff)2692 SCIP_RETCODE addExtraCliques(
2693 SCIP*const scip, /**< SCIP data structure */
2694 SCIP_VAR**const binvars, /**< binary variables to create clique constraints */
2695 int const nbinvars, /**< number of binary variables to create clique constraints */
2696 int*const cliquepartition, /**< clique partition of binary variables */
2697 int const ncliques, /**< number of cliques in cliquepartition */
2698 SCIP_CONS**const usefulconss, /**< storage for created constraints */
2699 int*const nusefulconss, /**< pointer to store number of useful created constraints */
2700 int const nrounds, /**< actual presolving round */
2701 int*const nfixedvars, /**< pointer to count number of deleted variables */
2702 int*const naddconss, /**< pointer to count number of added constraints */
2703 int*const ndelconss, /**< pointer to count number of deleted constraints */
2704 int*const nchgcoefs, /**< pointer to count number of deleted coefficients */
2705 SCIP_Bool*const cutoff /**< pointer to store if the problem is infeasible due to a fixing */
2706 )
2707 {
2708 SCIP_CONS* cliquecons;
2709 char name[SCIP_MAXSTRLEN];
2710 int lastclqidx;
2711 int nadded;
2712 int c;
2713 int v;
2714
2715 assert(scip != NULL);
2716 assert(binvars != NULL || nbinvars == 0);
2717 assert(cliquepartition != NULL || nbinvars == 0);
2718 assert(ncliques >= 0 && ncliques <= nbinvars);
2719 assert(usefulconss != NULL);
2720 assert(nusefulconss != NULL);
2721 assert(nfixedvars != NULL);
2722 assert(naddconss != NULL);
2723 assert(ndelconss != NULL);
2724 assert(nchgcoefs != NULL);
2725 assert(cutoff != NULL);
2726
2727 /* no given binary variables */
2728 if( nbinvars == 0 || ncliques == 0 )
2729 return SCIP_OKAY;
2730
2731 assert(binvars != NULL);
2732 assert(cliquepartition != NULL);
2733
2734 /* no useful clique information */
2735 if( ncliques == nbinvars )
2736 return SCIP_OKAY;
2737
2738 lastclqidx = 0;
2739
2740 /* @todo: maybe sort cliques and accordingly the variables so it will be faster to add the constraints */
2741 for( c = 0; c < ncliques - 1; ++c )
2742 {
2743 if( lastclqidx >= cliquepartition[c] )
2744 continue;
2745
2746 nadded = 0;
2747
2748 /* name the clique constraint */
2749 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "extra_clq_%d_round_%d", cliquepartition[c], nrounds);
2750 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, 0, NULL,
2751 TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
2752
2753 /* add variables to clique constraint */
2754 for( v = c; v < nbinvars - 1; ++v )
2755 {
2756 if( cliquepartition[c] == cliquepartition[v] )
2757 {
2758 SCIP_CALL( addCoef(scip, cliquecons, binvars[v]) );
2759 ++nadded;
2760 }
2761 }
2762
2763 /* @todo: try to find a good value for what are enough variables to create this constraint, maybe at least
2764 * (nmaxvars(over all conss)-nminvars(over all conss))/2 */
2765 if( nadded >= 2 )
2766 {
2767 SCIP_CONSDATA* cliqueconsdata;
2768
2769 SCIPdebugMsg(scip, " -> adding clique constraint: ");
2770 SCIPdebugPrintCons(scip, cliquecons, NULL);
2771 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
2772 ++(*naddconss);
2773
2774 /* we only want to consider merged constraints */
2775 SCIP_CALL( mergeMultiples(scip, cliquecons, nfixedvars, ndelconss, nchgcoefs, cutoff) );
2776 if( *cutoff )
2777 {
2778 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
2779
2780 return SCIP_OKAY;
2781 }
2782
2783 cliqueconsdata = SCIPconsGetData(cliquecons);
2784 assert(cliqueconsdata != NULL);
2785
2786 /* the artificial constraints could be deleted while merging */
2787 if( !SCIPconsIsDeleted(cliquecons) && nadded - cliqueconsdata->nfixedzeros >= 2 )
2788 {
2789 assert(cliqueconsdata->nfixedones == 0);
2790
2791 /* save the type and constraint */
2792 usefulconss[*nusefulconss] = cliquecons;
2793 ++(*nusefulconss);
2794 }
2795 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
2796 }
2797 else
2798 {
2799 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
2800 }
2801 lastclqidx = cliquepartition[c];
2802 }
2803
2804 return SCIP_OKAY;
2805 }
2806
2807
2808 /** start to collect setpartitioning and setpacking constraints, and try to remove fixed variables and merged these
2809 * constraints
2810 */
2811 static
collectCliqueConss(SCIP * const scip,SCIP_CONS ** const conss,int const nconss,SCIP_CONS ** const usefulconss,int * const nusefulconss,int * const nfixedvars,int * const ndelconss,int * const nchgcoefs,SCIP_Bool * const cutoff)2812 SCIP_RETCODE collectCliqueConss(
2813 SCIP*const scip, /**< SCIP data structure */
2814 SCIP_CONS**const conss, /**< constraint set */
2815 int const nconss, /**< number of constraints in constraint set */
2816 SCIP_CONS**const usefulconss, /**< storage for created constraints */
2817 int*const nusefulconss, /**< pointer to store number of useful created constraints */
2818 int*const nfixedvars, /**< pointer to count number of deleted variables */
2819 int*const ndelconss, /**< pointer to count number of deleted constraints */
2820 int*const nchgcoefs, /**< pointer to count number of deleted coefficients */
2821 SCIP_Bool*const cutoff /**< pointer to store if the problem is infeasible due to a fixing */
2822 )
2823 {
2824 SCIP_CONS* cons;
2825 SCIP_CONSDATA* consdata;
2826 SCIP_Bool addcut;
2827 SCIP_Bool mustcheck;
2828 int nlocaladdconss = 0;
2829 int c;
2830
2831 assert(scip != NULL);
2832 assert(conss != NULL || nconss == 0);
2833 assert(usefulconss != NULL);
2834 assert(nusefulconss != NULL);
2835 assert(nfixedvars != NULL);
2836 assert(ndelconss != NULL);
2837 assert(nchgcoefs != NULL);
2838 assert(cutoff != NULL);
2839
2840 if( nconss == 0 )
2841 return SCIP_OKAY;
2842
2843 assert(conss != NULL);
2844
2845 for( c = nconss - 1; c >= 0; --c )
2846 {
2847 cons = conss[c];
2848
2849 /* we only want to consider constraints with either active or negated of active variables, applyfixings removes
2850 * aggregated and fixed variables to zero, processFixings removes fixings to one but no aggregation
2851 *
2852 * @todo: maybe write a new method for deleting aggregations and all fixings
2853 */
2854 SCIP_CALL( applyFixings(scip, cons, &nlocaladdconss, ndelconss, nfixedvars, cutoff) );
2855 if( *cutoff )
2856 return SCIP_OKAY;
2857
2858 if( SCIPconsIsDeleted(cons) )
2859 {
2860 /* reset nlocaladdconss and continue */
2861 nlocaladdconss = 0;
2862 continue;
2863 }
2864 assert(nlocaladdconss == 0);
2865
2866 SCIP_CALL( processFixings(scip, cons, cutoff, nfixedvars, &addcut, &mustcheck) );
2867 if( *cutoff )
2868 return SCIP_OKAY;
2869
2870 consdata = SCIPconsGetData(cons);
2871 assert(consdata != NULL);
2872
2873 /* we only want to consider merged constraints */
2874 SCIP_CALL( mergeMultiples(scip, cons, nfixedvars, ndelconss, nchgcoefs, cutoff) );
2875 if( *cutoff )
2876 return SCIP_OKAY;
2877
2878 if( SCIPconsIsModifiable(cons) || !SCIPconsIsActive(cons) )
2879 continue;
2880
2881 assert(consdata->nfixedones == 0);
2882
2883 if( consdata->nvars == 0 )
2884 continue;
2885
2886 /* @todo: check for covering constraints with only two variables which are equal to a packing constraint with
2887 * negated variables */
2888 if( consdata->setppctype != SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
2889 {
2890 assert(consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || consdata->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/
2891
2892 usefulconss[*nusefulconss] = cons;
2893 ++(*nusefulconss);
2894 }
2895 }
2896
2897 return SCIP_OKAY; /*lint !e438*/
2898 }
2899
2900 /** creating all necessary data in array structure, collect all clique constraint variables and occurrences,
2901 * @note works only with merged and active not set-covering constraints
2902 */
2903 static
collectCliqueData(SCIP * const scip,SCIP_CONS ** const usefulconss,int const nusefulconss,SCIP_VAR ** const usefulvars,int * const nusefulvars,SCIP_HASHMAP * const vartoindex,int * const varnconss,int * const maxnvarconsidx,int ** const varconsidxs,int * const maxnvars)2904 SCIP_RETCODE collectCliqueData(
2905 SCIP*const scip, /**< SCIP data structure */
2906 SCIP_CONS**const usefulconss, /**< clique constraints */
2907 int const nusefulconss, /**< number of clique constraints */
2908 SCIP_VAR**const usefulvars, /**< storage for all found variables */
2909 int*const nusefulvars, /**< pointer to store number of added variables */
2910 SCIP_HASHMAP*const vartoindex, /**< hashmap mapping variables to indices */
2911 int*const varnconss, /**< storage for remembering the number of constraints a variable occurs */
2912 int*const maxnvarconsidx, /**< storage for the maximal number of occurrences of a variable */
2913 int**const varconsidxs, /**< storage for constraint indices in which the corresponding variable exists */
2914 int*const maxnvars /**< pointer to store maximal number of variables of a constraint */
2915 )
2916 {
2917 SCIP_CONS* cons;
2918 SCIP_CONSDATA* consdata;
2919 int varindex;
2920 int c;
2921 int v;
2922
2923 assert(scip != NULL);
2924 assert(usefulconss != NULL || nusefulconss == 0);
2925 assert(usefulvars != NULL);
2926 assert(nusefulvars != NULL);
2927 assert(vartoindex != NULL);
2928 assert(varnconss != NULL);
2929 assert(maxnvarconsidx != NULL);
2930 assert(varconsidxs != NULL);
2931 assert(maxnvars != NULL);
2932
2933 if( nusefulconss == 0 )
2934 return SCIP_OKAY;
2935
2936 assert(usefulconss != NULL);
2937
2938 for( c = nusefulconss - 1; c >= 0; --c )
2939 {
2940 cons = usefulconss[c];
2941
2942 assert(SCIPconsIsActive(cons));
2943
2944 consdata = SCIPconsGetData(cons);
2945 assert(consdata != NULL);
2946
2947 /* here we should have no covering constraints anymore and the constraint data should be merged */
2948 assert(consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || consdata->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/
2949 assert(consdata->merged);
2950
2951 /* save maximal number of vars */
2952 if( consdata->nvars > *maxnvars )
2953 *maxnvars = consdata->nvars;
2954
2955 /* adding variables and information about occurrences to local data structure */
2956 for( v = consdata->nvars - 1; v >= 0; --v )
2957 {
2958 SCIP_VAR* var;
2959
2960 var = consdata->vars[v];
2961 assert(var != NULL);
2962
2963 /* don't remember fixed vars */
2964 if( SCIPvarGetLbLocal(var) > 0.5 || SCIPvarGetUbLocal(var) < 0.5 )
2965 continue;
2966
2967 /* only collect active or negated active variables */
2968 assert(SCIPvarIsActive(var) || (SCIPvarIsNegated(var) && SCIPvarIsActive(SCIPvarGetNegationVar(var))));
2969
2970 if( !SCIPhashmapExists(vartoindex, (void*) var) )
2971 {
2972 SCIP_VAR* tmpvar;
2973
2974 usefulvars[*nusefulvars] = var;
2975 ++(*nusefulvars);
2976 varindex = *nusefulvars;
2977 SCIP_CALL( SCIPhashmapInsertInt(vartoindex, (void*) var, varindex) );
2978
2979 /* get the maximal number of occurrences of this variable, if this variables */
2980 tmpvar = SCIPvarIsNegated(var) ? SCIPvarGetNegatedVar(var) : var;
2981 maxnvarconsidx[varindex] = SCIPvarGetNLocksDownType(tmpvar, SCIP_LOCKTYPE_MODEL)
2982 + SCIPvarGetNLocksUpType(tmpvar, SCIP_LOCKTYPE_MODEL);
2983 SCIP_CALL( SCIPallocBufferArray(scip, &(varconsidxs[varindex]), maxnvarconsidx[varindex]) ); /*lint !e866*/
2984 }
2985 else
2986 {
2987 assert(SCIPhashmapExists(vartoindex, (void*) var));
2988 varindex = SCIPhashmapGetImageInt(vartoindex, (void*) var);
2989 }
2990
2991 /* the number of occurrences of a variable is not limited by the locks (so maybe we have to increase memory),
2992 * because for examples converted cuts are not check and therefore they have no locks on their variables */
2993 if( varnconss[varindex] == maxnvarconsidx[varindex] )
2994 {
2995 maxnvarconsidx[varindex] = SCIPcalcMemGrowSize(scip, maxnvarconsidx[varindex] + 1);
2996 SCIP_CALL( SCIPreallocBufferArray(scip, &(varconsidxs[varindex]), maxnvarconsidx[varindex]) ); /*lint !e866*/
2997 }
2998
2999 assert(varnconss[varindex] < maxnvarconsidx[varindex]);
3000 /* add the constraint number to the variable list */
3001 varconsidxs[varindex][varnconss[varindex]] = c;
3002 /* increase number of occurrences for variables */
3003 ++(varnconss[varindex]);
3004 }
3005 } /* data structure created */
3006
3007 return SCIP_OKAY;
3008 }
3009
3010 /** correct clique data due to an aggregation */
3011 static
deleteCliqueDataEntry(SCIP_VAR * const var,int const considx,SCIP_HASHMAP * const vartoindex,int * const varnconss,int ** const varconsidxs)3012 void deleteCliqueDataEntry(
3013 SCIP_VAR*const var, /**< variable which appears less */
3014 int const considx, /**< constraint index which to remove */
3015 SCIP_HASHMAP*const vartoindex, /**< hashmap mapping variables to indices */
3016 int*const varnconss, /**< storage for remembering the number of constraints a variable occurs */
3017 int**const varconsidxs /**< storage for constraint indices in which the corresponding variable exists */
3018 )
3019 {
3020 int varindex;
3021 int i;
3022 #ifndef NDEBUG
3023 SCIP_Bool found = FALSE;
3024 #endif
3025
3026 assert(var != NULL);
3027 assert(SCIPvarGetLbLocal(var) < 0.5 && SCIPvarGetUbLocal(var) > 0.5);
3028 assert(considx >= 0);
3029 assert(vartoindex != NULL);
3030 assert(varnconss != NULL);
3031 assert(varconsidxs != NULL);
3032
3033 assert(SCIPhashmapExists(vartoindex, (void*) var));
3034 varindex = SCIPhashmapGetImageInt(vartoindex, (void*) var);
3035
3036 /* remove entry of variable at the given position */
3037 for( i = 0; i < varnconss[varindex]; ++i )
3038 {
3039 if( varconsidxs[varindex][i] == considx )
3040 {
3041 varconsidxs[varindex][i] = varconsidxs[varindex][varnconss[varindex] - 1];
3042 #ifndef NDEBUG
3043 found = TRUE;
3044 #endif
3045 --(varnconss[varindex]);
3046 break;
3047 }
3048 }
3049 assert(found);
3050 }
3051
3052 /* correct local data structure, add constraint entry to variable data */
3053 static
addCliqueDataEntry(SCIP * const scip,SCIP_VAR * const addvar,int const considx,SCIP_Bool const maybenew,SCIP_VAR ** const usefulvars,int * const nusefulvars,SCIP_HASHMAP * const vartoindex,int * const varnconss,int * const maxnvarconsidx,int ** const varconsidxs)3054 SCIP_RETCODE addCliqueDataEntry(
3055 SCIP*const scip, /**< SCIP data structure */
3056 SCIP_VAR*const addvar, /**< variable which was added */
3057 int const considx, /**< constraint index which to add */
3058 SCIP_Bool const maybenew, /**< could be a new variables, a negated of an already existing */
3059 SCIP_VAR**const usefulvars, /**< storage for all found variables */
3060 int*const nusefulvars, /**< pointer to store number of added variables */
3061 SCIP_HASHMAP*const vartoindex, /**< hashmap mapping variables to indices */
3062 int*const varnconss, /**< storage for remembering the number of constraints a variable occurs */
3063 int*const maxnvarconsidx, /**< storage for the maximal number of occurrences of a variable */
3064 int**const varconsidxs /**< storage for constraint indices in which the corresponding variable exists */
3065 )
3066 {
3067 int varindex;
3068
3069 assert(scip != NULL);
3070 assert(addvar != NULL);
3071 assert(SCIPvarGetLbLocal(addvar) < 0.5 && SCIPvarGetUbLocal(addvar) > 0.5);
3072 assert(usefulvars != NULL);
3073 assert(nusefulvars != NULL);
3074 assert(vartoindex != NULL);
3075 assert(varnconss != NULL);
3076 assert(maxnvarconsidx != NULL);
3077 assert(varconsidxs != NULL);
3078
3079 /* we add the variable to the hashmap if its new */
3080 if( maybenew && !SCIPhashmapExists(vartoindex, (void*) addvar) )
3081 {
3082 assert(SCIPvarIsActive(addvar) || SCIPvarIsNegated(addvar));
3083 assert(SCIPvarGetNegatedVar(addvar) != NULL && SCIPhashmapExists(vartoindex, (void*) SCIPvarGetNegatedVar(addvar)));
3084
3085 /* @note because we can only have created a negated variable, and we already allocated enough memory for
3086 * all (even not existing) negated variables the usefulvars array should be big enough
3087 */
3088 SCIPsortedvecInsertDownPtr((void**)usefulvars, SCIPvarCompActiveAndNegated, addvar, nusefulvars, NULL);
3089 varindex = *nusefulvars;
3090 SCIP_CALL( SCIPhashmapInsertInt(vartoindex, (void*) addvar, varindex) );
3091
3092 assert(varconsidxs[varindex] == NULL);
3093
3094 maxnvarconsidx[varindex] = 1;
3095 SCIP_CALL( SCIPallocBufferArray(scip, &(varconsidxs[varindex]), maxnvarconsidx[varindex]) ); /*lint !e866*/
3096 varnconss[varindex] = 0;
3097 }
3098 else
3099 {
3100 varindex = SCIPhashmapGetImageInt(vartoindex, (void*) addvar);
3101
3102 /* grow the needed memory if we added a variable */
3103 if( varnconss[varindex] == maxnvarconsidx[varindex] )
3104 {
3105 maxnvarconsidx[varindex] = SCIPcalcMemGrowSize(scip, maxnvarconsidx[varindex] + 1);
3106 SCIP_CALL( SCIPreallocBufferArray(scip, &(varconsidxs[varindex]), maxnvarconsidx[varindex]) ); /*lint !e866*/
3107 }
3108 }
3109 assert(varnconss[varindex] < maxnvarconsidx[varindex]);
3110 varconsidxs[varindex][varnconss[varindex]] = considx;
3111
3112 /* increase number of occurrences for variables */
3113 ++(varnconss[varindex]);
3114
3115 return SCIP_OKAY;
3116 }
3117
3118
3119 /** check if constraint is already redundant or infeasible due to fixings, fix or aggregate left over variables if
3120 * possible
3121 */
3122 static
presolvePropagateCons(SCIP * const scip,SCIP_CONS * const cons,SCIP_Bool const aggregate,SCIP_VAR ** undoneaggrvars,SCIP_Bool * undoneaggrtypes,int * const naggregations,int * const saggregations,int * const nfixedvars,int * const naggrvars,int * const ndelconss,SCIP_Bool * const cutoff)3123 SCIP_RETCODE presolvePropagateCons(
3124 SCIP*const scip, /**< SCIP data structure */
3125 SCIP_CONS*const cons, /**< constraint */
3126 SCIP_Bool const aggregate, /**< try to aggregate if possible */
3127 SCIP_VAR** undoneaggrvars, /**< array to store aggregation variables, if aggregation is not performed
3128 * yet; both variables are standing next to each other; or NULL if
3129 * aggregate == TRUE
3130 */
3131 SCIP_Bool* undoneaggrtypes, /**< array to store aggregation type, if aggregation is not performed yet;
3132 * type FALSE means the aggregation is of the form x + y = 1; type TRUE means
3133 * the aggregation is of the form x = y; or NULL if aggregate == TRUE
3134 */
3135 int*const naggregations, /**< pointer to store number of aggregations which are not yet performed;
3136 * or NULL if aggregate == TRUE
3137 */
3138 int*const saggregations, /**< pointer to store size of the array for aggregation type and two times
3139 * the value is the size of the array for the aggregation variables which
3140 * are not yet performed; or NULL if aggregate == TRUE
3141 */
3142 int*const nfixedvars, /**< pointer to count number of deleted variables */
3143 int*const naggrvars, /**< pointer to count number of aggregated variables */
3144 int*const ndelconss, /**< pointer to count number of deleted constraints */
3145 SCIP_Bool*const cutoff /**< pointer to store if the problem is infeasible due to a fixing */
3146 )
3147 {
3148 SCIP_CONSDATA* consdata;
3149 SCIP_VAR** vars;
3150 int nvars;
3151 int v;
3152 SCIP_Bool fixed;
3153
3154 assert(scip != NULL);
3155 assert(cons != NULL);
3156 assert(nfixedvars != NULL);
3157 assert(naggrvars != NULL);
3158 assert(ndelconss != NULL);
3159 assert(cutoff != NULL);
3160
3161 if( !SCIPconsIsActive(cons) )
3162 return SCIP_OKAY;
3163
3164 consdata = SCIPconsGetData(cons);
3165 assert(consdata != NULL);
3166
3167 if( consdata->presolpropagated )
3168 return SCIP_OKAY;
3169
3170 consdata->presolpropagated = TRUE;
3171
3172 vars = consdata->vars;
3173 nvars = consdata->nvars;
3174
3175 /* no variables left */
3176 if( nvars == 0 && !SCIPconsIsModifiable(cons) )
3177 {
3178 if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
3179 {
3180 SCIPdebugMsg(scip, "empty set-partition/-covering constraint <%s> found -> cutoff\n", SCIPconsGetName(cons));
3181 *cutoff = TRUE;
3182
3183 return SCIP_OKAY;
3184 }
3185 else
3186 {
3187 assert(consdata->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/
3188
3189 /* delete constraint */
3190 SCIPdebugMsg(scip, " -> deleting constraint <%s>, no variables left\n", SCIPconsGetName(cons));
3191 SCIP_CALL( SCIPdelCons(scip, cons) );
3192 ++(*ndelconss);
3193
3194 return SCIP_OKAY;
3195 }
3196 }
3197
3198 /* more then two variables are fixed */
3199 if( consdata->nfixedones > 1 )
3200 {
3201 /* at least two variables are fixed to 1:
3202 * - a set covering constraint is feasible anyway and can be deleted
3203 * - a set partitioning or packing constraint is infeasible
3204 */
3205 if( consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
3206 {
3207 /* delete constraint */
3208 SCIPdebugMsg(scip, " -> deleting set-covering constraint <%s>, at least two variables are fixed to 1\n", SCIPconsGetName(cons));
3209 SCIP_CALL( SCIPdelCons(scip, cons) );
3210 ++(*ndelconss);
3211
3212 return SCIP_OKAY;
3213 }
3214
3215 SCIPdebugMsg(scip, "set partitioning / packing constraint <%s> is infeasible, %d variables fixed to one\n", SCIPconsGetName(cons), consdata->nfixedones);
3216 *cutoff = TRUE;
3217
3218 return SCIP_OKAY;
3219 }
3220
3221 if( consdata->nfixedones == 1 )
3222 {
3223 /* exactly one variable is fixed to 1:
3224 * - a set covering constraint is feasible anyway and can be disabled
3225 * - all other variables in a set partitioning or packing constraint must be zero
3226 */
3227 if( consdata->setppctype != SCIP_SETPPCTYPE_COVERING && consdata->nfixedzeros < nvars - 1 ) /*lint !e641*/
3228 {
3229 assert(vars != NULL);
3230
3231 for( v = nvars - 1; v >= 0; --v )
3232 {
3233 if( SCIPvarGetLbLocal(vars[v]) + 0.5 < SCIPvarGetUbLocal(vars[v]) )
3234 {
3235 SCIPdebugMsg(scip, "trying to fix <%s> to 0 due to at least one variable is already fixed to 1\n", SCIPvarGetName(vars[v]));
3236
3237 /* fix all remaining variables to zero, constraint is already feasible or infeasible */
3238 SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, cutoff, &fixed) );
3239 if( *cutoff )
3240 {
3241 SCIPdebugMsg(scip, "setppc constraint <%s>: infeasible fixing <%s> == 0\n",
3242 SCIPconsGetName(cons), SCIPvarGetName(vars[v]));
3243
3244 return SCIP_OKAY;
3245 }
3246
3247 assert(fixed);
3248 ++(*nfixedvars);
3249 }
3250 }
3251 }
3252
3253 if( !SCIPconsIsModifiable(cons) || consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
3254 {
3255 /* delete constraint */
3256 SCIPdebugMsg(scip, " -> deleting constraint <%s>, all variables are fixed\n", SCIPconsGetName(cons));
3257 assert(SCIPconsIsActive(cons));
3258 SCIP_CALL( SCIPdelCons(scip, cons) );
3259 ++(*ndelconss);
3260 }
3261
3262 return SCIP_OKAY;
3263 }
3264
3265 /* other propagations can only be done on not modifiable constraints */
3266 if( SCIPconsIsModifiable(cons) )
3267 return SCIP_OKAY;
3268
3269 assert(vars != NULL);
3270
3271 /* all variables were fixed to zero then either delete the constraint or stop with infeasibility */
3272 if( consdata->nfixedzeros == nvars )
3273 {
3274 assert(consdata->nfixedones == 0);
3275
3276 /* all variables are fixed to zero:
3277 * - a set packing constraint is feasible anyway and can be deleted
3278 * - a set partitioning or covering constraint is infeasible, and so is the whole problem
3279 */
3280 if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
3281 {
3282 SCIPdebugMsg(scip, "set partitioning / covering constraint <%s> is infeasible\n", SCIPconsGetName(cons));
3283 *cutoff = TRUE;
3284
3285 return SCIP_OKAY;
3286 }
3287
3288 /* delete constraint */
3289 SCIPdebugMsg(scip, " -> deleting set-packing constraint <%s>, all variables are fixed to zero\n", SCIPconsGetName(cons));
3290 assert(SCIPconsIsActive(cons));
3291 SCIP_CALL( SCIPdelCons(scip, cons) );
3292 ++(*ndelconss);
3293
3294 return SCIP_OKAY;
3295 }
3296
3297 /* all but one variable were fixed to zero then delete the constraint and for setpartition fix the remaining variable to 1 */
3298 if( consdata->nfixedzeros + 1 == nvars )
3299 {
3300 assert(consdata->nfixedones == 0);
3301
3302 /* all variables except one are fixed to zero:
3303 * - a set packing constraint is feasible anyway, and can be deleted
3304 * - a set partitioning or covering constraint is feasible and can be deleted after the
3305 * remaining variable is fixed to one
3306 */
3307 if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || consdata->setppctype == SCIP_SETPPCTYPE_COVERING ) /*lint !e641*/
3308 {
3309 fixed = FALSE;
3310 for( v = nvars - 1; v >= 0; --v )
3311 {
3312 assert(SCIPvarGetLbLocal(vars[v]) < 0.5);
3313 if( SCIPvarGetUbLocal(vars[v]) > 0.5 )
3314 {
3315 SCIPdebugMsg(scip, "trying to fix <%s> to 1 due to it's the last unfixed variable is the set-partitioning/covering constraint\n", SCIPvarGetName(vars[v]));
3316
3317 /* fix the remaining set partition variable */
3318 SCIP_CALL( SCIPfixVar(scip, vars[v], 1.0, cutoff, &fixed) );
3319 if( *cutoff )
3320 {
3321 SCIPdebugMsg(scip, "setppc constraint <%s>: infeasible fixing <%s> == 1\n",
3322 SCIPconsGetName(cons), SCIPvarGetName(vars[v]));
3323
3324 return SCIP_OKAY;
3325 }
3326
3327 assert(fixed);
3328 ++(*nfixedvars);
3329 break;
3330 }
3331 }
3332 assert(fixed);
3333 }
3334
3335 /* delete constraint */
3336 SCIPdebugMsg(scip, " -> deleting constraint <%s>, all %svariables are fixed\n", SCIPconsGetName(cons), consdata->setppctype == (int) SCIP_SETPPCTYPE_PACKING ? "but one " : "");
3337 assert(SCIPconsIsActive(cons));
3338 SCIP_CALL( SCIPdelCons(scip, cons) );
3339 ++(*ndelconss);
3340
3341 return SCIP_OKAY;
3342 }
3343
3344 /* all but two variable were fixed to zero in a setpartitioning constraint then delete the constraint and
3345 * aggregate the remaining two variables
3346 */
3347 if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata->nfixedzeros + 2 == nvars ) /*lint !e641*/
3348 {
3349 SCIP_VAR* var;
3350
3351 var = NULL;
3352 for( v = nvars - 1; v >= 0; --v )
3353 {
3354 assert(SCIPvarGetLbLocal(vars[v]) < 0.5);
3355
3356 if( SCIPvarGetUbLocal(vars[v]) > 0.5 )
3357 {
3358 if( var == NULL )
3359 var = vars[v];
3360 else
3361 {
3362 SCIP_Bool redundant;
3363 SCIP_Bool aggregated;
3364 #ifdef VARUSES
3365 SCIP_CONSHDLR* conshdlr;
3366 SCIP_CONSHDLRDATA* conshdlrdata;
3367
3368 /* get event handler and event handler data */
3369 conshdlr = SCIPconsGetHdlr(cons);
3370 assert(conshdlr != NULL);
3371 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3372 assert(conshdlrdata != NULL);
3373 #endif
3374 if( aggregate )
3375 {
3376 SCIPdebugMsg(scip, "trying to aggregate <%s> and <%s> due to they are the last two unfixed variables in the set partitionning constraint <%s>\n", SCIPvarGetName(var), SCIPvarGetName(vars[v]), SCIPconsGetName(cons));
3377
3378 #ifdef VARUSES
3379 /* in order to not mess up the variable usage counting, we have to decrease usage counting, aggregate,
3380 * and increase usage counting again
3381 */
3382 SCIP_CALL( conshdlrdataDecVaruses(scip, conshdlrdata, var) );
3383 SCIP_CALL( conshdlrdataDecVaruses(scip, conshdlrdata, vars[v]) );
3384 #endif
3385
3386 /* aggregate last remaining variables in the set partitioning constraint */
3387 SCIP_CALL( SCIPaggregateVars(scip, var, vars[v], 1.0, 1.0, 1.0, cutoff, &redundant, &aggregated) );
3388 if( *cutoff )
3389 {
3390 SCIPdebugMsg(scip, "set partitioning constraint <%s>: aggregate <%s> + <%s> == 1\n",
3391 SCIPconsGetName(cons), SCIPvarGetName(var), SCIPvarGetName(vars[v]));
3392
3393 return SCIP_OKAY;
3394 }
3395
3396 #ifdef VARUSES
3397 /* increase variable usage counting again */
3398 SCIP_CALL( conshdlrdataIncVaruses(scip, conshdlrdata, var) );
3399 SCIP_CALL( conshdlrdataIncVaruses(scip, conshdlrdata, vars[v]) );
3400 #endif
3401
3402 if( aggregated )
3403 ++(*naggrvars);
3404
3405 if( redundant )
3406 {
3407 /* delete constraint */
3408 SCIPdebugMsg(scip, " -> deleting constraint <%s>, all variables are fixed\n", SCIPconsGetName(cons));
3409 assert(SCIPconsIsActive(cons));
3410 SCIP_CALL( SCIPdelCons(scip, cons) );
3411 ++(*ndelconss);
3412 }
3413 }
3414 else
3415 {
3416 assert(undoneaggrvars != NULL);
3417 assert(undoneaggrtypes != NULL);
3418 assert(naggregations != NULL);
3419 assert(saggregations != NULL);
3420
3421 SCIPdebugMsg(scip, "memorize the aggregation of <%s> + <%s> = 1, because they are the last two unfixed variable in the set partitioning constraints <%s>\n", SCIPvarGetName(var), SCIPvarGetName(vars[v]), SCIPconsGetName(cons));
3422
3423 /* resize the aggregation arrays if necessary */
3424 if( *saggregations == *naggregations )
3425 {
3426 *saggregations = SCIPcalcMemGrowSize(scip, *naggregations + 1);
3427 assert(*saggregations > *naggregations);
3428 SCIP_CALL( SCIPreallocBufferArray(scip, &undoneaggrtypes, *saggregations) );
3429 SCIP_CALL( SCIPreallocBufferArray(scip, &undoneaggrvars, 2 * (*saggregations)) );
3430
3431 /* clear the aggregation type array to set the default to the aggregation of the form x + y = 1 */
3432 BMSclearMemoryArray(&(undoneaggrtypes[*naggregations]), *saggregations - *naggregations); /*lint !e866*/
3433 }
3434
3435 /* memorize aggregation variables*/
3436 assert(undoneaggrtypes[*naggregations] == FALSE);
3437 undoneaggrvars[2 * (*naggregations)] = var;
3438 undoneaggrvars[2 * (*naggregations) + 1] = vars[v];
3439 ++(*naggregations);
3440
3441 if( !SCIPdoNotAggr(scip) )
3442 {
3443 /* delete constraint */
3444 SCIPdebugMsg(scip, " -> deleting constraint <%s>, all variables are fixed\n", SCIPconsGetName(cons));
3445 assert(SCIPconsIsActive(cons));
3446 SCIP_CALL( SCIPdelCons(scip, cons) );
3447 ++(*ndelconss);
3448 }
3449 }
3450
3451 return SCIP_OKAY;
3452 }
3453 }
3454 }
3455 /* we should never be here, because the last to unfixed variables should have been either aggregated or a cutoff
3456 * should be applied
3457 */
3458 assert(FALSE); /*lint !e506*/
3459 }
3460
3461 return SCIP_OKAY;
3462 }
3463
3464 /** check for overlapping constraint */
3465 static
checkForOverlapping(SCIP * const scip,SCIP_CONS * const cons,int const considx,int const endidx,SCIP_CONS ** const usefulconss,int const nusefulconss,SCIP_VAR ** const usefulvars,int * const nusefulvars,SCIP_HASHMAP * const vartoindex,int * const varnconss,int * const maxnvarconsidx,int ** const varconsidxs,int * const countofoverlapping,SCIP_Bool const shrinking,SCIP_Bool * const chgcons,SCIP_VAR ** undoneaggrvars,SCIP_Bool * undoneaggrtypes,int * const naggregations,int * const saggregations,int * const nfixedvars,int * const naggrvars,int * const nchgcoefs,int * const ndelconss,SCIP_Bool * const cutoff)3466 SCIP_RETCODE checkForOverlapping(
3467 SCIP*const scip, /**< SCIP data structure */
3468 SCIP_CONS*const cons, /**< constraint which may overlap */
3469 int const considx, /**< constraint index to avoid checking against itself */
3470 int const endidx, /**< end index to check against given constraint */
3471 SCIP_CONS**const usefulconss, /**< clique constraints */
3472 int const nusefulconss, /**< number of clique constraints */
3473 SCIP_VAR**const usefulvars, /**< storage for all found variables */
3474 int*const nusefulvars, /**< pointer to store number of added variables */
3475 SCIP_HASHMAP*const vartoindex, /**< hashmap mapping variables to indices */
3476 int*const varnconss, /**< storage for remembering the number of constraints a variable occurs */
3477 int*const maxnvarconsidx, /**< storage for the maximal number of occurrences of a variable */
3478 int**const varconsidxs, /**< storage for constraint indices in which the corresponding variable exists */
3479 int*const countofoverlapping, /**< the amount of variables of cons which overlap in all other constraint */
3480 SCIP_Bool const shrinking, /**< try to replace some variables with one variable */
3481 SCIP_Bool*const chgcons, /**< pointer to store if the given constraint was changed, due to
3482 * added/deleted variables
3483 */
3484 SCIP_VAR** undoneaggrvars, /**< array to store aggregation variables, if aggregation is not performed
3485 * yet; both variables are standing next to each other;
3486 */
3487 SCIP_Bool* undoneaggrtypes, /**< array to store aggregation type, if aggregation is not performed yet;
3488 * type FALSE means the aggregation is of the form x + y = 1; type TRUE means
3489 * the aggregation is of the form x = y;
3490 */
3491 int*const naggregations, /**< pointer to store number of aggregations which are not yet performed; */
3492 int*const saggregations, /**< pointer to store size of the array for aggregation type and two times
3493 * the value is the size of the array for the aggregation variables which
3494 * are not yet performed;
3495 */
3496 int*const nfixedvars, /**< pointer to count number of deleted variables */
3497 int*const naggrvars, /**< pointer to count number of aggregated variables */
3498 int*const nchgcoefs, /**< pointer to count number of changed coefficients */
3499 int*const ndelconss, /**< pointer to count number of deleted constraints */
3500 SCIP_Bool*const cutoff /**< pointer to store if the problem is infeasible due to a fixing */
3501 )
3502 {
3503 SCIP_CONS* cons1;
3504 SCIP_CONSDATA* consdata1;
3505 SCIP_CONSDATA* consdata;
3506 SCIP_VAR** vars;
3507 SCIP_VAR** vars1;
3508 SCIP_VAR* var;
3509 SCIP_VAR* var1;
3510 SCIP_Bool fixed;
3511 SCIP_Bool overlapdestroyed;
3512 int nvars;
3513 int nvars1;
3514 int oldnfixedzeros;
3515 int c;
3516 int v;
3517 int v1;
3518 #ifndef NDEBUG
3519 int oldnaggrvars;
3520 #endif
3521
3522 assert(scip != NULL);
3523 assert(cons != NULL);
3524 assert(usefulconss != NULL && nusefulconss > 0);
3525 assert(0 <= considx && considx < nusefulconss);
3526 assert(usefulconss[considx] == cons);
3527 assert(0 <= endidx && endidx <= nusefulconss);
3528 assert(countofoverlapping != NULL);
3529 assert(chgcons != NULL);
3530 assert(undoneaggrvars != NULL);
3531 assert(undoneaggrtypes != NULL);
3532 assert(naggregations != NULL);
3533 assert(saggregations != NULL);
3534 assert(nfixedvars != NULL);
3535 assert(naggrvars != NULL);
3536 assert(nchgcoefs != NULL);
3537 assert(ndelconss != NULL);
3538 assert(cutoff != NULL);
3539
3540 if( !SCIPconsIsActive(cons) )
3541 return SCIP_OKAY;
3542
3543 consdata = SCIPconsGetData(cons);
3544 assert(consdata != NULL);
3545
3546 nvars = consdata->nvars;
3547
3548 if( nvars == 0 )
3549 return SCIP_OKAY;
3550
3551 vars = consdata->vars;
3552 assert(vars != NULL);
3553
3554 oldnfixedzeros = consdata->nfixedzeros;
3555 overlapdestroyed = FALSE;
3556
3557 /* first check for redundancy for all unprocessed constraints with cons */
3558 for( c = endidx - 1; c >= 0; --c )
3559 {
3560 cons1 = usefulconss[c];
3561
3562 if( !SCIPconsIsActive(cons1) )
3563 continue;
3564
3565 /* avoid checking constraint against itself */
3566 if( considx == c )
3567 continue;
3568
3569 assert(usefulconss[c] != cons);
3570
3571 #ifndef NDEBUG
3572 oldnaggrvars = *naggrvars;
3573 #endif
3574
3575 /* check if constraint is already redundant or infeasible due to fixings, fix or aggregate left over variables if
3576 * possible
3577 */
3578 SCIP_CALL( presolvePropagateCons(scip, cons1, FALSE, undoneaggrvars, undoneaggrtypes, naggregations, saggregations, nfixedvars, naggrvars, ndelconss, cutoff) );
3579
3580 if( *cutoff )
3581 return SCIP_OKAY;
3582
3583 /* we can't handle aggregated variables later on so we should have saved them for later */
3584 assert(*naggrvars == oldnaggrvars);
3585
3586 if( !SCIPconsIsActive(cons1) )
3587 continue;
3588
3589 consdata1 = SCIPconsGetData(cons1);
3590 assert(consdata1 != NULL);
3591
3592 nvars1 = consdata1->nvars;
3593
3594 if( nvars1 == 0 )
3595 continue;
3596
3597 /* no more variables from cons as nvars1 can overlap */
3598 assert(countofoverlapping[c] <= nvars1);
3599
3600 /* constraint should not be redundant or infeasible */
3601 assert(consdata1->nfixedones == 0);
3602
3603 SCIPdebugMsg(scip, "constraint <%s> overlaps with constraint <%s> by %d variables\n", SCIPconsGetName(cons), SCIPconsGetName(cons1), countofoverlapping[c]);
3604
3605 /* cons1 includes cons */
3606 if( !overlapdestroyed && countofoverlapping[c] == nvars - consdata->nfixedzeros )
3607 {
3608 if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/
3609 {
3610 if( nvars - consdata->nfixedzeros < nvars1 )
3611 {
3612 #ifndef NDEBUG
3613 SCIP_Bool negated0;
3614 SCIP_Bool negated1;
3615 #endif
3616
3617 /* both constraints should stay merged */
3618 assert(consdata->merged);
3619 assert(consdata1->merged);
3620
3621 vars1 = consdata1->vars;
3622 assert(vars1 != NULL);
3623
3624 /* sorting array after indices of variables, negated and active counterparts would stand side by side */
3625 SCIPsortDownPtr((void**)vars1, SCIPvarCompActiveAndNegated, nvars1);
3626 /* standard setppc-sorting now lost */
3627 consdata1->sorted = FALSE;
3628
3629 /* iterate over the both cliques variables the "same" time */
3630 for( v = nvars - 1, v1 = nvars1 - 1; v >= 0 && v1 >= 0; )
3631 {
3632 if( SCIPvarGetLbLocal(vars1[v1]) > 0.5 || SCIPvarGetUbLocal(vars1[v1]) < 0.5 )
3633 {
3634 --v1;
3635 continue;
3636 }
3637 if( SCIPvarGetLbLocal(vars[v]) > 0.5 || SCIPvarGetUbLocal(vars[v]) < 0.5 )
3638 {
3639 --v;
3640 continue;
3641 }
3642
3643 /* all variables inside the second clique constraint should be either active or negated of an active one */
3644 assert(SCIPvarIsActive(vars1[v1]) || (SCIPvarGetStatus(vars1[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars1[v1]))));
3645
3646 /* get not negated variable and clique value in cons */
3647 if( SCIPvarGetStatus(vars[v]) != SCIP_VARSTATUS_NEGATED )
3648 {
3649 var = vars[v];
3650 #ifndef NDEBUG
3651 negated0 = FALSE;
3652 #endif
3653 }
3654 else
3655 {
3656 var = SCIPvarGetNegationVar(vars[v]);
3657 #ifndef NDEBUG
3658 negated0 = TRUE;
3659 #endif
3660 }
3661
3662 /* get active variable and clique value of next variable */
3663 if( SCIPvarIsActive(vars1[v1]) )
3664 {
3665 var1 = vars1[v1];
3666 #ifndef NDEBUG
3667 negated1 = FALSE;
3668 #endif
3669 }
3670 else
3671 {
3672 assert(SCIPvarGetStatus(vars1[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars1[v1])));
3673 var1 = SCIPvarGetNegationVar(vars1[v1]);
3674 #ifndef NDEBUG
3675 negated1 = TRUE;
3676 #endif
3677 }
3678
3679 /* variable index in the constraint smaller than the other one, so go to the next variable in cons */
3680 if( SCIPvarGetIndex(var) < SCIPvarGetIndex(var1) )
3681 --v;
3682 /* variable index in the constraint is greater than the other one, so fix this variable */
3683 else if( SCIPvarGetIndex(var) > SCIPvarGetIndex(var1) )
3684 {
3685 SCIPdebugMsg(scip, "trying to fix <%s> to 0 because it is in the same clique with a complete set partitioning constraint\n", SCIPvarGetName(vars1[v1]));
3686
3687 /* fix all variables except the one which has the negated var in the clique to zero */
3688 SCIP_CALL( SCIPfixVar(scip, vars1[v1], 0.0, cutoff, &fixed) );
3689 if( *cutoff )
3690 {
3691 SCIPdebugMsg(scip, "fixing led to cutoff\n");
3692
3693 return SCIP_OKAY;
3694 }
3695
3696 assert(fixed);
3697 ++(*nfixedvars);
3698 --v1;
3699 }
3700 else
3701 {
3702 /* because the constraint's are merged it is not possible that one constraint contains a negated
3703 * variable of another and because all variables in cons are in cons1 this should be really the
3704 * same variable here; so we can decrease v and v1
3705 */
3706 assert(negated0 == negated1);
3707
3708 --v;
3709 --v1;
3710 }
3711 }
3712 /* maybe we ended because of cons(v reached -1) so try to add rest of cons1 to cons */
3713 for( ; v1 >= 0; --v1)
3714 {
3715 if( SCIPvarGetLbLocal(vars1[v1]) > 0.5 || SCIPvarGetUbLocal(vars1[v1]) < 0.5 )
3716 continue;
3717
3718 SCIPdebugMsg(scip, "trying to fix <%s> to 0 because it is in the same clique with a complete set partitioning constraint\n", SCIPvarGetName(vars1[v1]));
3719
3720 /* fix all variables except the one which has the negated var in the clique to zero */
3721 SCIP_CALL( SCIPfixVar(scip, vars1[v1], 0.0, cutoff, &fixed) );
3722 if( *cutoff )
3723 {
3724 SCIPdebugMsg(scip, "fixing led to cutoff\n");
3725
3726 return SCIP_OKAY;
3727 }
3728
3729 assert(fixed);
3730 ++(*nfixedvars);
3731 }
3732 }
3733
3734 /* if caused by all fixings now this set partitioning constraint doesn't have any variable which was
3735 * fixed to one, it's infeasible */
3736 if( consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata1->nfixedzeros == nvars1 && consdata1->nfixedones != 1 ) /*lint !e641*/
3737 {
3738 SCIPdebugMsg(scip, "all variables in the set-partitioning constraint <%s> are fixed to zero, this leads to a cutoff\n", SCIPconsGetName(cons1));
3739 *cutoff = TRUE;
3740
3741 return SCIP_OKAY;
3742 }
3743
3744 assert(SCIPconsIsActive(cons1));
3745 /* delete second constraint */
3746 SCIPdebugMsg(scip, " -> deleting constraint <%s> number <%d> because it includes the setpartitioning constraint <%s> number <%d>\n", SCIPconsGetName(cons1), c, SCIPconsGetName(cons), considx);
3747
3748 SCIP_CALL( SCIPupdateConsFlags(scip, cons, cons1) );
3749 SCIP_CALL( SCIPdelCons(scip, cons1) );
3750 ++(*ndelconss);
3751 }
3752 /* could already be deleted because the constraint was included in another set partition constraint */
3753 else if( SCIPconsIsActive(cons) )
3754 {
3755 /* delete cons due to redundancy to cons1 */
3756 SCIPdebugMsg(scip, " -> deleting constraint <%s> number <%d> due to inclusion in constraint <%s> number <%d>\n", SCIPconsGetName(cons), considx, SCIPconsGetName(cons1), c);
3757
3758 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons) );
3759 SCIP_CALL( SCIPdelCons(scip, cons) );
3760 ++(*ndelconss);
3761 }
3762 }
3763 /* cons includes cons1
3764 *
3765 * @note that zero fixations from above can only appear through a set-partitioning constraint, this means if
3766 * cons was the set-partitioning constraint only variables which are not in this constraint could be fixed
3767 * to zero, and this also means that the overlapping variables in this particular case are still active or
3768 * fixed to 1
3769 * later on it could be possible that even variables in cons are fixed to zero, which can lead to wrong
3770 * results when checking if countofoverlapping[c] + consdata1->nfixedzeros == nvars1, because a fixed
3771 * variable could be counted twice
3772 */
3773 else if( (!overlapdestroyed && countofoverlapping[c] + consdata1->nfixedzeros == nvars1) || countofoverlapping[c] == nvars1 )
3774 {
3775 /* even in deleted constraints we may fix unfixed variables */
3776 if( consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/
3777 {
3778 const int oldnfixedvars = *nfixedvars;
3779 #ifndef NDEBUG
3780 SCIP_Bool negated0;
3781 SCIP_Bool negated1;
3782 #endif
3783 /* both constraints should stay merged */
3784 assert(consdata->merged);
3785 assert(consdata1->merged);
3786
3787 vars1 = consdata1->vars;
3788
3789 /* sorting array after indices of variables, negated and active counterparts would stand side by side */
3790 SCIPsortDownPtr((void**)vars1, SCIPvarCompActiveAndNegated, nvars1);
3791 /* standard setppc-sorting now lost */
3792 consdata1->sorted = FALSE;
3793
3794 /* iterate over the both cliques variables the "same" time */
3795 for( v = nvars - 1, v1 = nvars1 - 1; v >= 0 && v1 >= 0; )
3796 {
3797 if( SCIPvarGetLbLocal(vars1[v1]) > 0.5 || SCIPvarGetUbLocal(vars1[v1]) < 0.5 )
3798 {
3799 --v1;
3800 continue;
3801 }
3802 if( SCIPvarGetLbLocal(vars[v]) > 0.5 || SCIPvarGetUbLocal(vars[v]) < 0.5 )
3803 {
3804 --v;
3805 continue;
3806 }
3807
3808 /* all variables inside the second clique constraint should be either active or negated of an active one */
3809 assert(SCIPvarIsActive(vars1[v1]) || (SCIPvarGetStatus(vars1[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars1[v1]))));
3810 /* all variables inside the first clique constraint should be either active or negated of an active one */
3811 assert(SCIPvarIsActive(vars[v]) || (SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[v]))));
3812
3813 /* get not negated variable and clique value in cons */
3814 if( SCIPvarIsActive(vars[v]) )
3815 {
3816 var = vars[v];
3817 #ifndef NDEBUG
3818 negated0 = FALSE;
3819 #endif
3820 }
3821 else
3822 {
3823 assert(SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[v])));
3824 var = SCIPvarGetNegationVar(vars[v]);
3825 #ifndef NDEBUG
3826 negated0 = TRUE;
3827 #endif
3828 }
3829
3830 /* get active variable and clique value of next variable */
3831 if( SCIPvarIsActive(vars1[v1]) )
3832 {
3833 var1 = vars1[v1];
3834 #ifndef NDEBUG
3835 negated1 = FALSE;
3836 #endif
3837 }
3838 else
3839 {
3840 assert(SCIPvarGetStatus(vars1[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars1[v1])));
3841 var1 = SCIPvarGetNegationVar(vars1[v1]);
3842 #ifndef NDEBUG
3843 negated1 = TRUE;
3844 #endif
3845 }
3846
3847 /* variable index in the constraint smaller than the other one, so go to the next variable in cons */
3848 if( SCIPvarGetIndex(var) < SCIPvarGetIndex(var1) )
3849 {
3850 SCIPdebugMsg(scip, "trying to fix <%s> to 0 because it is in the same clique with a complete set partitioning constraint\n", SCIPvarGetName(var));
3851
3852 /* fix all variables except the one which has the negated var in the clique to zero */
3853 SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, cutoff, &fixed) );
3854 if( *cutoff )
3855 {
3856 SCIPdebugMsg(scip, "fixing led to cutoff\n");
3857
3858 return SCIP_OKAY;
3859 }
3860
3861 assert(fixed);
3862 ++(*nfixedvars);
3863
3864 --v;
3865 }
3866 /* variable index in the constraint is greater than the other one, so fix this variable */
3867 else if( SCIPvarGetIndex(var) > SCIPvarGetIndex(var1) )
3868 --v1;
3869 else
3870 {
3871 /* because the constraint's are merged it is not possible that one constraint contains a negated
3872 * variable of another and because all variables in cons1 are in cons this should be really the same
3873 * variable here; so we can decrease v and v1
3874 */
3875 assert(negated0 == negated1);
3876
3877 --v;
3878 --v1;
3879 }
3880 }
3881
3882 /* maybe we ended because of cons1(v1 reached -1) so try to add rest of cons to cons1 */
3883 for( ; v >= 0; --v)
3884 {
3885 if( SCIPvarGetLbLocal(vars[v]) > 0.5 || SCIPvarGetUbLocal(vars[v]) < 0.5 )
3886 continue;
3887
3888 SCIPdebugMsg(scip, "trying to fix <%s> to 0 because it is in the same clique with a complete set partitioning constraint\n", SCIPvarGetName(vars[v]));
3889
3890 /* fix all variables except the one which has the negated var in the clique to zero */
3891 SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, cutoff, &fixed) );
3892 if( *cutoff )
3893 {
3894 SCIPdebugMsg(scip, "fixing led to cutoff\n");
3895
3896 return SCIP_OKAY;
3897 }
3898
3899 assert(fixed);
3900 ++(*nfixedvars);
3901 }
3902
3903 /* if caused by all fixings now this set partitioning constraint doesn't have any variable which was
3904 * fixed to one, it's infeasible */
3905 if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata->nfixedzeros == nvars && consdata->nfixedones != 1 ) /*lint !e641*/
3906 {
3907 SCIPdebugMsg(scip, "all variables in the set-partitioning constraint <%s> are fixed to zero, this leads to a cutoff\n", SCIPconsGetName(cons1));
3908 *cutoff = TRUE;
3909
3910 return SCIP_OKAY;
3911 }
3912
3913 /* could already be deleted because the constraint was included in another set partition constraint */
3914 if( SCIPconsIsActive(cons) )
3915 {
3916 /* delete cons because it include another set partitioning constraint */
3917 SCIPdebugMsg(scip, " -> deleting constraint <%s> number <%d> because it includes the setpartitioning constraint <%s> number <%d>\n", SCIPconsGetName(cons), considx, SCIPconsGetName(cons1), c);
3918 assert(SCIPconsIsActive(cons));
3919
3920 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons) );
3921 SCIP_CALL( SCIPdelCons(scip, cons) );
3922 ++(*ndelconss);
3923 }
3924
3925 /* due to fixings in cons0 mark overlapping invalid for checking with fixedzero variables together */
3926 if( oldnfixedvars < *nfixedvars )
3927 overlapdestroyed = TRUE;
3928 }
3929 else
3930 {
3931 assert(consdata1->setppctype == SCIP_SETPPCTYPE_PACKING); /*lint !e641*/
3932
3933 /* delete cons1 due to redundancy to cons */
3934 SCIPdebugMsg(scip, " -> deleting constraint <%s> number <%d> due to inclusion in constraint <%s> number <%d>\n", SCIPconsGetName(cons1), c, SCIPconsGetName(cons), considx);
3935 assert(SCIPconsIsActive(cons1));
3936
3937 SCIP_CALL( SCIPupdateConsFlags(scip, cons, cons1) );
3938 SCIP_CALL( SCIPdelCons(scip, cons1) );
3939 ++(*ndelconss);
3940 }
3941 }
3942 /* if cons has only one unfixed variable which is not in cons1 and cons1 has one variable which does not appear in
3943 * cons and both constraints are setpartitioning constraints we might aggregate both not overlapping variables and
3944 * delete one constraint
3945 */
3946 else if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING && consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && countofoverlapping[c] == nvars - oldnfixedzeros - 1 && countofoverlapping[c] == nvars1 - 1 ) /*lint !e641*/
3947 {
3948 SCIP_VAR* aggvar1;
3949 SCIP_VAR* aggvar2;
3950 SCIP_Bool negated0;
3951 SCIP_Bool negated1;
3952
3953 aggvar1 = NULL;
3954 aggvar2 = NULL;
3955
3956 /* both constraints should stay merged */
3957 assert(consdata->merged);
3958 assert(consdata1->merged);
3959
3960 vars1 = consdata1->vars;
3961
3962 /* sorting array after indices of variables, negated and active counterparts would stand side by side */
3963 SCIPsortDownPtr((void**)vars1, SCIPvarCompActiveAndNegated, nvars1);
3964 /* standard setppc-sorting now lost */
3965 consdata1->sorted = FALSE;
3966
3967 /* iterate over the both cliques variables the "same" time */
3968 for( v = nvars - 1, v1 = nvars1 - 1; v >= 0 && v1 >= 0; )
3969 {
3970 if( SCIPvarGetLbLocal(vars1[v1]) > 0.5 || SCIPvarGetUbLocal(vars1[v1]) < 0.5 )
3971 {
3972 --v1;
3973 continue;
3974 }
3975 if( SCIPvarGetLbLocal(vars[v]) > 0.5 || SCIPvarGetUbLocal(vars[v]) < 0.5 )
3976 {
3977 --v;
3978 continue;
3979 }
3980
3981 /* all variables inside the second clique constraint should be either active or negated of an active one */
3982 assert(SCIPvarIsActive(vars1[v1]) || (SCIPvarGetStatus(vars1[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars1[v1]))));
3983 /* all variables inside the first clique constraint should be either active or negated of an active one */
3984 assert(SCIPvarIsActive(vars[v]) || (SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[v]))));
3985
3986 /* get not negated variable and clique value in cons */
3987 if( SCIPvarIsActive(vars[v]) )
3988 {
3989 var = vars[v];
3990 negated0 = FALSE;
3991 }
3992 else
3993 {
3994 assert(SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[v])));
3995 var = SCIPvarGetNegationVar(vars[v]);
3996 negated0 = TRUE;
3997 }
3998
3999 /* get active variable and clique value of next variable */
4000 if( SCIPvarIsActive(vars1[v1]) )
4001 {
4002 var1 = vars1[v1];
4003 negated1 = FALSE;
4004 }
4005 else
4006 {
4007 assert(SCIPvarGetStatus(vars1[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars1[v1])));
4008 var1 = SCIPvarGetNegationVar(vars1[v1]);
4009 negated1 = TRUE;
4010 }
4011
4012 /* variable index in the constraint smaller than the other one, so go to the next variable in cons */
4013 if( SCIPvarGetIndex(var) < SCIPvarGetIndex(var1) )
4014 {
4015 assert(aggvar1 == NULL);
4016 aggvar1 = vars[v];
4017
4018 if( aggvar2 != NULL )
4019 break;
4020
4021 --v;
4022 }
4023 /* variable index in the constraint is greater than the other one, so fix this variable */
4024 else if( SCIPvarGetIndex(var) > SCIPvarGetIndex(var1) )
4025 {
4026 assert(aggvar2 == NULL);
4027 aggvar2 = vars1[v1];
4028
4029 if( aggvar1 != NULL )
4030 break;
4031
4032 --v1;
4033 }
4034 else
4035 {
4036 /* because the constraint's are merged it is not possible that one constraint contains a negated variable
4037 * of another, but both variables in both constraints still can be negated to each other
4038 */
4039 if( negated0 != negated1 )
4040 {
4041 /* cons is except for one variable equal to cons1 and the unequal variable in cons is negated
4042 * to the one in cons1, so the problem is infeasible
4043 */
4044 SCIPdebugMsg(scip, "two set-partitioning constraint <%s> and <%s> have only one variable not in common, but this variable <%s> appears in one constraint as the negated version as in the other constraint\n", SCIPconsGetName(cons), SCIPconsGetName(cons1), SCIPvarGetName(vars[v]));
4045 *cutoff = TRUE;
4046
4047 return SCIP_OKAY;
4048 }
4049 --v;
4050 --v1;
4051 }
4052 }
4053
4054 /* due to fixings, it is possible that there are no active variables left, we we did not recognize which variables we could aggregate */
4055 if( aggvar1 == NULL && aggvar2 == NULL )
4056 continue;
4057
4058 /* determine second aggregation var, if not yet done */
4059 if( aggvar2 == NULL )
4060 {
4061 for( ; v1 >= 0; --v1)
4062 {
4063 if( SCIPvarGetLbLocal(vars1[v1]) > 0.5 || SCIPvarGetUbLocal(vars1[v1]) < 0.5 )
4064 continue;
4065
4066 aggvar2 = vars1[v1];
4067 break;
4068 }
4069 }
4070 /* determine first aggregation var, if not yet done */
4071 else if( aggvar1 == NULL )
4072 {
4073 /* maybe we ended because of cons1(v1 reached -1) so find the aggvar1 in cons */
4074 for( ; v >= 0; --v)
4075 {
4076 if( SCIPvarGetLbLocal(vars[v]) > 0.5 || SCIPvarGetUbLocal(vars[v]) < 0.5 )
4077 continue;
4078
4079 aggvar1 = vars[v];
4080 break;
4081 }
4082 }
4083
4084 /* due to fixings, it is possible that there are no active variables left, we we did not recognize which variables we could aggregate */
4085 if( aggvar1 == NULL || aggvar2 == NULL )
4086 continue;
4087
4088 SCIPdebugMsg(scip, "memorize the aggregation of <%s> == <%s>, because they are the last two variable which are different in these two set partitioning constraints <%s> <%s>\n", SCIPvarGetName(aggvar1), SCIPvarGetName(aggvar2), SCIPconsGetName(cons), SCIPconsGetName(cons1));
4089
4090 /* resize the aggregation arrays if necessary */
4091 if( *saggregations == *naggregations )
4092 {
4093 *saggregations = SCIPcalcMemGrowSize(scip, *naggregations + 1);
4094 assert(*saggregations > *naggregations);
4095 SCIP_CALL( SCIPreallocBufferArray(scip, &undoneaggrtypes, *saggregations) );
4096 SCIP_CALL( SCIPreallocBufferArray(scip, &undoneaggrvars, 2 * (*saggregations)) );
4097
4098 /* clear the aggregation type array to set the default to the aggregation of the form x + y = 1 */
4099 BMSclearMemoryArray(&(undoneaggrtypes[*naggregations]), *saggregations - *naggregations); /*lint !e866*/
4100 }
4101
4102 /* memorize aggregation variables*/
4103 undoneaggrtypes[*naggregations] = TRUE;
4104 undoneaggrvars[2 * (*naggregations)] = aggvar1;
4105 undoneaggrvars[2 * (*naggregations) + 1] = aggvar2;
4106 ++(*naggregations);
4107
4108 if( !SCIPdoNotAggr(scip) )
4109 {
4110 /* delete constraint */
4111 SCIPdebugMsg(scip, " -> deleting constraint <%s> number <%d> because it is dominated by constraint <%s>\n", SCIPconsGetName(cons1), c, SCIPconsGetName(cons));
4112 assert(SCIPconsIsActive(cons1));
4113
4114 SCIP_CALL( SCIPupdateConsFlags(scip, cons, cons1) );
4115 SCIP_CALL( SCIPdelCons(scip, cons1) );
4116 ++(*ndelconss);
4117 }
4118 }
4119 /* w.l.o.g. cons is a setpartitioning constraint and countofoverlapping == nvars - oldnfixedzeros - 1 we can
4120 * delete all overlapping variables in cons1 and add the negated variable of the not overlapped variable to cons
4121 * 1; the result should be a shorter constraint with the same impact
4122 */
4123 else if( shrinking && !overlapdestroyed && countofoverlapping[c] > 1 && ((consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING && countofoverlapping[c] == nvars - oldnfixedzeros - 1) || (consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING && countofoverlapping[c] == nvars1 - 1)) ) /*lint !e641*/
4124 {
4125 SCIP_CONSDATA* consdatachange;
4126 SCIP_VAR** varstostay;
4127 SCIP_VAR** varstochange;
4128 SCIP_CONS* constochange;
4129 SCIP_CONS* constostay;
4130 SCIP_VAR* addvar;
4131 SCIP_Bool negated0;
4132 SCIP_Bool negated1;
4133 int nvarstostay;
4134 int nvarstochange;
4135 int constochangeidx;
4136 #ifndef NDEBUG
4137 const int oldnchgcoefs = *nchgcoefs;
4138 #endif
4139
4140 addvar = NULL;
4141
4142 assert((consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING) != (consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING) || countofoverlapping[c] != nvars - 1 || countofoverlapping[c] != nvars1 - 1); /*lint !e641*/
4143
4144 /* both constraints should stay merged */
4145 assert(consdata->merged);
4146 assert(consdata1->merged);
4147
4148 /* sorting array after indices of variables, negated and active counterparts would stand side by side */
4149 SCIPsortDownPtr((void**)(consdata1->vars), SCIPvarCompActiveAndNegated, nvars1);
4150 /* standard setppc-sorting now lost */
4151 consdata1->sorted = FALSE;
4152
4153 /* initialize variables */
4154 if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING && countofoverlapping[c] == nvars - oldnfixedzeros - 1) /*lint !e641*/
4155 {
4156 varstostay = vars;
4157 varstochange = consdata1->vars;
4158 nvarstostay = nvars;
4159 nvarstochange = nvars1;
4160 constostay = cons;
4161 constochange = cons1;
4162 consdatachange = consdata1;
4163 constochangeidx = c;
4164 }
4165 else
4166 {
4167 varstostay = consdata1->vars;
4168 varstochange = vars;
4169 nvarstostay = nvars1;
4170 nvarstochange = nvars;
4171 constostay = cons1;
4172 constochange = cons;
4173 consdatachange = consdata;
4174 constochangeidx = considx;
4175
4176 *chgcons = TRUE;
4177 }
4178
4179 /* iterate over the both cliques variables the "same" time, here we need the backward loop, because we
4180 * delete some variables and we don not want to loose order
4181 */
4182 for( v = nvarstostay - 1, v1 = nvarstochange - 1; v >= 0 && v1 >= 0; )
4183 {
4184 if( SCIPvarGetLbLocal(varstochange[v1]) > 0.5 || SCIPvarGetUbLocal(varstochange[v1]) < 0.5 )
4185 {
4186 --v1;
4187 continue;
4188 }
4189 if( SCIPvarGetLbLocal(varstostay[v]) > 0.5 || SCIPvarGetUbLocal(varstostay[v]) < 0.5 )
4190 {
4191 --v;
4192 continue;
4193 }
4194
4195 /* all variables inside the second clique constraint should be either active or negated of an active one */
4196 assert(SCIPvarIsActive(varstochange[v1]) || (SCIPvarGetStatus(varstochange[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(varstochange[v1]))));
4197 /* all variables inside the first clique constraint should be either active or negated of an active one */
4198 assert(SCIPvarIsActive(varstostay[v]) || (SCIPvarGetStatus(varstostay[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(varstostay[v]))));
4199
4200 /* get not negated variable and clique value in constostay */
4201 if( SCIPvarIsActive(varstostay[v]) )
4202 {
4203 var = varstostay[v];
4204 negated0 = FALSE;
4205 }
4206 else
4207 {
4208 assert(SCIPvarGetStatus(varstostay[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(varstostay[v])));
4209 var = SCIPvarGetNegationVar(varstostay[v]);
4210 negated0 = TRUE;
4211 }
4212
4213 /* get active variable and clique value of in constochange*/
4214 if( SCIPvarIsActive(varstochange[v1]) )
4215 {
4216 var1 = varstochange[v1];
4217 negated1 = FALSE;
4218 }
4219 else
4220 {
4221 assert(SCIPvarGetStatus(varstochange[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(varstochange[v1])));
4222 var1 = SCIPvarGetNegationVar(varstochange[v1]);
4223 negated1 = TRUE;
4224 }
4225
4226 /* variable index in the constraint smaller than the other one, so go to the next variable in cons */
4227 if( SCIPvarGetIndex(var) < SCIPvarGetIndex(var1) )
4228 {
4229 assert(addvar == NULL);
4230 addvar = varstostay[v];
4231 --v;
4232 }
4233 /* variable index in the constraint is greater than the other one, so fix this variable */
4234 else if( SCIPvarGetIndex(var) > SCIPvarGetIndex(var1) )
4235 {
4236 --v1;
4237 }
4238 else
4239 {
4240 /* because the constraint's are merged it is not possible that one constraint contains a negated variable
4241 * of another, but both constraint might have a variable in negated form of the other
4242 */
4243 if( negated0 != negated1 )
4244 {
4245 assert(addvar == NULL);
4246
4247 SCIPdebugMsg(scip, "-> trying to fix <%s> to 0 because it would exist twice in a constraint\n", SCIPvarGetName(varstochange[v1]));
4248
4249 /* fix variable to zero */
4250 SCIP_CALL( SCIPfixVar(scip, varstochange[v1], 0.0, cutoff, &fixed) );
4251 if( *cutoff )
4252 {
4253 SCIPdebugMsg(scip, "fixing led to cutoff\n");
4254
4255 return SCIP_OKAY;
4256 }
4257
4258 assert(fixed);
4259 ++(*nfixedvars);
4260
4261 /* the above fixing is equal to the fixation of varstostay[v] to 1, so we can call presolvePropagateCons() for consstay */
4262 SCIP_CALL( presolvePropagateCons(scip, constostay, FALSE, NULL, NULL, NULL, NULL, nfixedvars, naggrvars, ndelconss, cutoff) );
4263
4264 return SCIP_OKAY;
4265 }
4266 else
4267 {
4268 /* correct local data structure, remove variable from constraint entry where it will be removed */
4269 deleteCliqueDataEntry(varstochange[v1], constochangeidx, vartoindex, varnconss, varconsidxs);
4270
4271 SCIPdebugMsg(scip, " -> deleting variable <%s> in constraint <%s> number %d, because it will be replaced\n", SCIPvarGetName(varstochange[v1]), SCIPconsGetName(constochange), constochangeidx);
4272 /* delete overlapping variables in constochange */
4273 SCIP_CALL( delCoefPos(scip, constochange, v1) );
4274 ++(*nchgcoefs);
4275 }
4276
4277 --v;
4278 --v1;
4279 }
4280 }
4281 assert(addvar != NULL || v >= 0);
4282 /* we should have removed exactly countofoverlapping[c] variables from the constochange */
4283 assert(*nchgcoefs - oldnchgcoefs == countofoverlapping[c]);
4284
4285 /* determine addvar if not yet found */
4286 if( addvar == NULL )
4287 {
4288 for( ; v >= 0; --v)
4289 {
4290 if( SCIPvarGetLbLocal(varstostay[v]) > 0.5 || SCIPvarGetUbLocal(varstostay[v]) < 0.5 )
4291 continue;
4292
4293 /* all variables inside the first clique constraint should be either active or negated of an active one */
4294 assert(SCIPvarIsActive(varstostay[v]) || (SCIPvarGetStatus(varstostay[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(varstostay[v]))));
4295
4296 addvar = varstostay[v];
4297 break;
4298 }
4299 }
4300 assert(addvar != NULL);
4301
4302 /* get representative variable for all deleted variables */
4303 SCIP_CALL( SCIPgetNegatedVar(scip, addvar, &addvar) );
4304 assert(addvar != NULL);
4305
4306 SCIPdebugMsg(scip, " -> adding variable <%s> to constraint <%s> number %d\n", SCIPvarGetName(addvar), SCIPconsGetName(constochange), constochangeidx);
4307 /* add representative for overlapping instead */
4308 SCIP_CALL( addCoef(scip, constochange, addvar) );
4309 ++(*nchgcoefs);
4310
4311 /* constraint should be still merged because this added variable is new in this constraint */
4312 consdatachange->merged = TRUE;
4313 assert(constochangeidx == (cons == constochange ? considx : c));
4314
4315 /* correct local data structure, add constraint entry to variable data */
4316 SCIP_CALL( addCliqueDataEntry(scip, addvar, constochangeidx, TRUE, usefulvars, nusefulvars, vartoindex, varnconss, maxnvarconsidx, varconsidxs) );
4317
4318 /* cons changed so much, that it cannot be used for more overlapping checks */
4319 if( *chgcons )
4320 return SCIP_OKAY;
4321 }
4322 }
4323
4324 return SCIP_OKAY;
4325 }
4326
4327 /** try to lift variables to given constraint */
4328 /** @todo try another variant by determine lifting variables as the intersection of all cliques variables of the
4329 * constraint variables, note that the intersection changes after one variable was added
4330 */
4331 static
liftCliqueVariables(SCIP * const scip,SCIP_CONS * const cons,int const arraypos,SCIP_VAR ** const usefulvars,int * const nusefulvars,int const endidx,SCIP_Bool ** cliquevalues,SCIP_HASHMAP * const vartoindex,int * const varnconss,int * const maxnvarconsidx,int ** const varconsidxs,int * const maxnvars,int * const nadded,SCIP_Bool * const chgcons,int * const nfixedvars,int * const ndelconss,SCIP_Bool * const cutoff)4332 SCIP_RETCODE liftCliqueVariables(
4333 SCIP*const scip, /**< SCIP data structure */
4334 SCIP_CONS*const cons, /**< constraint which may overlap */
4335 int const arraypos, /**< position of constraint in global array */
4336 SCIP_VAR**const usefulvars, /**< possible variables to lift */
4337 int*const nusefulvars, /**< pointer to store number of added variables */
4338 int const endidx, /**< end index for possible lifting variables */
4339 SCIP_Bool** cliquevalues, /**< pointer to clique values of constraint-variables, either one if the
4340 * variable is active or zero if the variable is negated
4341 * @note this array can be resized in this method
4342 */
4343 SCIP_HASHMAP*const vartoindex, /**< hashmap mapping variables to indices */
4344 int*const varnconss, /**< array with number of constraints a variable occurs */
4345 int*const maxnvarconsidx, /**< array with the maximal number of occurrences of a variable */
4346 int**const varconsidxs, /**< array with constraint indices in which the corresponding variable
4347 * exists
4348 */
4349 int*const maxnvars, /**< pointer to store maximal number of variables of a constraint */
4350 int*const nadded, /**< pointer to store number of possible added variables */
4351 SCIP_Bool*const chgcons, /**< pointer to store if the constraint was changed, due to added
4352 * variables
4353 */
4354 int*const nfixedvars, /**< pointer to count number of deleted variables */
4355 int*const ndelconss, /**< pointer to count number of deleted constraints */
4356 SCIP_Bool*const cutoff /**< pointer to store if the problem is infeasible due to a fixing */
4357 )
4358 {
4359 SCIP_CONSDATA* consdata;
4360 SCIP_VAR** vars;
4361 SCIP_VAR* var;
4362 SCIP_VAR* var1;
4363 SCIP_Bool fixed;
4364 SCIP_Bool value;
4365 int nvars;
4366 int nottocheck; /* will be the position for a variable in cons0 which is in negated form in the same clique */
4367 int v;
4368 int v1;
4369 int k;
4370
4371 assert(scip != NULL);
4372 assert(cons != NULL);
4373 assert(usefulvars != NULL);
4374 assert(cliquevalues != NULL);
4375 assert(*cliquevalues != NULL);
4376 assert(vartoindex != NULL);
4377 assert(varnconss != NULL);
4378 assert(maxnvarconsidx != NULL);
4379 assert(varconsidxs != NULL);
4380 assert(maxnvars != NULL);
4381 assert(nadded != NULL);
4382 assert(chgcons != NULL);
4383 assert(nfixedvars != NULL);
4384 assert(ndelconss != NULL);
4385 assert(cutoff != NULL);
4386
4387 if( !SCIPconsIsActive(cons) )
4388 return SCIP_OKAY;
4389
4390 consdata = SCIPconsGetData(cons);
4391 assert(consdata != NULL);
4392
4393 nvars = consdata->nvars;
4394
4395 if( nvars == 0 )
4396 return SCIP_OKAY;
4397
4398 assert(nvars <= *maxnvars);
4399
4400 vars = consdata->vars;
4401 assert(vars != NULL);
4402
4403 v1 = endidx;
4404
4405 /* now we try to add variables with index prior to endidx to cons */
4406 for( v = nvars - 1; v >= 0 && v1 >= 0; )
4407 {
4408 if( SCIPvarGetLbLocal(usefulvars[v1]) > 0.5 || SCIPvarGetUbLocal(usefulvars[v1]) < 0.5 )
4409 {
4410 --v1;
4411 continue;
4412 }
4413 if( SCIPvarGetUbLocal(vars[v]) < 0.5 )
4414 {
4415 --v;
4416 continue;
4417 }
4418
4419 /* check that constraint variables are still correctly sorted, indices of active variables should be decreasing */
4420 assert(v == 0 || SCIPvarCompareActiveAndNegated(vars[v], vars[v - 1]) <= 0);
4421
4422 /* there should no variables fixed to one occur in our constraint */
4423 assert(SCIPvarGetLbLocal(vars[v]) < 0.5 && SCIPvarGetUbLocal(vars[v]) > 0.5);
4424 assert(SCIPvarGetLbLocal(usefulvars[v1]) < 0.5 && SCIPvarGetUbLocal(usefulvars[v1]) > 0.5);
4425
4426 /* all variables which we have inside the clique constraint and which can possibly be added should be either active or negated */
4427 assert(SCIPvarIsActive(vars[v]) || (SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[v]))));
4428 assert(SCIPvarIsActive(usefulvars[v1]) || (SCIPvarGetStatus(usefulvars[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(usefulvars[v1]))));
4429
4430 /* constraint should during adding of variables stay merged, because for each variable which is added holds that
4431 * the index of this corresponding active variable is pairwise different to all indices of all active
4432 * corresponding variables inside the constraint
4433 * @note it should not happen that we add one variable and the corresponding counterpart to the same constraint */
4434 assert(consdata->merged);
4435
4436 /* get active variable and clique value in cons */
4437 if( (*cliquevalues)[v] )
4438 var = vars[v];
4439 else
4440 {
4441 assert(SCIPvarGetStatus(vars[v]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[v])));
4442 var = SCIPvarGetNegationVar(vars[v]);
4443 }
4444
4445 /* get active variable and clique value of next variable */
4446 if( SCIPvarIsActive(usefulvars[v1]) )
4447 {
4448 var1 = usefulvars[v1];
4449 value = TRUE;
4450 }
4451 else
4452 {
4453 assert(SCIPvarGetStatus(usefulvars[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(usefulvars[v1])));
4454 var1 = SCIPvarGetNegationVar(usefulvars[v1]);
4455 value = FALSE;
4456 }
4457
4458 nottocheck = -1;
4459 k = 0;
4460
4461 /* variable index in the constraint smaller than the other one, so go to the next variable in cons */
4462 if( SCIPvarGetIndex(var) < SCIPvarGetIndex(var1) )
4463 {
4464 --v;
4465 continue;
4466 }
4467 /* variable index in the constraint is greater than the other one, so check for possible inclusion of the variable */
4468 else if( SCIPvarGetIndex(var) > SCIPvarGetIndex(var1) )
4469 {
4470 assert(consdata == SCIPconsGetData(cons));
4471
4472 /* check if every variable in the actual clique is in clique with the new variable */
4473 for( k = nvars - 1; k >= 0; --k )
4474 {
4475 if( SCIPvarGetUbLocal(vars[k]) > 0.5 )
4476 {
4477 /* there should no variables fixed to one occur in our constraint */
4478 assert(SCIPvarGetLbLocal(vars[k]) < 0.5);
4479 assert(SCIPvarIsActive(vars[k]) || (SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k]))));
4480
4481 if( (*cliquevalues)[k] )
4482 {
4483 assert(SCIPvarIsActive(vars[k]));
4484 var = vars[k];
4485 }
4486 else
4487 {
4488 assert(SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k])));
4489 var = SCIPvarGetNegationVar(vars[k]);
4490 }
4491 if( !SCIPhaveVarsCommonClique(scip, var1, value, var, (*cliquevalues)[k], TRUE) )
4492 break;
4493 }
4494 }
4495 --v1;
4496 }
4497 /* variable index in the constraint is equal to the index of the other variable, check if these variables are
4498 * negated of each other so memorize the position and check for possible inclusion of the new variable and if
4499 * possible decrease indices
4500 */
4501 else
4502 {
4503 /* one clique contains the negated and the other clique the corresponding active var */
4504 if( value != (*cliquevalues)[v] )
4505 {
4506 nottocheck = v;
4507
4508 assert(consdata == SCIPconsGetData(cons));
4509 assert(nvars <= consdata->nvars);
4510
4511 /* check if every variable in the actual clique is in clique with the new variable */
4512 for( k = nvars - 1; k >= 0; --k )
4513 {
4514 if( SCIPvarGetUbLocal(vars[k]) > 0.5 )
4515 {
4516 /* there should no variables fixed to one occur in our constraint */
4517 assert(SCIPvarGetLbLocal(vars[k]) < 0.5);
4518
4519 assert(SCIPvarIsActive(vars[k]) || (SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k]))));
4520
4521 if( k == nottocheck )
4522 continue;
4523
4524 if( (*cliquevalues)[k] )
4525 {
4526 assert(SCIPvarIsActive(vars[k]));
4527 var = vars[k];
4528 }
4529 else
4530 {
4531 assert(SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k])));
4532 var = SCIPvarGetNegationVar(vars[k]);
4533 }
4534
4535 if( !SCIPhaveVarsCommonClique(scip, var1, value, var, (*cliquevalues)[k], TRUE) )
4536 break;
4537 }
4538 }
4539 }
4540 /* don't decrease v because it might happen that the corresponding negated variable of var is next in
4541 * usefulvars
4542 */
4543 --v1;
4544 }
4545
4546 /* if k is smaller than 0 than the possible new variables is in the same clique with all variables of cons,
4547 * so we add the new variable to clique constraint or fix some variables */
4548 if( k < 0 )
4549 {
4550 ++(*nadded);
4551
4552 /* we found a variable which is the negated variable of another one in this clique so we can fix all
4553 * other variable to zero and if it's a partitioning constraint we can also fix the variable of the
4554 * negated to one and we can delete the constraint too */
4555 if( nottocheck >= 0 )
4556 {
4557 assert(consdata == SCIPconsGetData(cons));
4558 assert(nvars <= consdata->nvars);
4559 assert(consdata->merged);
4560
4561 /* process all vars for possible fixing */
4562 for( k = consdata->nvars - 1; k >= 0; --k )
4563 {
4564 if( SCIPvarGetUbLocal(vars[k]) > 0.5 )
4565 {
4566 /* there should no variables fixed to one occur in our constraint */
4567 assert(SCIPvarGetLbLocal(vars[v]) < 0.5);
4568
4569 assert(SCIPvarIsActive(vars[k]) || (SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k]))));
4570
4571 if( k != nottocheck )
4572 {
4573 SCIPdebugMsg(scip, "trying to fix <%s> to 0 because we could lift a negated variable of another constraint variable\n", SCIPvarGetName(vars[k]));
4574 /* fix variable to zero */
4575 SCIP_CALL( SCIPfixVar(scip, vars[k], 0.0, cutoff, &fixed) );
4576
4577 if( *cutoff )
4578 {
4579 SCIPdebugMsg(scip, "fixing led to cutoff\n");
4580
4581 return SCIP_OKAY;
4582 }
4583
4584 assert(fixed);
4585
4586 ++(*nfixedvars);
4587 }
4588 }
4589 }
4590 if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/
4591 {
4592 assert(SCIPvarIsActive(vars[nottocheck]) || (SCIPvarGetStatus(vars[nottocheck]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[nottocheck]))));
4593
4594 SCIPdebugMsg(scip, "trying to fix <%s> to 1 due to this setpartitioning variable is with its negated in the same clique\n", SCIPvarGetName(vars[nottocheck]));
4595 /* fix the remaining variable to one, due to it's the only one left to satisfy the constraint */
4596 SCIP_CALL( SCIPfixVar(scip, vars[nottocheck], 1.0, cutoff, &fixed) );
4597 if( *cutoff )
4598 {
4599 SCIPdebugMsg(scip, "fixing led to cutoff\n");
4600
4601 return SCIP_OKAY;
4602 }
4603
4604 assert(fixed);
4605 ++(*nfixedvars);
4606 }
4607
4608 /* delete constraint */
4609 SCIPdebugMsg(scip, " -> deleting constraint <%s> number <%d> due to active and negated variable in the same clique constraint\n", SCIPconsGetName(cons), arraypos);
4610 assert(SCIPconsIsActive(cons));
4611 SCIP_CALL( SCIPdelCons(scip, cons) );
4612 ++(*ndelconss);
4613
4614 break;
4615 }
4616 /* we found a variable which could be added to a partitioning constraint so we can fix it to zero */
4617 else if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/
4618 {
4619 SCIPdebugMsg(scip, "trying to fix <%s> to 0 because this variable is in the same clique with a set partition\n", SCIPvarGetName(usefulvars[v1 + 1]));
4620 /* fix variable to zero */
4621 SCIP_CALL( SCIPfixVar(scip, usefulvars[v1 + 1], 0.0, cutoff, &fixed) );
4622
4623 if( *cutoff )
4624 {
4625 SCIPdebugMsg(scip, "fixing led to cutoff\n");
4626
4627 return SCIP_OKAY;
4628 }
4629
4630 assert(fixed);
4631
4632 ++(*nfixedvars);
4633 }
4634 /* we have found a new variable for a set packing constraint cons, so add the found variable to the first constraint */
4635 else
4636 {
4637 SCIP_VAR* addvar;
4638
4639 assert(SCIPconsIsActive(cons));
4640
4641 addvar = usefulvars[v1 + 1];
4642
4643 assert(SCIPvarGetLbLocal(addvar) < 0.5 && SCIPvarGetUbLocal(addvar) > 0.5);
4644
4645 /* add representative instead */
4646 SCIPdebugMsg(scip, " -> adding variable <%s> to constraint <%s> number %d\n", SCIPvarGetName(usefulvars[v1 + 1]), SCIPconsGetName(cons), arraypos);
4647 SCIP_CALL( addCoef(scip, cons, addvar) );
4648 assert(consdata == SCIPconsGetData(cons));
4649 /* we know that this constraint stays merged but later on we have to resort */
4650 consdata->merged = TRUE;
4651
4652 /* second we add the constraint index to the list of indices where this variable occurs */
4653 assert(SCIPhashmapExists(vartoindex, (void*) addvar));
4654
4655 /* correct local data structure, add constraint entry to variable data */
4656 SCIP_CALL( addCliqueDataEntry(scip, addvar, arraypos, FALSE, usefulvars, nusefulvars, vartoindex, varnconss, maxnvarconsidx, varconsidxs) );
4657
4658 /* we need the new pointer to the variables, because due to adding variables it is possible that we
4659 * did reallocate the variables array inside the constraint, the index v should stay the same because the
4660 * added variable was inserted at the end and we are decreasing v in our for loop
4661 */
4662 vars = consdata->vars;
4663 nvars = consdata->nvars;
4664
4665 /* we need to update our data structure */
4666
4667 /* resize clique array if necessary, due to adding variables */
4668 if( (*maxnvars) < nvars )
4669 {
4670 while( (*maxnvars) < nvars )
4671 (*maxnvars) *= 2 ;
4672 SCIP_CALL( SCIPreallocBufferArray(scip, cliquevalues, (*maxnvars)) );
4673 }
4674 (*cliquevalues)[nvars - 1] = SCIPvarIsActive(addvar) ? TRUE : FALSE;
4675
4676 (*chgcons) = TRUE;
4677 }
4678 }
4679 }
4680
4681 if( !SCIPconsIsActive(cons) )
4682 return SCIP_OKAY;
4683
4684 /* maybe we stopped because of cons(v reached -1) so try to add rest in usefulvars */
4685 for( ; v1 >= 0; --v1)
4686 {
4687 if( SCIPvarGetLbLocal(usefulvars[v1]) > 0.5 || SCIPvarGetUbLocal(usefulvars[v1]) < 0.5 )
4688 continue;
4689
4690 /* get active variable and clique value */
4691 if( SCIPvarIsActive(usefulvars[v1]) )
4692 {
4693 var1 = usefulvars[v1];
4694 value = TRUE;
4695 }
4696 else
4697 {
4698 assert(SCIPvarGetStatus(usefulvars[v1]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(usefulvars[v1])));
4699 var1 = SCIPvarGetNegationVar(usefulvars[v1]);
4700 value = FALSE;
4701 }
4702
4703 assert(consdata == SCIPconsGetData(cons));
4704 assert(nvars <= consdata->nvars);
4705
4706 /* check if every variable in the actual clique is in clique with the new variable */
4707 for( k = nvars - 1; k >= 0; --k )
4708 {
4709 if( SCIPvarGetUbLocal(vars[k]) > 0.5 )
4710 {
4711 /* there should no variables fixed to one occur in our constraint */
4712 assert(SCIPvarGetLbLocal(vars[k]) < 0.5);
4713
4714 assert(SCIPvarIsActive(vars[k]) || (SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k]))));
4715
4716 if( (*cliquevalues)[k] )
4717 {
4718 assert(SCIPvarIsActive(vars[k]));
4719 var = vars[k];
4720 }
4721 else
4722 {
4723 assert(SCIPvarGetStatus(vars[k]) == SCIP_VARSTATUS_NEGATED && SCIPvarIsActive(SCIPvarGetNegationVar(vars[k])));
4724 var = SCIPvarGetNegationVar(vars[k]);
4725 }
4726
4727 if( !SCIPvarsHaveCommonClique(var1, value, var, (*cliquevalues)[k], TRUE) )
4728 break;
4729 }
4730 }
4731
4732 /* add new variable to clique constraint or fix some variables */
4733 if( k < 0 )
4734 {
4735 /* we found a variable which could be added to a partitioning constraint so we can fix it to zero */
4736 if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/
4737 {
4738 SCIPdebugMsg(scip, "trying to fix <%s> to 0 because this variable is in the same clique with a set partition\n", SCIPvarGetName(usefulvars[v1]));
4739
4740 /* fix variable to zero */
4741 SCIP_CALL( SCIPfixVar(scip, usefulvars[v1], 0.0, cutoff, &fixed) );
4742 if( *cutoff )
4743 {
4744 SCIPdebugMsg(scip, "fixing led to cutoff\n");
4745
4746 return SCIP_OKAY;
4747 }
4748 assert(fixed);
4749
4750 ++(*nfixedvars);
4751 ++(*nadded);
4752 }
4753 /* add the found variable to the first constraint */
4754 else
4755 {
4756 SCIP_VAR* addvar;
4757
4758 assert(SCIPconsIsActive(cons));
4759
4760 addvar = usefulvars[v1];
4761
4762 assert(SCIPvarGetLbLocal(addvar) < 0.5 && SCIPvarGetUbLocal(addvar) > 0.5);
4763
4764 /* add representative instead */
4765 SCIPdebugMsg(scip, " -> adding variable <%s> to constraint <%s> number %d\n", SCIPvarGetName(addvar), SCIPconsGetName(cons), arraypos);
4766 SCIP_CALL( addCoef(scip, cons, addvar) );
4767 assert(consdata == SCIPconsGetData(cons));
4768 /* we know that this constraint stays merged but later on we have to resort */
4769 consdata->merged = TRUE;
4770
4771 /* second we add the constraint index to the list of indices where this variable occurs */
4772 assert(SCIPhashmapExists(vartoindex, (void*) addvar));
4773
4774 /* correct local data structure, add constraint entry to variable data */
4775 SCIP_CALL( addCliqueDataEntry(scip, addvar, arraypos, FALSE, usefulvars, nusefulvars, vartoindex, varnconss, maxnvarconsidx, varconsidxs) );
4776
4777 /* we need the new pointer to the variables, because due to adding variables it is possible that we
4778 * did reallocate the variables array inside the constraint, the index v should stay the same because the
4779 * added variable was inserted at the end and we are decreasing v in our for loop
4780 */
4781 vars = consdata->vars;
4782 nvars = consdata->nvars;
4783
4784 /* we need to update our data structure */
4785
4786 /* resize clique array if necessary, due to adding variables */
4787 if( (*maxnvars) < nvars )
4788 {
4789 while( (*maxnvars) < nvars )
4790 (*maxnvars) *= 2 ;
4791 SCIP_CALL( SCIPreallocBufferArray(scip, cliquevalues, (*maxnvars)) );
4792 }
4793 (*cliquevalues)[nvars - 1] = SCIPvarIsActive(addvar) ? TRUE : FALSE;
4794
4795 ++(*nadded);
4796 (*chgcons) = TRUE;
4797 }
4798 }
4799 }
4800
4801 return SCIP_OKAY;
4802 }
4803
4804 /** perform all collected aggregations */
4805 static
performAggregations(SCIP * const scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_VAR ** const undoneaggrvars,SCIP_Bool * const undoneaggrtypes,int const naggregations,int * const naggrvars,SCIP_Bool * const cutoff)4806 SCIP_RETCODE performAggregations(
4807 SCIP*const scip, /**< SCIP data structure */
4808 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4809 SCIP_VAR**const undoneaggrvars, /**< aggregation variables storage */
4810 SCIP_Bool*const undoneaggrtypes, /**< aggregation type storage, type FALSE means the aggregation is of the
4811 * form x + y = 1; type TRUE means the aggregation is of the form x = y;
4812 */
4813 int const naggregations, /**< number of aggregations to performed */
4814 int*const naggrvars, /**< pointer to count number of aggregated variables */
4815 SCIP_Bool*const cutoff /**< pointer to store if the problem is infeasible due to a fixing */
4816 )
4817 { /*lint --e{715}*/
4818 SCIP_VAR* var1;
4819 SCIP_VAR* var2;
4820 SCIP_Bool aggregated;
4821 SCIP_Bool redundant;
4822 int a;
4823
4824 assert(scip != NULL);
4825 assert(conshdlrdata != NULL);
4826 assert(undoneaggrvars != NULL);
4827 assert(undoneaggrtypes != NULL);
4828 assert(naggregations > 0);
4829 assert(naggrvars != NULL);
4830 assert(cutoff != NULL);
4831
4832 /* loop over all open aggregations and try to aggregate them */
4833 for( a = 0; a < naggregations; ++a )
4834 {
4835 var1 = undoneaggrvars[2 * a];
4836 var2 = undoneaggrvars[2 * a + 1];
4837 assert(var1 != NULL);
4838 assert(var2 != NULL);
4839
4840 SCIPdebugMsg(scip, "trying to aggregate <%s> %s <%s>%s\n", SCIPvarGetName(var1), undoneaggrtypes[a] ? "=" : "+", SCIPvarGetName(var2), undoneaggrtypes[a] ? "" : " = 1");
4841
4842 #ifdef VARUSES
4843 /* in order to not mess up the variable usage counting, we have to decrease usage counting, aggregate,
4844 * and increase usage counting again
4845 */
4846 SCIP_CALL( conshdlrdataDecVaruses(scip, conshdlrdata, var1) );
4847 SCIP_CALL( conshdlrdataDecVaruses(scip, conshdlrdata, var2) );
4848 #endif
4849
4850 /* aggregate last remaining variables in the set partitioning constraint */
4851 if( undoneaggrtypes[a] )
4852 {
4853 SCIP_CALL( SCIPaggregateVars(scip, var1, var2, 1.0, -1.0, 0.0, cutoff, &redundant, &aggregated) );
4854 }
4855 else
4856 {
4857 SCIP_CALL( SCIPaggregateVars(scip, var1, var2, 1.0, 1.0, 1.0, cutoff, &redundant, &aggregated) );
4858 }
4859
4860 if( *cutoff )
4861 {
4862 SCIPdebugMsg(scip, "aggregation was infeasible\n");
4863
4864 return SCIP_OKAY;
4865 }
4866 /* binary variables should always be aggregated, or due to fixation the aggregation is redundant */
4867 assert(redundant);
4868
4869 if( aggregated )
4870 ++(*naggrvars);
4871
4872 #ifdef VARUSES
4873 /* increase variable usage counting again */
4874 SCIP_CALL( conshdlrdataIncVaruses(scip, conshdlrdata, var1) );
4875 SCIP_CALL( conshdlrdataIncVaruses(scip, conshdlrdata, var2) );
4876 #endif
4877 }
4878
4879 return SCIP_OKAY;
4880 }
4881
4882 /** check whether we can combine or grow cliques so some constraints become redundant or we can fix variables */
4883 /** @todo try another variant, by building up the clique graph and delete unnecessary (transitive closure) edges and do
4884 * a bfs search to search for common ancestors to get all possible lifting variables
4885 */
4886 static
preprocessCliques(SCIP * const scip,SCIP_CONSHDLRDATA * conshdlrdata,SCIP_CONS ** const conss,int const nconss,int const nrounds,int * const firstchange,int * const firstclique,int * const lastclique,int * const nfixedvars,int * const naggrvars,int * const ndelconss,int * const nchgcoefs,SCIP_Bool * const cutoff)4887 SCIP_RETCODE preprocessCliques(
4888 SCIP*const scip, /**< SCIP data structure */
4889 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4890 SCIP_CONS**const conss, /**< constraint set */
4891 int const nconss, /**< number of constraints in constraint set */
4892 int const nrounds, /**< actual presolving round */
4893 int*const firstchange, /**< pointer to store first changed constraint */
4894 int*const firstclique, /**< pointer to store first constraint to start adding clique again */
4895 int*const lastclique, /**< pointer to store last constraint to add cliques again */
4896 int*const nfixedvars, /**< pointer to count number of deleted variables */
4897 int*const naggrvars, /**< pointer to count number of aggregated variables */
4898 int*const ndelconss, /**< pointer to count number of deleted constraints */
4899 int*const nchgcoefs, /**< pointer to count number of deleted coefficients */
4900 SCIP_Bool*const cutoff /**< pointer to store if the problem is infeasible due to a fixing */
4901 )
4902 {
4903 /* extend cliques/constraints by checking whether some variables are in the same clique, no pairwise clique lifting
4904 * which would be slower
4905 */
4906 SCIP_CONS** usefulconss; /* array with pointers of constraint of setpartitioning and setpacking type */
4907 SCIP_VAR** usefulvars; /* array with pointers of variables in setpartitioning and setpacking constraints */
4908 int** varconsidxs; /* array consisting of constraint indices in which the corresponding variable exists */
4909 int* varnconss; /* array consisting of number of constraints the variable occurs */
4910 int* maxnvarconsidx; /* maximal number of occurrences of a variable */
4911 int* countofoverlapping = NULL; /* the amount of variables which are in another constraint */
4912 SCIP_Bool* cliquevalues = NULL; /* values of clique-variables, either one if the variable is active or zero if the variable is negated */
4913
4914 SCIP_HASHMAP* vartoindex; /* mapping of SCIP variables to indices */
4915 SCIP_CONSDATA* consdata;
4916
4917 SCIP_Bool chgcons0;
4918 int nvars;
4919 int c;
4920 int v;
4921 int nusefulconss;
4922 int nusefulvars;
4923 int susefulvars;
4924 int maxnvars;
4925 int varindex;
4926
4927 SCIP_VAR** undoneaggrvars; /* storage for not yet performed aggregations */
4928 SCIP_Bool* undoneaggrtypes; /* storage for not yet performed aggregation type (x = y or x + y = 1) */
4929 int saggregations;
4930 int naggregations;
4931
4932 assert(scip != NULL);
4933 assert(conshdlrdata != NULL);
4934 assert(conss != NULL || nconss == 0);
4935 assert(firstchange != NULL);
4936 assert(firstclique != NULL);
4937 assert(lastclique != NULL);
4938 assert(nfixedvars != NULL);
4939 assert(naggrvars != NULL);
4940 assert(ndelconss != NULL);
4941 assert(nchgcoefs != NULL);
4942 assert(cutoff != NULL);
4943
4944 *cutoff = FALSE;
4945
4946 if( nconss == 0 )
4947 return SCIP_OKAY;
4948
4949 nvars = SCIPgetNVars(scip);
4950
4951 if( nvars == 0 )
4952 return SCIP_OKAY;
4953
4954 susefulvars = 2 * nvars; /* two times because of negated vars, maybe due to deleted variables we need to increase this */
4955
4956 /* a hashmap from varindex to postion in varconsidxs array, because above is still too small */
4957 SCIP_CALL( SCIPhashmapCreate(&vartoindex, SCIPblkmem(scip), nvars) );
4958
4959 /* get temporary memory for the aggregation storage, to memorize aggregations which will be performed later, otherwise we would destroy our local data structures */
4960 saggregations = nvars;
4961 SCIP_CALL( SCIPallocBufferArray(scip, &undoneaggrvars, 2 * saggregations) );
4962 SCIP_CALL( SCIPallocBufferArray(scip, &undoneaggrtypes, saggregations) );
4963 BMSclearMemoryArray(undoneaggrtypes, saggregations);
4964 naggregations = 0;
4965
4966 /* get temporary memory for all clique constraints, all appearing variables and the mapping from variables to constraints */
4967 SCIP_CALL( SCIPallocBufferArray(scip, &usefulconss, nconss) );
4968 SCIP_CALL( SCIPallocBufferArray(scip, &usefulvars, susefulvars) );
4969 BMSclearMemoryArray(usefulvars, susefulvars);
4970 SCIP_CALL( SCIPallocBufferArray(scip, &varnconss, susefulvars + 1) );
4971 BMSclearMemoryArray(varnconss, susefulvars + 1);
4972 SCIP_CALL( SCIPallocBufferArray(scip, &maxnvarconsidx, susefulvars + 1) );
4973 SCIP_CALL( SCIPallocBufferArray(scip, &varconsidxs, susefulvars + 1) );
4974 BMSclearMemoryArray(varconsidxs, susefulvars + 1);
4975 nusefulvars = 0;
4976 nusefulconss = 0;
4977 maxnvars = 0;
4978
4979 /* @todo: check for round limit for adding extra clique constraints */
4980 /* adding clique constraints which arises from global clique information */
4981 if( conshdlrdata->nclqpresolve == 0 && conshdlrdata->addvariablesascliques )
4982 {
4983 SCIP_VAR** vars = SCIPgetVars(scip);
4984 SCIP_VAR** binvars;
4985 int* cliquepartition;
4986 int ncliques;
4987 int nbinvars;
4988 int naddconss;
4989
4990 nbinvars = SCIPgetNBinVars(scip);
4991 SCIP_CALL( SCIPduplicateBufferArray(scip, &binvars, vars, nbinvars) );
4992 SCIP_CALL( SCIPallocBufferArray(scip, &cliquepartition, nbinvars) );
4993
4994 /* @todo: check for better permutations/don't permute the first round
4995 * @todo: take binary variables which are not of vartype SCIP_VARTYPE_BINARY into account
4996 */
4997 SCIPrandomPermuteArray(conshdlrdata->randnumgen, (void**)binvars, 0, nbinvars);
4998
4999 /* try to create a clique-partition over all binary variables and create these cliques as new setppc constraints
5000 * and add them to the usefulconss array and adjust all necessary data this will hopefully lead to faster
5001 * detection of redundant constraints
5002 */
5003 SCIP_CALL( SCIPcalcCliquePartition(scip, binvars, nbinvars, cliquepartition, &ncliques) );
5004
5005 /* resize usefulconss array if necessary */
5006 SCIP_CALL( SCIPreallocBufferArray(scip, &usefulconss, nconss + ncliques) );
5007
5008 naddconss = 0;
5009
5010 /* add extra clique constraints resulting from the cliquepartition calculation to SCIP and to the local data structure */
5011 SCIP_CALL( addExtraCliques(scip, binvars, nbinvars, cliquepartition, ncliques, usefulconss, &nusefulconss,
5012 nrounds, nfixedvars, &naddconss, ndelconss, nchgcoefs, cutoff) );
5013
5014 /* bad hack, we don't want to count these artificial created constraints if they got deleted, so ndelconss
5015 * can become negative which will be change to zero at the end of this method if it's still negative
5016 */
5017 *ndelconss -= naddconss;
5018
5019 SCIPfreeBufferArray(scip, &cliquepartition);
5020 SCIPfreeBufferArray(scip, &binvars);
5021
5022 if( *cutoff )
5023 goto TERMINATE;
5024 }
5025
5026 /* start to collect setpartitioning and setpacking constraints, and try to remove fixed variables and merged these
5027 * constraints
5028 */
5029 SCIP_CALL( collectCliqueConss(scip, conss, nconss, usefulconss, &nusefulconss, nfixedvars, ndelconss, nchgcoefs, cutoff) );
5030 /* @Note: Even after the call above some constraints can have fixed variables, because it might happen that caused by
5031 * mergeMultiplies some variables were fixed which occurred already in previous constraints
5032 */
5033 if( *cutoff )
5034 goto TERMINATE;
5035
5036 /* no usefulconss found */
5037 if( nusefulconss <= 1 )
5038 goto TERMINATE;
5039
5040 /* @todo: maybe sort them after biggest indices too, or another variant would be to restore the order as they were
5041 * read in
5042 */
5043 /* sort constraints first after type (partitioning before packing) and second after number of variables such that the
5044 * partitioning constraints have increasing number of variables and the packing constraints have decreasing number of
5045 * variables, because we loop from back to front we sort them downwards, so they are the other way around
5046 */
5047 SCIPsortDownPtr((void**)usefulconss, setppcConssSort, nusefulconss);
5048
5049 /* creating all necessary data in array structure, collect all clique constraint variables and occurrences */
5050 SCIP_CALL( collectCliqueData(scip, usefulconss, nusefulconss, usefulvars, &nusefulvars, vartoindex, varnconss, maxnvarconsidx, varconsidxs, &maxnvars) );
5051 assert(maxnvars > 0);
5052
5053 /* allocate temporary memory for actual clique */
5054 SCIP_CALL( SCIPallocBufferArray(scip, &cliquevalues, maxnvars) );
5055 /* allocate temporary memory for counting an overlap of variables */
5056 SCIP_CALL( SCIPallocBufferArray(scip, &countofoverlapping, nusefulconss) );
5057
5058 /* sort usefulvars after indices of variables, negated and active counterparts will stand side by side */
5059 SCIPsortDownPtr((void**)usefulvars, SCIPvarCompActiveAndNegated, nusefulvars);
5060
5061 /* extend cliques/constraints by checking whether some variables of a second constraint are in the same clique */
5062 for( c = nusefulconss - 1; c >= 0 && !SCIPisStopped(scip); --c )
5063 {
5064 SCIP_VAR** cons0vars; /* these are the clique variables */
5065 SCIP_CONS* cons0;
5066 int ncons0vars;
5067 SCIP_VAR* var0;
5068 int v1;
5069 int nadded; /* number of possible added variables to constraint */
5070 int cons0fixedzeros;
5071 int oldnchgcoefs;
5072 #ifndef NDEBUG
5073 const int oldnaggrvars = *naggrvars;
5074 #endif
5075 cons0 = usefulconss[c];
5076
5077 if( !SCIPconsIsActive(cons0) )
5078 continue;
5079
5080 /* check if constraint is already redundant or infeasible due to fixings, fix or aggregate left over variables if
5081 * possible
5082 */
5083 SCIP_CALL( presolvePropagateCons(scip, cons0, FALSE, undoneaggrvars, undoneaggrtypes, &naggregations, &saggregations, nfixedvars, naggrvars, ndelconss, cutoff) );
5084
5085 if( *cutoff )
5086 break;
5087
5088 /* we can't handle aggregated variables later on so we should have saved them for later */
5089 assert(*naggrvars == oldnaggrvars);
5090
5091 if( !SCIPconsIsActive(cons0) )
5092 continue;
5093
5094 /* we need to determine the cliquedata in each iteration because we eventual will change it later */
5095 consdata = SCIPconsGetData(cons0);
5096 assert(consdata != NULL);
5097
5098 cons0vars = consdata->vars;
5099 ncons0vars = consdata->nvars;
5100
5101 /* sorting array after indices of variables, negated and active counterparts will stand side by side */
5102 SCIPsortDownPtr((void**)cons0vars, SCIPvarCompActiveAndNegated, ncons0vars);
5103 /* standard setppc-sorting now lost */
5104 consdata->sorted = FALSE;
5105
5106 /* clique array should be long enough */
5107 assert(maxnvars >= ncons0vars);
5108
5109 /* clear old entries in overlapping constraint */
5110 BMSclearMemoryArray(countofoverlapping, nusefulconss);
5111
5112 /* calculate overlapping */
5113 for( v = ncons0vars - 1; v >= 0 ; --v )
5114 {
5115 var0 = cons0vars[v];
5116
5117 /* fixed variables later to the count */
5118 if( SCIPvarGetLbLocal(var0) > 0.5 || SCIPvarGetUbLocal(var0) < 0.5 )
5119 continue;
5120
5121 assert(SCIPhashmapExists(vartoindex, (void*) var0));
5122
5123 varindex = SCIPhashmapGetImageInt(vartoindex, (void*) var0);
5124 for( v1 = varnconss[varindex] - 1; v1 >= 0 ; --v1 )
5125 ++(countofoverlapping[varconsidxs[varindex][v1]]);
5126 }
5127
5128 oldnchgcoefs = *nchgcoefs;
5129 cons0fixedzeros = consdata->nfixedzeros;
5130
5131 chgcons0 = FALSE;
5132
5133 /* check for overlapping constraint before starting lifting */
5134 SCIP_CALL( checkForOverlapping(scip, cons0, c, c, usefulconss, nusefulconss, usefulvars, &nusefulvars, vartoindex,
5135 varnconss, maxnvarconsidx, varconsidxs, countofoverlapping, conshdlrdata->cliqueshrinking, &chgcons0,
5136 undoneaggrvars, undoneaggrtypes, &naggregations, &saggregations,
5137 nfixedvars, naggrvars, nchgcoefs, ndelconss, cutoff) );
5138
5139 if( *cutoff )
5140 break;
5141
5142 /* we can't handle aggregated variables later on so we should have saved them for later */
5143 assert(*naggrvars == oldnaggrvars);
5144
5145 /* if cons0 changed, we need to reorder the variables */
5146 if( chgcons0 && *nchgcoefs > oldnchgcoefs )
5147 {
5148 consdata = SCIPconsGetData(cons0);
5149 assert(consdata != NULL);
5150
5151 cons0vars = consdata->vars;
5152 ncons0vars = consdata->nvars;
5153
5154 /* sorting array after indices of variables, negated and active counterparts will stand side by side */
5155 SCIPsortDownPtr((void**)cons0vars, SCIPvarCompActiveAndNegated, ncons0vars);
5156 /* standard setppc-sorting now lost */
5157 consdata->sorted = FALSE;
5158 }
5159
5160 /* check cons0 again for redundancy/fixings, because due to fixings in all other constraints it might happen that cons0 is redundant now */
5161 if( consdata->nfixedones > 0 || consdata->nfixedzeros > cons0fixedzeros )
5162 {
5163 /* check if constraint is already redundant or infeasible due to fixings, fix or aggregate left over variables if
5164 * possible
5165 */
5166 SCIP_CALL( presolvePropagateCons(scip, cons0, FALSE, undoneaggrvars, undoneaggrtypes, &naggregations, &saggregations, nfixedvars, naggrvars, ndelconss, cutoff) );
5167
5168 if( *cutoff )
5169 break;
5170
5171 /* we can't handle aggregated variables later on so we should have saved them for later */
5172 assert(*naggrvars == oldnaggrvars);
5173
5174 if( !SCIPconsIsActive(cons0) )
5175 continue;
5176 }
5177
5178 nadded = 0;
5179
5180 /* iterate over the cliques variables and all possible new clique variables at the "same" time, determine starting
5181 * index
5182 *
5183 * @note: it might be better to start the first round with our computed v1, but maybe it's better to switch to
5184 * trying to add all variables the second time for set packing constraints
5185 */
5186
5187 /* we try to add all variables to the partitioning constraints, to try to fix as much as possible */
5188 if( consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/
5189 v1 = nusefulvars - 1;
5190 else
5191 {
5192 /* if we already ran a presolving round we want to try to add new variables */
5193 if( conshdlrdata->nclqpresolve > 0 )
5194 v1 = nusefulvars - 1;
5195 else
5196 {
5197 /* find start position of variable which we will try to add to our constraint, so we will get better clique constraints */
5198 (void) SCIPsortedvecFindDownPtr((void**)usefulvars, SCIPvarCompActiveAndNegated, (void*)cons0vars[ncons0vars - 1], nusefulvars, &v1);
5199 assert(v1 >= 0 && v1 < nusefulvars);
5200 /* if constraint is not merged and we found a variable which is negated the same as it's neighbour we have to
5201 * increase v1 to make sure that we don't loose this important variable */
5202 if( v1 + 1 < nusefulvars && ((SCIPvarIsNegated(usefulvars[v1 + 1]) && SCIPvarGetNegatedVar(usefulvars[v1 + 1]) == usefulvars[v1]) || (SCIPvarIsNegated(usefulvars[v1]) && SCIPvarGetNegatedVar(usefulvars[v1]) == usefulvars[v1 + 1])) )
5203 ++v1;
5204 }
5205 }
5206
5207 assert(maxnvars >= ncons0vars);
5208 /* initialize the cliquevalues array */
5209 for( v = ncons0vars - 1; v >= 0; --v )
5210 {
5211 if( SCIPvarGetLbLocal(cons0vars[v]) < 0.5 && SCIPvarGetUbLocal(cons0vars[v]) > 0.5 )
5212 {
5213 /* variable has to be either active or a negated variable of an active one */
5214 assert(SCIPvarIsActive(cons0vars[v]) || (SCIPvarGetStatus(cons0vars[v]) == SCIP_VARSTATUS_NEGATED &&
5215 SCIPvarIsActive(SCIPvarGetNegationVar(cons0vars[v]))));
5216 cliquevalues[v] = SCIPvarIsActive(cons0vars[v]) ? TRUE : FALSE;
5217 }
5218 }
5219
5220 chgcons0 = FALSE;
5221
5222 /* try to lift variables to cons0 */
5223 SCIP_CALL( liftCliqueVariables(scip, cons0, c, usefulvars, &nusefulvars, v1, &cliquevalues, vartoindex, varnconss,
5224 maxnvarconsidx, varconsidxs, &maxnvars, &nadded, &chgcons0, nfixedvars, ndelconss, cutoff) );
5225
5226 if( *cutoff )
5227 break;
5228
5229 if( !SCIPconsIsActive(cons0) )
5230 continue;
5231
5232 /* check for redundant constraints due to changing cons0 */
5233 if( chgcons0 )
5234 {
5235 int i;
5236
5237 *firstchange = MIN(*firstchange, c);
5238 *firstclique = MIN(*firstclique, c);
5239 *lastclique = MAX(*lastclique, c);
5240
5241 /* variables array has changed due to lifting variables, so get new values */
5242 assert(consdata == SCIPconsGetData(cons0));
5243 cons0vars = consdata->vars;
5244 ncons0vars = consdata->nvars;
5245
5246 /* resorting array, because we added new variables, in order of indices of variables, negated
5247 * and active counterparts would stand side by side
5248 */
5249 SCIPsortDownPtr((void**)cons0vars, SCIPvarCompActiveAndNegated, ncons0vars);
5250 /* standard setppc-sorting now lost */
5251 consdata->sorted = FALSE;
5252
5253 /* clear old entries in overlapping constraint */
5254 BMSclearMemoryArray(countofoverlapping, nusefulconss);
5255
5256 for( v = ncons0vars - 1; v >= 0 ; --v )
5257 {
5258 var0 = cons0vars[v];
5259
5260 /* fixed variables later to the count */
5261 if( SCIPvarGetLbLocal(var0) > 0.5 || SCIPvarGetUbLocal(var0) < 0.5 )
5262 continue;
5263
5264 assert(SCIPhashmapExists(vartoindex, (void*) var0));
5265
5266 varindex = SCIPhashmapGetImageInt(vartoindex, (void*) var0);
5267 for( i = varnconss[varindex] - 1; i >= 0 ; --i )
5268 ++(countofoverlapping[varconsidxs[varindex][i]]);
5269 }
5270
5271 chgcons0 = FALSE;
5272
5273 /* check for overlapping constraint after lifting, in the first round we will only check up front */
5274 SCIP_CALL( checkForOverlapping(scip, cons0, c, (conshdlrdata->nclqpresolve > 0) ? nusefulconss : c,
5275 usefulconss, nusefulconss, usefulvars, &nusefulvars, vartoindex, varnconss, maxnvarconsidx, varconsidxs,
5276 countofoverlapping, conshdlrdata->cliqueshrinking, &chgcons0,
5277 undoneaggrvars, undoneaggrtypes, &naggregations, &saggregations,
5278 nfixedvars, naggrvars, nchgcoefs, ndelconss, cutoff) );
5279
5280 if( *cutoff )
5281 break;
5282
5283 /* we can't handle aggregated variables later on so we should have saved them for later */
5284 assert(*naggrvars == oldnaggrvars);
5285 }
5286 }
5287
5288 TERMINATE:
5289 SCIPfreeBufferArrayNull(scip, &countofoverlapping);
5290 SCIPfreeBufferArrayNull(scip, &cliquevalues);
5291
5292 /* free temporary memory for constraints, variables and the mapping between them in reverse order as they were
5293 * allocated
5294 */
5295 for( c = nusefulvars; c > 0; --c )
5296 {
5297 if( varconsidxs[c] != NULL )
5298 {
5299 SCIPfreeBufferArrayNull(scip, &(varconsidxs[c]));
5300 }
5301 }
5302
5303 SCIPfreeBufferArray(scip, &varconsidxs);
5304 SCIPfreeBufferArray(scip, &maxnvarconsidx);
5305 SCIPfreeBufferArray(scip, &varnconss);
5306 SCIPfreeBufferArray(scip, &usefulvars);
5307 SCIPfreeBufferArray(scip, &usefulconss);
5308
5309 /* perform all collected aggregations */
5310 if( !*cutoff && naggregations > 0 && !SCIPdoNotAggr(scip) )
5311 {
5312 SCIP_CALL( performAggregations(scip, conshdlrdata, undoneaggrvars, undoneaggrtypes, naggregations, naggrvars, cutoff) );
5313 }
5314
5315 /* free temporary memory for the aggregation storage */
5316 SCIPfreeBufferArray(scip, &undoneaggrtypes);
5317 SCIPfreeBufferArray(scip, &undoneaggrvars);
5318
5319 /* free hashmap */
5320 SCIPhashmapFree(&vartoindex);
5321
5322 if( *ndelconss < 0 )
5323 *ndelconss = 0;
5324
5325 return SCIP_OKAY;
5326 }
5327
5328
5329 /** add cliques to SCIP */
5330 static
addCliques(SCIP * scip,SCIP_CONS ** conss,int nconss,int firstclique,int lastclique,int * naddconss,int * ndelconss,int * nchgbds,SCIP_Bool * cutoff)5331 SCIP_RETCODE addCliques(
5332 SCIP* scip, /**< SCIP data structure */
5333 SCIP_CONS** conss, /**< constraint set */
5334 int nconss, /**< number of constraints in constraint set */
5335 int firstclique, /**< first constraint to start to add cliques */
5336 int lastclique, /**< last constraint to start to add cliques */
5337 int* naddconss, /**< pointer to count number of added constraints */
5338 int* ndelconss, /**< pointer to count number of deleted constraints */
5339 int* nchgbds, /**< pointer to count number of changed bounds */
5340 SCIP_Bool* cutoff /**< pointer to store if the problem is infeasible due to a fixing */
5341 )
5342 {
5343 SCIP_CONS* cons;
5344 SCIP_CONSDATA* consdata;
5345 SCIP_Bool infeasible;
5346 int nlocalbdchgs;
5347 int c;
5348
5349 assert(scip != NULL);
5350 assert(firstclique >= 0);
5351 assert(lastclique <= nconss);
5352 assert(conss != NULL || ((nconss == 0) && (lastclique == 0)));
5353
5354 /* add clique and implication information */
5355 for( c = firstclique; c < lastclique; ++c )
5356 {
5357 cons = conss[c]; /*lint !e613*/
5358 assert(cons != NULL);
5359
5360 /* ignore deleted constraints */
5361 if( !SCIPconsIsActive(cons) )
5362 continue;
5363
5364 nlocalbdchgs = 0;
5365 SCIP_CALL( applyFixings(scip, cons, naddconss, ndelconss, &nlocalbdchgs, cutoff) );
5366 *nchgbds += nlocalbdchgs;
5367
5368 if( *cutoff )
5369 return SCIP_OKAY;
5370
5371 consdata = SCIPconsGetData(cons);
5372 assert(consdata != NULL);
5373
5374 if( SCIPconsIsDeleted(cons) )
5375 continue;
5376
5377 if( !consdata->cliqueadded && consdata->nvars >= 2 )
5378 {
5379 /* add a set partitioning / packing constraint as clique */
5380 if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING || (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING )
5381 {
5382 SCIP_CALL( SCIPaddClique(scip, consdata->vars, NULL, consdata->nvars,
5383 ((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING), &infeasible, &nlocalbdchgs) );
5384 *nchgbds += nlocalbdchgs;
5385
5386 if( infeasible )
5387 {
5388 *cutoff = TRUE;
5389 return SCIP_OKAY;
5390 }
5391 }
5392 else if( consdata->nvars == 2 && !SCIPconsIsModifiable(cons) )
5393 {
5394 /* a two-variable set covering constraint x + y >= 1 yields the implication x == 0 -> y == 1 */
5395 SCIP_CALL( SCIPaddVarImplication(scip, consdata->vars[0], FALSE, consdata->vars[1],
5396 SCIP_BOUNDTYPE_LOWER, 1.0, &infeasible, &nlocalbdchgs) );
5397 *nchgbds += nlocalbdchgs;
5398
5399 if( infeasible )
5400 {
5401 *cutoff = TRUE;
5402 return SCIP_OKAY;
5403 }
5404 }
5405 consdata->cliqueadded = TRUE;
5406 }
5407 }
5408
5409 return SCIP_OKAY;
5410 }
5411
5412 /** perform multi-aggregation on variables resulting from a set-partitioning/-packing constraint */
5413 static
multiAggregateBinvar(SCIP * scip,SCIP_Bool linearconshdlrexist,SCIP_VAR ** vars,int nvars,int pos,SCIP_Bool * infeasible,SCIP_Bool * aggregated)5414 SCIP_RETCODE multiAggregateBinvar(
5415 SCIP* scip, /**< SCIP data structure */
5416 SCIP_Bool linearconshdlrexist,/**< does the linear constraint handler exist, necessary for multi-aggregations */
5417 SCIP_VAR** vars, /**< all variables including the variable to which will be multi-aggregated */
5418 int nvars, /**< number of all variables */
5419 int pos, /**< position of variable for multi-aggregation */
5420 SCIP_Bool* infeasible, /**< pointer to store infeasibility status of aggregation */
5421 SCIP_Bool* aggregated /**< pointer to store aggregation status */
5422 )
5423 {
5424 SCIP_VAR** tmpvars;
5425 SCIP_Real* scalars;
5426 int v;
5427
5428 assert(scip != NULL);
5429 assert(vars != NULL);
5430 assert(nvars > 1);
5431 assert(0 <= pos && pos < nvars);
5432 assert(infeasible != NULL);
5433 assert(aggregated != NULL);
5434
5435 if( nvars == 2 )
5436 {
5437 SCIP_Bool redundant;
5438
5439 SCIPdebugMsg(scip, "aggregating %s = 1 - %s\n", SCIPvarGetName(vars[pos]), SCIPvarGetName(vars[nvars - pos - 1]));
5440
5441 /* perform aggregation on variables resulting from a set-packing constraint */
5442 SCIP_CALL( SCIPaggregateVars(scip, vars[pos], vars[nvars - pos - 1], 1.0, 1.0, 1.0, infeasible, &redundant, aggregated) );
5443 assert(*infeasible || *aggregated);
5444
5445 return SCIP_OKAY;
5446 }
5447
5448 if( !linearconshdlrexist )
5449 {
5450 *infeasible = FALSE;
5451 return SCIP_OKAY;
5452 }
5453
5454 /* if the last variable will be multi-aggregated, we do not need to copy the variables */
5455 if( pos == nvars - 1 )
5456 tmpvars = vars;
5457 else
5458 {
5459 /* copy variables for aggregation */
5460 SCIP_CALL( SCIPduplicateBufferArray(scip, &tmpvars, vars, nvars) );
5461 tmpvars[pos] = tmpvars[nvars - 1];
5462 }
5463
5464 SCIP_CALL( SCIPallocBufferArray(scip, &scalars, nvars - 1) );
5465 /* initialize scalars */
5466 for( v = nvars - 2; v >= 0; --v )
5467 scalars[v] = -1.0;
5468
5469 SCIPdebugMsg(scip, "multi-aggregating binary variable <%s> (locks: [%d,%d]; to %d variables)\n",
5470 SCIPvarGetName(vars[pos]), SCIPvarGetNLocksDownType(vars[pos], SCIP_LOCKTYPE_MODEL),
5471 SCIPvarGetNLocksUpType(vars[pos], SCIP_LOCKTYPE_MODEL), nvars - 1);
5472
5473 /* perform multi-aggregation */
5474 SCIP_CALL( SCIPmultiaggregateVar(scip, vars[pos], nvars - 1, tmpvars, scalars, 1.0, infeasible, aggregated) );
5475 assert(!(*infeasible));
5476
5477 SCIPfreeBufferArray(scip, &scalars);
5478
5479 if( pos < nvars - 1 )
5480 {
5481 assert(tmpvars != vars);
5482 SCIPfreeBufferArray(scip, &tmpvars);
5483 }
5484
5485 return SCIP_OKAY;
5486 }
5487
5488 /** determine singleton variables in set-partitioning/-packing constraints, or doubleton variables (active and negated)
5489 * in any combination of set-partitioning and set-packing constraints
5490 *
5491 * we can multi-aggregate the variable and either change the set-partitioning constraint to a set-packing constraint or
5492 * even delete it
5493 *
5494 * 1. c1: x + y + z = 1, uplocks(x) = 1, downlocks(x) = 1 => x = 1 - y - z and change c1 to y + z <= 1
5495 *
5496 * 2. c2: x + y + z <= 1, uplocks(x) = 1, downlocks(x) = 0, obj(x) < 0 => x = 1 - y - z and change c2 to y + z <= 1
5497 *
5498 * 3. d1: x + y + z <= 1 and d2: ~x + u + v <= 1, uplocks(x) = 1, downlocks(x) = 1
5499 * a) obj(x) <= 0 => x = 1 - y - z and delete d1
5500 * b) obj(x) > 0 => ~x = 1 - u - v and delete d2
5501 *
5502 * 4. e1: x + y + z == 1 and e2: ~x + u + v (<= or ==) 1, uplocks(x) = (1 or 2), downlocks(x) = 2
5503 * => x = 1 - y - z and delete e1
5504 *
5505 * we can also aggregate a variable in a set-packing constraint with only two variables when the uplocks are equal to
5506 * one and then delete this constraint
5507 *
5508 * 5. f1: x + y <= 1, uplocks(x) = 1, obj(x) <= 0 => x = 1 - y and delete f1
5509 *
5510 * @todo might want to multi-aggregate variables even with more locks, when the fill in is still smaller or equal to
5511 * the old number of non-zeros, e.g.
5512 *
5513 * x + y + z = 1
5514 * ~x + u + v <=/= 1
5515 * ~x + w <= 1
5516 */
5517 static
removeDoubleAndSingletonsAndPerformDualpresolve(SCIP * scip,SCIP_CONS ** conss,int nconss,SCIP_Bool dualpresolvingenabled,SCIP_Bool linearconshdlrexist,int * nfixedvars,int * naggrvars,int * ndelconss,int * nchgcoefs,int * nchgsides,SCIP_Bool * cutoff)5518 SCIP_RETCODE removeDoubleAndSingletonsAndPerformDualpresolve(
5519 SCIP* scip, /**< SCIP data structure */
5520 SCIP_CONS** conss, /**< constraint set */
5521 int nconss, /**< number of constraints in constraint set */
5522 SCIP_Bool dualpresolvingenabled,/**< is dual presolving enabled */
5523 SCIP_Bool linearconshdlrexist,/**< does the linear constraint handler exist, necessary for
5524 * multi-aggregations
5525 */
5526 int* nfixedvars, /**< pointer to count number of deleted variables */
5527 int* naggrvars, /**< pointer to count number of aggregated variables */
5528 int* ndelconss, /**< pointer to count number of deleted constraints */
5529 int* nchgcoefs, /**< pointer to count number of changed coefficients */
5530 int* nchgsides, /**< pointer to count number of changed left hand sides */
5531 SCIP_Bool* cutoff /**< pointer to store if a cut off was detected */
5532 )
5533 {
5534 SCIP_CONS** usefulconss;
5535 SCIP_VAR** binvars;
5536 SCIP_HASHMAP* vartoindex;
5537 SCIP_Bool* chgtype;
5538 int* considxs;
5539 int* posincons;
5540 SCIP_Bool infeasible;
5541 SCIP_Bool aggregated;
5542 SCIP_Bool donotaggr;
5543 SCIP_Bool donotmultaggr;
5544 SCIP_Bool mustcheck;
5545 SCIP_Bool addcut;
5546 int nposvars;
5547 int ndecs;
5548 int nbinvars;
5549 int nposbinvars;
5550 int nuplocks;
5551 int ndownlocks;
5552 int posreplacements;
5553 int nhashmapentries;
5554 int nlocaladdconss;
5555 int v;
5556 int c;
5557
5558 assert(scip != NULL);
5559 assert(conss != NULL);
5560 assert(nconss > 0);
5561 assert(nfixedvars != NULL);
5562 assert(naggrvars != NULL);
5563 assert(ndelconss != NULL);
5564 assert(nchgcoefs != NULL);
5565 assert(nchgsides != NULL);
5566
5567 nbinvars = SCIPgetNBinVars(scip);
5568 nposbinvars = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
5569 assert(nbinvars + SCIPgetNIntVars(scip) + SCIPgetNImplVars(scip) == nposbinvars);
5570
5571 binvars = SCIPgetVars(scip);
5572
5573 /* determine number for possible multi-aggregations */
5574 nposvars = 0;
5575 for( v = nposbinvars - 1; v >= 0; --v )
5576 {
5577 assert(SCIPvarGetType(binvars[v]) != SCIP_VARTYPE_CONTINUOUS);
5578
5579 if( v < nbinvars || SCIPvarIsBinary(binvars[v]) )
5580 {
5581 nuplocks = SCIPvarGetNLocksUpType(binvars[v], SCIP_LOCKTYPE_MODEL);
5582 ndownlocks = SCIPvarGetNLocksDownType(binvars[v], SCIP_LOCKTYPE_MODEL);
5583
5584 if( (nuplocks == 1 && ndownlocks <= 1) || (nuplocks <= 1 && ndownlocks == 1) || (nuplocks <= 2 && ndownlocks <= 2 && SCIPvarGetNegatedVar(binvars[v]) != NULL) )
5585 ++nposvars;
5586 }
5587 }
5588
5589 SCIPdebugMsg(scip, "found %d binary variables for possible multi-aggregation\n", nposvars);
5590
5591 if( nposvars == 0 )
5592 return SCIP_OKAY;
5593
5594 /* a hashmap from var to index when found in a set-partitioning constraint */
5595 SCIP_CALL( SCIPhashmapCreate(&vartoindex, SCIPblkmem(scip), nposvars) );
5596
5597 /* get temporary memory */
5598 SCIP_CALL( SCIPallocBufferArray(scip, &chgtype, nconss) );
5599 BMSclearMemoryArray(chgtype, nconss);
5600
5601 SCIP_CALL( SCIPallocBufferArray(scip, &considxs, nposbinvars) );
5602 SCIP_CALL( SCIPallocBufferArray(scip, &posincons, nposbinvars) );
5603
5604 SCIP_CALL( SCIPduplicateBufferArray(scip, &usefulconss, conss, nconss) );
5605 /* sort constraints */
5606 SCIPsortPtr((void**)usefulconss, setppcConssSort2, nconss);
5607
5608 posreplacements = 0;
5609 nhashmapentries = 0;
5610 ndecs = 0;
5611 donotaggr = SCIPdoNotAggr(scip);
5612 donotmultaggr = SCIPdoNotMultaggr(scip);
5613 assert(!donotaggr || !donotmultaggr);
5614
5615 /* determine singleton variables in set-partitioning/-packing constraints, or doubleton variables (active and
5616 * negated) in any combination of set-partitioning and set-packing constraints
5617 *
5618 * we can multi-aggregate the variable and either change the set-partitioning constraint to a set-packing constraint
5619 * or even delete it
5620 */
5621 for( c = 0; c < nconss; ++c )
5622 {
5623 SCIP_CONS* cons;
5624 SCIP_CONSDATA* consdata;
5625 int oldnfixedvars;
5626 nlocaladdconss = 0;
5627
5628 cons = usefulconss[c];
5629 assert(cons != NULL);
5630
5631 if( SCIPconsIsDeleted(cons) )
5632 continue;
5633
5634 consdata = SCIPconsGetData(cons);
5635 assert(consdata != NULL);
5636
5637 /* if we cannot find any constraint to perform a useful multi-aggregation, stop */
5638 if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_COVERING )
5639 break;
5640
5641 if( !SCIPconsIsChecked(cons) )
5642 continue;
5643
5644 if( SCIPconsIsModifiable(cons) )
5645 continue;
5646
5647 /* update the variables */
5648 SCIP_CALL( applyFixings(scip, cons, &nlocaladdconss, ndelconss, nfixedvars, cutoff) );
5649
5650 if( *cutoff )
5651 break;
5652
5653 /* due to resolving multi-aggregations a constraint can become deleted */
5654 if( SCIPconsIsDeleted(cons) )
5655 continue;
5656
5657 SCIP_CALL( processFixings(scip, cons, cutoff, nfixedvars, &addcut, &mustcheck) );
5658 assert(!addcut);
5659
5660 if( *cutoff )
5661 break;
5662
5663 if( SCIPconsIsDeleted(cons) )
5664 continue;
5665
5666 oldnfixedvars = *nfixedvars;
5667
5668 /* merging unmerged constraints */
5669 SCIP_CALL( mergeMultiples(scip, cons, nfixedvars, ndelconss, nchgcoefs, cutoff) );
5670
5671 if( *cutoff )
5672 break;
5673
5674 if( SCIPconsIsDeleted(cons) )
5675 continue;
5676
5677 if( oldnfixedvars < *nfixedvars )
5678 {
5679 /* update the variables */
5680 SCIP_CALL( applyFixings(scip, cons, &nlocaladdconss, ndelconss, nfixedvars, cutoff) );
5681 assert(!SCIPconsIsDeleted(cons));
5682 assert(nlocaladdconss == 0);
5683 assert(!*cutoff);
5684
5685 if( SCIPconsIsDeleted(cons) )
5686 continue;
5687 }
5688
5689 /* if the constraint was not merged and consists of a variable with its negation, the constraint is redundant */
5690 if( consdata->nvars < 2 )
5691 {
5692 /* deleting redundant set-packing constraint */
5693 if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING )
5694 {
5695 SCIPdebugMsg(scip, "deleting redundant set-packing constraint <%s>\n", SCIPconsGetName(cons));
5696
5697 SCIP_CALL( SCIPdelCons(scip, cons) );
5698 ++(*ndelconss);
5699
5700 continue;
5701 }
5702 else
5703 {
5704 SCIP_Bool fixed;
5705
5706 assert((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING);
5707
5708 if( consdata->nvars == 0 )
5709 {
5710 SCIPdebugMsg(scip, "empty set partition constraint <%s> led to infeasibility\n", SCIPconsGetName(cons));
5711
5712 *cutoff = TRUE;
5713 break;
5714 }
5715
5716 SCIPdebugMsg(scip, "fixing <%s> to 1 because this variable is the last variable in a set partition constraint <%s>\n", SCIPvarGetName(consdata->vars[0]), SCIPconsGetName(cons));
5717
5718 SCIP_CALL( SCIPfixVar(scip, consdata->vars[0], 1.0, &infeasible, &fixed) );
5719 assert(!infeasible);
5720
5721 if( fixed )
5722 ++(*nfixedvars);
5723
5724 assert(SCIPvarGetLbGlobal(consdata->vars[0]) > 0.5);
5725
5726 SCIPdebugMsg(scip, "deleting redundant set-partition constraint <%s>\n", SCIPconsGetName(cons));
5727
5728 SCIP_CALL( SCIPdelCons(scip, cons) );
5729 ++(*ndelconss);
5730
5731 continue;
5732 }
5733 }
5734
5735 /* perform dualpresolve on set-packing constraints with exactly two variables */
5736 if( !donotaggr && consdata->nvars == 2 && dualpresolvingenabled && (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING )
5737 {
5738 SCIP_VAR* var;
5739 SCIP_Real objval;
5740 SCIP_Bool redundant;
5741
5742 var = consdata->vars[0];
5743 assert(var != NULL);
5744 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
5745
5746 SCIP_CALL( SCIPvarGetAggregatedObj(var, &objval) );
5747
5748 nuplocks = SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL);
5749
5750 if( nuplocks == 1 && objval <= 0 )
5751 {
5752 SCIPdebugMsg(scip, "dualpresolve, aggregating %s + %s = 1, in set-packing constraint %s\n", SCIPvarGetName(var), SCIPvarGetName(consdata->vars[1]), SCIPconsGetName(cons));
5753
5754 /* perform aggregation on variables resulting from a set-packing constraint */
5755 SCIP_CALL( SCIPaggregateVars(scip, var, consdata->vars[1], 1.0, 1.0, 1.0, &infeasible, &redundant, &aggregated) );
5756
5757 if( infeasible )
5758 {
5759 *cutoff = TRUE;
5760 break;
5761 }
5762
5763 assert(aggregated);
5764 ++(*naggrvars);
5765
5766 SCIP_CALL( SCIPdelCons(scip, cons) );
5767 ++(*ndelconss);
5768
5769 continue;
5770 }
5771 else
5772 {
5773 var = consdata->vars[1];
5774 assert(var != NULL);
5775 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
5776
5777 SCIP_CALL( SCIPvarGetAggregatedObj(var, &objval) );
5778
5779 nuplocks = SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL);
5780
5781 if( nuplocks == 1 && objval <= 0 )
5782 {
5783 SCIPdebugMsg(scip, "dualpresolve, aggregating %s + %s = 1, in set-packing constraint %s\n", SCIPvarGetName(var), SCIPvarGetName(consdata->vars[0]), SCIPconsGetName(cons));
5784
5785 /* perform aggregation on variables resulting from a set-packing constraint */
5786 SCIP_CALL( SCIPaggregateVars(scip, var, consdata->vars[0], 1.0, 1.0, 1.0, &infeasible, &redundant, &aggregated) );
5787
5788 if( infeasible )
5789 {
5790 *cutoff = TRUE;
5791 break;
5792 }
5793 assert(aggregated);
5794 ++(*naggrvars);
5795
5796 SCIP_CALL( SCIPdelCons(scip, cons) );
5797 ++(*ndelconss);
5798
5799 continue;
5800 }
5801 }
5802 }
5803 else if( !donotaggr && consdata->nvars == 2 && (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING )
5804 {
5805 SCIP_Bool redundant;
5806
5807 SCIPdebugMsg(scip, "aggregating %s + %s = 1, in set-partition constraint %s\n", SCIPvarGetName(consdata->vars[0]), SCIPvarGetName(consdata->vars[1]), SCIPconsGetName(cons));
5808
5809 /* perform aggregation on variables resulting from a set-partitioning constraint */
5810 SCIP_CALL( SCIPaggregateVars(scip, consdata->vars[0], consdata->vars[1], 1.0, 1.0, 1.0, &infeasible, &redundant, &aggregated) );
5811
5812 if( infeasible )
5813 {
5814 *cutoff = TRUE;
5815 break;
5816 }
5817
5818 assert(aggregated);
5819 ++(*naggrvars);
5820
5821 SCIP_CALL( SCIPdelCons(scip, cons) );
5822 ++(*ndelconss);
5823
5824 continue;
5825 }
5826
5827 /* we already found all possible variables for multi-aggregation */
5828 if( ndecs >= nposvars )
5829 continue;
5830
5831 /* no multi aggregation is allowed, so we can continue */
5832 if( donotmultaggr )
5833 continue;
5834
5835 /* if the following condition does not hold, we have an unmerged constraint, and we might need to merge it first */
5836 assert(nposbinvars >= consdata->nvars);
5837
5838 /* search for possible variables for multi-aggregation */
5839 for( v = consdata->nvars - 1; v >= 0; --v )
5840 {
5841 SCIP_VAR* var;
5842 int deleteconsindex = -1;
5843
5844 var = consdata->vars[v];
5845 assert(var != NULL);
5846 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(var) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(var) == SCIP_VARSTATUS_LOOSE);
5847
5848 aggregated = FALSE;
5849 nuplocks = SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL);
5850 ndownlocks = SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL);
5851 assert(nuplocks >= 1 && ndownlocks >= 0); /* we are only treating set partitioning and set packing constraints, so every variable in there should have an uplock */
5852
5853 if( dualpresolvingenabled && (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING && nuplocks <= 1 && nuplocks + ndownlocks <= 2 )
5854 {
5855 assert(nuplocks == 1 && ndownlocks <= 1);
5856
5857 /* we found a redundant variable in a set-partitioning constraint */
5858 if( ndownlocks == 0 )
5859 {
5860 SCIP_Real objval;
5861
5862 SCIP_CALL( SCIPvarGetAggregatedObj(var, &objval) );
5863
5864 /* if the objective value is >= 0 the fixing is normally done by the dualfix presolver */
5865 if( !SCIPisNegative(scip, objval) )
5866 {
5867 SCIP_Bool fixed;
5868
5869 SCIPdebugMsg(scip, "dual-fixing of variable <%s> to 0.0\n", SCIPvarGetName(var));
5870
5871 SCIP_CALL( SCIPfixVar(scip, var, 0.0, &infeasible, &fixed) );
5872 assert(!infeasible);
5873 assert(fixed);
5874
5875 ++(*nfixedvars);
5876 }
5877 else
5878 {
5879 SCIPdebugMsg(scip, "multi-aggregating in set-packing constraint\n");
5880
5881 /* perform aggregation on variables resulting from a set-packing constraint */
5882 SCIP_CALL( multiAggregateBinvar(scip, linearconshdlrexist, consdata->vars, consdata->nvars, v, &infeasible, &aggregated) );
5883
5884 if( infeasible )
5885 {
5886 *cutoff = TRUE;
5887 break;
5888 }
5889 }
5890
5891 ++ndecs;
5892 }
5893 else if( ndownlocks == 1 && SCIPvarGetNegatedVar(var) != NULL )
5894 {
5895 SCIP_CONSDATA* aggrconsdata;
5896 SCIP_VAR* negvar;
5897 SCIP_VAR* activevar;
5898 SCIP_Real objval;
5899 int multaggridx;
5900 int notmultaggridx;
5901 int image;
5902 int consindex;
5903 int varindex;
5904
5905 assert(!SCIPhashmapExists(vartoindex, (void*) var));
5906
5907 negvar = SCIPvarGetNegatedVar(var);
5908
5909 /* if we found a new variable add it to the data */
5910 if( !SCIPhashmapExists(vartoindex, (void*) negvar) )
5911 {
5912 ++nhashmapentries;
5913 SCIP_CALL( SCIPhashmapInsertInt(vartoindex, (void*) var, nhashmapentries) );
5914
5915 considxs[nhashmapentries - 1] = c;
5916 posincons[nhashmapentries - 1] = v;
5917
5918 ++posreplacements;
5919 continue;
5920 }
5921
5922 assert(SCIPhashmapExists(vartoindex, (void*) negvar));
5923 image = SCIPhashmapGetImageInt(vartoindex, (void*) negvar);
5924 assert(image > 0 && image <= nhashmapentries);
5925
5926 consindex = considxs[image - 1];
5927 assert(0 <= consindex && consindex < nconss);
5928
5929 /* if the following assert fails, the constraint was not merged, or something really strange happened */
5930 assert(consindex < c);
5931
5932 ++ndecs;
5933 --posreplacements;
5934 assert(posreplacements >= 0);
5935
5936 varindex = posincons[image - 1];
5937 considxs[image - 1] = -1;
5938 posincons[image - 1] = -1;
5939 SCIP_CALL( SCIPhashmapRemove(vartoindex, (void*) negvar) );
5940
5941 /* if two variables in one constraint might be multi-aggregated, it might happen that this constraint was already removed */
5942 if( SCIPconsIsDeleted(usefulconss[consindex]) )
5943 continue;
5944
5945 aggrconsdata = SCIPconsGetData(usefulconss[consindex]);
5946 assert(aggrconsdata != NULL);
5947 assert((SCIP_SETPPCTYPE)aggrconsdata->setppctype == SCIP_SETPPCTYPE_PACKING);
5948 assert(0 <= varindex);
5949
5950 /* it might be that due to other multi-aggregations the constraint has fewer variables than when we
5951 * remembered the position, therefore we need to find the variable again
5952 */
5953 if( varindex >= aggrconsdata->nvars || aggrconsdata->vars[varindex] != negvar )
5954 {
5955 int v2;
5956
5957 /* if the following assert is raised, then the constraint is redundant and we do not need to aggregate
5958 * anymore and can delete this constraint
5959 */
5960 assert(aggrconsdata->nvars >= 2);
5961
5962 for( v2 = aggrconsdata->nvars - 1; v2 >= 0; --v2 )
5963 {
5964 if( aggrconsdata->vars[v2] == negvar )
5965 break;
5966 }
5967 assert(v2 >= 0);
5968
5969 varindex = v2;
5970 }
5971 assert(0 <= varindex && varindex < aggrconsdata->nvars);
5972 assert(aggrconsdata->vars[varindex] == negvar);
5973 assert(SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(negvar) == SCIP_VARSTATUS_NEGATED);
5974
5975 /* determine active variable and constraint that corresponds to */
5976 if( SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED )
5977 {
5978 activevar = negvar;
5979 multaggridx = consindex;
5980 notmultaggridx = c;
5981 }
5982 else
5983 {
5984 activevar = var;
5985 multaggridx = c;
5986 notmultaggridx = consindex;
5987 }
5988 objval = SCIPvarGetObj(activevar);
5989
5990 SCIPdebugMsg(scip, "multi-aggregating in two set-packing constraint\n");
5991
5992 if( objval <= 0.0 )
5993 {
5994 /* perform aggregation on variables resulting from a set-packing constraint */
5995 if( multaggridx == c )
5996 {
5997 SCIP_CALL( multiAggregateBinvar(scip, linearconshdlrexist, consdata->vars, consdata->nvars, v, &infeasible, &aggregated) );
5998 }
5999 else
6000 {
6001 SCIP_CALL( multiAggregateBinvar(scip, linearconshdlrexist, aggrconsdata->vars, aggrconsdata->nvars, varindex, &infeasible, &aggregated) );
6002 }
6003 deleteconsindex = multaggridx;
6004 }
6005 else
6006 {
6007 /* perform aggregation on variables resulting from a set-packing constraint */
6008 /* coverity[copy_paste_error] */
6009 if( multaggridx == c )
6010 {
6011 SCIP_CALL( multiAggregateBinvar(scip, linearconshdlrexist, aggrconsdata->vars, aggrconsdata->nvars, varindex, &infeasible, &aggregated) );
6012 }
6013 else
6014 {
6015 SCIP_CALL( multiAggregateBinvar(scip, linearconshdlrexist, consdata->vars, consdata->nvars, v, &infeasible, &aggregated) );
6016 }
6017 deleteconsindex = notmultaggridx;
6018 }
6019
6020 if( infeasible )
6021 {
6022 *cutoff = TRUE;
6023 break;
6024 }
6025
6026 assert(deleteconsindex >= 0 && deleteconsindex <= c);
6027 }
6028 }
6029 /* we found a redundant variable in a set-partitioning constraint */
6030 else if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING && nuplocks == 1 && ndownlocks == 1 )
6031 {
6032 SCIPdebugMsg(scip, "multi-aggregating in set-partitioning constraint\n");
6033
6034 /* perform aggregation on variables resulting from a set-partitioning constraint */
6035 SCIP_CALL( multiAggregateBinvar(scip, linearconshdlrexist, consdata->vars, consdata->nvars, v, &infeasible, &aggregated) );
6036
6037 if( infeasible )
6038 {
6039 *cutoff = TRUE;
6040 break;
6041 }
6042
6043 ++ndecs;
6044 }
6045 /* we might have found a redundant variable */
6046 else if( ndownlocks <= 2 && nuplocks <= 2 && SCIPvarGetNegatedVar(var) != NULL )
6047 {
6048 SCIP_CONSDATA* aggrconsdata;
6049 int image;
6050 int consindex;
6051 int varindex;
6052
6053 /* if we have two times the same variable in a set-partitioning constraint, we cannot aggregate this */
6054 if( SCIPhashmapExists(vartoindex, (void*) var) )
6055 {
6056 image = SCIPhashmapGetImageInt(vartoindex, (void*) var);
6057 assert(image > 0 && image <= nhashmapentries);
6058
6059 assert(0 <= considxs[image - 1] && considxs[image - 1] < nconss);
6060 assert(SCIPconsIsDeleted(usefulconss[considxs[image - 1]]) || chgtype[considxs[image - 1]] || (0 <= posincons[image - 1] && posincons[image - 1] < SCIPconsGetData(usefulconss[considxs[image - 1]])->nvars));
6061
6062 considxs[image - 1] = -1;
6063 posincons[image - 1] = -1;
6064
6065 SCIP_CALL( SCIPhashmapRemove(vartoindex, (void*) var) );
6066
6067 --posreplacements;
6068 assert(posreplacements >= 0);
6069
6070 continue;
6071 }
6072 else if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING )
6073 {
6074 /* if we found a new variable add it to the data */
6075 if( !SCIPhashmapExists(vartoindex, (void*) SCIPvarGetNegatedVar(var)) )
6076 {
6077 assert(!SCIPhashmapExists(vartoindex, (void*) var));
6078
6079 ++nhashmapentries;
6080 SCIP_CALL( SCIPhashmapInsertInt(vartoindex, (void*) var, nhashmapentries) );
6081
6082 considxs[nhashmapentries - 1] = c;
6083 posincons[nhashmapentries - 1] = v;
6084
6085 ++posreplacements;
6086 continue;
6087 }
6088 }
6089 else
6090 {
6091 assert((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING);
6092
6093 /* the negated variable did not occur in a set partitioning constraint (those will be iterated over
6094 * first), so we cannot aggregate this variable
6095 */
6096 if( !SCIPhashmapExists(vartoindex, (void*) SCIPvarGetNegatedVar(var)) )
6097 continue;
6098 }
6099
6100 assert(!chgtype[c]);
6101 assert(SCIPhashmapExists(vartoindex, (void*) SCIPvarGetNegatedVar(var)));
6102 image = SCIPhashmapGetImageInt(vartoindex, (void*) SCIPvarGetNegatedVar(var));
6103 assert(image > 0 && image <= nhashmapentries);
6104
6105 consindex = considxs[image - 1];
6106 assert(0 <= consindex && consindex < nconss);
6107
6108 /* if the following assert fails, the constraint was not merged, or something really strange happened */
6109 assert(consindex < c);
6110
6111 ++ndecs;
6112 --posreplacements;
6113 assert(posreplacements >= 0);
6114
6115 varindex = posincons[image - 1];
6116 considxs[image - 1] = -1;
6117 posincons[image - 1] = -1;
6118 SCIP_CALL( SCIPhashmapRemove(vartoindex, (void*) SCIPvarGetNegatedVar(var)) );
6119
6120 /* if two variables in one constraint might be multi-aggregated, it might happen that this constraint was
6121 * already removed
6122 */
6123 if( SCIPconsIsDeleted(usefulconss[consindex]) )
6124 continue;
6125
6126 aggrconsdata = SCIPconsGetData(usefulconss[consindex]);
6127 assert(aggrconsdata != NULL);
6128
6129 /* must not multi-aggregate variables that are locked more then twice by all setppc constraints */
6130 if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING &&
6131 (SCIP_SETPPCTYPE)aggrconsdata->setppctype == SCIP_SETPPCTYPE_PACKING )
6132 {
6133 assert(!dualpresolvingenabled || nuplocks + ndownlocks > 2);
6134 continue;
6135 }
6136
6137 assert((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING ||
6138 (SCIP_SETPPCTYPE)aggrconsdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING);
6139
6140 /* we already removed a variable before, so our positioning information might be wrong, so we need to walk
6141 * over all variables again
6142 */
6143 if( chgtype[consindex] )
6144 {
6145 #ifndef NDEBUG
6146 int v2;
6147
6148 assert((SCIP_SETPPCTYPE)aggrconsdata->setppctype == SCIP_SETPPCTYPE_PACKING);
6149
6150 /* negated variables needs to be still in the upgraded set-packing constraint */
6151 for( v2 = aggrconsdata->nvars - 1; v2 >= 0; --v2 )
6152 {
6153 if( aggrconsdata->vars[v2] == SCIPvarGetNegatedVar(var) )
6154 break;
6155 }
6156 assert(v2 >= 0);
6157 #endif
6158 assert((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING);
6159
6160 SCIPdebugMsg(scip, "multi-aggregating in one set-partitioning or one set-packing constraint\n");
6161
6162 /* perform aggregation on variables resulting from a set-partitioning constraint */
6163 SCIP_CALL( multiAggregateBinvar(scip, linearconshdlrexist, consdata->vars, consdata->nvars, v, &infeasible, &aggregated) );
6164
6165 if( infeasible )
6166 {
6167 *cutoff = TRUE;
6168 break;
6169 }
6170 assert(deleteconsindex == -1);
6171 }
6172 else
6173 {
6174 /* @note it might have happened that we have a variable at hand which exists actually in a set-packing
6175 * constraint and due to some other aggregation we increased the number of locks and reached this
6176 * part of the code, where we would expect only set-partitioning constraints in general, so in
6177 * such a strange case we cannot aggregate anything
6178 */
6179 if( (SCIP_SETPPCTYPE)aggrconsdata->setppctype != SCIP_SETPPCTYPE_PARTITIONING )
6180 continue;
6181
6182 assert(0 <= varindex && varindex < aggrconsdata->nvars);
6183 assert(aggrconsdata->vars[varindex] == SCIPvarGetNegatedVar(var));
6184 assert((SCIP_SETPPCTYPE)aggrconsdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING);
6185
6186 SCIPdebugMsg(scip, "multi-aggregating in two set-partitioning or one set-partitioning and -packing constraint\n");
6187
6188 /* perform aggregation on variables resulting from a set-partitioning constraint */
6189 SCIP_CALL( multiAggregateBinvar(scip, linearconshdlrexist, aggrconsdata->vars, aggrconsdata->nvars, varindex, &infeasible, &aggregated) );
6190
6191 if( infeasible )
6192 {
6193 *cutoff = TRUE;
6194 break;
6195 }
6196
6197 /* change pointer for deletion */
6198 cons = usefulconss[consindex];
6199 assert(deleteconsindex == -1);
6200 }
6201 }
6202
6203 if( aggregated )
6204 {
6205 assert(nuplocks >= 1 && ndownlocks >= 0); /* repeated from above */
6206 ++(*naggrvars);
6207
6208 if( nuplocks == 1 && ndownlocks == 0 && (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PACKING )
6209 {
6210 assert(deleteconsindex < 0);
6211
6212 SCIP_CALL( delCoefPos(scip, cons, v) );
6213 ++(*nchgcoefs);
6214 }
6215 else if( nuplocks == 1 && ndownlocks == 1 && (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING )
6216 {
6217 assert(deleteconsindex < 0);
6218
6219 SCIP_CALL( delCoefPos(scip, cons, v) );
6220 ++(*nchgcoefs);
6221
6222 SCIPdebugMsg(scip, "changing constraint <%s> from set-partitioning to set-packing, due to multi-aggregation\n", SCIPconsGetName(cons));
6223
6224 chgtype[c] = TRUE;
6225
6226 SCIP_CALL( setSetppcType(scip, cons, SCIP_SETPPCTYPE_PACKING) );
6227 ++(*nchgsides);
6228 }
6229 else
6230 {
6231 if( deleteconsindex >= 0 )
6232 {
6233 SCIPdebugMsg(scip, "1: deleting redundant constraint <%s>, due to multi-aggregation\n", SCIPconsGetName(usefulconss[deleteconsindex]));
6234 SCIPdebugPrintCons(scip, usefulconss[deleteconsindex], NULL);
6235
6236 assert(!SCIPconsIsDeleted(usefulconss[deleteconsindex]));
6237 SCIP_CALL( SCIPdelCons(scip, usefulconss[deleteconsindex]) );
6238 }
6239 else
6240 {
6241 SCIPdebugMsg(scip, "2: deleting redundant constraint <%s>, due to multi-aggregation\n", SCIPconsGetName(cons));
6242 SCIPdebugPrintCons(scip, cons, NULL);
6243
6244 assert(!SCIPconsIsDeleted(cons));
6245 SCIP_CALL( SCIPdelCons(scip, cons) );
6246 }
6247 ++(*ndelconss);
6248 }
6249
6250 break;
6251 }
6252 }
6253 }
6254
6255 /* free temporary memory */
6256 SCIPfreeBufferArray(scip, &usefulconss);
6257 SCIPfreeBufferArray(scip, &posincons);
6258 SCIPfreeBufferArray(scip, &considxs);
6259 SCIPfreeBufferArray(scip, &chgtype);
6260
6261 /* free hashmap */
6262 SCIPhashmapFree(&vartoindex);
6263
6264 return SCIP_OKAY;
6265 }
6266
6267
6268 /** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
6269 * accordingly; in contrast to removeRedundantConstraints(), it uses a hash table
6270 */
6271 static
detectRedundantConstraints(SCIP * scip,BMS_BLKMEM * blkmem,SCIP_CONS ** conss,int nconss,int * firstchange,int * ndelconss,int * nchgsides)6272 SCIP_RETCODE detectRedundantConstraints(
6273 SCIP* scip, /**< SCIP data structure */
6274 BMS_BLKMEM* blkmem, /**< block memory */
6275 SCIP_CONS** conss, /**< constraint set */
6276 int nconss, /**< number of constraints in constraint set */
6277 int* firstchange, /**< pointer to store first changed constraint */
6278 int* ndelconss, /**< pointer to count number of deleted constraints */
6279 int* nchgsides /**< pointer to count number of changed left/right hand sides */
6280 )
6281 {
6282 SCIP_HASHTABLE* hashtable;
6283 int hashtablesize;
6284 int c;
6285
6286 assert(scip != NULL);
6287 assert(blkmem != NULL);
6288 assert(conss != NULL || nconss == 0);
6289 assert(firstchange != NULL);
6290 assert(ndelconss != NULL);
6291 assert(nchgsides != NULL);
6292
6293 if( nconss == 0 )
6294 return SCIP_OKAY;
6295
6296 assert(conss != NULL);
6297
6298 /* create a hash table for the constraint set */
6299 hashtablesize = nconss;
6300 hashtablesize = MAX(hashtablesize, HASHSIZE_SETPPCCONS);
6301 SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
6302 hashGetKeySetppccons, hashKeyEqSetppccons, hashKeyValSetppccons, (void*) scip) );
6303
6304 /* check all constraints in the given set for redundancy */
6305 for( c = 0; c < nconss; ++c )
6306 {
6307 SCIP_CONS* cons0;
6308 SCIP_CONS* cons1;
6309
6310 cons0 = conss[c];
6311
6312 if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
6313 continue;
6314
6315 /* get constraint from current hash table with same variables as cons0 and with coefficients either equal or negated
6316 * to the ones of cons0 */
6317 cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
6318
6319 if( cons1 != NULL )
6320 {
6321 SCIP_CONSDATA* consdata0;
6322 SCIP_CONSDATA* consdata1;
6323
6324 assert(SCIPconsIsActive(cons1));
6325 assert(!SCIPconsIsModifiable(cons1));
6326
6327 /* constraint found: create a new constraint with same coefficients and best left and right hand side;
6328 * delete old constraints afterwards
6329 */
6330 consdata0 = SCIPconsGetData(cons0);
6331 consdata1 = SCIPconsGetData(cons1);
6332
6333 assert(consdata0 != NULL && consdata1 != NULL);
6334 assert(consdata0->nvars >= 1 && consdata0->nvars == consdata1->nvars);
6335
6336 assert(consdata0->sorted && consdata1->sorted);
6337 assert(consdata0->vars[0] == consdata1->vars[0]);
6338
6339 SCIPdebugMsg(scip, "setppc constraints <%s> and <%s> have identical variable sets\n",
6340 SCIPconsGetName(cons0), SCIPconsGetName(cons1));
6341 SCIPdebugPrintCons(scip, cons0, NULL);
6342 SCIPdebugPrintCons(scip, cons1, NULL);
6343
6344 /* if necessary change type of setppc constraint */
6345 if( consdata1->setppctype != SCIP_SETPPCTYPE_PARTITIONING && consdata0->setppctype != consdata1->setppctype ) /*lint !e641*/
6346 {
6347 /* change the type of cons0 */
6348 SCIP_CALL( setSetppcType(scip, cons1, SCIP_SETPPCTYPE_PARTITIONING) );
6349 (*nchgsides)++;
6350 }
6351
6352 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
6353 /* coverity[swapped_arguments] */
6354 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
6355
6356 /* delete cons0 */
6357 SCIP_CALL( SCIPdelCons(scip, cons0) );
6358 (*ndelconss)++;
6359
6360 /* update the first changed constraint to begin the next aggregation round with */
6361 if( consdata0->changed && SCIPconsGetPos(cons1) < *firstchange )
6362 *firstchange = SCIPconsGetPos(cons1);
6363
6364 assert(SCIPconsIsActive(cons1));
6365 }
6366 else
6367 {
6368 /* no such constraint in current hash table: insert cons0 into hash table */
6369 SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
6370 }
6371 }
6372
6373 /* free hash table */
6374 SCIPhashtableFree(&hashtable);
6375
6376 return SCIP_OKAY;
6377 }
6378
6379 /** removes the redundant second constraint and updates the flags of the first one */
6380 static
removeRedundantCons(SCIP * scip,SCIP_CONS * cons0,SCIP_CONS * cons1,int * ndelconss)6381 SCIP_RETCODE removeRedundantCons(
6382 SCIP* scip, /**< SCIP data structure */
6383 SCIP_CONS* cons0, /**< constraint that should stay */
6384 SCIP_CONS* cons1, /**< constraint that should be deleted */
6385 int* ndelconss /**< pointer to count number of deleted constraints */
6386 )
6387 {
6388 assert(ndelconss != NULL);
6389
6390 SCIPdebugMsg(scip, " -> removing setppc constraint <%s> which is redundant to <%s>\n",
6391 SCIPconsGetName(cons1), SCIPconsGetName(cons0));
6392 SCIPdebugPrintCons(scip, cons0, NULL);
6393 SCIPdebugPrintCons(scip, cons1, NULL);
6394
6395 /* update flags of cons0 */
6396 SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
6397
6398 /* delete cons1 */
6399 SCIP_CALL( SCIPdelCons(scip, cons1) );
6400 (*ndelconss)++;
6401
6402 return SCIP_OKAY;
6403 }
6404
6405 /** for cons0 contained in cons1, fixes variables of cons1 that are not in cons0 to zero */
6406 static
fixAdditionalVars(SCIP * scip,SCIP_CONS * cons0,SCIP_CONS * cons1,SCIP_Bool * cutoff,int * nfixedvars)6407 SCIP_RETCODE fixAdditionalVars(
6408 SCIP* scip, /**< SCIP data structure */
6409 SCIP_CONS* cons0, /**< constraint that is contained in the other */
6410 SCIP_CONS* cons1, /**< constraint that is a superset of the other */
6411 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */
6412 int* nfixedvars /**< pointer to count number of fixed variables */
6413 )
6414 {
6415 SCIP_CONSDATA* consdata0;
6416 SCIP_CONSDATA* consdata1;
6417 int v0;
6418 int v1;
6419
6420 assert(cutoff != NULL);
6421 assert(nfixedvars != NULL);
6422
6423 *cutoff = FALSE;
6424
6425 /* get constraint data */
6426 consdata0 = SCIPconsGetData(cons0);
6427 consdata1 = SCIPconsGetData(cons1);
6428 assert(consdata0 != NULL);
6429 assert(consdata1 != NULL);
6430 assert(consdata0->nvars < consdata1->nvars);
6431 assert(consdata0->sorted);
6432 assert(consdata1->sorted);
6433
6434 /* fix variables in the range of cons0 */
6435 for( v0 = 0, v1 = 0; v0 < consdata0->nvars && !(*cutoff); ++v0, ++v1 )
6436 {
6437 int index0;
6438
6439 assert(v1 < consdata1->nvars);
6440 index0 = SCIPvarGetIndex(consdata0->vars[v0]);
6441 for( ; SCIPvarGetIndex(consdata1->vars[v1]) < index0 && !(*cutoff); ++v1 ) /*lint !e445*/
6442 {
6443 SCIP_Bool fixed;
6444
6445 /* fix variable to zero */
6446 SCIP_CALL( SCIPfixVar(scip, consdata1->vars[v1], 0.0, cutoff, &fixed) );
6447 if( fixed )
6448 {
6449 SCIPdebugMsg(scip, " -> fixed <%s> == 0\n", SCIPvarGetName(consdata1->vars[v1]));
6450 (*nfixedvars)++;
6451 }
6452 assert(v1 < consdata1->nvars-1);
6453 }
6454 assert(SCIPvarGetIndex(consdata1->vars[v1]) == index0 || *cutoff);
6455 }
6456
6457 /* fix remaining variables of cons1 */
6458 for( ; v1 < consdata1->nvars && !(*cutoff); ++v1 )
6459 {
6460 SCIP_Bool fixed;
6461
6462 assert(consdata0->nvars == 0
6463 || SCIPvarGetIndex(consdata1->vars[v1]) > SCIPvarGetIndex(consdata0->vars[consdata0->nvars-1]));
6464
6465 /* fix variable to zero */
6466 SCIP_CALL( SCIPfixVar(scip, consdata1->vars[v1], 0.0, cutoff, &fixed) );
6467 if( fixed )
6468 {
6469 SCIPdebugMsg(scip, " -> fixed <%s> == 0\n", SCIPvarGetName(consdata1->vars[v1]));
6470 (*nfixedvars)++;
6471 }
6472 }
6473
6474 return SCIP_OKAY;
6475 }
6476
6477 /** applies reductions for cons0 being contained in cons1 */
6478 static
processContainedCons(SCIP * scip,SCIP_CONS * cons0,SCIP_CONS * cons1,SCIP_Bool * cutoff,int * nfixedvars,int * ndelconss,int * nchgsides)6479 SCIP_RETCODE processContainedCons(
6480 SCIP* scip, /**< SCIP data structure */
6481 SCIP_CONS* cons0, /**< constraint that is contained in the other */
6482 SCIP_CONS* cons1, /**< constraint that is a superset of the other */
6483 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */
6484 int* nfixedvars, /**< pointer to count number of fixed variables */
6485 int* ndelconss, /**< pointer to count number of deleted constraints */
6486 int* nchgsides /**< pointer to count number of changed left/right hand sides */
6487 )
6488 {
6489 SCIP_CONSDATA* consdata0;
6490 SCIP_CONSDATA* consdata1;
6491
6492 assert(cutoff != NULL);
6493 assert(nfixedvars != NULL);
6494 assert(ndelconss != NULL);
6495 assert(nchgsides != NULL);
6496
6497 *cutoff = FALSE;
6498
6499 /* get constraint data */
6500 consdata0 = SCIPconsGetData(cons0);
6501 consdata1 = SCIPconsGetData(cons1);
6502 assert(consdata0 != NULL);
6503 assert(consdata1 != NULL);
6504 assert(consdata0->nvars < consdata1->nvars);
6505 assert(consdata0->sorted);
6506 assert(consdata1->sorted);
6507
6508 switch( consdata0->setppctype )
6509 {
6510 case SCIP_SETPPCTYPE_PARTITIONING:
6511 switch( consdata1->setppctype )
6512 {
6513 case SCIP_SETPPCTYPE_PARTITIONING:
6514 case SCIP_SETPPCTYPE_PACKING:
6515 /* cons0: partitioning, cons1: partitioning or packing
6516 * -> fix additional variables in cons1 to zero, remove cons1
6517 */
6518 SCIP_CALL( fixAdditionalVars(scip, cons0, cons1, cutoff, nfixedvars) );
6519 SCIP_CALL( removeRedundantCons(scip, cons0, cons1, ndelconss) );
6520 break;
6521
6522 case SCIP_SETPPCTYPE_COVERING:
6523 /* cons0: partitioning, cons1: covering
6524 * -> remove cons1
6525 */
6526 SCIP_CALL( removeRedundantCons(scip, cons0, cons1, ndelconss) );
6527 break;
6528
6529 default:
6530 SCIPerrorMessage("invalid setppc type <%d> of constraint <%s>\n", consdata1->setppctype, SCIPconsGetName(cons1));
6531 return SCIP_INVALIDDATA;
6532 }
6533 break;
6534
6535 case SCIP_SETPPCTYPE_PACKING:
6536 switch( consdata1->setppctype )
6537 {
6538 case SCIP_SETPPCTYPE_PARTITIONING:
6539 case SCIP_SETPPCTYPE_PACKING:
6540 /* cons0: packing, cons1: partitioning or packing
6541 * -> remove cons0
6542 */
6543 SCIP_CALL( removeRedundantCons(scip, cons1, cons0, ndelconss) );
6544 break;
6545
6546 case SCIP_SETPPCTYPE_COVERING:
6547 /* cons0: packing, cons1: covering
6548 * -> nothing can be deduced
6549 */
6550 break;
6551
6552 default:
6553 SCIPerrorMessage("invalid setppc type <%d> of constraint <%s>\n", consdata1->setppctype, SCIPconsGetName(cons1));
6554 return SCIP_INVALIDDATA;
6555 }
6556 break;
6557
6558 case SCIP_SETPPCTYPE_COVERING:
6559 switch( consdata1->setppctype )
6560 {
6561 case SCIP_SETPPCTYPE_PARTITIONING:
6562 case SCIP_SETPPCTYPE_PACKING:
6563 /* cons0: covering, cons1: partitioning or packing
6564 * -> fix additional variables in cons1 to zero, remove cons1, convert cons0 into partitioning
6565 */
6566 SCIP_CALL( fixAdditionalVars(scip, cons0, cons1, cutoff, nfixedvars) );
6567 SCIP_CALL( setSetppcType(scip, cons0, SCIP_SETPPCTYPE_PARTITIONING) );
6568 SCIP_CALL( removeRedundantCons(scip, cons0, cons1, ndelconss) );
6569 (*nchgsides)++;
6570 break;
6571
6572 case SCIP_SETPPCTYPE_COVERING:
6573 /* cons0: covering, cons1: covering
6574 * -> remove cons1
6575 */
6576 SCIP_CALL( removeRedundantCons(scip, cons0, cons1, ndelconss) );
6577 break;
6578
6579 default:
6580 SCIPerrorMessage("invalid setppc type <%d> of constraint <%s>\n", consdata1->setppctype, SCIPconsGetName(cons1));
6581 return SCIP_INVALIDDATA;
6582 }
6583 break;
6584
6585 default:
6586 SCIPerrorMessage("invalid setppc type <%d> of constraint <%s>\n", consdata0->setppctype, SCIPconsGetName(cons0));
6587 return SCIP_INVALIDDATA;
6588 }
6589
6590 return SCIP_OKAY;
6591 }
6592
6593 /** deletes redundant constraints */
6594 static
removeRedundantConstraints(SCIP * scip,SCIP_CONS ** conss,int firstchange,int chkind,SCIP_Bool * cutoff,int * nfixedvars,int * ndelconss,int * nchgsides)6595 SCIP_RETCODE removeRedundantConstraints(
6596 SCIP* scip, /**< SCIP data structure */
6597 SCIP_CONS** conss, /**< constraint set */
6598 int firstchange, /**< first constraint that changed since last pair preprocessing round */
6599 int chkind, /**< index of constraint to check against all prior indices up to startind */
6600 SCIP_Bool* cutoff, /**< pointer to store whether a cutoff was found */
6601 int* nfixedvars, /**< pointer to count number of fixed variables */
6602 int* ndelconss, /**< pointer to count number of deleted constraints */
6603 int* nchgsides /**< pointer to count number of changed left/right hand sides */
6604 )
6605 {
6606 SCIP_CONS* cons0;
6607 SCIP_CONSDATA* consdata0;
6608 uint64_t signature0;
6609 SCIP_Bool cons0changed;
6610 int c;
6611
6612 assert(scip != NULL);
6613 assert(conss != NULL);
6614 assert(cutoff != NULL);
6615 assert(nfixedvars != NULL);
6616 assert(ndelconss != NULL);
6617 assert(nchgsides != NULL);
6618
6619 *cutoff = FALSE;
6620
6621 /* get the constraint to be checked against all prior constraints */
6622 cons0 = conss[chkind];
6623 assert(SCIPconsIsActive(cons0));
6624 assert(!SCIPconsIsModifiable(cons0));
6625
6626 consdata0 = SCIPconsGetData(cons0);
6627 assert(consdata0 != NULL);
6628 assert(consdata0->nvars >= 1);
6629
6630 /* sort the constraint cons0 */
6631 consdataSort(consdata0);
6632
6633 /* get the bit signature of the constraint */
6634 signature0 = consdataGetSignature(consdata0);
6635
6636 /* check constraint against all prior constraints */
6637 cons0changed = consdata0->changed;
6638 consdata0->changed = FALSE;
6639 for( c = (cons0changed ? 0 : firstchange); c < chkind && !(*cutoff) && SCIPconsIsActive(cons0); ++c )
6640 {
6641 SCIP_CONS* cons1;
6642 SCIP_CONSDATA* consdata1;
6643 uint64_t signature1;
6644 uint64_t jointsignature;
6645 SCIP_Bool cons0iscontained;
6646 SCIP_Bool cons1iscontained;
6647 int v0;
6648 int v1;
6649
6650 cons1 = conss[c];
6651
6652 /* ignore inactive and modifiable constraints */
6653 if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
6654 continue;
6655
6656 consdata1 = SCIPconsGetData(cons1);
6657 assert(consdata1 != NULL);
6658
6659 /* sort the constraint cons1 */
6660 consdataSort(consdata1);
6661
6662 /* get the bit signature of cons1 */
6663 signature1 = consdataGetSignature(consdata1);
6664
6665 /* check (based on signature) if the two constraints are not included in each other */
6666 jointsignature = (signature0 | signature1);
6667 if( jointsignature != signature0 && jointsignature != signature1 )
6668 continue;
6669
6670 /* check whether one constraint is really a subset of the other */
6671 cons0iscontained = (consdata0->nvars <= consdata1->nvars);
6672 cons1iscontained = (consdata1->nvars <= consdata0->nvars);
6673 v0 = 0;
6674 v1 = 0;
6675 while( v0 < consdata0->nvars && v1 < consdata1->nvars )
6676 {
6677 int index0;
6678 int index1;
6679
6680 index0 = SCIPvarGetIndex(consdata0->vars[v0]);
6681 index1 = SCIPvarGetIndex(consdata1->vars[v1]);
6682 if( index0 < index1 )
6683 {
6684 cons0iscontained = FALSE;
6685 if( !cons1iscontained )
6686 break;
6687 for( v0++; v0 < consdata0->nvars && SCIPvarGetIndex(consdata0->vars[v0]) < index1; v0++ )
6688 {}
6689 }
6690 else if( index1 < index0 )
6691 {
6692 cons1iscontained = FALSE;
6693 if( !cons0iscontained )
6694 break;
6695 for( v1++; v1 < consdata1->nvars && SCIPvarGetIndex(consdata1->vars[v1]) < index0; v1++ )
6696 {}
6697 }
6698 else
6699 {
6700 v0++;
6701 v1++;
6702 }
6703 }
6704 cons0iscontained = cons0iscontained && (v0 == consdata0->nvars);
6705 cons1iscontained = cons1iscontained && (v1 == consdata1->nvars);
6706
6707 if( cons0iscontained && cons1iscontained )
6708 {
6709 SCIPdebugMsg(scip, "setppc constraints <%s> and <%s> have identical variable sets\n",
6710 SCIPconsGetName(cons0), SCIPconsGetName(cons1));
6711 SCIPdebugPrintCons(scip, cons0, NULL);
6712 SCIPdebugPrintCons(scip, cons1, NULL);
6713
6714 /* both constraints consists of the same variables */
6715 if( consdata0->setppctype == consdata1->setppctype )
6716 {
6717 /* both constraints are equal: update flags in cons0 and delete cons1 */
6718 SCIP_CALL( removeRedundantCons(scip, cons0, cons1, ndelconss) );
6719 }
6720 else if( consdata0->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/
6721 {
6722 /* the set partitioning constraint is stronger: remove the other one */
6723 SCIP_CALL( removeRedundantCons(scip, cons0, cons1, ndelconss) );
6724 }
6725 else if( consdata1->setppctype == SCIP_SETPPCTYPE_PARTITIONING ) /*lint !e641*/
6726 {
6727 /* the set partitioning constraint is stronger: remove the other one */
6728 SCIP_CALL( removeRedundantCons(scip, cons1, cons0, ndelconss) );
6729 }
6730 else
6731 {
6732 /* one is a covering, the other one a packing constraint: replace them by a single partitioning constraint */
6733 assert((consdata0->setppctype == SCIP_SETPPCTYPE_COVERING && consdata1->setppctype == SCIP_SETPPCTYPE_PACKING)
6734 || (consdata1->setppctype == SCIP_SETPPCTYPE_COVERING && consdata0->setppctype == SCIP_SETPPCTYPE_PACKING)); /*lint !e641*/
6735
6736 /* change the type of cons0 */
6737 SCIP_CALL( setSetppcType(scip, cons0, SCIP_SETPPCTYPE_PARTITIONING) );
6738 (*nchgsides)++;
6739
6740 /* delete cons1 */
6741 SCIP_CALL( removeRedundantCons(scip, cons0, cons1, ndelconss) );
6742 }
6743 }
6744 else if( cons0iscontained )
6745 {
6746 /* cons0 is contained in cons1 */
6747 SCIPdebugMsg(scip, "setppc constraint <%s> is contained in <%s>\n", SCIPconsGetName(cons0), SCIPconsGetName(cons1));
6748 SCIPdebugPrintCons(scip, cons0, NULL);
6749 SCIPdebugPrintCons(scip, cons1, NULL);
6750 SCIP_CALL( processContainedCons(scip, cons0, cons1, cutoff, nfixedvars, ndelconss, nchgsides) );
6751 }
6752 else if( cons1iscontained )
6753 {
6754 /* cons1 is contained in cons1 */
6755 SCIPdebugMsg(scip, "setppc constraint <%s> is contained in <%s>\n", SCIPconsGetName(cons1), SCIPconsGetName(cons0));
6756 SCIPdebugPrintCons(scip, cons0, NULL);
6757 SCIPdebugPrintCons(scip, cons1, NULL);
6758 SCIP_CALL( processContainedCons(scip, cons1, cons0, cutoff, nfixedvars, ndelconss, nchgsides) );
6759 }
6760 }
6761
6762 return SCIP_OKAY;
6763 }
6764
6765 /* perform deletion of variables in all constraints of the constraint handler */
6766 static
performVarDeletions(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_CONS ** conss,int nconss)6767 SCIP_RETCODE performVarDeletions(
6768 SCIP* scip, /**< SCIP data structure */
6769 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6770 SCIP_CONS** conss, /**< array of constraints */
6771 int nconss /**< number of constraints */
6772 )
6773 {
6774 SCIP_CONSDATA* consdata;
6775 int i;
6776 int v;
6777
6778 assert(scip != NULL);
6779 assert(conshdlr != NULL);
6780 assert(conss != NULL);
6781 assert(nconss >= 0);
6782 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
6783
6784 /* iterate over all constraints */
6785 for( i = 0; i < nconss; i++ )
6786 {
6787 consdata = SCIPconsGetData(conss[i]);
6788
6789 /* constraint is marked, that some of its variables were deleted */
6790 if( consdata->varsdeleted )
6791 {
6792 /* iterate over all variables of the constraint and delete marked variables */
6793 for( v = consdata->nvars - 1; v >= 0; v-- )
6794 {
6795 if( SCIPvarIsDeleted(consdata->vars[v]) )
6796 {
6797 SCIP_CALL( delCoefPos(scip, conss[i], v) );
6798 }
6799 }
6800 consdata->varsdeleted = FALSE;
6801 }
6802 }
6803
6804 return SCIP_OKAY;
6805 }
6806
6807 /** helper function to enforce constraints */
6808 static
enforceConstraint(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_CONS ** conss,int nconss,int nusefulconss,SCIP_SOL * sol,SCIP_RESULT * result)6809 SCIP_RETCODE enforceConstraint(
6810 SCIP* scip, /**< SCIP data structure */
6811 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6812 SCIP_CONS** conss, /**< constraints to process */
6813 int nconss, /**< number of constraints */
6814 int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
6815 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
6816 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
6817 )
6818 {
6819 SCIP_Bool cutoff;
6820 SCIP_Bool separated;
6821 SCIP_Bool reduceddom;
6822 int c;
6823
6824 assert(conshdlr != NULL);
6825 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
6826 assert(nconss == 0 || conss != NULL);
6827 assert(result != NULL);
6828
6829 SCIPdebugMsg(scip, "Enforcing %d set partitioning / packing / covering constraints for %s solution\n", nconss,
6830 sol == NULL ? "LP" : "relaxation");
6831
6832 *result = SCIP_FEASIBLE;
6833
6834 cutoff = FALSE;
6835 separated = FALSE;
6836 reduceddom = FALSE;
6837
6838 /* check all useful set partitioning / packing / covering constraints for feasibility */
6839 for( c = 0; c < nusefulconss && !cutoff && !reduceddom; ++c )
6840 {
6841 SCIP_CALL( separateCons(scip, conss[c], sol, TRUE, &cutoff, &separated, &reduceddom) );
6842 }
6843
6844 /* check all obsolete set partitioning / packing / covering constraints for feasibility */
6845 for( c = nusefulconss; c < nconss && !cutoff && !separated && !reduceddom; ++c )
6846 {
6847 SCIP_CALL( separateCons(scip, conss[c], sol, TRUE, &cutoff, &separated, &reduceddom) );
6848 }
6849
6850 #ifdef VARUSES
6851 #ifdef BRANCHLP
6852 /* @todo also branch on relaxation solution */
6853 if( (sol == NULL) && !cutoff && !separated && !reduceddom )
6854 {
6855 /* if solution is not integral, choose a variable set to branch on */
6856 SCIP_CALL( branchLP(scip, conshdlr, result) );
6857 if( *result != SCIP_FEASIBLE )
6858 return SCIP_OKAY;
6859 }
6860 #endif
6861 #endif
6862
6863 /* return the correct result */
6864 if( cutoff )
6865 *result = SCIP_CUTOFF;
6866 else if( separated )
6867 *result = SCIP_SEPARATED;
6868 else if( reduceddom )
6869 *result = SCIP_REDUCEDDOM;
6870
6871 return SCIP_OKAY;
6872 }
6873
6874 /*
6875 * upgrading of linear constraints
6876 */
6877
6878
6879 /** creates and captures a set partitioning / packing / covering constraint */
6880 static
createConsSetppc(SCIP * scip,SCIP_CONS ** cons,const char * name,int nvars,SCIP_VAR ** vars,SCIP_SETPPCTYPE setppctype,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)6881 SCIP_RETCODE createConsSetppc(
6882 SCIP* scip, /**< SCIP data structure */
6883 SCIP_CONS** cons, /**< pointer to hold the created constraint */
6884 const char* name, /**< name of constraint */
6885 int nvars, /**< number of variables in the constraint */
6886 SCIP_VAR** vars, /**< array with variables of constraint entries */
6887 SCIP_SETPPCTYPE setppctype, /**< type of constraint: set partitioning, packing, or covering constraint */
6888 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
6889 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
6890 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
6891 * Usually set to TRUE. */
6892 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
6893 * TRUE for model constraints, FALSE for additional, redundant constraints. */
6894 SCIP_Bool check, /**< should the constraint be checked for feasibility?
6895 * TRUE for model constraints, FALSE for additional, redundant constraints. */
6896 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
6897 * Usually set to TRUE. */
6898 SCIP_Bool local, /**< is constraint only valid locally?
6899 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
6900 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
6901 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
6902 * adds coefficients to this constraint. */
6903 SCIP_Bool dynamic, /**< is constraint subject to aging?
6904 * Usually set to FALSE. Set to TRUE for own cuts which
6905 * are separated as constraints. */
6906 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
6907 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
6908 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
6909 * if it may be moved to a more global node?
6910 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
6911 )
6912 {
6913 SCIP_CONSHDLR* conshdlr;
6914 SCIP_CONSDATA* consdata;
6915 SCIP_CONSHDLRDATA* conshdlrdata;
6916
6917 assert(scip != NULL);
6918
6919 /* find the set partitioning constraint handler */
6920 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
6921 if( conshdlr == NULL )
6922 {
6923 SCIPerrorMessage("set partitioning / packing / covering constraint handler not found\n");
6924 return SCIP_INVALIDCALL;
6925 }
6926
6927 /* create the constraint specific data */
6928 if( SCIPgetStage(scip) == SCIP_STAGE_PROBLEM )
6929 {
6930 /* create constraint in original problem */
6931 SCIP_CALL( consdataCreate(scip, &consdata, nvars, vars, setppctype) );
6932 }
6933 else
6934 {
6935 /* create constraint in transformed problem */
6936 SCIP_CALL( consdataCreateTransformed(scip, &consdata, nvars, vars, setppctype) );
6937 }
6938
6939 /* create constraint */
6940 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
6941 local, modifiable, dynamic, removable, stickingatnode) );
6942
6943 conshdlrdata = SCIPconshdlrGetData(conshdlr);
6944 assert(conshdlrdata != NULL);
6945
6946 if( SCIPisTransformed(scip) && setppctype == SCIP_SETPPCTYPE_PARTITIONING )
6947 {
6948 ++(conshdlrdata->nsetpart);
6949 assert(conshdlrdata->nsetpart >= 0);
6950 }
6951
6952 if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
6953 {
6954 /* get event handler */
6955 assert(conshdlrdata->eventhdlr != NULL);
6956
6957 /* catch bound change events of variables */
6958 SCIP_CALL( catchAllEvents(scip, *cons, conshdlrdata->eventhdlr) );
6959 }
6960
6961 return SCIP_OKAY;
6962 }
6963
6964 /** creates and captures a normalized (with all coefficients +1) setppc constraint */
6965 static
createNormalizedSetppc(SCIP * scip,SCIP_CONS ** cons,const char * name,int nvars,SCIP_VAR ** vars,SCIP_Real * vals,int mult,SCIP_SETPPCTYPE setppctype,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)6966 SCIP_RETCODE createNormalizedSetppc(
6967 SCIP* scip, /**< SCIP data structure */
6968 SCIP_CONS** cons, /**< pointer to hold the created constraint */
6969 const char* name, /**< name of constraint */
6970 int nvars, /**< number of variables in the constraint */
6971 SCIP_VAR** vars, /**< array with variables of constraint entries */
6972 SCIP_Real* vals, /**< array with coefficients (+1.0 or -1.0) */
6973 int mult, /**< multiplier on the coefficients(+1 or -1) */
6974 SCIP_SETPPCTYPE setppctype, /**< type of constraint: set partitioning, packing, or covering constraint */
6975 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
6976 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
6977 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
6978 * Usually set to TRUE. */
6979 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
6980 * TRUE for model constraints, FALSE for additional, redundant constraints. */
6981 SCIP_Bool check, /**< should the constraint be checked for feasibility?
6982 * TRUE for model constraints, FALSE for additional, redundant constraints. */
6983 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
6984 * Usually set to TRUE. */
6985 SCIP_Bool local, /**< is constraint only valid locally?
6986 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
6987 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
6988 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
6989 * adds coefficients to this constraint. */
6990 SCIP_Bool dynamic, /**< is constraint subject to aging?
6991 * Usually set to FALSE. Set to TRUE for own cuts which
6992 * are separated as constraints. */
6993 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
6994 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
6995 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
6996 * if it may be moved to a more global node?
6997 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
6998 )
6999 {
7000 SCIP_VAR** transvars;
7001 int v;
7002
7003 assert(nvars == 0 || vars != NULL);
7004 assert(nvars == 0 || vals != NULL);
7005 assert(mult == +1 || mult == -1);
7006
7007 /* get temporary memory */
7008 SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
7009
7010 /* negate positive or negative variables */
7011 for( v = 0; v < nvars; ++v )
7012 {
7013 if( mult * vals[v] > 0.0 )
7014 transvars[v] = vars[v];
7015 else
7016 {
7017 SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &transvars[v]) );
7018 }
7019 assert(transvars[v] != NULL);
7020 }
7021
7022 /* create the constraint */
7023 SCIP_CALL( createConsSetppc(scip, cons, name, nvars, transvars, setppctype,
7024 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
7025
7026 /* release temporary memory */
7027 SCIPfreeBufferArray(scip, &transvars);
7028
7029 return SCIP_OKAY;
7030 }
7031
7032 /** check, if linear constraint can be upgraded to set partitioning, packing, or covering constraint */
7033 static
SCIP_DECL_LINCONSUPGD(linconsUpgdSetppc)7034 SCIP_DECL_LINCONSUPGD(linconsUpgdSetppc)
7035 { /*lint --e{715}*/
7036 assert(upgdcons != NULL);
7037 assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), "linear") == 0 );
7038
7039 /* check, if linear constraint can be upgraded to set partitioning, packing, or covering constraint
7040 * - all set partitioning / packing / covering constraints consist only of binary variables with a
7041 * coefficient of +1.0 or -1.0 (variables with -1.0 coefficients can be negated):
7042 * lhs <= x1 + ... + xp - y1 - ... - yn <= rhs
7043 * - negating all variables y = (1-Y) with negative coefficients gives:
7044 * lhs + n <= x1 + ... + xp + Y1 + ... + Yn <= rhs + n
7045 * - negating all variables x = (1-X) with positive coefficients and multiplying with -1 gives:
7046 * p - rhs <= X1 + ... + Xp + y1 + ... + yn <= p - lhs
7047 * - a set partitioning constraint has left hand side of +1.0, and right hand side of +1.0 : x(S) == 1.0
7048 * -> without negations: lhs == rhs == 1 - n or lhs == rhs == p - 1
7049 * - a set packing constraint has left hand side of -infinity, and right hand side of +1.0 : x(S) <= 1.0
7050 * -> without negations: (lhs == -inf and rhs == 1 - n) or (lhs == p - 1 and rhs = +inf)
7051 * - a set covering constraint has left hand side of +1.0, and right hand side of +infinity: x(S) >= 1.0
7052 * -> without negations: (lhs == 1 - n and rhs == +inf) or (lhs == -inf and rhs = p - 1)
7053 */
7054 if( nposbin + nnegbin + nposimplbin + nnegimplbin == nvars && ncoeffspone + ncoeffsnone == nvars )
7055 {
7056 int mult;
7057
7058 if( SCIPisEQ(scip, lhs, rhs) && (SCIPisEQ(scip, lhs, 1.0 - ncoeffsnone) || SCIPisEQ(scip, lhs, ncoeffspone - 1.0)) )
7059 {
7060 SCIPdebugMsg(scip, "upgrading constraint <%s> to set partitioning constraint\n", SCIPconsGetName(cons));
7061
7062 /* check, if we have to multiply with -1 (negate the positive vars) or with +1 (negate the negative vars) */
7063 mult = SCIPisEQ(scip, lhs, 1.0 - ncoeffsnone) ? +1 : -1;
7064
7065 /* create the set partitioning constraint (an automatically upgraded constraint is always unmodifiable) */
7066 assert(!SCIPconsIsModifiable(cons));
7067 SCIP_CALL( createNormalizedSetppc(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, mult,
7068 SCIP_SETPPCTYPE_PARTITIONING,
7069 SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
7070 SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons),
7071 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons),
7072 SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );
7073 }
7074 else if( (SCIPisInfinity(scip, -lhs) && SCIPisEQ(scip, rhs, 1.0 - ncoeffsnone))
7075 || (SCIPisEQ(scip, lhs, ncoeffspone - 1.0) && SCIPisInfinity(scip, rhs)) )
7076 {
7077 SCIPdebugMsg(scip, "upgrading constraint <%s> to set packing constraint\n", SCIPconsGetName(cons));
7078
7079 /* check, if we have to multiply with -1 (negate the positive vars) or with +1 (negate the negative vars) */
7080 mult = SCIPisInfinity(scip, -lhs) ? +1 : -1;
7081
7082 /* create the set packing constraint (an automatically upgraded constraint is always unmodifiable) */
7083 assert(!SCIPconsIsModifiable(cons));
7084 SCIP_CALL( createNormalizedSetppc(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, mult,
7085 SCIP_SETPPCTYPE_PACKING,
7086 SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
7087 SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons),
7088 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons),
7089 SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );
7090 }
7091 else if( (SCIPisEQ(scip, lhs, 1.0 - ncoeffsnone) && SCIPisInfinity(scip, rhs))
7092 || (SCIPisInfinity(scip, -lhs) && SCIPisEQ(scip, rhs, ncoeffspone - 1.0)) )
7093 {
7094 SCIPdebugMsg(scip, "upgrading constraint <%s> to set covering constraint\n", SCIPconsGetName(cons));
7095
7096 /* check, if we have to multiply with -1 (negate the positive vars) or with +1 (negate the negative vars) */
7097 mult = SCIPisInfinity(scip, rhs) ? +1 : -1;
7098
7099 /* create the set covering constraint (an automatically upgraded constraint is always unmodifiable) */
7100 assert(!SCIPconsIsModifiable(cons));
7101 SCIP_CALL( createNormalizedSetppc(scip, upgdcons, SCIPconsGetName(cons), nvars, vars, vals, mult,
7102 SCIP_SETPPCTYPE_COVERING,
7103 SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
7104 SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons),
7105 SCIPconsIsLocal(cons), SCIPconsIsModifiable(cons),
7106 SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );
7107 }
7108 }
7109
7110 return SCIP_OKAY;
7111 }
7112
7113 /** tries to upgrade a quadratic constraint to a setpacking constraint */
7114 static
SCIP_DECL_QUADCONSUPGD(quadraticUpgdSetppc)7115 SCIP_DECL_QUADCONSUPGD(quadraticUpgdSetppc)
7116 {
7117 SCIP_QUADVARTERM* quadvarterms;
7118 SCIP_BILINTERM* term;
7119 SCIP_VAR* vars[2];
7120 SCIP_Real coefx;
7121 SCIP_Real coefy;
7122 SCIP_Real rhs;
7123
7124 assert( scip != NULL );
7125 assert( cons != NULL );
7126 assert( nupgdconss != NULL );
7127 assert( upgdconss != NULL );
7128 assert( ! SCIPconsIsModifiable(cons) );
7129 assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), "quadratic") == 0 );
7130
7131 *nupgdconss = 0;
7132
7133 SCIPdebugMsg(scip, "try to upgrade quadratic constraint <%s> to setpacking constraint ...\n", SCIPconsGetName(cons));
7134 SCIPdebugPrintCons(scip, cons, NULL);
7135
7136 /* cannot currently handle linear part */
7137 if( SCIPgetNLinearVarsQuadratic(scip, cons) > 0 )
7138 return SCIP_OKAY;
7139
7140 /* need only one bilinear term */
7141 if( SCIPgetNBilinTermsQuadratic(scip, cons) != 1 )
7142 return SCIP_OKAY;
7143
7144 /* need exactly two quadratic variables */
7145 if( SCIPgetNQuadVarTermsQuadratic(scip, cons) != 2 )
7146 return SCIP_OKAY;
7147
7148 /* get bilinear term */
7149 term = SCIPgetBilinTermsQuadratic(scip, cons);
7150 if( SCIPisZero(scip, term->coef) )
7151 return SCIP_OKAY;
7152
7153 /* check types */
7154 if( SCIPvarGetType(term->var1) != SCIP_VARTYPE_BINARY || SCIPvarGetType(term->var2) != SCIP_VARTYPE_BINARY )
7155 return SCIP_OKAY;
7156
7157 /* left and right hand side need to be equal
7158 * @todo we could also handle inequalities
7159 */
7160 rhs = SCIPgetRhsQuadratic(scip, cons);
7161 if( SCIPisInfinity(scip, rhs) || !SCIPisEQ(scip, SCIPgetLhsQuadratic(scip, cons), rhs) )
7162 return SCIP_OKAY;
7163
7164 quadvarterms = SCIPgetQuadVarTermsQuadratic(scip, cons);
7165
7166 coefx = quadvarterms[0].lincoef + quadvarterms[0].sqrcoef; /* for binary variables, we can treat sqr coef as lin coef */
7167 coefy = quadvarterms[1].lincoef + quadvarterms[0].sqrcoef; /* for binary variables, we can treat sqr coef as lin coef */
7168
7169 /* divide constraint by coefficient of x*y */
7170 coefx /= term->coef;
7171 coefy /= term->coef;
7172 rhs /= term->coef;
7173
7174 /* constraint is now of the form coefx * x + coefy * y + x * y == rhs
7175 * we can rewrite as (x + coefy) * (y + coefx) == rhs + coefx * coefy
7176 */
7177
7178 /* we can only upgrade if coefx and coefy are 0 or -1 and rhs == -coefx * coefy */
7179 if( !SCIPisZero(scip, coefx) && !SCIPisEQ(scip, coefx, -1.0) )
7180 return SCIP_OKAY;
7181 if( !SCIPisZero(scip, coefy) && !SCIPisEQ(scip, coefy, -1.0) )
7182 return SCIP_OKAY;
7183 if( !SCIPisEQ(scip, rhs, -coefx * coefy) )
7184 return SCIP_OKAY;
7185
7186 if( SCIPisZero(scip, coefy) )
7187 {
7188 vars[0] = quadvarterms[0].var;
7189 }
7190 else
7191 {
7192 assert(SCIPisEQ(scip, coefy, -1.0));
7193 /* x - 1 = -(1-x) = -(~x) */
7194 SCIP_CALL( SCIPgetNegatedVar(scip, quadvarterms[0].var, &vars[0]) );
7195 }
7196 if( SCIPisZero(scip, coefx) )
7197 {
7198 vars[1] = quadvarterms[1].var;
7199 }
7200 else
7201 {
7202 assert(SCIPisEQ(scip, coefx, -1.0));
7203 /* y - 1 = -(1 - y) = -(~y) */
7204 SCIP_CALL( SCIPgetNegatedVar(scip, quadvarterms[1].var, &vars[1]) );
7205 }
7206
7207 /* constraint is now of the form vars[0] * vars[1] == 0 */
7208
7209 SCIPdebugMsg(scip, "constraint <%s> can be upgraded ...\n", SCIPconsGetName(cons));
7210
7211 /* vars[0] + vars[1] <= 1 */
7212 SCIP_CALL( SCIPcreateConsSetpack(scip, &upgdconss[0], SCIPconsGetName(cons), 2, vars,
7213 SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons), SCIPconsIsEnforced(cons),
7214 SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons), SCIPconsIsLocal(cons),
7215 SCIPconsIsModifiable(cons), SCIPconsIsDynamic(cons), SCIPconsIsRemovable(cons), SCIPconsIsStickingAtNode(cons)) );
7216 SCIPdebugPrintCons(scip, upgdconss[0], NULL);
7217
7218 ++(*nupgdconss);
7219
7220 return SCIP_OKAY;
7221 } /*lint !e715*/
7222
7223
7224 /*
7225 * Callback methods of constraint handler
7226 */
7227
7228 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
7229 static
SCIP_DECL_CONSHDLRCOPY(conshdlrCopySetppc)7230 SCIP_DECL_CONSHDLRCOPY(conshdlrCopySetppc)
7231 { /*lint --e{715}*/
7232 assert(scip != NULL);
7233 assert(conshdlr != NULL);
7234 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
7235
7236 /* call inclusion method of constraint handler */
7237 SCIP_CALL( SCIPincludeConshdlrSetppc(scip) );
7238
7239 *valid = TRUE;
7240
7241 return SCIP_OKAY;
7242 }
7243
7244 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
7245 static
SCIP_DECL_CONSFREE(consFreeSetppc)7246 SCIP_DECL_CONSFREE(consFreeSetppc)
7247 { /*lint --e{715}*/
7248 SCIP_CONSHDLRDATA* conshdlrdata;
7249
7250 assert(conshdlr != NULL);
7251 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
7252 assert(scip != NULL);
7253
7254 /* free constraint handler data */
7255 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7256 assert(conshdlrdata != NULL);
7257 SCIP_CALL( conshdlrdataFree(scip, &conshdlrdata) );
7258
7259 SCIPconshdlrSetData(conshdlr, NULL);
7260
7261 return SCIP_OKAY;
7262 }
7263
7264
7265 /** initialization method of constraint handler (called after problem was transformed) */
7266 static
SCIP_DECL_CONSINIT(consInitSetppc)7267 SCIP_DECL_CONSINIT(consInitSetppc)
7268 { /*lint --e{715}*/
7269 SCIP_CONSHDLRDATA* conshdlrdata;
7270
7271 assert(conshdlr != NULL);
7272 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
7273 assert(scip != NULL);
7274
7275 /* free constraint handler data */
7276 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7277 assert(conshdlrdata != NULL);
7278
7279 conshdlrdata->noldfixedvars = 0;
7280 conshdlrdata->noldimpls = 0;
7281 conshdlrdata->noldcliques = 0;
7282 conshdlrdata->noldupgrs = 0;
7283 conshdlrdata->nclqpresolve = 0;
7284 conshdlrdata->updatedsetppctype = FALSE;
7285 conshdlrdata->enablecliquelifting = TRUE;
7286
7287 return SCIP_OKAY;
7288 }
7289
7290
7291 /** presolving deinitialization method of constraint handler (called after presolving has been finished) */
7292 static
SCIP_DECL_CONSEXITPRE(consExitpreSetppc)7293 SCIP_DECL_CONSEXITPRE(consExitpreSetppc)
7294 { /*lint --e{715}*/
7295 int c;
7296
7297 assert(scip != NULL);
7298 assert(conshdlr != NULL);
7299
7300 for( c = 0; c < nconss; ++c )
7301 {
7302 if( !SCIPconsIsDeleted(conss[c]) )
7303 {
7304 /* we are not allowed to detect infeasibility in the exitpre stage */
7305 SCIP_CALL( applyFixings(scip, conss[c], NULL, NULL, NULL, NULL) );
7306 }
7307 }
7308
7309 return SCIP_OKAY;
7310 }
7311
7312 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
7313 static
SCIP_DECL_CONSEXITSOL(consExitsolSetppc)7314 SCIP_DECL_CONSEXITSOL(consExitsolSetppc)
7315 { /*lint --e{715}*/
7316 SCIP_CONSDATA* consdata;
7317 int c;
7318
7319 /* release the rows of all constraints */
7320 for( c = 0; c < nconss; ++c )
7321 {
7322 consdata = SCIPconsGetData(conss[c]);
7323 assert(consdata != NULL);
7324
7325 if( consdata->row != NULL )
7326 {
7327 SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
7328 }
7329 }
7330
7331 return SCIP_OKAY;
7332 }
7333
7334
7335 /** frees specific constraint data */
7336 static
SCIP_DECL_CONSDELETE(consDeleteSetppc)7337 SCIP_DECL_CONSDELETE(consDeleteSetppc)
7338 { /*lint --e{715}*/
7339 SCIP_CONSHDLRDATA* conshdlrdata;
7340
7341 assert(conshdlr != NULL);
7342 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
7343
7344 /* get event handler */
7345 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7346 assert(conshdlrdata != NULL);
7347 assert(conshdlrdata->eventhdlr != NULL);
7348
7349 if( SCIPisTransformed(scip) )
7350 {
7351 if( (SCIP_SETPPCTYPE)((*consdata)->setppctype) == SCIP_SETPPCTYPE_PARTITIONING )
7352 {
7353 --(conshdlrdata->nsetpart);
7354 assert(conshdlrdata->nsetpart >= 0);
7355 }
7356 }
7357
7358 /* if constraint belongs to transformed problem space, drop bound change events on variables */
7359 if( (*consdata)->nvars > 0 && SCIPvarIsTransformed((*consdata)->vars[0]) )
7360 {
7361 SCIP_CALL( dropAllEvents(scip, cons, conshdlrdata->eventhdlr) );
7362 }
7363
7364 /* free setppc constraint data */
7365 SCIP_CALL( consdataFree(scip, consdata) );
7366
7367 return SCIP_OKAY;
7368 }
7369
7370
7371 /** transforms constraint data into data belonging to the transformed problem */
7372 static
SCIP_DECL_CONSTRANS(consTransSetppc)7373 SCIP_DECL_CONSTRANS(consTransSetppc)
7374 { /*lint --e{715}*/
7375 SCIP_CONSHDLRDATA* conshdlrdata;
7376 SCIP_CONSDATA* sourcedata;
7377 SCIP_CONSDATA* targetdata;
7378
7379 /*debugMsg(scip, "Trans method of setppc constraints\n");*/
7380
7381 assert(conshdlr != NULL);
7382 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
7383 assert(SCIPgetStage(scip) == SCIP_STAGE_TRANSFORMING);
7384 assert(sourcecons != NULL);
7385 assert(targetcons != NULL);
7386
7387 /* get event handler */
7388 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7389 assert(conshdlrdata != NULL);
7390 assert(conshdlrdata->eventhdlr != NULL);
7391
7392 sourcedata = SCIPconsGetData(sourcecons);
7393 assert(sourcedata != NULL);
7394 assert(sourcedata->row == NULL); /* in original problem, there cannot be LP rows */
7395
7396 /* create constraint data for target constraint */
7397 SCIP_CALL( consdataCreateTransformed(scip, &targetdata, sourcedata->nvars, sourcedata->vars,
7398 (SCIP_SETPPCTYPE)sourcedata->setppctype) );
7399
7400 /* create target constraint */
7401 SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
7402 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
7403 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
7404 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
7405 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
7406
7407 if( (SCIP_SETPPCTYPE)sourcedata->setppctype == SCIP_SETPPCTYPE_PARTITIONING )
7408 {
7409 ++(conshdlrdata->nsetpart);
7410 assert(conshdlrdata->nsetpart >= 0);
7411 }
7412
7413 /* catch bound change events of variables */
7414 SCIP_CALL( catchAllEvents(scip, *targetcons, conshdlrdata->eventhdlr) );
7415
7416 return SCIP_OKAY;
7417 }
7418
7419
7420 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
7421 static
SCIP_DECL_CONSINITLP(consInitlpSetppc)7422 SCIP_DECL_CONSINITLP(consInitlpSetppc)
7423 { /*lint --e{715}*/
7424 int c;
7425
7426 *infeasible = FALSE;
7427
7428 for( c = 0; c < nconss && !(*infeasible); ++c )
7429 {
7430 assert(SCIPconsIsInitial(conss[c]));
7431 SCIP_CALL( addCut(scip, conss[c], infeasible) );
7432 }
7433
7434 return SCIP_OKAY;
7435 }
7436
7437
7438 /** separation method of constraint handler for LP solutions */
7439 static
SCIP_DECL_CONSSEPALP(consSepalpSetppc)7440 SCIP_DECL_CONSSEPALP(consSepalpSetppc)
7441 { /*lint --e{715}*/
7442 SCIP_Bool cutoff;
7443 SCIP_Bool separated;
7444 SCIP_Bool reduceddom;
7445 int c;
7446
7447 assert(conshdlr != NULL);
7448 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
7449 assert(nconss == 0 || conss != NULL);
7450 assert(result != NULL);
7451
7452 SCIPdebugMsg(scip, "separating %d/%d set partitioning / packing / covering constraints\n", nusefulconss, nconss);
7453
7454 *result = SCIP_DIDNOTFIND;
7455
7456 cutoff = FALSE;
7457 separated = FALSE;
7458 reduceddom = FALSE;
7459
7460 /* check all useful set partitioning / packing / covering constraints for feasibility */
7461 for( c = 0; c < nusefulconss && !cutoff; ++c )
7462 {
7463 SCIP_CALL( separateCons(scip, conss[c], NULL, TRUE, &cutoff, &separated, &reduceddom) );
7464 }
7465
7466 /* combine set partitioning / packing / covering constraints to get more cuts */
7467 /**@todo further cuts of set partitioning / packing / covering constraints */
7468
7469 /* return the correct result */
7470 if( cutoff )
7471 *result = SCIP_CUTOFF;
7472 else if( reduceddom )
7473 *result = SCIP_REDUCEDDOM;
7474 else if( separated )
7475 *result = SCIP_SEPARATED;
7476
7477 return SCIP_OKAY;
7478 }
7479
7480
7481 /** separation method of constraint handler for arbitrary primal solutions */
7482 static
SCIP_DECL_CONSSEPASOL(consSepasolSetppc)7483 SCIP_DECL_CONSSEPASOL(consSepasolSetppc)
7484 { /*lint --e{715}*/
7485 SCIP_Bool cutoff;
7486 SCIP_Bool separated;
7487 SCIP_Bool reduceddom;
7488 int c;
7489
7490 assert(conshdlr != NULL);
7491 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
7492 assert(nconss == 0 || conss != NULL);
7493 assert(result != NULL);
7494
7495 SCIPdebugMsg(scip, "separating %d/%d set partitioning / packing / covering constraints\n", nusefulconss, nconss);
7496
7497 *result = SCIP_DIDNOTFIND;
7498
7499 cutoff = FALSE;
7500 separated = FALSE;
7501 reduceddom = FALSE;
7502
7503 /* check all useful set partitioning / packing / covering constraints for feasibility */
7504 for( c = 0; c < nusefulconss && !cutoff; ++c )
7505 {
7506 SCIP_CALL( separateCons(scip, conss[c], sol, FALSE, &cutoff, &separated, &reduceddom) );
7507 }
7508
7509 /* combine set partitioning / packing / covering constraints to get more cuts */
7510 /**@todo further cuts of set partitioning / packing / covering constraints */
7511
7512 /* return the correct result */
7513 if( cutoff )
7514 *result = SCIP_CUTOFF;
7515 else if( reduceddom )
7516 *result = SCIP_REDUCEDDOM;
7517 else if( separated )
7518 *result = SCIP_SEPARATED;
7519
7520 return SCIP_OKAY;
7521 }
7522
7523
7524 #ifdef VARUSES
7525 #ifdef BRANCHLP
7526 /** if fractional variables exist, chooses a set S of them and branches on (i) x(S) == 0, and (ii) x(S) >= 1 */
7527 static
branchLP(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_RESULT * result)7528 SCIP_RETCODE branchLP(
7529 SCIP* scip, /**< SCIP data structure */
7530 SCIP_CONSHDLR* conshdlr, /**< set partitioning / packing / covering constraint handler */
7531 SCIP_RESULT* result /**< pointer to store the result SCIP_BRANCHED, if branching was applied */
7532 )
7533 {
7534 SCIP_CONSHDLRDATA* conshdlrdata;
7535 SCIP_INTARRAY* varuses;
7536 SCIP_VAR** lpcands;
7537 SCIP_VAR** sortcands;
7538 SCIP_VAR* var;
7539 SCIP_Real branchweight;
7540 SCIP_Real solval;
7541 int* uses;
7542 int nlpcands;
7543 int nsortcands;
7544 int nselcands;
7545 int numuses;
7546 int i;
7547 int j;
7548
7549 /**@todo use a better set partitioning / packing / covering branching on LP solution (use SOS branching) */
7550
7551 assert(conshdlr != NULL);
7552 assert(result != NULL);
7553
7554 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7555 assert(conshdlrdata != NULL);
7556
7557 varuses = conshdlrdata->varuses;
7558 assert(varuses != NULL);
7559
7560 /* get fractional variables */
7561 SCIP_CALL( SCIPgetLPBranchCands(scip, &lpcands, NULL, NULL, &nlpcands, NULL, NULL) );
7562 if( nlpcands == 0 )
7563 return SCIP_OKAY;
7564
7565 assert(MINBRANCHWEIGHT <= MAXBRANCHWEIGHT);
7566
7567 /* get temporary memory */
7568 SCIP_CALL( SCIPallocBufferArray(scip, &sortcands, nlpcands) );
7569 SCIP_CALL( SCIPallocBufferArray(scip, &uses, nlpcands) );
7570
7571 /* sort fractional variables by number of uses in enabled set partitioning / packing / covering constraints */
7572 nsortcands = 0;
7573 for( i = 0; i < nlpcands; ++i )
7574 {
7575 var = lpcands[i];
7576 numuses = SCIPgetIntarrayVal(scip, varuses, SCIPvarGetIndex(var));
7577 if( numuses > 0 )
7578 {
7579 for( j = nsortcands; j > 0 && numuses > uses[j-1]; --j )
7580 {
7581 sortcands[j] = sortcands[j-1];
7582 uses[j] = uses[j-1];
7583 }
7584 assert(0 <= j && j <= nsortcands);
7585 sortcands[j] = var;
7586 uses[j] = numuses;
7587 nsortcands++;
7588 }
7589 }
7590 assert(nsortcands <= nlpcands);
7591
7592 /* if none of the fractional variables is member of a set partitioning / packing / covering constraint,
7593 * we are not responsible for doing the branching
7594 */
7595 if( nsortcands > 0 )
7596 {
7597 SCIP_Real cumprio = 0.0;
7598 SCIP_Real minprio = SCIP_INVALID;
7599 SCIP_Real minestzero = SCIP_INVALID;
7600 SCIP_Real minestone = SCIP_INVALID;
7601 SCIP_Real tmp;
7602
7603 /* select the first variables from the sorted candidate list, until MAXBRANCHWEIGHT is reached;
7604 * then choose one less
7605 */
7606 branchweight = 0.0;
7607 solval = 0.0;
7608 for( nselcands = 0; nselcands < nsortcands; ++nselcands )
7609 {
7610 solval = SCIPgetVarSol(scip, sortcands[nselcands]);
7611 assert(SCIPisFeasGE(scip, solval, 0.0) && SCIPisFeasLE(scip, solval, 1.0));
7612 branchweight += solval;
7613
7614 /* did we exceed the maximal weight */
7615 if( branchweight > MAXBRANCHWEIGHT )
7616 break;
7617
7618 /* @todo instead of taking the minimum into account try other variants like the maximum and the average */
7619 /* calculate priorities and estimates by adding up/taking the minimum of all single priorities/estimates */
7620 cumprio += SCIPcalcNodeselPriority(scip, sortcands[nselcands], SCIP_BRANCHDIR_DOWNWARDS, 0.0);
7621 tmp = SCIPcalcNodeselPriority(scip, sortcands[nselcands], SCIP_BRANCHDIR_UPWARDS, 1.0);
7622 minprio = MIN(minprio, tmp);
7623 tmp = SCIPcalcChildEstimate(scip, sortcands[nselcands], 0.0);;
7624 minestzero = MIN(minestzero, tmp);
7625 tmp = SCIPcalcChildEstimate(scip, sortcands[nselcands], 1.0);;
7626 minestone = MIN(minestone, tmp);
7627 }
7628 assert(minestzero != SCIP_INVALID); /*lint !e777*/
7629 assert(minestone != SCIP_INVALID); /*lint !e777*/
7630 assert(minprio != SCIP_INVALID); /*lint !e777*/
7631 assert(nselcands > 0);
7632 branchweight -= solval;
7633
7634 /* check, if we accumulated at least MIN and at most MAXBRANCHWEIGHT weight */
7635 if( MINBRANCHWEIGHT <= branchweight && branchweight <= MAXBRANCHWEIGHT )
7636 {
7637 SCIP_NODE* node;
7638
7639 /* perform the binary set branching on the selected variables */
7640 assert(1 <= nselcands && nselcands <= nlpcands);
7641
7642 /* create left child, fix x_i = 0 for all i \in S */
7643 SCIP_CALL( SCIPcreateChild(scip, &node, cumprio, minestzero) );
7644 for( i = 0; i < nselcands; ++i )
7645 {
7646 SCIP_CALL( SCIPchgVarUbNode(scip, node, sortcands[i], 0.0) );
7647 }
7648
7649 /* create right child: add constraint x(S) >= 1 */
7650 SCIP_CALL( SCIPcreateChild(scip, &node, minprio, minestone) );
7651 if( nselcands == 1 )
7652 {
7653 /* only one candidate selected: fix it to 1.0 */
7654 SCIPdebugMsg(scip, "fixing variable <%s> to 1.0 in right child node\n", SCIPvarGetName(sortcands[0]));
7655 SCIP_CALL( SCIPchgVarLbNode(scip, node, sortcands[0], 1.0) );
7656 }
7657 else
7658 {
7659 SCIP_CONS* newcons;
7660 char name[SCIP_MAXSTRLEN];
7661
7662 /* add set covering constraint x(S) >= 1 */
7663 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "BSB%" SCIP_LONGINT_FORMAT, SCIPgetNTotalNodes(scip));
7664
7665 SCIP_CALL( SCIPcreateConsSetcover(scip, &newcons, name, nselcands, sortcands,
7666 FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE) );
7667 SCIP_CALL( SCIPaddConsNode(scip, node, newcons, NULL) );
7668 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
7669 }
7670
7671 *result = SCIP_BRANCHED;
7672
7673 #ifdef SCIP_DEBUG
7674 SCIPdebugMsg(scip, "binary set branching: nselcands=%d/%d, weight(S)=%g, A={", nselcands, nlpcands, branchweight);
7675 for( i = 0; i < nselcands; ++i )
7676 SCIPdebugMsgPrint(scip, " %s[%g]", SCIPvarGetName(sortcands[i]), SCIPgetSolVal(scip, NULL, sortcands[i]));
7677 SCIPdebugMsgPrint(scip, " }\n");
7678 #endif
7679 }
7680 }
7681
7682 /* free temporary memory */
7683 SCIPfreeBufferArray(scip, &uses);
7684 SCIPfreeBufferArray(scip, &sortcands);
7685
7686 return SCIP_OKAY;
7687 }
7688 #endif
7689
7690 /** if unfixed variables exist, chooses a set S of them and creates |S|+1 child nodes:
7691 * - for each variable i from S, create child node with x_0 = ... = x_i-1 = 0, x_i = 1
7692 * - create an additional child node x_0 = ... = x_n-1 = 0
7693 */
7694 static
branchPseudo(SCIP * scip,SCIP_CONSHDLR * conshdlr,SCIP_RESULT * result)7695 SCIP_RETCODE branchPseudo(
7696 SCIP* scip, /**< SCIP data structure */
7697 SCIP_CONSHDLR* conshdlr, /**< set partitioning / packing / covering constraint handler */
7698 SCIP_RESULT* result /**< pointer to store the result SCIP_BRANCHED, if branching was applied */
7699 )
7700 {
7701 SCIP_CONSHDLRDATA* conshdlrdata;
7702 SCIP_INTARRAY* varuses;
7703 SCIP_VAR** pseudocands;
7704 SCIP_VAR** branchcands;
7705 SCIP_VAR* var;
7706 SCIP_NODE* node;
7707 int* canduses;
7708 int npseudocands;
7709 int maxnbranchcands;
7710 int nbranchcands;
7711 int uses;
7712 int i;
7713 int j;
7714
7715 /**@todo use a better set partitioning / packing / covering branching on pseudo solution (use SOS branching) */
7716
7717 assert(conshdlr != NULL);
7718 assert(result != NULL);
7719
7720 conshdlrdata = SCIPconshdlrGetData(conshdlr);
7721 assert(conshdlrdata != NULL);
7722
7723 /* check, if pseudo branching is disabled */
7724 if( conshdlrdata->npseudobranches <= 1 )
7725 return SCIP_OKAY;
7726
7727 /* get fractional variables */
7728 SCIP_CALL( SCIPgetPseudoBranchCands(scip, &pseudocands, NULL, &npseudocands) );
7729 if( npseudocands == 0 )
7730 return SCIP_OKAY;
7731
7732 varuses = conshdlrdata->varuses;
7733 assert(varuses != NULL);
7734
7735 /* choose the maximal number of branching variables */
7736 maxnbranchcands = conshdlrdata->npseudobranches-1;
7737 assert(maxnbranchcands >= 1);
7738
7739 /* get temporary memory */
7740 SCIP_CALL( SCIPallocBufferArray(scip, &branchcands, maxnbranchcands) );
7741 SCIP_CALL( SCIPallocBufferArray(scip, &canduses, maxnbranchcands) );
7742
7743 /* sort unfixed variables by number of uses in enabled set partitioning / packing / covering constraints */
7744 nbranchcands = 0;
7745 for( i = 0; i < npseudocands; ++i )
7746 {
7747 var = pseudocands[i];
7748 uses = SCIPgetIntarrayVal(scip, varuses, SCIPvarGetIndex(var));
7749 if( uses > 0 )
7750 {
7751 if( nbranchcands < maxnbranchcands || uses > canduses[nbranchcands-1] )
7752 {
7753 for( j = MIN(nbranchcands, maxnbranchcands-1); j > 0 && uses > canduses[j-1]; --j )
7754 {
7755 branchcands[j] = branchcands[j-1];
7756 canduses[j] = canduses[j-1];
7757 }
7758 assert(0 <= j && j <= nbranchcands && j < maxnbranchcands);
7759 branchcands[j] = var;
7760 canduses[j] = uses;
7761 if( nbranchcands < maxnbranchcands )
7762 nbranchcands++;
7763 }
7764 }
7765 }
7766 assert(nbranchcands <= maxnbranchcands);
7767
7768 /* if none of the unfixed variables is member of a set partitioning / packing / covering constraint,
7769 * we are not responsible for doing the branching
7770 */
7771 if( nbranchcands > 0 )
7772 {
7773 SCIP_Real* estone;
7774 SCIP_Real minestzero = SCIP_INVALID;
7775 SCIP_Real tmp;
7776
7777 SCIP_CALL( SCIPallocBufferArray(scip, &estone, nbranchcands) );
7778
7779 /* @todo instead of taking the minimum into account try other variants like the maximum and the average */
7780 /* @todo calculate priorities instead of setting it to the number of branching candidates */
7781 /* calculate estimates by taking the minimum over all single estimates */
7782 for( i = 0; i < nbranchcands; ++i )
7783 {
7784 tmp = SCIPcalcChildEstimate(scip, branchcands[i], 0.0);;
7785 minestzero = MIN(minestzero, tmp);
7786 estone[i] = SCIPcalcChildEstimate(scip, branchcands[i], 1.0);
7787 }
7788 assert(minestzero != SCIP_INVALID); /*lint !e777*/
7789
7790 /* branch on the first part of the sorted candidates:
7791 * - for each of these variables i, create a child node x_0 = ... = x_i-1 = 0, x_i = 1
7792 * - create an additional child node x_0 = ... = x_n-1 = 0
7793 */
7794 for( i = 0; i < nbranchcands; ++i )
7795 {
7796 /* create child with x_0 = ... = x_i-1 = 0, x_i = 1 */
7797 SCIP_CALL( SCIPcreateChild(scip, &node, (SCIP_Real)nbranchcands, MIN(minestzero, estone[i])) );
7798 for( j = 0; j < i; ++j )
7799 {
7800 SCIP_CALL( SCIPchgVarUbNode(scip, node, branchcands[j], 0.0) );
7801 }
7802 SCIP_CALL( SCIPchgVarLbNode(scip, node, branchcands[i], 1.0) );
7803 }
7804 /* create child with x_0 = ... = x_n = 0 */
7805 SCIP_CALL( SCIPcreateChild(scip, &node, (SCIP_Real)nbranchcands, minestzero) );
7806 for( i = 0; i < nbranchcands; ++i )
7807 {
7808 SCIP_CALL( SCIPchgVarUbNode(scip, node, branchcands[i], 0.0) );
7809 }
7810
7811 *result = SCIP_BRANCHED;
7812
7813 SCIPfreeBufferArray(scip, &estone);
7814
7815 #ifdef SCIP_DEBUG
7816 {
7817 int nchildren;
7818 SCIP_CALL( SCIPgetChildren(scip, NULL, &nchildren) );
7819 SCIPdebugMsg(scip, "branched on pseudo solution: %d children\n", nchildren);
7820 }
7821 #endif
7822 }
7823
7824 /* free temporary memory */
7825 SCIPfreeBufferArray(scip, &canduses);
7826 SCIPfreeBufferArray(scip, &branchcands);
7827
7828 return SCIP_OKAY;
7829 }
7830 #endif
7831
7832
7833 /** constraint enforcing method of constraint handler for LP solutions */
7834 static
SCIP_DECL_CONSENFOLP(consEnfolpSetppc)7835 SCIP_DECL_CONSENFOLP(consEnfolpSetppc)
7836 { /*lint --e{715}*/
7837 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, NULL, result) );
7838
7839 return SCIP_OKAY;
7840 }
7841
7842
7843 /** constraint enforcing method of constraint handler for relaxation solutions */
7844 static
SCIP_DECL_CONSENFORELAX(consEnforelaxSetppc)7845 SCIP_DECL_CONSENFORELAX(consEnforelaxSetppc)
7846 { /*lint --e{715}*/
7847 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, nusefulconss, sol, result) );
7848
7849 return SCIP_OKAY;
7850 }
7851
7852
7853 /** constraint enforcing method of constraint handler for pseudo solutions */
7854 static
SCIP_DECL_CONSENFOPS(consEnfopsSetppc)7855 SCIP_DECL_CONSENFOPS(consEnfopsSetppc)
7856 { /*lint --e{715}*/
7857 SCIP_Bool cutoff;
7858 SCIP_Bool infeasible;
7859 SCIP_Bool reduceddom;
7860 SCIP_Bool solvelp;
7861 int c;
7862
7863 assert(conshdlr != NULL);
7864 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
7865 assert(nconss == 0 || conss != NULL);
7866 assert(result != NULL);
7867
7868 /* if the solution is infeasible anyway due to objective value, skip the constraint processing and branch directly */
7869 #ifdef VARUSES
7870 if( objinfeasible )
7871 {
7872 *result = SCIP_DIDNOTRUN;
7873 SCIP_CALL( branchPseudo(scip, conshdlr, result) );
7874 return SCIP_OKAY;
7875 }
7876 #endif
7877
7878 SCIPdebugMsg(scip, "pseudo enforcing %d set partitioning / packing / covering constraints\n", nconss);
7879
7880 *result = SCIP_FEASIBLE;
7881
7882 cutoff = FALSE;
7883 infeasible = FALSE;
7884 reduceddom = FALSE;
7885 solvelp = FALSE;
7886
7887 /* check all set partitioning / packing / covering constraints for feasibility */
7888 for( c = 0; c < nconss && !cutoff && !reduceddom && !solvelp; ++c )
7889 {
7890 SCIP_CALL( enforcePseudo(scip, conss[c], &cutoff, &infeasible, &reduceddom, &solvelp) );
7891 }
7892
7893 if( cutoff )
7894 *result = SCIP_CUTOFF;
7895 else if( reduceddom )
7896 *result = SCIP_REDUCEDDOM;
7897 else if( solvelp )
7898 *result = SCIP_SOLVELP;
7899 else if( infeasible )
7900 {
7901 *result = SCIP_INFEASIBLE;
7902
7903 #ifdef VARUSES
7904 /* at least one constraint is violated by pseudo solution and we didn't find a better way to resolve this:
7905 * -> branch on pseudo solution
7906 */
7907 SCIP_CALL( branchPseudo(scip, conshdlr, result) );
7908 #endif
7909 }
7910
7911 return SCIP_OKAY;
7912 }
7913
7914
7915 /** feasibility check method of constraint handler for integral solutions */
7916 static
SCIP_DECL_CONSCHECK(consCheckSetppc)7917 SCIP_DECL_CONSCHECK(consCheckSetppc)
7918 { /*lint --e{715}*/
7919 SCIP_CONS* cons;
7920 SCIP_CONSDATA* consdata;
7921 int c;
7922
7923 assert(conshdlr != NULL);
7924 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
7925 assert(nconss == 0 || conss != NULL);
7926 assert(result != NULL);
7927
7928 *result = SCIP_FEASIBLE;
7929
7930 /* check all set partitioning / packing / covering constraints for feasibility */
7931 for( c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c )
7932 {
7933 cons = conss[c];
7934 consdata = SCIPconsGetData(cons);
7935 assert(consdata != NULL);
7936 if( checklprows || consdata->row == NULL || !SCIProwIsInLP(consdata->row) )
7937 {
7938 if( !checkCons(scip, consdata, sol) )
7939 {
7940 /* constraint is violated */
7941 *result = SCIP_INFEASIBLE;
7942
7943 if( printreason )
7944 {
7945 SCIP_Real sum = 0.0;
7946 int v;
7947
7948 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
7949
7950 for( v = 0; v < consdata->nvars; ++v )
7951 {
7952 assert(SCIPvarIsBinary(consdata->vars[v]));
7953
7954 sum += SCIPgetSolVal(scip, sol, consdata->vars[v]);
7955 }
7956 SCIPinfoMessage(scip, NULL, ";\n");
7957 SCIPinfoMessage(scip, NULL, "violation: the right hand side is violated by by %.15g\n", ABS(sum - 1));
7958 }
7959 }
7960 }
7961 }
7962
7963 return SCIP_OKAY;
7964 }
7965
7966 /** domain propagation method of constraint handler */
7967 static
SCIP_DECL_CONSPROP(consPropSetppc)7968 SCIP_DECL_CONSPROP(consPropSetppc)
7969 { /*lint --e{715}*/
7970 SCIP_Bool cutoff;
7971 SCIP_Bool addcut;
7972 SCIP_Bool mustcheck;
7973 SCIP_Bool inpresolve;
7974 int nfixedvars = 0;
7975 int c;
7976
7977 assert(conshdlr != NULL);
7978 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
7979 assert(nconss == 0 || conss != NULL);
7980 assert(result != NULL);
7981
7982 *result = SCIP_DIDNOTFIND;
7983
7984 SCIPdebugMsg(scip, "propagating %d/%d set partitioning / packing / covering constraints\n", nmarkedconss, nconss);
7985
7986 cutoff = FALSE;
7987 inpresolve = (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE);
7988
7989 /* propagate all marked set partitioning / packing / covering constraints */
7990 for( c = nmarkedconss - 1; c >= 0 && !cutoff; --c )
7991 {
7992 assert(SCIPconsGetData(conss[c]) != NULL);
7993
7994 /* during presolving, we do not want to propagate constraints with multiaggregated variables. After presolving,
7995 * we want to resolve the multiaggregation to have a clean data structure; All initial constraints should not
7996 * have multiaggregated variables, but this is not true for constraints that were introduced during solving
7997 */
7998 if( SCIPconsGetData(conss[c])->existmultaggr )
7999 {
8000 int naddconss, ndelconss;
8001
8002 if( inpresolve )
8003 continue;
8004
8005 naddconss = ndelconss = 0;
8006 SCIP_CALL( applyFixings(scip, conss[c], &naddconss, &ndelconss, &nfixedvars, &cutoff) );
8007
8008 if( cutoff )
8009 break;
8010 }
8011
8012 /* all multiaggregations should be resolved at here */
8013 assert(inpresolve || ! SCIPconsGetData(conss[c])->existmultaggr);
8014
8015 SCIP_CALL( processFixings(scip, conss[c], &cutoff, &nfixedvars, &addcut, &mustcheck) );
8016
8017 SCIP_CALL( SCIPunmarkConsPropagate(scip, conss[c]) );
8018 }
8019
8020 /* return the correct result */
8021 if( cutoff )
8022 *result = SCIP_CUTOFF;
8023 else if( nfixedvars > 0 )
8024 *result = SCIP_REDUCEDDOM;
8025
8026 return SCIP_OKAY; /*lint !e438*/
8027 }
8028
8029
8030 /** presolving method of constraint handler */
8031 static
SCIP_DECL_CONSPRESOL(consPresolSetppc)8032 SCIP_DECL_CONSPRESOL(consPresolSetppc)
8033 { /*lint --e{715}*/
8034 SCIP_CONSHDLRDATA* conshdlrdata;
8035 int oldnfixedvars;
8036 int oldnaggrvars;
8037 int oldndelconss;
8038 int oldnchgcoefs;
8039 int firstchange;
8040 int firstclique;
8041 int lastclique;
8042 int startdelconss;
8043 int c;
8044 SCIP_Bool cutoff;
8045
8046 assert(conshdlr != NULL);
8047 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
8048 assert(scip != NULL);
8049 assert(result != NULL);
8050
8051 *result = SCIP_DIDNOTFIND;
8052 oldnfixedvars = *nfixedvars;
8053 oldndelconss = *ndelconss;
8054 oldnaggrvars = *naggrvars;
8055 oldnchgcoefs = *nchgcoefs;
8056 cutoff = FALSE;
8057
8058 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8059 assert(conshdlrdata != NULL);
8060
8061 /* determine whether we want to run the clique lifting procedure */
8062 conshdlrdata->enablecliquelifting = conshdlrdata->enablecliquelifting || conshdlrdata->updatedsetppctype
8063 || conshdlrdata->noldfixedvars != SCIPgetNFixedVars(scip) || conshdlrdata->noldimpls != SCIPgetNImplications(scip)
8064 || conshdlrdata->noldcliques != SCIPgetNCliques(scip) || conshdlrdata->noldupgrs != nconss;
8065
8066 /* remember old values */
8067 startdelconss = *ndelconss;
8068 conshdlrdata->noldimpls = SCIPgetNImplications(scip);
8069 conshdlrdata->noldcliques = SCIPgetNCliques(scip);
8070 conshdlrdata->updatedsetppctype = FALSE;
8071
8072 /* process constraints */
8073 firstchange = INT_MAX;
8074 firstclique = INT_MAX;
8075 lastclique = -1;
8076 for( c = 0; c < nconss && !SCIPisStopped(scip); ++c )
8077 {
8078 SCIP_CONS* cons;
8079 SCIP_CONSDATA* consdata;
8080
8081 assert(*result != SCIP_CUTOFF);
8082
8083 cons = conss[c];
8084 assert(cons != NULL);
8085 consdata = SCIPconsGetData(cons);
8086 assert(consdata != NULL);
8087
8088 /*SCIPdebugMsg(scip, "presolving set partitioning / packing / covering constraint <%s>\n", SCIPconsGetName(cons));*/
8089
8090 /* remove all variables that are fixed to zero and replace all aggregated variables */
8091 if( consdata->nfixedzeros > 0 || nnewaggrvars > 0 || nnewaddconss > 0 || nnewupgdconss > 0
8092 || *naggrvars > oldnaggrvars || (nrounds == 0 && SCIPgetNRuns(scip) > 1) )
8093 {
8094 SCIP_CALL( applyFixings(scip, cons, naddconss, ndelconss, nfixedvars, &cutoff) );
8095
8096 if( cutoff )
8097 {
8098 *result = SCIP_CUTOFF;
8099 return SCIP_OKAY;
8100 }
8101
8102 if( SCIPconsIsDeleted(cons) )
8103 continue;
8104 }
8105
8106 /* find pairs of negated variables in constraint:
8107 * partitioning/packing: all other variables must be zero, constraint is redundant
8108 * covering: constraint is redundant
8109 *
8110 * find sets of equal variables in constraint:
8111 * partitioning/packing: variable must be zero
8112 * covering: multiple entries of variable can be replaced by single entry
8113 */
8114 SCIP_CALL( mergeMultiples(scip, cons, nfixedvars, ndelconss, nchgcoefs, &cutoff) );
8115
8116 if( cutoff )
8117 {
8118 *result = SCIP_CUTOFF;
8119 return SCIP_OKAY;
8120 }
8121
8122 /* if constraint was deleted while merging, go to the next constraint */
8123 if( !SCIPconsIsActive(cons) )
8124 continue;
8125
8126 /* remove fixings found by merging */
8127 if( consdata->nfixedzeros > 0 )
8128 {
8129 SCIP_CALL( applyFixings(scip, cons, naddconss, ndelconss, nfixedvars, &cutoff) );
8130
8131 if( cutoff )
8132 {
8133 *result = SCIP_CUTOFF;
8134 return SCIP_OKAY;
8135 }
8136
8137 if( SCIPconsIsDeleted(cons) )
8138 continue;
8139 }
8140
8141 /* check if constraint is already redundant or infeasible due to fixings, fix or aggregate left over variables if
8142 * possible
8143 */
8144 SCIP_CALL( presolvePropagateCons(scip, cons, TRUE, NULL, NULL, NULL, NULL, nfixedvars, naggrvars, ndelconss, &cutoff) );
8145
8146 if( cutoff )
8147 {
8148 *result = SCIP_CUTOFF;
8149 return SCIP_OKAY;
8150 }
8151
8152 /* if constraint was deleted while propagation, go to the next constraint */
8153 if( !SCIPconsIsActive(cons) )
8154 continue;
8155
8156 /* remove fixings found by presolvePropagateCons() */
8157 if( consdata->nfixedzeros > 0 )
8158 {
8159 SCIP_CALL( applyFixings(scip, cons, naddconss, ndelconss, nfixedvars, &cutoff) );
8160
8161 if( cutoff )
8162 {
8163 *result = SCIP_CUTOFF;
8164 return SCIP_OKAY;
8165 }
8166
8167 if( SCIPconsIsDeleted(cons) )
8168 continue;
8169 }
8170
8171 /* perform dual reductions */
8172 if( conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip) )
8173 {
8174 SCIP_CALL( dualPresolving(scip, cons, nfixedvars, ndelconss, result) );
8175
8176 /* if dual reduction deleted the constraint we take the next */
8177 if( !SCIPconsIsActive(cons) )
8178 continue;
8179 }
8180
8181 /* remember the first changed constraint to begin the next redundancy round with */
8182 if( firstchange == INT_MAX && consdata->changed )
8183 firstchange = c;
8184
8185 /* remember the first and last constraints for which we have to add the clique information */
8186 if( !consdata->cliqueadded && consdata->nvars >= 2 )
8187 {
8188 if( firstclique == INT_MAX )
8189 firstclique = c;
8190 lastclique = c;
8191 }
8192 }
8193
8194 /* update result pointer */
8195 if( oldnfixedvars < *nfixedvars || oldnaggrvars < *naggrvars || oldndelconss < *ndelconss || oldnchgcoefs < *nchgcoefs )
8196 *result = SCIP_SUCCESS;
8197
8198 if( firstchange < nconss && conshdlrdata->presolusehashing )
8199 {
8200 /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
8201 SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &firstchange, ndelconss, nchgsides) );
8202 if( oldndelconss < *ndelconss )
8203 *result = SCIP_SUCCESS;
8204 }
8205
8206 /* determine singleton variables in set-partitioning/-packing constraints, or doubleton variables (active and
8207 * negated) in any combination of set-partitioning and set-packing constraints
8208 */
8209 if( nconss > 1 && (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0
8210 && ((conshdlrdata->nsetpart > 0 && !SCIPdoNotMultaggr(scip) && conshdlrdata->conshdlrlinear != NULL)
8211 || (conshdlrdata->dualpresolving && SCIPallowStrongDualReds(scip)
8212 && conshdlrdata->nsetpart < nconss && !SCIPdoNotAggr(scip))) )
8213 {
8214 SCIP_CALL( removeDoubleAndSingletonsAndPerformDualpresolve(scip, conss, nconss, conshdlrdata->dualpresolving
8215 && SCIPallowStrongDualReds(scip), conshdlrdata->conshdlrlinear != NULL, nfixedvars,
8216 naggrvars, ndelconss, nchgcoefs, nchgsides, &cutoff) );
8217
8218 if( cutoff )
8219 {
8220 *result = SCIP_CUTOFF;
8221 return SCIP_OKAY;
8222 }
8223 else if( oldnfixedvars < *nfixedvars || oldnaggrvars < *naggrvars || oldndelconss < *ndelconss )
8224 *result = SCIP_SUCCESS;
8225 }
8226
8227 /* clique lifting */
8228 if( conshdlrdata->cliquelifting && conshdlrdata->enablecliquelifting && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
8229 {
8230 /* add cliques first before lifting variables */
8231 SCIP_CALL( addCliques(scip, conss, nconss, firstclique, lastclique, naddconss, ndelconss, nchgbds, &cutoff) );
8232
8233 if( cutoff )
8234 {
8235 *result = SCIP_CUTOFF;
8236 return SCIP_OKAY;
8237 }
8238
8239 firstclique = nconss;
8240 lastclique = -1;
8241
8242 /* lift variables and check for fixings due to clique information */
8243 SCIP_CALL( preprocessCliques(scip, conshdlrdata, conss, nconss, nrounds, &firstchange, &firstclique,
8244 &lastclique, nfixedvars, naggrvars, ndelconss, nchgcoefs, &cutoff) );
8245 ++(conshdlrdata->nclqpresolve);
8246
8247 if( cutoff )
8248 {
8249 *result = SCIP_CUTOFF;
8250 return SCIP_OKAY;
8251 }
8252 else if( oldnfixedvars < *nfixedvars || oldnaggrvars < *naggrvars || oldndelconss < *ndelconss || oldnchgcoefs < *nchgcoefs )
8253 *result = SCIP_SUCCESS;
8254
8255 /* remember the number of fixings */
8256 conshdlrdata->noldfixedvars = *nfixedvars + *naggrvars;
8257 }
8258
8259 if( oldndelconss == *ndelconss && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
8260 {
8261 /* check constraints for redundancy */
8262 if( conshdlrdata->presolpairwise )
8263 {
8264 SCIP_Longint npaircomparisons = 0;
8265
8266 oldndelconss = *ndelconss;
8267 oldnfixedvars = *nfixedvars;
8268
8269 for( c = firstchange; c < nconss && !SCIPisStopped(scip); ++c )
8270 {
8271 assert(*result != SCIP_CUTOFF);
8272
8273 if( SCIPconsIsActive(conss[c]) && !SCIPconsIsModifiable(conss[c]) )
8274 {
8275 npaircomparisons += (SCIPconsGetData(conss[c])->changed) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange);
8276
8277 SCIP_CALL( removeRedundantConstraints(scip, conss, firstchange, c, &cutoff, nfixedvars, ndelconss, nchgsides) );
8278 if( cutoff )
8279 {
8280 *result = SCIP_CUTOFF;
8281 return SCIP_OKAY;
8282 }
8283
8284 if( npaircomparisons > NMINCOMPARISONS )
8285 {
8286 if( (*ndelconss - oldndelconss + *nfixedvars - oldnfixedvars) / ((SCIP_Real)npaircomparisons) < MINGAINPERNMINCOMPARISONS )
8287 break;
8288 oldndelconss = *ndelconss;
8289 oldnfixedvars = *nfixedvars;
8290 npaircomparisons = 0;
8291 *result = SCIP_SUCCESS;
8292 }
8293 }
8294 }
8295 }
8296 }
8297
8298 /* add cliques after lifting variables */
8299 SCIP_CALL( addCliques(scip, conss, nconss, MIN(firstclique, nconss), MIN(lastclique, nconss), naddconss, ndelconss,
8300 nchgbds, &cutoff) );
8301
8302 if( cutoff )
8303 *result = SCIP_CUTOFF;
8304
8305 conshdlrdata->enablecliquelifting = FALSE;
8306 conshdlrdata->noldupgrs = nconss - (*ndelconss - startdelconss);
8307
8308 return SCIP_OKAY;
8309 }
8310
8311
8312 /** propagation conflict resolving method of constraint handler */
8313 static
SCIP_DECL_CONSRESPROP(consRespropSetppc)8314 SCIP_DECL_CONSRESPROP(consRespropSetppc)
8315 { /*lint --e{715}*/
8316 SCIP_CONSDATA* consdata;
8317 int v;
8318
8319 assert(conshdlr != NULL);
8320 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
8321 assert(cons != NULL);
8322 assert(infervar != NULL);
8323 assert(result != NULL);
8324
8325 consdata = SCIPconsGetData(cons);
8326 assert(consdata != NULL);
8327
8328 SCIPdebugMsg(scip, "conflict resolving method of set partitioning / packing / covering constraint handler\n");
8329
8330 if( (SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_COVERING
8331 || ((SCIP_SETPPCTYPE)consdata->setppctype == SCIP_SETPPCTYPE_PARTITIONING
8332 && SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE) > 0.5) )
8333 {
8334 #ifndef NDEBUG
8335 SCIP_Bool confvarfound;
8336 #endif
8337
8338 /* the inference constraint is a set partitioning or covering constraint with the inference variable inferred to 1.0:
8339 * the reason for the deduction is the assignment of 0.0 to all other variables
8340 */
8341 #ifndef NDEBUG
8342 confvarfound = FALSE;
8343 #endif
8344 for( v = 0; v < consdata->nvars; ++v )
8345 {
8346 if( consdata->vars[v] != infervar )
8347 {
8348 /* the reason variable must be assigned to zero */
8349 assert(SCIPgetVarUbAtIndex(scip, consdata->vars[v], bdchgidx, FALSE) < 0.5);
8350 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[v]) );
8351 }
8352 #ifndef NDEBUG
8353 else
8354 {
8355 assert(!confvarfound);
8356 confvarfound = TRUE;
8357 }
8358 #endif
8359 }
8360 assert(confvarfound);
8361 }
8362 else
8363 {
8364 /* the inference constraint is a set partitioning or packing constraint with the inference variable inferred to 0.0:
8365 * the reason for the deduction is the assignment of 1.0 to a single variable
8366 */
8367 assert(SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE) < 0.5);
8368
8369 if( inferinfo >= 0 )
8370 {
8371 assert(SCIPgetVarLbAtIndex(scip, consdata->vars[inferinfo], bdchgidx, FALSE) > 0.5);
8372 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[inferinfo]) );
8373 }
8374 else
8375 {
8376 for( v = 0; v < consdata->nvars; ++v )
8377 {
8378 if( SCIPgetVarLbAtIndex(scip, consdata->vars[v], bdchgidx, FALSE) > 0.5 )
8379 {
8380 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[v]) );
8381 break;
8382 }
8383 }
8384 assert(v < consdata->nvars);
8385 }
8386 }
8387
8388 *result = SCIP_SUCCESS;
8389
8390 return SCIP_OKAY;
8391 }
8392
8393
8394 /** variable rounding lock method of constraint handler */
8395 static
SCIP_DECL_CONSLOCK(consLockSetppc)8396 SCIP_DECL_CONSLOCK(consLockSetppc)
8397 { /*lint --e{715}*/
8398 SCIP_CONSDATA* consdata;
8399 int nlocksdown;
8400 int nlocksup;
8401 int i;
8402
8403 consdata = SCIPconsGetData(cons);
8404 assert(consdata != NULL);
8405
8406 switch( consdata->setppctype )
8407 {
8408 case SCIP_SETPPCTYPE_PARTITIONING:
8409 nlocksdown = nlockspos + nlocksneg;
8410 nlocksup = nlockspos + nlocksneg;
8411 break;
8412 case SCIP_SETPPCTYPE_PACKING:
8413 nlocksdown = nlocksneg;
8414 nlocksup = nlockspos;
8415 break;
8416 case SCIP_SETPPCTYPE_COVERING:
8417 nlocksdown = nlockspos;
8418 nlocksup = nlocksneg;
8419 break;
8420 default:
8421 SCIPerrorMessage("unknown setppc type\n");
8422 return SCIP_INVALIDDATA;
8423 }
8424
8425 for( i = 0; i < consdata->nvars; ++i )
8426 {
8427 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlocksdown, nlocksup) );
8428 }
8429
8430 return SCIP_OKAY;
8431 }
8432
8433
8434 /** constraint activation notification method of constraint handler */
8435 static
SCIP_DECL_CONSACTIVE(consActiveSetppc)8436 SCIP_DECL_CONSACTIVE(consActiveSetppc)
8437 { /*lint --e{715}*/
8438 assert(cons != NULL);
8439 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
8440 assert(SCIPconsIsTransformed(cons));
8441
8442 SCIPdebugMsg(scip, "activation information for set partitioning / packing / covering constraint <%s>\n",
8443 SCIPconsGetName(cons));
8444
8445 /* we only might add the constraint to the propagation list, when we are not activating it in probing mode */
8446 if( SCIPgetStage(scip) > SCIP_STAGE_TRANSFORMING )
8447 {
8448 SCIP_CONSDATA* consdata = SCIPconsGetData(cons);
8449 assert(consdata != NULL);
8450
8451 if( consdata->nfixedones >= 1 || consdata->nfixedzeros >= consdata->nvars - 1 )
8452 {
8453 SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
8454 }
8455 }
8456
8457 #ifdef VARUSES
8458 /* increase the number of uses for each variable in the constraint */
8459 SCIP_CALL( consdataIncVaruses(scip, SCIPconshdlrGetData(conshdlr), SCIPconsGetData(cons)) );
8460 #endif
8461
8462 return SCIP_OKAY;
8463 }
8464
8465
8466 /** constraint deactivation notification method of constraint handler */
8467 static
SCIP_DECL_CONSDEACTIVE(consDeactiveSetppc)8468 SCIP_DECL_CONSDEACTIVE(consDeactiveSetppc)
8469 { /*lint --e{715}*/
8470 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
8471 assert(SCIPconsIsTransformed(cons));
8472
8473 SCIPdebugMsg(scip, "deactivation information for set partitioning / packing / covering constraint <%s>\n",
8474 SCIPconsGetName(cons));
8475
8476 #ifdef VARUSES
8477 /* decrease the number of uses for each variable in the constraint */
8478 SCIP_CALL( consdataDecVaruses(scip, SCIPconshdlrGetData(conshdlr), SCIPconsGetData(cons)) );
8479 #endif
8480
8481 if( SCIPconsIsDeleted(cons) )
8482 {
8483 SCIP_CONSHDLRDATA* conshdlrdata;
8484 SCIP_CONSDATA* consdata;
8485
8486 /* get constraint data */
8487 consdata = SCIPconsGetData(cons);
8488 assert(consdata != NULL);
8489
8490 /* get event handler */
8491 conshdlrdata = SCIPconshdlrGetData(conshdlr);
8492 assert(conshdlrdata != NULL);
8493 assert(conshdlrdata->eventhdlr != NULL);
8494
8495 /* if constraint belongs to transformed problem space, drop bound change events on variables */
8496 if( consdata->nvars > 0 && SCIPvarIsTransformed(consdata->vars[0]) )
8497 {
8498 SCIP_CALL( dropAllEvents(scip, cons, conshdlrdata->eventhdlr) );
8499 }
8500 }
8501
8502 return SCIP_OKAY;
8503 }
8504
8505 /** variable deletion method of constraint handler */
8506 static
SCIP_DECL_CONSDELVARS(consDelvarsSetppc)8507 SCIP_DECL_CONSDELVARS(consDelvarsSetppc)
8508 {
8509 assert( scip != NULL );
8510 assert( conshdlr != NULL );
8511 assert( conss != NULL || nconss == 0 );
8512
8513 if( nconss > 0 )
8514 {
8515 SCIP_CALL( performVarDeletions(scip, conshdlr, conss, nconss) );
8516 }
8517
8518 return SCIP_OKAY;
8519 }
8520
8521
8522
8523 /** constraint display method of constraint handler */
8524 static
SCIP_DECL_CONSPRINT(consPrintSetppc)8525 SCIP_DECL_CONSPRINT(consPrintSetppc)
8526 { /*lint --e{715}*/
8527 assert( scip != NULL );
8528 assert( conshdlr != NULL );
8529 assert( cons != NULL );
8530
8531 SCIP_CALL( consdataPrint(scip, SCIPconsGetData(cons), file) );
8532
8533 return SCIP_OKAY;
8534 }
8535
8536 /** constraint copying method of constraint handler */
8537 static
SCIP_DECL_CONSCOPY(consCopySetppc)8538 SCIP_DECL_CONSCOPY(consCopySetppc)
8539 { /*lint --e{715}*/
8540 SCIP_VAR** sourcevars;
8541 const char* consname;
8542 SCIP_Real lhs;
8543 SCIP_Real rhs;
8544 int nvars;
8545 SCIP_SETPPCTYPE type;
8546
8547 /* get variables and coefficients of the source constraint */
8548 sourcevars = SCIPgetVarsSetppc(sourcescip, sourcecons);
8549 nvars = SCIPgetNVarsSetppc(sourcescip, sourcecons);
8550
8551 /* get setppc type */
8552 type = SCIPgetTypeSetppc(sourcescip, sourcecons);
8553 lhs = -SCIPinfinity(scip);
8554 rhs = SCIPinfinity(scip);
8555
8556 switch( type )
8557 {
8558 case SCIP_SETPPCTYPE_PARTITIONING:
8559 lhs = 1.0;
8560 rhs = 1.0;
8561 break;
8562 case SCIP_SETPPCTYPE_PACKING:
8563 rhs = 1.0;
8564 break;
8565 case SCIP_SETPPCTYPE_COVERING:
8566 lhs = 1.0;
8567 break;
8568 default:
8569 SCIPerrorMessage("unknown setppc type\n");
8570 return SCIP_INVALIDDATA;
8571 }
8572
8573 if( name != NULL )
8574 consname = name;
8575 else
8576 consname = SCIPconsGetName(sourcecons);
8577
8578 /* copy the logic using the linear constraint copy method */
8579 SCIP_CALL( SCIPcopyConsLinear(scip, cons, sourcescip, consname, nvars, sourcevars, NULL,
8580 lhs, rhs, varmap, consmap,
8581 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode, global, valid) );
8582 assert(cons != NULL);
8583
8584 return SCIP_OKAY;
8585 }
8586
8587 /** constraint parsing method of constraint handler */
8588 static
SCIP_DECL_CONSPARSE(consParseSetppc)8589 SCIP_DECL_CONSPARSE(consParseSetppc)
8590 { /*lint --e{715}*/
8591 SCIP_VAR** vars;
8592 int nvars;
8593
8594 assert(scip != NULL);
8595 assert(success != NULL);
8596 assert(str != NULL);
8597 assert(name != NULL);
8598 assert(cons != NULL);
8599
8600 *success = TRUE;
8601
8602 nvars = 0;
8603 vars = NULL;
8604
8605 /* check if lhs is just 0 */
8606 if( str[0] == '0' )
8607 {
8608 assert(str[1] == ' ');
8609 str += 2;
8610 }
8611 else
8612 {
8613 SCIP_Real* coefs;
8614 char* endptr;
8615 int coefssize;
8616 int requsize;
8617
8618 /* initialize buffers for storing the coefficients */
8619 coefssize = 100;
8620 SCIP_CALL( SCIPallocBufferArray(scip, &vars, coefssize) );
8621 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, coefssize) );
8622
8623 /* parse linear sum to get variables and coefficients */
8624 SCIP_CALL( SCIPparseVarsLinearsum(scip, str, vars, coefs, &nvars, coefssize, &requsize, &endptr, success) );
8625
8626 if( *success && requsize > coefssize )
8627 {
8628 /* realloc buffers and try again */
8629 coefssize = requsize;
8630 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, coefssize) );
8631 SCIP_CALL( SCIPreallocBufferArray(scip, &coefs, coefssize) );
8632
8633 SCIP_CALL( SCIPparseVarsLinearsum(scip, str, vars, coefs, &nvars, coefssize, &requsize, &endptr, success) );
8634 assert(!*success || requsize <= coefssize); /* if successful, then should have had enough space now */
8635 }
8636
8637 if( !*success )
8638 {
8639 SCIPerrorMessage("no luck in parsing linear sum '%s'\n", str);
8640 }
8641 else
8642 str = endptr;
8643
8644 /* free coefficient array */
8645 SCIPfreeBufferArray(scip, &coefs);
8646 }
8647
8648 /* remove white spaces */
8649 while( isspace((unsigned char)*str) )
8650 str++;
8651
8652 if( *success )
8653 {
8654 switch( *str )
8655 {
8656 case '=' :
8657 SCIP_CALL( SCIPcreateConsSetpart(scip, cons, name, nvars, vars,
8658 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
8659 break;
8660 case '<' :
8661 SCIP_CALL( SCIPcreateConsSetpack(scip, cons, name, nvars, vars,
8662 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
8663 break;
8664 case '>' :
8665 SCIP_CALL( SCIPcreateConsSetcover(scip, cons, name, nvars, vars,
8666 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
8667 break;
8668 default:
8669 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "error parsing setppc type\n");
8670 *success = FALSE;
8671 break;
8672 }
8673 }
8674
8675 /* free variable array */
8676 SCIPfreeBufferArrayNull(scip, &vars);
8677
8678 return SCIP_OKAY;
8679 }
8680
8681 /** constraint method of constraint handler which returns the variables (if possible) */
8682 static
SCIP_DECL_CONSGETVARS(consGetVarsSetppc)8683 SCIP_DECL_CONSGETVARS(consGetVarsSetppc)
8684 { /*lint --e{715}*/
8685 SCIP_CONSDATA* consdata;
8686
8687 consdata = SCIPconsGetData(cons);
8688 assert(consdata != NULL);
8689
8690 if( varssize < consdata->nvars )
8691 (*success) = FALSE;
8692 else
8693 {
8694 assert(vars != NULL);
8695
8696 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
8697 (*success) = TRUE;
8698 }
8699
8700 return SCIP_OKAY;
8701 }
8702
8703 /** constraint method of constraint handler which returns the number of variables (if possible) */
8704 static
SCIP_DECL_CONSGETNVARS(consGetNVarsSetppc)8705 SCIP_DECL_CONSGETNVARS(consGetNVarsSetppc)
8706 { /*lint --e{715}*/
8707 SCIP_CONSDATA* consdata;
8708
8709 consdata = SCIPconsGetData(cons);
8710 assert(consdata != NULL);
8711
8712 (*nvars) = consdata->nvars;
8713 (*success) = TRUE;
8714
8715 return SCIP_OKAY;
8716 }
8717
8718 /*
8719 * Callback methods of event handler
8720 */
8721
8722 static
SCIP_DECL_EVENTEXEC(eventExecSetppc)8723 SCIP_DECL_EVENTEXEC(eventExecSetppc)
8724 { /*lint --e{715}*/
8725 SCIP_CONS* cons;
8726 SCIP_CONSDATA* consdata;
8727 SCIP_EVENTTYPE eventtype;
8728
8729 assert(eventhdlr != NULL);
8730 assert(eventdata != NULL);
8731 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
8732 assert(event != NULL);
8733
8734 /*debugMsg(scip, "Exec method of bound change event handler for set partitioning / packing / covering constraints\n");*/
8735
8736 cons = (SCIP_CONS*)eventdata;
8737 assert(cons != NULL);
8738
8739 consdata = SCIPconsGetData(cons);
8740 assert(consdata != NULL);
8741
8742 eventtype = SCIPeventGetType(event);
8743
8744 switch( eventtype )
8745 {
8746 case SCIP_EVENTTYPE_LBTIGHTENED:
8747 consdata->nfixedones++;
8748 break;
8749 case SCIP_EVENTTYPE_LBRELAXED:
8750 consdata->nfixedones--;
8751 break;
8752 case SCIP_EVENTTYPE_UBTIGHTENED:
8753 consdata->nfixedzeros++;
8754 break;
8755 case SCIP_EVENTTYPE_UBRELAXED:
8756 consdata->nfixedzeros--;
8757 break;
8758 case SCIP_EVENTTYPE_VARDELETED:
8759 consdata->varsdeleted = TRUE;
8760 break;
8761 case SCIP_EVENTTYPE_VARFIXED:
8762 if( consdata->merged )
8763 {
8764 SCIP_VAR* var = SCIPeventGetVar(event);
8765
8766 /* this event should only arise during the presolving stage */
8767 assert(SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING);
8768 assert(var != NULL);
8769
8770 /* one variable was changed to a negated or aggregated variable, so maybe we can merge again */
8771 if( SCIPvarGetStatus(var) != SCIP_VARSTATUS_FIXED && SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5 )
8772 consdata->merged = FALSE;
8773 }
8774
8775 if( !consdata->existmultaggr )
8776 {
8777 SCIP_VAR* var = SCIPeventGetVar(event);
8778 assert(var != NULL);
8779
8780 if( SCIPvarGetStatus(SCIPvarGetProbvar(var)) == SCIP_VARSTATUS_MULTAGGR )
8781 consdata->existmultaggr = TRUE;
8782 }
8783 break;
8784 default:
8785 SCIPerrorMessage("invalid event type\n");
8786 return SCIP_INVALIDDATA;
8787 }
8788 assert(0 <= consdata->nfixedzeros && consdata->nfixedzeros <= consdata->nvars);
8789 assert(0 <= consdata->nfixedones && consdata->nfixedones <= consdata->nvars);
8790
8791 if( eventtype & SCIP_EVENTTYPE_BOUNDTIGHTENED )
8792 {
8793 if( consdata->nfixedones >= 1 || consdata->nfixedzeros >= consdata->nvars - 1 )
8794 {
8795 consdata->presolpropagated = FALSE;
8796 SCIP_CALL( SCIPmarkConsPropagate(scip, cons) );
8797 }
8798 else if( (SCIPgetStage(scip) < SCIP_STAGE_INITSOLVE) && (consdata->nfixedzeros >= consdata->nvars - 2) )
8799 {
8800 consdata->presolpropagated = FALSE;
8801 }
8802 }
8803
8804 /*debugMsg(scip, " -> constraint has %d zero-fixed and %d one-fixed of %d variables\n",
8805 consdata->nfixedzeros, consdata->nfixedones, consdata->nvars);*/
8806
8807 return SCIP_OKAY;
8808 }
8809
8810
8811
8812
8813 /*
8814 * Callback methods of conflict handler
8815 */
8816
8817 /** conflict processing method of conflict handler (called when conflict was found) */
8818 static
SCIP_DECL_CONFLICTEXEC(conflictExecSetppc)8819 SCIP_DECL_CONFLICTEXEC(conflictExecSetppc)
8820 { /*lint --e{715}*/
8821 SCIP_VAR** vars;
8822 int i;
8823
8824 assert(conflicthdlr != NULL);
8825 assert(strcmp(SCIPconflicthdlrGetName(conflicthdlr), CONFLICTHDLR_NAME) == 0);
8826 assert(bdchginfos != NULL || nbdchginfos == 0);
8827 assert(result != NULL);
8828
8829 /* don't process already resolved conflicts */
8830 if( resolved )
8831 {
8832 *result = SCIP_DIDNOTRUN;
8833 return SCIP_OKAY;
8834 }
8835
8836 *result = SCIP_DIDNOTFIND;
8837
8838 /* for two (binary) variables we will create a set packing constraint and add the clique information of the conflict is global */
8839 if( nbdchginfos == 2 )
8840 {
8841 SCIP_CONS* cons;
8842 char consname[SCIP_MAXSTRLEN];
8843 SCIP_VAR* twovars[2];
8844
8845 assert(bdchginfos != NULL);
8846
8847 twovars[0] = SCIPbdchginfoGetVar(bdchginfos[0]);
8848
8849 /* we can only treat binary variables */
8850 if( !SCIPvarIsBinary(twovars[0]) )
8851 return SCIP_OKAY;
8852
8853 /* if the variable is fixed to zero in the conflict set, we have to use its negation */
8854 if( SCIPbdchginfoGetNewbound(bdchginfos[0]) < 0.5 )
8855 {
8856 SCIP_CALL( SCIPgetNegatedVar(scip, twovars[0], &twovars[0]) );
8857 }
8858
8859 twovars[1] = SCIPbdchginfoGetVar(bdchginfos[1]);
8860
8861 /* we can only treat binary variables */
8862 if( !SCIPvarIsBinary(twovars[1]) )
8863 return SCIP_OKAY;
8864
8865 /* if the variable is fixed to zero in the conflict set, we have to use its negation */
8866 if( SCIPbdchginfoGetNewbound(bdchginfos[1]) < 0.5 )
8867 {
8868 SCIP_CALL( SCIPgetNegatedVar(scip, twovars[1], &twovars[1]) );
8869 }
8870
8871 /* create a constraint out of the conflict set */
8872 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "cf%d_%" SCIP_LONGINT_FORMAT, SCIPgetNRuns(scip), SCIPgetNConflictConssApplied(scip));
8873 SCIP_CALL( SCIPcreateConsSetpack(scip, &cons, consname, 2, twovars,
8874 FALSE, separate, FALSE, FALSE, TRUE, local, FALSE, dynamic, removable, FALSE) );
8875
8876 /* if the constraint gets globally added, we also add the clique information */
8877 if( !SCIPconsIsLocal(cons) )
8878 {
8879 SCIP_Bool infeasible;
8880 int ncliquebdchgs;
8881
8882 SCIP_CALL( SCIPaddClique(scip, twovars, NULL, 2, FALSE, &infeasible, &ncliquebdchgs) );
8883
8884 SCIPdebugMsg(scip, "new clique of conflict constraint %s led to %d fixings\n", consname, ncliquebdchgs);
8885
8886 if( infeasible )
8887 {
8888 SCIPdebugMsg(scip, "new clique of conflict constraint %s led to infeasibility\n", consname);
8889 }
8890 }
8891
8892 /* add conflict to SCIP */
8893 SCIP_CALL( SCIPaddConflict(scip, node, cons, validnode, conftype, cutoffinvolved) );
8894
8895 *result = SCIP_CONSADDED;
8896
8897 return SCIP_OKAY;
8898 }
8899
8900 /* create array of variables in conflict constraint */
8901 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nbdchginfos) );
8902 for( i = 0; i < nbdchginfos; ++i )
8903 {
8904 assert(bdchginfos != NULL);
8905
8906 vars[i] = SCIPbdchginfoGetVar(bdchginfos[i]);
8907
8908 /* we can only treat binary variables */
8909 if( !SCIPvarIsBinary(vars[i]) )
8910 break;
8911
8912 /* if the variable is fixed to one in the conflict set, we have to use its negation */
8913 if( SCIPbdchginfoGetNewbound(bdchginfos[i]) > 0.5 )
8914 {
8915 SCIP_CALL( SCIPgetNegatedVar(scip, vars[i], &vars[i]) );
8916 }
8917 }
8918
8919 if( i == nbdchginfos )
8920 {
8921 SCIP_CONS* cons;
8922 char consname[SCIP_MAXSTRLEN];
8923
8924 /* create a constraint out of the conflict set */
8925 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "cf%d_%" SCIP_LONGINT_FORMAT, SCIPgetNRuns(scip), SCIPgetNConflictConssApplied(scip));
8926 SCIP_CALL( SCIPcreateConsSetcover(scip, &cons, consname, nbdchginfos, vars,
8927 FALSE, separate, FALSE, FALSE, TRUE, local, FALSE, dynamic, removable, FALSE) );
8928 SCIP_CALL( SCIPaddConsNode(scip, node, cons, validnode) );
8929 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
8930
8931 *result = SCIP_CONSADDED;
8932 }
8933
8934 /* free temporary memory */
8935 SCIPfreeBufferArray(scip, &vars);
8936
8937 return SCIP_OKAY;
8938 }
8939
8940
8941
8942
8943 /*
8944 * constraint specific interface methods
8945 */
8946
8947 /** creates the handler for set partitioning / packing / covering constraints and includes it in SCIP */
SCIPincludeConshdlrSetppc(SCIP * scip)8948 SCIP_RETCODE SCIPincludeConshdlrSetppc(
8949 SCIP* scip /**< SCIP data structure */
8950 )
8951 {
8952 SCIP_CONSHDLRDATA* conshdlrdata;
8953 SCIP_CONSHDLR* conshdlr;
8954 SCIP_EVENTHDLR* eventhdlr;
8955
8956 /* create event handler for bound change events */
8957 SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC,
8958 eventExecSetppc, NULL) );
8959
8960 /* create conflict handler for setppc constraints */
8961 SCIP_CALL( SCIPincludeConflicthdlrBasic(scip, NULL, CONFLICTHDLR_NAME, CONFLICTHDLR_DESC, CONFLICTHDLR_PRIORITY,
8962 conflictExecSetppc, NULL) );
8963
8964 /* create constraint handler data */
8965 SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
8966
8967 /* include constraint handler */
8968 SCIP_CALL( SCIPincludeConshdlrBasic(scip, &conshdlr, CONSHDLR_NAME, CONSHDLR_DESC,
8969 CONSHDLR_ENFOPRIORITY, CONSHDLR_CHECKPRIORITY, CONSHDLR_EAGERFREQ, CONSHDLR_NEEDSCONS,
8970 consEnfolpSetppc, consEnfopsSetppc, consCheckSetppc, consLockSetppc,
8971 conshdlrdata) );
8972 assert(conshdlr != NULL);
8973
8974 /* set non-fundamental callbacks via specific setter functions */
8975 SCIP_CALL( SCIPsetConshdlrActive(scip, conshdlr, consActiveSetppc) );
8976 SCIP_CALL( SCIPsetConshdlrDeactive(scip, conshdlr, consDeactiveSetppc) );
8977 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopySetppc, consCopySetppc) );
8978 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteSetppc) );
8979 SCIP_CALL( SCIPsetConshdlrDelvars(scip, conshdlr, consDelvarsSetppc) );
8980 SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreSetppc) );
8981 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolSetppc) );
8982 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeSetppc) );
8983 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsSetppc) );
8984 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsSetppc) );
8985 SCIP_CALL( SCIPsetConshdlrInit(scip, conshdlr, consInitSetppc) );
8986 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpSetppc) );
8987 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseSetppc) );
8988 SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolSetppc, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
8989 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintSetppc) );
8990 SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropSetppc, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
8991 CONSHDLR_PROP_TIMING) );
8992 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropSetppc) );
8993 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpSetppc, consSepasolSetppc, CONSHDLR_SEPAFREQ,
8994 CONSHDLR_SEPAPRIORITY, CONSHDLR_DELAYSEPA) );
8995 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransSetppc) );
8996 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxSetppc) );
8997
8998 conshdlrdata->conshdlrlinear = SCIPfindConshdlr(scip,"linear");
8999
9000 if( conshdlrdata->conshdlrlinear != NULL )
9001 {
9002 /* include the linear constraint to setppc constraint upgrade in the linear constraint handler */
9003 SCIP_CALL( SCIPincludeLinconsUpgrade(scip, linconsUpgdSetppc, LINCONSUPGD_PRIORITY, CONSHDLR_NAME) );
9004 }
9005 if( SCIPfindConshdlr(scip, "quadratic") != NULL )
9006 {
9007 /* notify function that upgrades quadratic constraint to setpacking */
9008 SCIP_CALL( SCIPincludeQuadconsUpgrade(scip, quadraticUpgdSetppc, QUADCONSUPGD_PRIORITY, TRUE, CONSHDLR_NAME) );
9009 }
9010
9011 /* set partitioning constraint handler parameters */
9012 SCIP_CALL( SCIPaddIntParam(scip,
9013 "constraints/" CONSHDLR_NAME "/npseudobranches",
9014 "number of children created in pseudo branching (0: disable pseudo branching)",
9015 &conshdlrdata->npseudobranches, TRUE, DEFAULT_NPSEUDOBRANCHES, 0, INT_MAX, NULL, NULL) );
9016 SCIP_CALL( SCIPaddBoolParam(scip,
9017 "constraints/" CONSHDLR_NAME "/presolpairwise",
9018 "should pairwise constraint comparison be performed in presolving?",
9019 &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
9020 SCIP_CALL( SCIPaddBoolParam(scip,
9021 "constraints/" CONSHDLR_NAME "/presolusehashing",
9022 "should hash table be used for detecting redundant constraints in advance",
9023 &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
9024 SCIP_CALL( SCIPaddBoolParam(scip,
9025 "constraints/" CONSHDLR_NAME "/dualpresolving",
9026 "should dual presolving steps be performed?",
9027 &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
9028 SCIP_CALL( SCIPaddBoolParam(scip,
9029 "constraints/" CONSHDLR_NAME "/cliquelifting",
9030 " should we try to lift variables into other clique constraints, fix variables, aggregate them, and also shrink the amount of variables in clique constraints",
9031 &conshdlrdata->cliquelifting, TRUE, DEFAULT_CLIQUELIFTING, NULL, NULL) );
9032 SCIP_CALL( SCIPaddBoolParam(scip,
9033 "constraints/" CONSHDLR_NAME "/addvariablesascliques",
9034 "should we try to generate extra cliques out of all binary variables to maybe fasten redundant constraint detection",
9035 &conshdlrdata->addvariablesascliques, TRUE, DEFAULT_ADDVARIABLESASCLIQUES, NULL, NULL) );
9036 SCIP_CALL( SCIPaddBoolParam(scip,
9037 "constraints/" CONSHDLR_NAME "/cliqueshrinking",
9038 "should we try to shrink the number of variables in a clique constraints, by replacing more than one variable by only one",
9039 &conshdlrdata->cliqueshrinking, TRUE, DEFAULT_CLIQUESHRINKING, NULL, NULL) );
9040
9041 return SCIP_OKAY;
9042 }
9043
9044 /** creates and captures a set partitioning constraint
9045 *
9046 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
9047 */
SCIPcreateConsSetpart(SCIP * scip,SCIP_CONS ** cons,const char * name,int nvars,SCIP_VAR ** vars,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)9048 SCIP_RETCODE SCIPcreateConsSetpart(
9049 SCIP* scip, /**< SCIP data structure */
9050 SCIP_CONS** cons, /**< pointer to hold the created constraint */
9051 const char* name, /**< name of constraint */
9052 int nvars, /**< number of variables in the constraint */
9053 SCIP_VAR** vars, /**< array with variables of constraint entries */
9054 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
9055 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9056 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
9057 * Usually set to TRUE. */
9058 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
9059 * TRUE for model constraints, FALSE for additional, redundant constraints. */
9060 SCIP_Bool check, /**< should the constraint be checked for feasibility?
9061 * TRUE for model constraints, FALSE for additional, redundant constraints. */
9062 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
9063 * Usually set to TRUE. */
9064 SCIP_Bool local, /**< is constraint only valid locally?
9065 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9066 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
9067 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
9068 * adds coefficients to this constraint. */
9069 SCIP_Bool dynamic, /**< is constraint subject to aging?
9070 * Usually set to FALSE. Set to TRUE for own cuts which
9071 * are separated as constraints. */
9072 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
9073 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9074 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9075 * if it may be moved to a more global node?
9076 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9077 )
9078 {
9079 return createConsSetppc(scip, cons, name, nvars, vars, SCIP_SETPPCTYPE_PARTITIONING,
9080 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode);
9081 }
9082
9083 /** creates and captures a set partitioning constraint with all constraint flags set
9084 * to their default values
9085 *
9086 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
9087 */
SCIPcreateConsBasicSetpart(SCIP * scip,SCIP_CONS ** cons,const char * name,int nvars,SCIP_VAR ** vars)9088 SCIP_RETCODE SCIPcreateConsBasicSetpart(
9089 SCIP* scip, /**< SCIP data structure */
9090 SCIP_CONS** cons, /**< pointer to hold the created constraint */
9091 const char* name, /**< name of constraint */
9092 int nvars, /**< number of variables in the constraint */
9093 SCIP_VAR** vars /**< array with variables of constraint entries */
9094 )
9095 {
9096 SCIP_CALL( SCIPcreateConsSetpart(scip, cons, name, nvars, vars,
9097 TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
9098
9099 return SCIP_OKAY;
9100 }
9101
9102 /** creates and captures a set packing constraint
9103 *
9104 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
9105 */
SCIPcreateConsSetpack(SCIP * scip,SCIP_CONS ** cons,const char * name,int nvars,SCIP_VAR ** vars,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)9106 SCIP_RETCODE SCIPcreateConsSetpack(
9107 SCIP* scip, /**< SCIP data structure */
9108 SCIP_CONS** cons, /**< pointer to hold the created constraint */
9109 const char* name, /**< name of constraint */
9110 int nvars, /**< number of variables in the constraint */
9111 SCIP_VAR** vars, /**< array with variables of constraint entries */
9112 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
9113 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9114 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
9115 * Usually set to TRUE. */
9116 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
9117 * TRUE for model constraints, FALSE for additional, redundant constraints. */
9118 SCIP_Bool check, /**< should the constraint be checked for feasibility?
9119 * TRUE for model constraints, FALSE for additional, redundant constraints. */
9120 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
9121 * Usually set to TRUE. */
9122 SCIP_Bool local, /**< is constraint only valid locally?
9123 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9124 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
9125 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
9126 * adds coefficients to this constraint. */
9127 SCIP_Bool dynamic, /**< is constraint subject to aging?
9128 * Usually set to FALSE. Set to TRUE for own cuts which
9129 * are separated as constraints. */
9130 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
9131 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9132 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9133 * if it may be moved to a more global node?
9134 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9135 )
9136 {
9137 return createConsSetppc(scip, cons, name, nvars, vars, SCIP_SETPPCTYPE_PACKING,
9138 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode);
9139 }
9140
9141 /** creates and captures a set packing constraint with all constraint flags set
9142 * to their default values
9143 *
9144 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
9145 */
SCIPcreateConsBasicSetpack(SCIP * scip,SCIP_CONS ** cons,const char * name,int nvars,SCIP_VAR ** vars)9146 SCIP_RETCODE SCIPcreateConsBasicSetpack(
9147 SCIP* scip, /**< SCIP data structure */
9148 SCIP_CONS** cons, /**< pointer to hold the created constraint */
9149 const char* name, /**< name of constraint */
9150 int nvars, /**< number of variables in the constraint */
9151 SCIP_VAR** vars /**< array with variables of constraint entries */
9152 )
9153 {
9154 SCIP_CALL( SCIPcreateConsSetpack(scip, cons, name, nvars, vars,
9155 TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
9156
9157 return SCIP_OKAY;
9158 }
9159
9160 /** creates and captures a set covering constraint
9161 *
9162 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
9163 */
SCIPcreateConsSetcover(SCIP * scip,SCIP_CONS ** cons,const char * name,int nvars,SCIP_VAR ** vars,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)9164 SCIP_RETCODE SCIPcreateConsSetcover(
9165 SCIP* scip, /**< SCIP data structure */
9166 SCIP_CONS** cons, /**< pointer to hold the created constraint */
9167 const char* name, /**< name of constraint */
9168 int nvars, /**< number of variables in the constraint */
9169 SCIP_VAR** vars, /**< array with variables of constraint entries */
9170 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
9171 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9172 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
9173 * Usually set to TRUE. */
9174 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
9175 * TRUE for model constraints, FALSE for additional, redundant constraints. */
9176 SCIP_Bool check, /**< should the constraint be checked for feasibility?
9177 * TRUE for model constraints, FALSE for additional, redundant constraints. */
9178 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
9179 * Usually set to TRUE. */
9180 SCIP_Bool local, /**< is constraint only valid locally?
9181 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9182 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
9183 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
9184 * adds coefficients to this constraint. */
9185 SCIP_Bool dynamic, /**< is constraint subject to aging?
9186 * Usually set to FALSE. Set to TRUE for own cuts which
9187 * are separated as constraints. */
9188 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
9189 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9190 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9191 * if it may be moved to a more global node?
9192 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9193 )
9194 {
9195 return createConsSetppc(scip, cons, name, nvars, vars, SCIP_SETPPCTYPE_COVERING,
9196 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode);
9197 }
9198
9199 /** creates and captures a set covering constraint with all constraint flags set
9200 * to their default values
9201 *
9202 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
9203 */
SCIPcreateConsBasicSetcover(SCIP * scip,SCIP_CONS ** cons,const char * name,int nvars,SCIP_VAR ** vars)9204 SCIP_RETCODE SCIPcreateConsBasicSetcover(
9205 SCIP* scip, /**< SCIP data structure */
9206 SCIP_CONS** cons, /**< pointer to hold the created constraint */
9207 const char* name, /**< name of constraint */
9208 int nvars, /**< number of variables in the constraint */
9209 SCIP_VAR** vars /**< array with variables of constraint entries */
9210 )
9211 {
9212 SCIP_CALL( SCIPcreateConsSetcover(scip, cons, name, nvars, vars,
9213 TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
9214
9215 return SCIP_OKAY;
9216 }
9217
9218 /** adds coefficient in set partitioning / packing / covering constraint */
SCIPaddCoefSetppc(SCIP * scip,SCIP_CONS * cons,SCIP_VAR * var)9219 SCIP_RETCODE SCIPaddCoefSetppc(
9220 SCIP* scip, /**< SCIP data structure */
9221 SCIP_CONS* cons, /**< constraint data */
9222 SCIP_VAR* var /**< variable to add to the constraint */
9223 )
9224 {
9225 assert(var != NULL);
9226
9227 /*debugMsg(scip, "adding variable <%s> to setppc constraint <%s>\n",
9228 SCIPvarGetName(var), SCIPconsGetName(cons));*/
9229
9230 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
9231 {
9232 SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n");
9233 return SCIP_INVALIDDATA;
9234 }
9235
9236 SCIP_CALL( addCoef(scip, cons, var) );
9237
9238 return SCIP_OKAY;
9239 }
9240
9241 /** gets number of variables in set partitioning / packing / covering constraint */
SCIPgetNVarsSetppc(SCIP * scip,SCIP_CONS * cons)9242 int SCIPgetNVarsSetppc(
9243 SCIP* scip, /**< SCIP data structure */
9244 SCIP_CONS* cons /**< constraint data */
9245 )
9246 {
9247 SCIP_CONSDATA* consdata;
9248
9249 assert(scip != NULL);
9250
9251 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
9252 {
9253 SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n");
9254 SCIPABORT();
9255 return -1; /*lint !e527*/
9256 }
9257
9258 consdata = SCIPconsGetData(cons);
9259 assert(consdata != NULL);
9260
9261 return consdata->nvars;
9262 }
9263
9264 /** gets array of variables in set partitioning / packing / covering constraint */
SCIPgetVarsSetppc(SCIP * scip,SCIP_CONS * cons)9265 SCIP_VAR** SCIPgetVarsSetppc(
9266 SCIP* scip, /**< SCIP data structure */
9267 SCIP_CONS* cons /**< constraint data */
9268 )
9269 {
9270 SCIP_CONSDATA* consdata;
9271
9272 assert(scip != NULL);
9273
9274 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
9275 {
9276 SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n");
9277 SCIPABORT();
9278 return NULL; /*lint !e527*/
9279 }
9280
9281 consdata = SCIPconsGetData(cons);
9282 assert(consdata != NULL);
9283
9284 return consdata->vars;
9285 }
9286
9287 /** gets type of set partitioning / packing / covering constraint */
SCIPgetTypeSetppc(SCIP * scip,SCIP_CONS * cons)9288 SCIP_SETPPCTYPE SCIPgetTypeSetppc(
9289 SCIP* scip, /**< SCIP data structure */
9290 SCIP_CONS* cons /**< constraint data */
9291 )
9292 {
9293 SCIP_CONSDATA* consdata;
9294
9295 assert(scip != NULL);
9296
9297 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
9298 {
9299 SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n");
9300 SCIPABORT();
9301 }
9302
9303 consdata = SCIPconsGetData(cons);
9304 assert(consdata != NULL);
9305
9306 return (SCIP_SETPPCTYPE)(consdata->setppctype);
9307 }
9308
9309 /** gets the dual solution of the set partitioning / packing / covering constraint in the current LP */
SCIPgetDualsolSetppc(SCIP * scip,SCIP_CONS * cons)9310 SCIP_Real SCIPgetDualsolSetppc(
9311 SCIP* scip, /**< SCIP data structure */
9312 SCIP_CONS* cons /**< constraint data */
9313 )
9314 {
9315 SCIP_CONSDATA* consdata;
9316
9317 assert(scip != NULL);
9318
9319 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
9320 {
9321 SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n");
9322 SCIPABORT();
9323 return SCIP_INVALID; /*lint !e527*/
9324 }
9325
9326 consdata = SCIPconsGetData(cons);
9327 assert(consdata != NULL);
9328
9329 if( consdata->row != NULL )
9330 return SCIProwGetDualsol(consdata->row);
9331 else
9332 return 0.0;
9333 }
9334
9335 /** gets the dual Farkas value of the set partitioning / packing / covering constraint in the current infeasible LP */
SCIPgetDualfarkasSetppc(SCIP * scip,SCIP_CONS * cons)9336 SCIP_Real SCIPgetDualfarkasSetppc(
9337 SCIP* scip, /**< SCIP data structure */
9338 SCIP_CONS* cons /**< constraint data */
9339 )
9340 {
9341 SCIP_CONSDATA* consdata;
9342
9343 assert(scip != NULL);
9344
9345 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
9346 {
9347 SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n");
9348 SCIPABORT();
9349 return SCIP_INVALID; /*lint !e527*/
9350 }
9351
9352 consdata = SCIPconsGetData(cons);
9353 assert(consdata != NULL);
9354
9355 if( consdata->row != NULL )
9356 return SCIProwGetDualfarkas(consdata->row);
9357 else
9358 return 0.0;
9359 }
9360
9361 /** returns the linear relaxation of the given set partitioning / packing / covering constraint; may return NULL if no
9362 * LP row was yet created; the user must not modify the row!
9363 */
SCIPgetRowSetppc(SCIP * scip,SCIP_CONS * cons)9364 SCIP_ROW* SCIPgetRowSetppc(
9365 SCIP* scip, /**< SCIP data structure */
9366 SCIP_CONS* cons /**< constraint data */
9367 )
9368 {
9369 SCIP_CONSDATA* consdata;
9370
9371 assert(scip != NULL);
9372
9373 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
9374 {
9375 SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n");
9376 SCIPABORT();
9377 return NULL; /*lint !e527*/
9378 }
9379
9380 consdata = SCIPconsGetData(cons);
9381 assert(consdata != NULL);
9382
9383 return consdata->row;
9384 }
9385
9386 /** returns current number of variables fixed to one in the constraint */
SCIPgetNFixedonesSetppc(SCIP * scip,SCIP_CONS * cons)9387 int SCIPgetNFixedonesSetppc(
9388 SCIP* scip, /**< SCIP data structure */
9389 SCIP_CONS* cons /**< constraint data */
9390 )
9391 {
9392 SCIP_CONSDATA* consdata;
9393
9394 assert(scip != NULL);
9395
9396 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
9397 {
9398 SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n");
9399 SCIPABORT();
9400 return -1; /*lint !e527*/
9401 }
9402
9403 consdata = SCIPconsGetData(cons);
9404 assert(consdata != NULL);
9405
9406 return consdata->nfixedones;
9407 }
9408
9409
9410 /** returns current number of variables fixed to zero in the constraint */
SCIPgetNFixedzerosSetppc(SCIP * scip,SCIP_CONS * cons)9411 int SCIPgetNFixedzerosSetppc(
9412 SCIP* scip, /**< SCIP data structure */
9413 SCIP_CONS* cons /**< constraint data */
9414 )
9415 {
9416 SCIP_CONSDATA* consdata;
9417
9418 assert(scip != NULL);
9419
9420 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
9421 {
9422 SCIPerrorMessage("constraint is not a set partitioning / packing / covering constraint\n");
9423 SCIPABORT();
9424 return -1; /*lint !e527*/
9425 }
9426
9427 consdata = SCIPconsGetData(cons);
9428 assert(consdata != NULL);
9429
9430 return consdata->nfixedzeros;
9431 }
9432
9433 /** cleans up (multi-)aggregations and fixings from setppc constraints */
SCIPcleanupConssSetppc(SCIP * scip,SCIP_Bool onlychecked,SCIP_Bool * infeasible,int * naddconss,int * ndelconss,int * nchgcoefs,int * nfixedvars)9434 SCIP_RETCODE SCIPcleanupConssSetppc(
9435 SCIP* scip, /**< SCIP data structure */
9436 SCIP_Bool onlychecked, /**< should only checked constraints be cleaned up? */
9437 SCIP_Bool* infeasible, /**< pointer to return whether problem was detected to be infeasible */
9438 int* naddconss, /**< pointer to count number of added (linear) constraints */
9439 int* ndelconss, /**< pointer to count number of deleted (setppc) constraints */
9440 int* nchgcoefs, /**< pointer to count number of changed coefficients */
9441 int* nfixedvars /**< pointer to count number of fixed variables */
9442 )
9443 {
9444 SCIP_CONSHDLR* conshdlr;
9445 SCIP_CONS** conss;
9446 int nconss;
9447 int i;
9448
9449 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
9450 if( conshdlr == NULL )
9451 return SCIP_OKAY;
9452
9453 assert(naddconss != NULL);
9454 assert(ndelconss != NULL);
9455 assert(nfixedvars != NULL);
9456 assert(infeasible != NULL);
9457 *infeasible = FALSE;
9458
9459 nconss = onlychecked ? SCIPconshdlrGetNCheckConss(conshdlr) : SCIPconshdlrGetNActiveConss(conshdlr);
9460 conss = onlychecked ? SCIPconshdlrGetCheckConss(conshdlr) : SCIPconshdlrGetConss(conshdlr);
9461
9462 /* loop backwards since then deleted constraints do not interfere with the loop */
9463 for( i = nconss - 1; i > 0; --i )
9464 {
9465 SCIP_CONS* cons = conss[i];
9466
9467 SCIP_CALL( applyFixings(scip, cons, naddconss, ndelconss, nfixedvars, infeasible) );
9468
9469 if( *infeasible )
9470 break;
9471
9472 if( SCIPconsIsDeleted(cons) )
9473 continue;
9474
9475 /* merging unmerged constraints */
9476 SCIP_CALL( mergeMultiples(scip, cons, nfixedvars, ndelconss, nchgcoefs, infeasible) );
9477
9478 if( *infeasible )
9479 break;
9480 }
9481
9482 return SCIP_OKAY;
9483 }
9484