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