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