Scippy

SCIP

Solving Constraint Integer Programs

cons_pseudoboolean.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2024 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file cons_pseudoboolean.c
26 * @ingroup DEFPLUGINS_CONS
27 * @brief constraint handler for pseudo Boolean constraints
28 * @author Gerald Gamrath
29 * @author Stefan Heinz
30 * @author Michael Winkler
31 * @author Dominik Kamp
32 *
33 * The constraint handler deals with pseudo Boolean constraints. These are constraints of the form
34 * \f[
35 * \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}
36 * \f]
37 * where all x are binary and all c are integer
38 *
39 * @todo Add eventhandling.
40 */
41
42/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
43
45#include "scip/cons_and.h"
46#include "scip/cons_indicator.h"
47#include "scip/cons_knapsack.h"
48#include "scip/cons_linear.h"
49#include "scip/cons_logicor.h"
51#include "scip/cons_setppc.h"
52#include "scip/cons_xor.h"
53#include "scip/debug.h"
54#include "scip/pub_cons.h"
55#include "scip/pub_message.h"
56#include "scip/pub_misc.h"
57#include "scip/pub_misc_sort.h"
58#include "scip/pub_var.h"
59#include "scip/scip_cons.h"
60#include "scip/scip_copy.h"
61#include "scip/scip_general.h"
62#include "scip/scip_mem.h"
63#include "scip/scip_message.h"
64#include "scip/scip_numerics.h"
65#include "scip/scip_param.h"
66#include "scip/scip_prob.h"
67#include "scip/scip_sol.h"
68#include "scip/scip_var.h"
69#include "scip/symmetry_graph.h"
70#include <string.h>
71
72#ifdef WITHEQKNAPSACK
73#include "scip/cons_eqknapsack.h"
74#endif
75
76/* constraint handler properties */
77#define CONSHDLR_NAME "pseudoboolean"
78#define CONSHDLR_DESC "constraint handler dealing with pseudo Boolean constraints"
79#define CONSHDLR_ENFOPRIORITY -1000000 /**< priority of the constraint handler for constraint enforcing */
80#define CONSHDLR_CHECKPRIORITY -5000000 /**< priority of the constraint handler for checking feasibility */
81#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
82 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
83#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
84#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
85
86#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_MEDIUM /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
87
88#define DEFAULT_DECOMPOSENORMALPBCONS FALSE /**< decompose every normal pseudo boolean constraint into a "linear" constraint and "and" constraints */
89#define DEFAULT_DECOMPOSEINDICATORPBCONS TRUE /**< decompose every soft pseudo boolean constraint into "indicator" constraints and "and" constraints */
90
91#define DEFAULT_SEPARATENONLINEAR TRUE /**< if decomposed, should the nonlinear constraints be separated during LP processing */
92#define DEFAULT_PROPAGATENONLINEAR TRUE /**< if decomposed, should the nonlinear constraints be propagated during node processing */
93#define DEFAULT_REMOVABLENONLINEAR TRUE /**< if decomposed, should the nonlinear constraints be removable */
94#define NONLINCONSUPGD_PRIORITY 60000 /**< priority of upgrading nonlinear constraints */
95
96/* remove this line to compile the upgrade from nonlinear to pseudoboolean constraints */
97#undef NONLINCONSUPGD_PRIORITY /*lint !e750*/
98
99/*
100 * Data structures
101 */
102#define HASHSIZE_PSEUDOBOOLEANNONLINEARTERMS 500 /**< minimal size of hash table in and constraint tables */
103
104
105/* - create special linear(knapsack, setppc, logicor, (eqknapsack)) and and-constraints with check flags FALSE, to
106 * get smaller amount of locks on the term variables, do all presolving ...?! in these constraint handlers
107 *
108 * - do the checking here, lock and-resultants in both directions and all and-variables according to their
109 * coefficients and sides of the constraint,
110 * @note this only works if the and-resultant has no objective cofficient, otherwise we need to lock variables also in both directions
111 *
112 * - need to keep and constraint pointer for special propagations like if two ands are due to their variables in
113 * one clique, add this cliques of and-resultants
114 *
115 * - do special presolving like on instance :
116 * check/IP/PseudoBoolean/normalized-PB07/OPT-SMALLINT-NLC/submittedPB07/manquinho/bsg/normalized-bsg_1000_25_1.opb.gz
117 *
118 * there exist constraint like: 1 x1 x2 + 1 x1 x3 + 1 x1 x4 + 1 x1 x5 <= 1 ;
119 * which "equals" a linear constraint: 3 x1 + x2 + x3 + x4 + x5 <= 4 ;
120 *
121 * in more general terms: 1 x1 x2 x3 x4 + 1 x1 x2 x5 x6 x7 + 1 x1 x2 x8 x9 <= 1 ;
122 * which "equals" a pseudoboolean constraint: 2 x1 + 2 x2 + 1 x3 x4 + 1 x5 x6 x7 + 1 x8 x9 <= 5 ;
123 *
124 * in an even more general terms: 5 x1 x2 x3 x4 + 1 x1 x2 x5 x6 x7 + 1 x1 x2 x8 x9 <= 6 ;
125 * equals(should the knapsack do) 1 x1 x2 x3 x4 + 1 x1 x2 x5 x6 x7 + 1 x1 x2 x8 x9 <= 2 ;
126 * which "equals" a pseudoboolean constraint: 2 x1 + 2 x2 + 1 x3 x4 + 1 x5 x6 x7 + 1 x8 x9 <= 6 ;
127 * ( without knapsack 7 x1 + 7 x2 + 5 x3 x4 + 1 x5 x6 x7 + 1 x8 x9 <= 20 ; )
128 *
129 * another special case : 1 x1 x2 x3 + 1 x1 x2 x4 + 1 x5 x6 <= 1 ;
130 * which "equals" a pseudoboolean constraint: 2 x1 + 2 x2 + 1 x3 + 1 x4 + 1 x5 x6 <= 5 ;
131 * which "equals" a pseudoboolean constraint: 4 x1 + 4 x2 + 2 x3 + 2 x4 + 1 x5 + 1 x6 <= 10 ;
132 *
133 * another special case : 1 x1 x2 + 1 x1 x3 + 2 x4 x5 <= 3 ;
134 * which "equals" a pseudoboolean constraint: 2 x1 + 1 x2 + 1 x3 + 2 x4 x5 <= 5 ;
135 * which "equals" a pseudoboolean constraint: 2 x1 + 1 x2 + 1 x3 + 1 x4 + 1 x5 <= 5 ;
136 */
137/* @todo - in and-constraint better count nfixed zeros in both directions and maybe nfixedones for better propagation
138 *
139 * - do better conflict analysis by choosing the earliest fixed variable which led to a conflict instead of maybe
140 * best coefficient or create more conflicts by using all to zero fixed variables one by one
141 *
142 * - how to make sure that we aggregate in a right way, when aggregating a resultant and a "normal" variable,
143 * maybe add in SCIPaggregateVars a check for original variables, to prefer them if the variable type is the
144 * same; probably it would be better too if we would aggregate two resultants that the one with less variables
145 * inside the and-constraint will stay active
146 *
147 * @note since product resultants are artificial, we do not care for their solution value, but this can lead to fixation
148 * of the resultant not representing the product, in 'optimization mode' we do not care, but this might make
149 * solution debugging complicated
150 */
151
152/** and-constraint data object */
154{
155 SCIP_CONS* cons; /**< pointer to the and-constraint of this 'term' of variables */
156 SCIP_CONS* origcons; /**< pointer to the original and-constraint of this 'term' of variables
157 * only after problem was transformed, NULL otherwise */
158 SCIP_VAR** vars; /**< all and-constraint variables */
159 int nvars; /**< number of all and-constraint variables */
160 int svars; /**< size for all and-constraint variables */
161 SCIP_VAR** newvars; /**< new variables in this presolving round */
162 int nnewvars; /**< number of new variables in this presolving round */
163 int snewvars; /**< size of new variables in this presolving round */
164 int noriguses; /**< how often is this data in used by original constraints */
165 int nuses; /**< how often is this data in used by transformed constraints */
166 unsigned int istransformed:1; /**< is transformed data active */
167 unsigned int isoriginal:1; /**< is original data active */
168};
170
171/** constraint data for pseudoboolean constraints */
172struct SCIP_ConsData
173{
174 SCIP_Real lhs; /**< left hand side of constraint */
175 SCIP_Real rhs; /**< right hand side of constraint */
176
177 SCIP_CONS* lincons; /**< linear constraint which represents this pseudoboolean constraint */
178 SCIP_LINEARCONSTYPE linconstype; /**< type of linear constraint which represents this pseudoboolean constraint */
179 int nlinvars; /**< number of linear variables (without and-resultants) */
180
181 CONSANDDATA** consanddatas; /**< array of and-constraints-data-objects sorted after problem index of
182 * and-resultant of corresponding and-constraint */
183 SCIP_Real* andcoefs; /**< array of coefficients for and-constraints of
184 * and-constraints-data-objects
185 * (changes during presolving, needs to be updated in every presolving
186 * round) */
187 SCIP_Bool* andnegs; /**< array of negation status for and-constraints of
188 * and-constraints-data-objects
189 * (changes during presolving, needs to be updated in every presolving
190 * round) */
191 int nconsanddatas; /**< number of and-constraints-data-objects */
192 int sconsanddatas; /**< size of and-constraints-data-objects array */
193
194 SCIP_VAR* intvar; /**< a artificial variable which was added only for the objective function,
195 * if this variable is not NULL this constraint (without this integer
196 * variable) describes the objective function */
197
198 SCIP_VAR* indvar; /**< indicator variable if it's a soft constraint, or NULL */
199 SCIP_Real weight; /**< weight of the soft constraint, if it is one */
200
201 unsigned int issoftcons:1; /**< is this a soft constraint */
202 unsigned int changed:1; /**< was constraint changed? */
203 unsigned int propagated:1; /**< is constraint already propagated? */
204 unsigned int presolved:1; /**< is constraint already presolved? */
205 unsigned int cliquesadded:1; /**< were the cliques of the constraint already extracted? */
206 unsigned int upgradetried:1; /**< was constraint upgrading already tried */
207};
208
209/** constraint handler data */
210struct SCIP_ConshdlrData
211{
212 CONSANDDATA** allconsanddatas; /**< array of all and-constraint data objects inside the whole problem,
213 * created via this constraint handler */
214 int nallconsanddatas; /**< number of all and-constraint data objects inside the whole problem,
215 * created via this constraint handler */
216 int sallconsanddatas; /**< size of all and-constraint data objects inside the whole problem,
217 * created via this constraint handler */
218 SCIP_HASHTABLE* hashtable; /**< hash table for all and-constraint data objects */
219 int hashtablesize; /**< size for hash table for all and-constraint data objects */
220
221 SCIP_HASHMAP* hashmap; /**< hash map for mapping all resultant to and-constraint */
222 int hashmapsize; /**< size for hash map for mapping all resultant to and-constraint */
223
224 SCIP_Bool decomposenormalpbcons; /**< decompose every normal pseudo boolean constraint into a "linear" constraint and "and" constraints */
225 SCIP_Bool decomposeindicatorpbcons; /**< decompose every soft pseudo boolean constraint into "indicator" constraints and "and" constraints */
226 SCIP_Bool inithashmapandtable;/**< flag to store if the hashmap and -table is initialized */
227 int nlinconss; /**< for counting number of created linear constraints */
228 int noriguses; /**< how many consanddata objects are used by original constraints */
229};
230
231
232/*
233 * Local methods
234 */
235
236/** comparison method for sorting and-resultants according to their problem index, which is used instead of the
237 * original index because the implicit resultants are shuffled when creating the constraints that otherwise results in
238 * shuffled problem copies,
239 * if an and-resultant is fixed, it will be put in front with respect to its original index
240 * if an and-resultant is negated, it will be put in front of its negation counterpart
241 */
242static
244{
245 SCIP_VAR* var1 = elem1;
246 SCIP_VAR* var2 = elem2;
247 SCIP_Bool varneg1 = SCIPvarIsNegated(var1);
248 SCIP_Bool varneg2 = SCIPvarIsNegated(var2);
249
250 if( varneg1 )
251 var1 = SCIPvarGetNegatedVar(var1);
252
253 if( varneg2 )
254 var2 = SCIPvarGetNegatedVar(var2);
255
256 int varind1 = SCIPvarGetProbindex(var1);
257 int varind2 = SCIPvarGetProbindex(var2);
258
259 if( varind1 == -1 && varind2 == -1 )
260 {
261 varind1 = SCIPvarGetIndex(var1);
262 varind2 = SCIPvarGetIndex(var2);
263 }
264
265 if( varind1 < varind2 )
266 return -1;
267 if( varind1 > varind2 )
268 return +1;
269
270 if( varneg1 && !varneg2 )
271 return -1;
272 if( !varneg1 && varneg2 )
273 return +1;
274
275 assert(elem1 == elem2);
276 return 0;
277}
278
279/** comparison method for sorting consanddatas according to the problem index of their corresponding and-resultants,
280 * if a consanddata object is deleted, it is handled like it has an inactive resultant, so this will be put
281 * in front while sorting
282 */
283static
284SCIP_DECL_SORTPTRCOMP(resvarCompWithInactive)
285{
286 CONSANDDATA* consanddata1 = (CONSANDDATA*)elem1;
287 CONSANDDATA* consanddata2 = (CONSANDDATA*)elem2;
288
289 assert(consanddata1 != NULL);
290 assert(consanddata2 != NULL);
291
292 /* consider that constraint data object can be only original */
293 if( consanddata1->istransformed != consanddata2->istransformed )
294 return consanddata1->istransformed ? +1 : -1;
295
296 SCIP_CONS* consand1;
297 SCIP_CONS* consand2;
298
299 if( consanddata1->istransformed )
300 {
301 consand1 = consanddata1->cons;
302 consand2 = consanddata2->cons;
303 }
304 else
305 {
306 consand1 = consanddata1->origcons;
307 consand2 = consanddata2->origcons;
308 }
309
310 /* check if and-constraint is still active */
311 if( SCIPconsIsDeleted(consand1) )
312 {
313 if( SCIPconsIsDeleted(consand2) )
314 return 0;
315 else
316 return -1;
317 }
318 else if( SCIPconsIsDeleted(consand2) )
319 return +1;
320
321 /* hack with setting the scip pointer to NULL */
322 return resvarComp((void*)SCIPgetResultantAnd(NULL, consand1), (void*)SCIPgetResultantAnd(NULL, consand2));
323}
324
325/** gets the key of the given element */
326static
327SCIP_DECL_HASHGETKEY(hashGetKeyAndConsDatas)
328{ /*lint --e{715}*/
329 /* the key is the element itself */
330 return elem;
331}
332
333/** returns TRUE iff both keys are equal; two non-linear terms are equal if they have the same variables */
334static
335SCIP_DECL_HASHKEYEQ(hashKeyEqAndConsDatas)
336{
337#ifndef NDEBUG
338 SCIP* scip;
339#endif
340 CONSANDDATA* cdata1;
341 CONSANDDATA* cdata2;
342 int v;
343
344 cdata1 = (CONSANDDATA*)key1;
345 cdata2 = (CONSANDDATA*)key2;
346
347#ifndef NDEBUG
348 scip = (SCIP*)userptr;
349#endif
350 assert(scip != NULL);
351 assert(cdata1 != NULL);
352 assert(cdata2 != NULL);
353 assert(cdata1->vars != NULL);
354 assert(cdata1->nvars > 1);
355 assert(cdata2->vars != NULL);
356 assert(cdata2->nvars > 1);
357
358#ifndef NDEBUG
359 /* check that cdata1 variables are sorted */
360 for( v = cdata1->nvars - 1; v > 0; --v )
361 assert(SCIPvarGetIndex(cdata1->vars[v]) >= SCIPvarGetIndex(cdata1->vars[v - 1]));
362 /* check that cdata2 variables are sorted */
363 for( v = cdata2->nvars - 1; v > 0; --v )
364 assert(SCIPvarGetIndex(cdata2->vars[v]) >= SCIPvarGetIndex(cdata2->vars[v - 1]));
365#endif
366
367 /* checks trivial case */
368 if( cdata1->nvars != cdata2->nvars )
369 return FALSE;
370
371 /* checks trivial case */
372 if( cdata1->cons != NULL && cdata2->cons != NULL && cdata1->cons != cdata2->cons )
373 return FALSE;
374
375 /* check each variable in both cdatas for equality */
376 for( v = cdata1->nvars - 1; v >= 0; --v )
377 {
378 assert(cdata1->vars[v] != NULL);
379 assert(cdata2->vars[v] != NULL);
380
381 /* tests if variables are equal */
382 if( cdata1->vars[v] != cdata2->vars[v] )
383 {
384 assert(SCIPvarCompare(cdata1->vars[v], cdata2->vars[v]) == 1 ||
385 SCIPvarCompare(cdata1->vars[v], cdata2->vars[v]) == -1);
386 return FALSE;
387 }
388 assert(SCIPvarCompare(cdata1->vars[v], cdata2->vars[v]) == 0);
389 }
390
391 return TRUE;
392}
393
394/** returns the hash value of the key */
395static
396SCIP_DECL_HASHKEYVAL(hashKeyValAndConsDatas)
397{ /*lint --e{715}*/
398 CONSANDDATA* cdata;
399 int minidx;
400 int mididx;
401 int maxidx;
402
403 cdata = (CONSANDDATA*)key;
404
405 assert(cdata != NULL);
406 assert(cdata->vars != NULL);
407 assert(cdata->nvars > 1);
408#ifndef NDEBUG
409 {
410 /* check that these variables are sorted */
411 int v;
412 for( v = cdata->nvars - 1; v > 0; --v )
413 assert(SCIPvarGetIndex(cdata->vars[v]) >= SCIPvarGetIndex(cdata->vars[v - 1]));
414 }
415#endif
416
417 minidx = SCIPvarGetIndex(cdata->vars[0]);
418 mididx = SCIPvarGetIndex(cdata->vars[cdata->nvars / 2]);
419 maxidx = SCIPvarGetIndex(cdata->vars[cdata->nvars - 1]);
420 assert(minidx >= 0 && minidx <= maxidx);
421
422 return SCIPhashFour(cdata->nvars, minidx, mididx, maxidx);
423}
424
425/** initializes the hashmap and -table used in this constraint handler data for artificial variables and specific
426 * and-constraint data objects
427 */
428static
430 SCIP*const scip, /**< SCIP data structure */
431 SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to store the constraint handler data */
432 )
433{
434 if( ((*conshdlrdata)->inithashmapandtable) )
435 {
436 assert((*conshdlrdata)->hashtable != NULL);
437 assert((*conshdlrdata)->hashmap != NULL);
438
439 return SCIP_OKAY;
440 }
441
442 assert((*conshdlrdata)->hashtable == NULL);
443 assert((*conshdlrdata)->hashmap == NULL);
444
445 /* create a hash table for and-constraint data objects */
446 (*conshdlrdata)->hashtablesize = HASHSIZE_PSEUDOBOOLEANNONLINEARTERMS;
447 SCIP_CALL( SCIPhashtableCreate(&((*conshdlrdata)->hashtable), SCIPblkmem(scip), (*conshdlrdata)->hashtablesize,
448 hashGetKeyAndConsDatas, hashKeyEqAndConsDatas, hashKeyValAndConsDatas, (void*) scip) );
449
450 /* create a hash table for and-resultant to and-constraint data objects */
451 (*conshdlrdata)->hashmapsize = HASHSIZE_PSEUDOBOOLEANNONLINEARTERMS;
452 SCIP_CALL( SCIPhashmapCreate(&((*conshdlrdata)->hashmap), SCIPblkmem(scip), (*conshdlrdata)->hashmapsize) );
453
454 (*conshdlrdata)->inithashmapandtable = TRUE;
455
456 return SCIP_OKAY;
457}
458
459/** creates constraint handler data for pseudo boolean constraint handler */
460static
462 SCIP*const scip, /**< SCIP data structure */
463 SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to store the constraint handler data */
464 )
465{
466 assert(scip != NULL);
467 assert(conshdlrdata != NULL);
468
469 SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
470
471 (*conshdlrdata)->allconsanddatas = NULL;
472 (*conshdlrdata)->nallconsanddatas = 0;
473 (*conshdlrdata)->sallconsanddatas = 10;
474
475 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &((*conshdlrdata)->allconsanddatas), (*conshdlrdata)->sallconsanddatas ) );
476
477 /* set hashmap and -table to NULL, mark them as uninitialized */
478 (*conshdlrdata)->inithashmapandtable = FALSE;
479 (*conshdlrdata)->hashtable = NULL;
480 (*conshdlrdata)->hashtablesize = 0;
481 (*conshdlrdata)->hashmap = NULL;
482 (*conshdlrdata)->hashmapsize = 0;
483
484 /* for constraint names count number of created constraints */
485 (*conshdlrdata)->nlinconss = 0;
486
487 /* initializes how many consanddata objects are used by original constraints */
488 (*conshdlrdata)->noriguses = 0;
489
490 return SCIP_OKAY;
491}
492
493
494/** frees constraint handler data for pseudo boolean constraint handler */
495static
497 SCIP*const scip, /**< SCIP data structure */
498 SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
499 )
500{
501 assert(scip != NULL);
502 assert(conshdlrdata != NULL);
503 assert(*conshdlrdata != NULL);
504 assert((*conshdlrdata)->nallconsanddatas == 0);
505
506 /* free hash table if necessary */
507 if( (*conshdlrdata)->inithashmapandtable )
508 {
509 SCIPhashmapFree(&((*conshdlrdata)->hashmap));
510 (*conshdlrdata)->hashmapsize = 0;
511 SCIPhashtableFree(&((*conshdlrdata)->hashtable));
512 (*conshdlrdata)->hashtablesize = 0;
513 }
514 else
515 {
516 assert((*conshdlrdata)->hashmap == NULL);
517 assert((*conshdlrdata)->hashtable == NULL);
518 }
519 (*conshdlrdata)->inithashmapandtable = FALSE;
520
521 /* clear array for all consanddata objects */
522 SCIPfreeBlockMemoryArray(scip, &((*conshdlrdata)->allconsanddatas), (*conshdlrdata)->sallconsanddatas );
523
524 (*conshdlrdata)->allconsanddatas = NULL;
525 (*conshdlrdata)->nallconsanddatas = 0;
526 (*conshdlrdata)->sallconsanddatas = 0;
527
528 SCIPfreeBlockMemory(scip, conshdlrdata);
529
530 return SCIP_OKAY;
531}
532
533/** gets number of variables in linear constraint */
534static
536 SCIP*const scip, /**< SCIP data structure */
537 SCIP_CONS*const cons, /**< linear constraint */
538 SCIP_LINEARCONSTYPE const constype, /**< linear constraint type */
539 int*const nvars /**< pointer to store number variables of linear constraint */
540 )
541{
542 assert(scip != NULL);
543 assert(cons != NULL);
544 assert(nvars != NULL);
545
546 /* determine for each special linear constranit all variables and coefficients */
547 switch( constype )
548 {
550 *nvars = SCIPgetNVarsLinear(scip, cons);
551 break;
553 *nvars = SCIPgetNVarsLogicor(scip, cons);
554 break;
556 *nvars = SCIPgetNVarsKnapsack(scip, cons);
557 break;
559 *nvars = SCIPgetNVarsSetppc(scip, cons);
560 break;
561#ifdef WITHEQKNAPSACK
562 case SCIP_LINEARCONSTYPE_EQKNAPSACK:
563 *nvars = SCIPgetNVarsEQKnapsack(scip, cons);
564 break;
565#endif
567 default:
568 SCIPerrorMessage("unknown linear constraint type\n");
569 return SCIP_INVALIDDATA;
570 }
571
572 return SCIP_OKAY;
573}
574
575
576/** gets sides of linear constraint */
577static
579 SCIP*const scip, /**< SCIP data structure */
580 SCIP_CONS*const cons, /**< linear constraint */
581 SCIP_LINEARCONSTYPE const constype, /**< linear constraint type */
582 SCIP_Real*const lhs, /**< pointer to store left hand side of linear constraint */
583 SCIP_Real*const rhs /**< pointer to store right hand side of linear constraint */
584 )
585{
586 SCIP_SETPPCTYPE type;
587
588 switch( constype )
589 {
591 *lhs = SCIPgetLhsLinear(scip, cons);
592 *rhs = SCIPgetRhsLinear(scip, cons);
593 break;
595 *lhs = 1.0;
596 *rhs = SCIPinfinity(scip);
597 break;
599 *lhs = -SCIPinfinity(scip);
600 *rhs = SCIPgetCapacityKnapsack(scip, cons);
601 break;
603 type = SCIPgetTypeSetppc(scip, cons);
604
605 switch( type )
606 {
608 *lhs = 1.0;
609 *rhs = 1.0;
610 break;
612 *lhs = -SCIPinfinity(scip);
613 *rhs = 1.0;
614 break;
616 *lhs = 1.0;
617 *rhs = SCIPinfinity(scip);
618 break;
619 default:
620 SCIPerrorMessage("unknown setppc type\n");
621 return SCIP_INVALIDDATA;
622 }
623 break;
624#ifdef WITHEQKNAPSACK
625 case SCIP_LINEARCONSTYPE_EQKNAPSACK:
626 *lhs = SCIPgetCapacityEQKnapsack(scip, cons);
627 *rhs = *lhs;
628 break;
629#endif
631 default:
632 SCIPerrorMessage("unknown linear constraint type\n");
633 return SCIP_INVALIDDATA;
634 }
635
636 return SCIP_OKAY;
637}
638
639/** gets variables and coefficients of linear constraint */
640static
642 SCIP*const scip, /**< SCIP data structure */
643 SCIP_CONS*const cons, /**< linear constraint */
644 SCIP_LINEARCONSTYPE const constype, /**< linear constraint type */
645 SCIP_VAR**const vars, /**< array to store variables of linear constraint */
646 SCIP_Real*const coefs, /**< array to store coefficient of linear constraint, or NULL */
647 int*const nvars /**< pointer to store number variables of linear constraint */
648 )
649{
650 SCIP_VAR** linvars;
651 int v;
652
653 assert(scip != NULL);
654 assert(cons != NULL);
655 assert(vars != NULL);
656 assert(nvars != NULL);
657
658 /* determine for each special linear constrait all variables and coefficients */
659 switch( constype )
660 {
662 {
663 SCIP_Real* lincoefs;
664
665 *nvars = SCIPgetNVarsLinear(scip, cons);
666 linvars = SCIPgetVarsLinear(scip, cons);
667
668 if( coefs != NULL )
669 {
670 lincoefs = SCIPgetValsLinear(scip, cons);
671
672 for( v = 0; v < *nvars; ++v )
673 {
674 vars[v] = linvars[v];
675 coefs[v] = lincoefs[v];
676 }
677 }
678 else
679 {
680 for( v = 0; v < *nvars; ++v )
681 vars[v] = linvars[v];
682 }
683
684 break;
685 }
687 *nvars = SCIPgetNVarsLogicor(scip, cons);
688 linvars = SCIPgetVarsLogicor(scip, cons);
689 assert( linvars != NULL );
690
691 if( coefs != NULL )
692 {
693 for( v = 0; v < *nvars; ++v )
694 {
695 vars[v] = linvars[v];
696 coefs[v] = 1.0;
697 }
698 }
699 else
700 {
701 for( v = 0; v < *nvars; ++v )
702 vars[v] = linvars[v];
703 }
704
705 break;
707 {
708 SCIP_Longint* weights;
709
710 *nvars = SCIPgetNVarsKnapsack(scip, cons);
711 linvars = SCIPgetVarsKnapsack(scip, cons);
712 assert( linvars != NULL );
713
714 if( coefs != NULL )
715 {
716 weights = SCIPgetWeightsKnapsack(scip, cons);
717
718 for( v = 0; v < *nvars; ++v )
719 {
720 vars[v] = linvars[v];
721 coefs[v] = (SCIP_Real) weights[v];
722 }
723 }
724 else
725 {
726 for( v = 0; v < *nvars; ++v )
727 vars[v] = linvars[v];
728 }
729
730 break;
731 }
733 *nvars = SCIPgetNVarsSetppc(scip, cons);
734 linvars = SCIPgetVarsSetppc(scip, cons);
735 assert( linvars != NULL );
736
737 if( coefs != NULL )
738 {
739 for( v = 0; v < *nvars; ++v )
740 {
741 vars[v] = linvars[v];
742 coefs[v] = 1.0;
743 }
744 }
745 else
746 {
747 for( v = 0; v < *nvars; ++v )
748 vars[v] = linvars[v];
749 }
750
751 break;
752#ifdef WITHEQKNAPSACK
753 case SCIP_LINEARCONSTYPE_EQKNAPSACK:
754 {
755 SCIP_Longint* weights;
756
757 *nvars = SCIPgetNVarsEQKnapsack(scip, cons);
758 linvars = SCIPgetVarsEQKnapsack(scip, cons);
759 assert( linvars != NULL );
760
761 if( coefs != NULL )
762 {
763 weights = SCIPgetWeightsEQKnapsack(scip, cons);
764
765 for( v = 0; v < *nvars; ++v )
766 {
767 vars[v] = linvars[v];
768 coefs[v] = (SCIP_Real) weights[v];
769 }
770 }
771 else
772 {
773 for( v = 0; v < *nvars; ++v )
774 vars[v] = linvars[v];
775 }
776
777 break;
778 }
779#endif
781 default:
782 SCIPerrorMessage("unknown linear constraint type\n");
783 return SCIP_INVALIDDATA;
784 }
785
786 return SCIP_OKAY;
787}
788
789/** splits up into original linear variables and artificial and-resultants */
790static
792 SCIP*const scip, /**< SCIP data structure */
793 SCIP_CONS*const cons, /**< pseudoboolean constraint */
794 SCIP_VAR**const vars, /**< all variables of linear constraint */
795 SCIP_Real*const coefs, /**< all coefficients of linear constraint, or NULL */
796 int const nvars, /**< number of all variables of linear constraint */
797 SCIP_VAR**const linvars, /**< array to store not and-resultant variables of linear constraint, or NULL */
798 SCIP_Real*const lincoefs, /**< array to store coefficients of not and-resultant variables of linear
799 * constraint, or NULL */
800 int*const nlinvars, /**< pointer to store number of not and-resultant variables, or NULL */
801 SCIP_VAR**const andress, /**< array to store and-resultant variables of linear constraint, or NULL */
802 SCIP_Real*const andcoefs, /**< array to store coefficients of and-resultant variables of linear
803 * constraint, or NULL */
804 SCIP_Bool*const andnegs, /**< array to store negation status of and-resultant variables of linear
805 * constraint, or NULL */
806 int*const nandress /**< pointer to store number of and-resultant variables, or NULL */
807 )
808{
809 SCIP_CONSHDLR* conshdlr;
810 SCIP_CONSHDLRDATA* conshdlrdata;
811 int v;
812
813 assert(scip != NULL);
814 assert(cons != NULL);
815 assert(vars != NULL);
816 assert((linvars != NULL) == (nlinvars != NULL));
817 assert((andress == NULL) || (nandress != NULL));
818 assert((andcoefs != NULL) == (andnegs != NULL));
819 assert((coefs != NULL) == ((lincoefs != NULL) || (andcoefs != NULL)));
820 assert(linvars != NULL || andress != NULL);
821
822 if( nlinvars != NULL )
823 *nlinvars = 0;
824 if( nandress != NULL )
825 *nandress = 0;
826
827 conshdlr = SCIPconsGetHdlr(cons);
828 assert(conshdlr != NULL);
829 conshdlrdata = SCIPconshdlrGetData(conshdlr);
830 assert(conshdlrdata != NULL);
831 assert(conshdlrdata->hashmap != NULL);
832
833 /* split variables into original and artificial variables */
834 for( v = 0; v < nvars; ++v )
835 {
836 SCIP_Bool hashmapentryexists;
837 SCIP_VAR* hashmapvar;
838
839 assert(vars[v] != NULL);
840
841 hashmapentryexists = SCIPhashmapExists(conshdlrdata->hashmap, (void*)(vars[v]));
842
843 if( !hashmapentryexists && SCIPvarIsNegated(vars[v]) )
844 {
845 hashmapvar = SCIPvarGetNegationVar(vars[v]);
846 hashmapentryexists = SCIPhashmapExists(conshdlrdata->hashmap, (void*)(hashmapvar));
847 }
848 else
849 hashmapvar = vars[v];
850
851 /* if and resultant is not a resultant anymore (meaning the corresponding and-constraint was deleted/upgraded),
852 * correct the flag and count this variable as normal linear variable
853 */
854 if( hashmapentryexists )
855 {
856 if( !SCIPconsIsOriginal(cons) )
857 {
858 CONSANDDATA* consanddata = (CONSANDDATA*) SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)(hashmapvar));
859 assert(consanddata != NULL);
860
861 hashmapentryexists = (consanddata->istransformed);
862
863 if( hashmapentryexists )
864 {
865 assert(consanddata->cons != NULL);
866 hashmapentryexists = !SCIPconsIsDeleted(consanddata->cons);
867 }
868 }
869 }
870
871 if( !hashmapentryexists && linvars != NULL && nlinvars != NULL )
872 {
873 linvars[*nlinvars] = vars[v];
874 if( lincoefs != NULL )
875 {
876 assert(coefs != NULL);
877 lincoefs[*nlinvars] = coefs[v];
878 }
879 ++(*nlinvars);
880 }
881 else if( hashmapentryexists && nandress != NULL )
882 {
883 if( andress != NULL )
884 {
885 andress[*nandress] = hashmapvar;
886
887 if( andcoefs != NULL )
888 {
889 assert(andnegs != NULL);
890 assert(coefs != NULL);
891 andcoefs[*nandress] = coefs[v];
892 andnegs[*nandress] = (vars[v] != hashmapvar);
893 }
894 }
895 ++(*nandress);
896 }
897 }
898
899 return SCIP_OKAY;
900}
901
902
903#ifdef CHECK_CONSISTENCY
904/** check constraint consistency */
905static
907 SCIP*const scip, /**< SCIP data structure */
908 SCIP_CONS*const cons /**< pseudoboolean constraint */
909 )
910{
911 SCIP_CONSDATA* consdata;
912 SCIP_VAR** vars;
913 SCIP_Real* coefs;
914 int nvars;
915 SCIP_VAR** linvars;
916 SCIP_Real* lincoefs;
917 int nlinvars;
918 SCIP_VAR** andress;
919 SCIP_Real* andcoefs;
920 SCIP_Bool* andnegs;
921 int nandress;
922 SCIP_Bool* alreadyfound;
923 SCIP_VAR* res;
924 int c;
925 int v;
926 SCIP_Real newlhs;
927 SCIP_Real newrhs;
928
929 assert(scip != NULL);
930 assert(cons != NULL);
931
933 return;
934
935 consdata = SCIPconsGetData(cons);
936 assert(consdata != NULL);
937
938 /* check standard pointers and sizes */
939 assert(consdata->lincons != NULL);
940 assert(!SCIPconsIsDeleted(consdata->lincons));
941 assert(consdata->linconstype > SCIP_LINEARCONSTYPE_INVALIDCONS);
942 assert(consdata->consanddatas != NULL);
943 assert(consdata->nconsanddatas > 0);
944 assert(consdata->nconsanddatas <= consdata->sconsanddatas);
945
946 /* get sides of linear constraint */
947 SCIP_CALL_ABORT( getLinearConsSides(scip, consdata->lincons, consdata->linconstype, &newlhs, &newrhs) );
948 assert(!SCIPisInfinity(scip, newlhs));
949 assert(!SCIPisInfinity(scip, -newrhs));
950 assert(SCIPisLE(scip, newlhs, newrhs));
951 assert(SCIPisEQ(scip, newrhs, consdata->rhs) || SCIPisEQ(scip, newrhs, -consdata->lhs));
952 assert(SCIPisEQ(scip, newlhs, consdata->lhs) || SCIPisEQ(scip, newlhs, -consdata->rhs));
953
954 /* check number of linear variables */
955 SCIP_CALL_ABORT( getLinearConsNVars(scip, consdata->lincons, consdata->linconstype, &nvars) );
956 assert(nvars == consdata->nlinvars + consdata->nconsanddatas);
957
958 /* get temporary memory */
959 SCIP_CALL_ABORT( SCIPallocBufferArray(scip, &vars, nvars) );
960 SCIP_CALL_ABORT( SCIPallocBufferArray(scip, &coefs, nvars) );
961 SCIP_CALL_ABORT( SCIPallocBufferArray(scip, &linvars, nvars) );
962 SCIP_CALL_ABORT( SCIPallocBufferArray(scip, &lincoefs, nvars) );
963 SCIP_CALL_ABORT( SCIPallocBufferArray(scip, &andress, nvars) );
964 SCIP_CALL_ABORT( SCIPallocBufferArray(scip, &andcoefs, nvars) );
965 SCIP_CALL_ABORT( SCIPallocBufferArray(scip, &andnegs, nvars) );
966 SCIP_CALL_ABORT( SCIPallocClearBufferArray(scip, &alreadyfound, nvars) );
967
968 /* get variables and coefficients */
969 SCIP_CALL_ABORT( getLinearConsVarsData(scip, consdata->lincons, consdata->linconstype, vars, coefs, &nvars) );
970 assert(nvars == 0 || (coefs != NULL));
971
972 /* calculate all not artificial linear variables and all artificial and-resultants */
973 SCIP_CALL_ABORT( getLinVarsAndAndRess(scip, cons, vars, coefs, nvars, linvars, lincoefs, &nlinvars,
974 andress, andcoefs, andnegs, &nandress) );
975 assert(nlinvars == consdata->nlinvars);
976 assert(nandress == consdata->nconsanddatas);
977
978 for( v = nandress - 1; v >= 0; --v )
979 {
980 SCIP_VAR* andresultant = andress[v];
981 int nfound = 0;
982
983 for( c = consdata->nconsanddatas - 1; c >= 0; --c )
984 {
985 assert(consdata->consanddatas[c] != NULL);
986 if( consdata->consanddatas[c]->cons != NULL )
987 {
988 res = SCIPgetResultantAnd(scip, consdata->consanddatas[c]->cons);
989 assert(res != NULL);
990
991 if( res == andresultant && consdata->andnegs[c] == andnegs[v] && consdata->andcoefs[c] == andcoefs[v] )
992 {
993 /* resultant should be either active or a negated variable of an active one */
995 assert(!alreadyfound[c]);
996
997 /* all and-resultants should be merged, so it is only allowed that each variable exists one time */
998 alreadyfound[c] = TRUE;
999 ++nfound;
1000 break;
1001 }
1002 }
1003 }
1004 assert(nfound == 1);
1005 }
1006
1007 for( c = consdata->nconsanddatas - 1; c >= 0; --c )
1008 {
1009 assert(alreadyfound[c]);
1010 }
1011
1012 /* free temporary memory */
1013 SCIPfreeBufferArray(scip, &alreadyfound);
1014 SCIPfreeBufferArray(scip, &andnegs);
1015 SCIPfreeBufferArray(scip, &andcoefs);
1016 SCIPfreeBufferArray(scip, &andress);
1017 SCIPfreeBufferArray(scip, &lincoefs);
1018 SCIPfreeBufferArray(scip, &linvars);
1019 SCIPfreeBufferArray(scip, &coefs);
1020 SCIPfreeBufferArray(scip, &vars);
1021}
1022#else
1023#define checkConsConsistency(scip, cons) /**/
1024#endif
1025
1026
1027/** transforming transformed consanddata object back to original space, if an corresponding original constraint exists,
1028 * also clearing all transformed data, i.e. releasing transformed variables
1029 */
1030static
1032 SCIP*const scip, /**< SCIP data structure */
1033 CONSANDDATA* consanddata, /**< consanddata object */
1034 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
1035 )
1036{
1037 SCIP_VAR** tmpvars;
1038 SCIP_Bool origdata;
1039 int ntmpvars;
1040 int v;
1041
1042 assert(scip != NULL);
1043 assert(consanddata != NULL);
1044 assert(conshdlrdata != NULL);
1045
1046 origdata = TRUE;
1047
1048 tmpvars = consanddata->vars;
1049 ntmpvars = consanddata->nvars;
1050
1051 /* release all transformed variables */
1052 for( v = ntmpvars - 1; v >= 0; --v )
1053 {
1054 assert(tmpvars[v] != NULL);
1055 if( SCIPvarIsTransformed(tmpvars[v]) )
1056 {
1057 SCIP_CALL( SCIPreleaseVar(scip, &tmpvars[v]) );
1058 origdata = FALSE;
1059 }
1060 }
1061
1062 tmpvars = consanddata->newvars;
1063 ntmpvars = consanddata->nnewvars;
1064
1065 /* release all variables */
1066 for( v = ntmpvars - 1; v >= 0; --v )
1067 {
1068 assert(tmpvars[v] != NULL);
1069 if( SCIPvarIsTransformed(tmpvars[v]) )
1070 {
1071 SCIP_CALL( SCIPreleaseVar(scip, &tmpvars[v]) );
1072 origdata = FALSE;
1073 }
1074 }
1075
1076 /* reinstall original data */
1077 if( !origdata || consanddata->nvars == 0 )
1078 {
1079 SCIPfreeBlockMemoryArrayNull(scip, &(consanddata->vars), consanddata->svars);
1080 SCIPfreeBlockMemoryArrayNull(scip, &(consanddata->newvars), consanddata->snewvars);
1081
1082 consanddata->nuses = 0;
1083 consanddata->nvars = 0;
1084 consanddata->svars = 0;
1085 consanddata->nnewvars = 0;
1086 consanddata->snewvars = 0;
1087 consanddata->istransformed = FALSE;
1088
1089 if( consanddata->noriguses > 0 )
1090 {
1091 assert(consanddata->origcons != NULL);
1092 assert(consanddata->isoriginal);
1093
1094 assert(SCIPgetNVarsAnd(scip, consanddata->origcons) > 0);
1095 assert(SCIPgetVarsAnd(scip, consanddata->origcons) != NULL);
1096 consanddata->nvars = SCIPgetNVarsAnd(scip, consanddata->origcons);
1097 consanddata->svars = consanddata->nvars;
1098
1099 if( consanddata->nvars > 0 )
1100 {
1101 SCIP_VAR** andvars = SCIPgetVarsAnd(scip, consanddata->origcons);
1102
1103 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(consanddata->vars), andvars, consanddata->nvars) );
1104
1105 /* sort variables */
1106 SCIPsortPtr((void**)(consanddata->vars), SCIPvarComp, consanddata->nvars);
1107 }
1108
1109 /* check that the hash map and tabkle are still having all information */
1110 if( conshdlrdata->inithashmapandtable )
1111 {
1112 assert(conshdlrdata->hashmap != NULL);
1113 assert(conshdlrdata->hashtable != NULL);
1114 assert(SCIPgetResultantAnd(scip, consanddata->origcons) != NULL);
1115 assert(SCIPhashtableExists(conshdlrdata->hashtable, (void*)consanddata));
1116 assert(consanddata == (CONSANDDATA*)(SCIPhashtableRetrieve(conshdlrdata->hashtable, (void*)consanddata)));
1117 assert(SCIPhashmapExists(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddata->origcons)));
1118 assert(consanddata == (CONSANDDATA*)(SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddata->origcons))));
1119 }
1120 }
1121 else
1122 assert(consanddata->origcons == NULL);
1123 }
1124 else
1125 {
1126 assert(consanddata->nuses == 0);
1127 assert(consanddata->nnewvars == 0);
1128 assert(consanddata->snewvars == 0);
1129 assert(consanddata->newvars == NULL);
1130
1131 consanddata->istransformed = FALSE;
1132
1133 if( consanddata->noriguses > 0 )
1134 {
1135 assert(consanddata->origcons != NULL);
1136 assert(consanddata->nvars > 0);
1137 assert(consanddata->svars > 0);
1138 assert(consanddata->vars != NULL);
1139 assert(consanddata->isoriginal);
1140
1141 /* check that the hash map and tabkle are still having all information */
1142 if( conshdlrdata->inithashmapandtable )
1143 {
1144 assert(conshdlrdata->hashmap != NULL);
1145 assert(conshdlrdata->hashtable != NULL);
1146 assert(SCIPgetResultantAnd(scip, consanddata->origcons) != NULL);
1147 assert(SCIPhashtableExists(conshdlrdata->hashtable, (void*)consanddata));
1148 assert(consanddata == (CONSANDDATA*)(SCIPhashtableRetrieve(conshdlrdata->hashtable, (void*)consanddata)));
1149 assert(SCIPhashmapExists(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddata->origcons)));
1150 assert(consanddata == (CONSANDDATA*)(SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddata->origcons))));
1151 }
1152 }
1153 }
1154
1155 return SCIP_OKAY;
1156}
1157
1158
1159
1160/** creates a pseudo boolean constraint data */
1161static
1163 SCIP*const scip, /**< SCIP data structure */
1164 SCIP_CONSHDLR*const conshdlr, /**< pseudoboolean constraint handler */
1165 SCIP_CONSDATA** consdata, /**< pointer to linear constraint data */
1166 SCIP_CONS*const lincons, /**< linear constraint with artificial and-resultants representing this pseudoboolean constraint */
1167 SCIP_LINEARCONSTYPE const linconstype, /**< type of linear constraint */
1168 SCIP_CONS**const andconss, /**< array of and-constraints which occur in this pseudoboolean constraint */
1169 SCIP_Real*const andcoefs, /**< coefficients of and-constraints */
1170 SCIP_Bool*const andnegs, /**< negation status of and-constraints (or NULL, if no negated resultants) */
1171 int const nandconss, /**< number of and-constraints */
1172 SCIP_VAR*const indvar, /**< indicator variable if it's a soft constraint, or NULL */
1173 SCIP_Real const weight, /**< weight of the soft constraint, if it is one */
1174 SCIP_Bool const issoftcons, /**< is this a soft constraint */
1175 SCIP_VAR* const intvar, /**< a artificial variable which was added only for the objective function,
1176 * if this variable is not NULL this constraint (without this integer
1177 * variable) describes the objective function */
1178 SCIP_Real lhs, /**< left hand side of row */
1179 SCIP_Real rhs, /**< right hand side of row */
1180 SCIP_Bool check, /**< is the new constraint a check constraint? */
1181 SCIP_Bool transforming /**< are we called by CONSTRANS */
1182 )
1183{
1184 SCIP_Bool transformed;
1185 int nvars;
1186
1187 assert(scip != NULL);
1188 assert(conshdlr != NULL);
1189 assert(consdata != NULL);
1190 assert(lincons != NULL && linconstype > SCIP_LINEARCONSTYPE_INVALIDCONS);
1191 assert(nandconss == 0 || (andconss != NULL && andcoefs != NULL));
1192 assert(!issoftcons || (!SCIPisZero(scip, weight) && indvar != NULL));
1193
1194 /* adjust right hand side */
1195 if( SCIPisInfinity(scip, rhs) )
1196 rhs = SCIPinfinity(scip);
1197 else if( SCIPisInfinity(scip, -rhs) )
1198 rhs = -SCIPinfinity(scip);
1199
1200 /* adjust left hand side */
1201 if( SCIPisInfinity(scip, -lhs) )
1202 lhs = -SCIPinfinity(scip);
1203 else if( SCIPisInfinity(scip, lhs) )
1204 lhs = SCIPinfinity(scip);
1205
1206 /* check left and right side */
1207 if( SCIPisGT(scip, lhs, rhs) )
1208 {
1209 SCIPerrorMessage("left hand side of pseudo boolean constraint greater than right hand side\n");
1210 SCIPerrorMessage(" -> lhs=%g, rhs=%g\n", lhs, rhs);
1211 return SCIP_INVALIDDATA;
1212 }
1213
1214 transformed = SCIPisTransformed(scip);
1215
1216 /* allocate memory for the constraint data */
1217 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
1218
1219 /* initialize the weights for soft constraints */
1220 (*consdata)->issoftcons = issoftcons;
1221 if( issoftcons )
1222 {
1223 (*consdata)->weight = weight;
1224 if( transformed )
1225 {
1226 SCIP_CALL( SCIPgetTransformedVar(scip, indvar, &((*consdata)->indvar)) );
1227 }
1228 else
1229 (*consdata)->indvar = indvar;
1230 }
1231 else
1232 (*consdata)->indvar = NULL;
1233
1234 /* copy artificial integer variable if it exist */
1235 if( intvar != NULL )
1236 {
1237 if( transformed )
1238 {
1239 SCIP_CALL( SCIPgetTransformedVar(scip, intvar, &((*consdata)->intvar)) );
1240 }
1241 else
1242 (*consdata)->intvar = intvar;
1243 }
1244 else
1245 (*consdata)->intvar = NULL;
1246
1247 /* copy linear constraint */
1248 (*consdata)->lincons = lincons;
1249 (*consdata)->linconstype = linconstype;
1250
1251 /* get transformed linear constraint and capture it if necessary */
1252 if( transforming )
1253 {
1254 /* do not capture the and constraint when scip is in transformed mode; this automatically happens in
1255 * SCIPtransformCons()
1256 */
1257 SCIP_CALL( SCIPtransformCons(scip, (*consdata)->lincons, &((*consdata)->lincons)) );
1258 assert((*consdata)->lincons != NULL);
1259 }
1260
1261 if( transforming || transformed )
1262 {
1263 assert(SCIPconsIsTransformed((*consdata)->lincons));
1264
1265 /* we want to check all necessary transformed linear constraints */
1266 SCIP_CALL( SCIPsetConsChecked(scip, (*consdata)->lincons, check) );
1267 }
1268
1269 /* get number of non-linear terms in pseudoboolean constraint */
1270 SCIP_CALL( getLinearConsNVars(scip, (*consdata)->lincons, (*consdata)->linconstype, &nvars) );
1271 (*consdata)->nlinvars = nvars - nandconss;
1272
1273 /* copy and-constraints */
1274 if( nandconss > 0 )
1275 {
1276 SCIP_CONSHDLRDATA* conshdlrdata;
1277 SCIP_VAR** andress;
1278 int c;
1279
1280 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &((*consdata)->consanddatas), nandconss) );
1281 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &((*consdata)->andcoefs), andcoefs, nandconss) );
1282 if( andnegs != NULL )
1283 {
1284 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &((*consdata)->andnegs), andnegs, nandconss) );
1285 }
1286 else
1287 {
1288 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &((*consdata)->andnegs), nandconss) );
1289 }
1290 (*consdata)->nconsanddatas = nandconss;
1291 (*consdata)->sconsanddatas = nandconss;
1292
1293 /* allocate temporary memory */
1294 SCIP_CALL( SCIPallocBufferArray(scip, &andress, nandconss) );
1295
1296 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1297 assert(conshdlrdata != NULL);
1298 assert(conshdlrdata->hashmap != NULL);
1299
1300 /* get all and-resultants for sorting */
1301 for( c = nandconss - 1; c >= 0; --c )
1302 {
1303 assert(andconss[c] != NULL);
1304
1305 andress[c] = SCIPgetResultantAnd(scip, andconss[c]);
1306 assert(andress[c] != NULL);
1307
1308 (*consdata)->consanddatas[c] = (CONSANDDATA*) SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)andress[c]);
1309 assert((*consdata)->consanddatas[c] != NULL);
1310 assert((*consdata)->consanddatas[c]->origcons == andconss[c] || (*consdata)->consanddatas[c]->cons == andconss[c]);
1311
1312 if( transforming )
1313 {
1314 /* if we perform a new transformation, we need to capture the transformed constraint */
1315 if( (*consdata)->consanddatas[c]->origcons != NULL && (*consdata)->consanddatas[c]->cons == NULL )
1316 {
1317 SCIP_VAR** vars;
1318 int ncvars;
1319 int v;
1320
1321 /* do not capture the and constraint when scip is in transformed mode; this automatically happens in
1322 * SCIPtransformCons()
1323 */
1324 SCIP_CALL( SCIPtransformCons(scip, (*consdata)->consanddatas[c]->origcons, &((*consdata)->consanddatas[c]->cons)) );
1325 assert((*consdata)->consanddatas[c]->cons != NULL);
1326 assert((*consdata)->consanddatas[c]->newvars == NULL);
1327 assert((*consdata)->consanddatas[c]->isoriginal);
1328
1329 (*consdata)->consanddatas[c]->istransformed = TRUE;
1330
1331 vars = (*consdata)->consanddatas[c]->vars;
1332 ncvars = (*consdata)->consanddatas[c]->nvars;
1333 assert(vars != NULL || ncvars == 0);
1334
1335 /* get transformed variables */
1336 SCIP_CALL( SCIPgetTransformedVars(scip, ncvars, vars, vars) );
1337
1338 /* resort variables in transformed problem, because the order might change while tranforming */
1339 SCIPsortPtr((void**)vars, SCIPvarComp, ncvars);
1340
1341 /* capture all transformed variables */
1342 for( v = ncvars - 1; v >= 0; --v )
1343 {
1344 SCIP_CALL( SCIPcaptureVar(scip, vars[v]) ); /*lint !e613*/
1345 }
1346 }
1347 else if( (*consdata)->consanddatas[c]->cons != NULL )
1348 assert((*consdata)->consanddatas[c]->istransformed);
1349
1350 ++((*consdata)->consanddatas[c]->nuses);
1351 }
1352 else if( transformed )
1353 {
1354 assert((*consdata)->consanddatas[c]->cons == andconss[c]);
1355 assert(SCIPconsIsTransformed(andconss[c]));
1356 assert((*consdata)->consanddatas[c]->istransformed);
1357 }
1358 }
1359
1360 /* sort and-constraints after problem indices of corresponding and-resultants */
1361 SCIPsortPtrPtrRealBool((void**)andress, (void**)((*consdata)->consanddatas), (*consdata)->andcoefs, (*consdata)->andnegs, resvarComp, nandconss);
1362
1363 /* free temporary memory */
1364 SCIPfreeBufferArray(scip, &andress);
1365 }
1366 else
1367 {
1368 (*consdata)->consanddatas = NULL;
1369 (*consdata)->andcoefs = NULL;
1370 (*consdata)->andnegs = NULL;
1371 (*consdata)->nconsanddatas = 0;
1372 (*consdata)->sconsanddatas = 0;
1373 }
1374
1375 /* copy left and right hand side */
1376 (*consdata)->lhs = lhs;
1377 (*consdata)->rhs = rhs;
1378
1379 (*consdata)->changed = TRUE;
1380 (*consdata)->propagated = FALSE;
1381 (*consdata)->presolved = FALSE;
1382 (*consdata)->cliquesadded = FALSE;
1383 (*consdata)->upgradetried = TRUE;
1384
1385 /* count number of used consanddata objects in original problem */
1387 {
1388 SCIP_CONSHDLRDATA* conshdlrdata;
1389 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1390 assert(conshdlrdata != NULL);
1391
1392 conshdlrdata->noriguses += (*consdata)->nconsanddatas;
1393 }
1394
1395 return SCIP_OKAY;
1396}
1397
1398/** free a pseudo boolean constraint data */
1399static
1401 SCIP*const scip, /**< SCIP data structure */
1402 SCIP_CONSDATA** consdata, /**< pointer to linear constraint data */
1403 SCIP_Bool isorig, /**< are we freeing an original constraint? */
1404 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
1405 )
1406{
1407 CONSANDDATA** consanddatas;
1408 int nconsanddatas;
1409 int c;
1410
1411 assert(scip != NULL);
1412 assert(consdata != NULL);
1413 assert(*consdata != NULL);
1414 assert((*consdata)->nconsanddatas == 0 || (*consdata)->consanddatas != NULL);
1415 assert(conshdlrdata != NULL);
1416
1417 /* release linear constraint */
1418 if( (*consdata)->lincons != NULL )
1419 {
1420 SCIP_CALL( SCIPreleaseCons(scip, &((*consdata)->lincons)) );
1421 }
1422
1423 nconsanddatas = (*consdata)->nconsanddatas;
1424 consanddatas = (*consdata)->consanddatas;
1425
1426 /* count down uses and if necessary release constraints and delete data from hashtable and -map */
1427 for( c = nconsanddatas - 1; c >= 0; --c )
1428 {
1429 assert((consanddatas[c]->origcons == NULL) == (consanddatas[c]->noriguses == 0));
1430 assert((consanddatas[c]->cons == NULL) == (consanddatas[c]->nuses == 0));
1431 assert(consanddatas[c]->nuses >= 0);
1432 assert(consanddatas[c]->noriguses >= 0);
1433 assert(isorig ? consanddatas[c]->cons == NULL : TRUE);
1434
1435 /* are we deleteing a transformed constraint */
1436 if( !isorig && consanddatas[c]->cons != NULL )
1437 {
1438 assert(!SCIPconsIsOriginal(consanddatas[c]->cons));
1439
1440 --(consanddatas[c]->nuses);
1441
1442 /* if the consanddata is not used anymore, release the constraint and clear the hashmap- and table */
1443 if( consanddatas[c]->nuses == 0 )
1444 {
1445 if( conshdlrdata->inithashmapandtable )
1446 {
1447 assert(conshdlrdata->hashmap != NULL);
1448 assert(conshdlrdata->hashtable != NULL);
1449
1450 /* remove consanddata from hashtable, if it existed only in transformed space */
1451 if( consanddatas[c]->origcons == NULL )
1452 {
1453 assert(SCIPhashtableExists(conshdlrdata->hashtable, (void*)consanddatas[c]));
1454 SCIP_CALL( SCIPhashtableRemove(conshdlrdata->hashtable, (void*)consanddatas[c]) );
1455 }
1456 assert(SCIPhashmapExists(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddatas[c]->cons)));
1457 SCIP_CALL( SCIPhashmapRemove(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddatas[c]->cons)) );
1458 }
1459
1460 SCIP_CALL( SCIPreleaseCons(scip, &(consanddatas[c]->cons)) );
1461
1462 /* if the consanddata object was only used in transformed space, delete the memory block */
1463 if( consanddatas[c]->origcons == NULL )
1464 {
1465 int d;
1466
1467 assert(conshdlrdata->nallconsanddatas > 0);
1468
1469 for( d = conshdlrdata->nallconsanddatas - 1; d >= 0; --d )
1470 {
1471 if( conshdlrdata->allconsanddatas[d] == consanddatas[c] )
1472 {
1473 --conshdlrdata->nallconsanddatas;
1474
1475 SCIPfreeBlockMemory(scip, &(conshdlrdata->allconsanddatas[d])); /*lint !e866*/
1476
1477 conshdlrdata->allconsanddatas[d] = conshdlrdata->allconsanddatas[conshdlrdata->nallconsanddatas];
1478 break;
1479 }
1480 }
1481 assert(d >= 0);
1482 continue;
1483 }
1484 }
1485 }
1486 /* are we deleteing an original constraint */
1487 else if( isorig && consanddatas[c]->origcons != NULL )
1488 {
1489 assert(SCIPconsIsOriginal(consanddatas[c]->origcons));
1490 assert(consanddatas[c]->nuses == 0);
1491 assert(consanddatas[c]->nnewvars == 0);
1492 assert(consanddatas[c]->snewvars == 0);
1493 assert(consanddatas[c]->newvars == NULL);
1494
1495 --(consanddatas[c]->noriguses);
1496
1497 /* if the consanddata is not used anymore, release the constraint and clear the hashmap- and table */
1498 if( consanddatas[c]->noriguses == 0 )
1499 {
1500 int d;
1501
1502 if( conshdlrdata->inithashmapandtable )
1503 {
1504 assert(conshdlrdata->hashmap != NULL);
1505 assert(conshdlrdata->hashtable != NULL);
1506
1507 assert(SCIPhashtableExists(conshdlrdata->hashtable, (void*)consanddatas[c]));
1508 SCIP_CALL( SCIPhashtableRemove(conshdlrdata->hashtable, (void*)consanddatas[c]) );
1509
1510 assert(SCIPhashmapExists(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddatas[c]->origcons)));
1511 SCIP_CALL( SCIPhashmapRemove(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddatas[c]->origcons)) );
1512 }
1513
1514 if( consanddatas[c]->vars != NULL )
1515 {
1516 assert(consanddatas[c]->nvars > 0);
1517 assert(consanddatas[c]->svars > 0);
1518 assert(consanddatas[c]->svars >= consanddatas[c]->nvars);
1519
1520 SCIPfreeBlockMemoryArrayNull(scip, &(consanddatas[c]->vars), consanddatas[c]->svars);
1521 consanddatas[c]->nvars = 0;
1522 consanddatas[c]->svars = 0;
1523 }
1524 else
1525 {
1526 assert(consanddatas[c]->nvars == 0);
1527 assert(consanddatas[c]->svars == 0);
1528 }
1529
1530 SCIP_CALL( SCIPreleaseCons(scip, &(consanddatas[c]->origcons)) );
1531 assert(consanddatas[c]->origcons == NULL);
1532
1533 /* delete consanddata object */
1534 assert(conshdlrdata->nallconsanddatas > 0);
1535 for( d = conshdlrdata->nallconsanddatas - 1; d >= 0; --d )
1536 {
1537 if( conshdlrdata->allconsanddatas[d] == consanddatas[c] )
1538 {
1539 --conshdlrdata->nallconsanddatas;
1540
1541 SCIPfreeBlockMemory(scip, &(conshdlrdata->allconsanddatas[d])); /*lint !e866*/
1542
1543 conshdlrdata->allconsanddatas[d] = conshdlrdata->allconsanddatas[conshdlrdata->nallconsanddatas];
1544 break;
1545 }
1546 }
1547 assert(d >= 0);
1548
1549 continue;
1550 }
1551 }
1552 else
1553 {
1554 assert(!consanddatas[c]->istransformed);
1555 assert(consanddatas[c]->cons == NULL);
1556 }
1557
1558 /* clear and remove capture of transformed consanddata */
1559 if( consanddatas[c]->nuses == 0 && consanddatas[c]->istransformed )
1560 {
1561 SCIP_CALL( transformToOrig(scip, consanddatas[c], conshdlrdata) );
1562 }
1563#ifndef NDEBUG
1564 else if( consanddatas[c]->nuses == 0 )
1565 {
1566 SCIP_VAR** tmpvars;
1567 int ntmpvars;
1568 int v;
1569
1570 assert(consanddatas[c]->nnewvars == 0);
1571 assert(consanddatas[c]->snewvars == 0);
1572 assert(consanddatas[c]->newvars == NULL);
1573
1574 tmpvars = consanddatas[c]->vars;
1575 ntmpvars = consanddatas[c]->nvars;
1576
1577 /* release all variables */
1578 for( v = ntmpvars - 1; v >= 0; --v )
1579 {
1580 assert(tmpvars[v] != NULL);
1581 assert(SCIPvarIsOriginal(tmpvars[v]));
1582 }
1583 }
1584#endif
1585
1586 /* restore original data */
1587 if( !consanddatas[c]->istransformed && consanddatas[c]->noriguses > 0 )
1588 {
1589 assert(consanddatas[c]->origcons != NULL);
1590 assert(consanddatas[c]->nuses == 0);
1591 assert(consanddatas[c]->nnewvars == 0);
1592 assert(consanddatas[c]->snewvars == 0);
1593 assert(consanddatas[c]->newvars == NULL);
1594 assert(consanddatas[c]->nvars > 0);
1595 assert(consanddatas[c]->svars > 0);
1596 assert(consanddatas[c]->svars >= consanddatas[c]->nvars);
1597 assert(consanddatas[c]->vars != NULL);
1598 assert(consanddatas[c]->isoriginal);
1599
1600 assert(consanddatas[c]->nvars == SCIPgetNVarsAnd(scip, consanddatas[c]->origcons));
1601 assert(SCIPgetVarsAnd(scip, consanddatas[c]->origcons) != NULL);
1602
1603 /* check that the hash map and tabkle are still having all information */
1604 if( conshdlrdata->inithashmapandtable )
1605 {
1606 assert(conshdlrdata->hashmap != NULL);
1607 assert(conshdlrdata->hashtable != NULL);
1608 assert(SCIPgetResultantAnd(scip, consanddatas[c]->origcons) != NULL);
1609 assert(SCIPhashtableExists(conshdlrdata->hashtable, (void*)consanddatas[c]));
1610 assert(consanddatas[c] == (CONSANDDATA*)(SCIPhashtableRetrieve(conshdlrdata->hashtable, (void*)consanddatas[c])));
1611 assert(SCIPhashmapExists(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddatas[c]->origcons)));
1612 assert(consanddatas[c] == (CONSANDDATA*)(SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddatas[c]->origcons))));
1613 }
1614 }
1615 }
1616
1617 /* free array of and-constraints */
1618 SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->andnegs), (*consdata)->sconsanddatas);
1619 SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->andcoefs), (*consdata)->sconsanddatas);
1620 SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->consanddatas), (*consdata)->sconsanddatas);
1621
1622 SCIPfreeBlockMemory(scip, consdata);
1623
1624 return SCIP_OKAY;
1625}
1626
1627/** check the locks of an AND resultant and removes it from all global structures if the resultant is not locked anymore */
1628static
1630 SCIP*const scip, /**< SCIP data structure */
1631 SCIP_VAR* res /**< resultant of AND constraint */
1632 )
1633{
1634 assert(scip != NULL);
1635 assert(res != NULL);
1636
1637 /* the resultant has no locks left and might be dual fixed now, we need to delete all its cliques */
1640 {
1642 }
1643
1644 return SCIP_OKAY;
1645}
1646
1647/** installs rounding locks for the given and-constraint associated with given coefficient */
1648static
1650 SCIP*const scip, /**< SCIP data structure */
1651 SCIP_CONS*const cons, /**< pseudoboolean constraint */
1652 CONSANDDATA*const consanddata, /**< CONSANDDATA object for which we want to add the locks */
1653 SCIP_Real const coef, /**< coefficient which led to old locks */
1654 SCIP_Real const lhs, /**< left hand side */
1655 SCIP_Real const rhs /**< right hand side */
1656 )
1657{
1658 SCIP_VAR** vars;
1659 int nvars;
1660 SCIP_VAR* res;
1661 SCIP_Bool haslhs;
1662 SCIP_Bool hasrhs;
1663 int v;
1664
1665 assert(scip != NULL);
1666 assert(cons != NULL);
1668 assert(consanddata != NULL);
1669 assert(!SCIPisInfinity(scip, coef) && !SCIPisInfinity(scip, -coef));
1670 assert(!SCIPisInfinity(scip, lhs));
1671 assert(!SCIPisInfinity(scip, -rhs));
1672 assert(SCIPisLE(scip, lhs, rhs));
1673
1674 /* choose correct variable array to add locks for, we only add locks for now valid variables */
1675 if( consanddata->nnewvars > 0 )
1676 {
1677 vars = consanddata->newvars;
1678 nvars = consanddata->nnewvars;
1679 }
1680 else
1681 {
1682 vars = consanddata->vars;
1683 nvars = consanddata->nvars;
1684 }
1685
1686 res = SCIPgetResultantAnd(scip, consanddata->cons);
1687 assert(nvars == 0 || (vars != NULL && res != NULL));
1688
1689 /* check which sites are infinity */
1690 haslhs = !SCIPisInfinity(scip, -lhs);
1691 hasrhs = !SCIPisInfinity(scip, rhs);
1692
1693 if( SCIPconsIsLocked(cons) )
1694 {
1695 /* locking variables */
1696 if( SCIPisPositive(scip, coef) )
1697 {
1698 for( v = nvars - 1; v >= 0; --v )
1699 {
1700 SCIP_CALL( SCIPlockVarCons(scip, vars[v], cons, haslhs, hasrhs) );
1701 }
1702 }
1703 else
1704 {
1705 for( v = nvars - 1; v >= 0; --v )
1706 {
1707 SCIP_CALL( SCIPlockVarCons(scip, vars[v], cons, hasrhs, haslhs) );
1708 }
1709 }
1710 SCIP_CALL( SCIPlockVarCons(scip, res, cons, TRUE, TRUE) );
1711 }
1712
1713 return SCIP_OKAY;
1714}
1715
1716/** removes rounding locks for the given and-constraint associated with given coefficient */
1717static
1719 SCIP*const scip, /**< SCIP data structure */
1720 SCIP_CONS*const cons, /**< pseudoboolean constraint */
1721 CONSANDDATA*const consanddata, /**< CONSANDDATA object for which we want to delete the locks */
1722 SCIP_Real const coef, /**< coefficient which led to old locks */
1723 SCIP_Real const lhs, /**< left hand side which led to old locks */
1724 SCIP_Real const rhs /**< right hand side which led to old locks */
1725 )
1726{
1727 SCIP_VAR** vars;
1728 int nvars;
1729 SCIP_VAR* res;
1730 SCIP_Bool haslhs;
1731 SCIP_Bool hasrhs;
1732 int v;
1733
1734 assert(scip != NULL);
1735 assert(cons != NULL);
1737 assert(consanddata != NULL);
1738 assert(!SCIPisInfinity(scip, coef) && !SCIPisInfinity(scip, -coef));
1739 assert(!SCIPisInfinity(scip, lhs));
1740 assert(!SCIPisInfinity(scip, -rhs));
1741 assert(SCIPisLE(scip, lhs, rhs));
1742
1743 vars = consanddata->vars;
1744 nvars = consanddata->nvars;
1745
1746 if( consanddata->cons != NULL )
1747 res = SCIPgetResultantAnd(scip, consanddata->cons);
1748 else
1749 res = NULL;
1750 assert(nvars == 0 || vars != NULL);
1751
1752 /* check which sites are infinity */
1753 haslhs = !SCIPisInfinity(scip, -lhs);
1754 hasrhs = !SCIPisInfinity(scip, rhs);
1755
1756 if( SCIPconsIsLocked(cons) )
1757 {
1758 /* unlock variables */
1759 if( SCIPisPositive(scip, coef) )
1760 {
1761 for( v = nvars - 1; v >= 0; --v )
1762 {
1763 SCIP_CALL( SCIPunlockVarCons(scip, vars[v], cons, haslhs, hasrhs) );
1764 }
1765 }
1766 else
1767 {
1768 for( v = nvars - 1; v >= 0; --v )
1769 {
1770 SCIP_CALL( SCIPunlockVarCons(scip, vars[v], cons, hasrhs, haslhs) );
1771 }
1772 }
1773
1774 if( res != NULL )
1775 {
1776 SCIP_CALL( SCIPunlockVarCons(scip, res, cons, TRUE, TRUE) );
1777
1779 }
1780 }
1781
1782 return SCIP_OKAY;
1783}
1784
1785/** prints pseudoboolean constraint in CIP format to file stream */
1786static
1788 SCIP*const scip, /**< SCIP data structure */
1789 SCIP_CONS*const cons, /**< pseudoboolean constraint */
1790 FILE*const file /**< output file (or NULL for standard output) */
1791 )
1792{
1793 SCIP_CONSHDLR* conshdlr;
1794 SCIP_CONSHDLRDATA* conshdlrdata;
1795 SCIP_CONSDATA* consdata;
1796 SCIP_VAR*** monomialvars;
1797 SCIP_VAR** vars;
1798 SCIP_Real* coefs;
1799 SCIP_Real* monomialcoefs;
1800 SCIP_Real lhs;
1801 SCIP_Real rhs;
1802 int* monomialnvars;
1803 int nvars;
1804 int nmonomials;
1805 int v;
1806
1807 assert(scip != NULL);
1808 assert(cons != NULL);
1809
1810 consdata = SCIPconsGetData(cons);
1811 assert(consdata != NULL);
1812 assert(consdata->intvar == NULL);
1813 assert(consdata->lincons != NULL);
1814
1815 /* gets number of variables in linear constraint */
1816 SCIP_CALL( getLinearConsNVars(scip, consdata->lincons, consdata->linconstype, &nvars) );
1817
1818 /* every variable in the linear constraint is either a linear variable or a term variable
1819 * but there can be additional fixed or negation-paired and-resultants with relevant and-constraints
1820 * whose values are already resolved in the linear constraint
1821 */
1822 assert(consdata->nlinvars + consdata->nconsanddatas >= nvars);
1823
1824 /* initialize buffers for storing the terms and coefficients */
1825 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
1826 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
1827 SCIP_CALL( SCIPallocBufferArray(scip, &monomialvars, nvars) );
1828 SCIP_CALL( SCIPallocBufferArray(scip, &monomialcoefs, nvars) );
1829 SCIP_CALL( SCIPallocBufferArray(scip, &monomialnvars, nvars) );
1830
1831 /* get sides of linear constraint */
1832 SCIP_CALL( getLinearConsSides(scip, consdata->lincons, consdata->linconstype, &lhs, &rhs) );
1833 assert(!SCIPisInfinity(scip, lhs));
1834 assert(!SCIPisInfinity(scip, -rhs));
1835 assert(SCIPisLE(scip, lhs, rhs));
1836
1837 /* get variables and coefficient of linear constraint */
1838 SCIP_CALL( getLinearConsVarsData(scip, consdata->lincons, consdata->linconstype, vars, coefs, &nvars) );
1839 assert(nvars == 0 || (coefs != NULL));
1840
1841 /* get and-data hashmap */
1842 conshdlr = SCIPconsGetHdlr(cons);
1843 assert(conshdlr != NULL);
1844 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1845 assert(conshdlrdata != NULL);
1846 assert(conshdlrdata->hashmap != NULL);
1847 nmonomials = 0;
1848
1849 /* collect all terms */
1850 for( v = 0; v < nvars; ++v )
1851 {
1852 CONSANDDATA* consanddata = NULL;
1853 SCIP_VAR** andvars = NULL;
1854 SCIP_VAR* var = vars[v];
1855 int nandvars = 0;
1856
1857 assert(SCIPvarIsBinary(var));
1858
1859 /* find and-constraint to standard or negated and-resultant */
1860 do
1861 {
1862 /* @todo: drop indicator variable */
1863 assert(!consdata->issoftcons || var != consdata->indvar);
1864 consanddata = (CONSANDDATA*)SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)var);
1865
1866 if( consanddata != NULL )
1867 {
1868 SCIP_CONS* andcons = SCIPconsIsOriginal(cons) ? consanddata->origcons : consanddata->cons;
1869
1870 andvars = SCIPgetVarsAnd(scip, andcons);
1871 nandvars = SCIPgetNVarsAnd(scip, andcons);
1872
1873 break;
1874 }
1875
1876 var = var == vars[v] ? SCIPvarGetNegatedVar(var) : vars[v];
1877 }
1878 while( var != vars[v] );
1879
1880 if( consanddata == NULL )
1881 {
1882 assert(var != NULL);
1883 assert(var == vars[v]);
1884 monomialvars[nmonomials] = vars + v;
1885 monomialnvars[nmonomials] = 1;
1886 }
1887 else
1888 {
1889 SCIP_Bool fixed = nandvars == 0;
1890 SCIP_Bool negated = var != vars[v];
1891
1892 if( fixed != negated )
1893 {
1894 if( !SCIPisInfinity(scip, -lhs) )
1895 lhs -= coefs[v];
1896
1897 if( !SCIPisInfinity(scip, rhs) )
1898 rhs -= coefs[v];
1899 }
1900
1901 if( fixed )
1902 continue;
1903
1904 if( negated )
1905 coefs[v] *= -1.0;
1906
1907 assert(andvars != NULL);
1908 monomialvars[nmonomials] = andvars;
1909 assert(nandvars >= 1);
1910 monomialnvars[nmonomials] = nandvars;
1911 }
1912
1913 assert(!SCIPisZero(scip, coefs[v]));
1914 monomialcoefs[nmonomials] = coefs[v];
1915 ++nmonomials;
1916 }
1917
1918 /* print left side */
1919 if( !SCIPisInfinity(scip, -lhs) && !SCIPisInfinity(scip, rhs) && lhs != rhs ) /*lint !e777*/
1920 SCIPinfoMessage(scip, file, "%.15g <= ", lhs);
1921
1922 /* print pseudoboolean polynomial */
1923 SCIP_CALL( SCIPwriteVarsPolynomial(scip, file, monomialvars, NULL, monomialcoefs, monomialnvars, nmonomials, TRUE) );
1924
1925 /* print right side */
1926 if( lhs == rhs ) /*lint !e777*/
1927 SCIPinfoMessage(scip, file, " == %.15g", rhs);
1928 else if( !SCIPisInfinity(scip, rhs) )
1929 SCIPinfoMessage(scip, file, " <= %.15g", rhs);
1930 else if( !SCIPisInfinity(scip, -lhs) )
1931 SCIPinfoMessage(scip, file, " >= %.15g", lhs);
1932 else
1933 SCIPinfoMessage(scip, file, " [free]");
1934
1935 /* free buffers for storing the terms and coefficients */
1936 SCIPfreeBufferArray(scip, &monomialnvars);
1937 SCIPfreeBufferArray(scip, &monomialcoefs);
1938 SCIPfreeBufferArray(scip, &monomialvars);
1939 SCIPfreeBufferArray(scip, &coefs);
1940 SCIPfreeBufferArray(scip, &vars);
1941
1942 /* print indicator variable if soft constraint */
1943 if( consdata->issoftcons )
1944 {
1945 SCIPinfoMessage(scip, file, " (indvar = ");
1946 SCIP_CALL( SCIPwriteVarName(scip, file, consdata->indvar, TRUE) );
1947 SCIPinfoMessage(scip, file, ")");
1948 assert(consdata->weight == SCIPvarGetObj(consdata->indvar)); /*lint !e777*/
1949 }
1950
1951 return SCIP_OKAY;
1952}
1953
1954/** creates and/or adds the resultant for a given term */
1955static
1957 SCIP*const scip, /**< SCIP data structure */
1958 SCIP_CONSHDLR*const conshdlr, /**< pseudoboolean constraint handler */
1959 SCIP_VAR**const vars, /**< array of variables to get and-constraints for */
1960 int const nvars, /**< number of variables to get and-constraints for */
1961 SCIP_Bool const initial, /**< should the LP relaxation of constraint be in the initial LP?
1962 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1963 SCIP_Bool const enforce, /**< should the constraint be enforced during node processing?
1964 * TRUE for model constraints, FALSE for additional, redundant
1965 * constraints. */
1966 SCIP_Bool const check, /**< should the constraint be checked for feasibility?
1967 * TRUE for model constraints, FALSE for additional, redundant
1968 * constraints. */
1969 SCIP_Bool const local, /**< is constraint only valid locally?
1970 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching
1971 * constraints. */
1972 SCIP_Bool const modifiable, /**< is constraint modifiable (subject to column generation)?
1973 * Usually set to FALSE. In column generation applications, set to TRUE
1974 * if pricing adds coefficients to this constraint. */
1975 SCIP_Bool const dynamic, /**< is constraint subject to aging?
1976 * Usually set to FALSE. Set to TRUE for own cuts which
1977 * are seperated as constraints. */
1978 SCIP_Bool const stickingatnode, /**< should the constraint always be kept at the node where it was added, even
1979 * if it may be moved to a more global node?
1980 * Usually set to FALSE. Set to TRUE to for constraints that represent
1981 * node data. */
1982 SCIP_CONS**const andcons /**< pointer to store and-constraint */
1983 )
1984{
1985 CONSANDDATA* newdata;
1986 CONSANDDATA* tmpdata;
1987 SCIP_CONSHDLRDATA* conshdlrdata;
1988 char name[SCIP_MAXSTRLEN];
1989 SCIP_Bool separate;
1990 SCIP_Bool propagate;
1991 SCIP_Bool removable;
1992 SCIP_Bool transformed;
1993
1994 assert(scip != NULL);
1995 assert(conshdlr != NULL);
1996 assert(vars != NULL);
1997 assert(nvars > 0);
1998 assert(andcons != NULL);
1999
2000 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2001 assert(conshdlrdata != NULL);
2002 assert(conshdlrdata->hashtable != NULL);
2003
2004 transformed = SCIPisTransformed(scip);
2005
2006 /* allocate memory for a possible new consanddata object */
2007 SCIP_CALL( SCIPallocBlockMemory(scip, &newdata) );
2008 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(newdata->vars), vars, nvars) );
2009 newdata->nvars = nvars;
2010 newdata->svars = nvars;
2011 newdata->newvars = NULL;
2012 newdata->nnewvars = 0;
2013 newdata->snewvars = 0;
2014 newdata->noriguses = 0;
2015 newdata->nuses = 0;
2016 newdata->istransformed = transformed;
2017 newdata->isoriginal = !transformed;
2018 newdata->cons = NULL;
2019 newdata->origcons = NULL;
2020
2021 /* sort variables */
2022 SCIPsortPtr((void**)(newdata->vars), SCIPvarComp, nvars);
2023
2024 /* get constraint from current hash table with same variables as cons0 */
2025 tmpdata = (CONSANDDATA*)(SCIPhashtableRetrieve(conshdlrdata->hashtable, (void*)newdata));
2026
2027 /* if there is already the same and constraint created use this resultant */
2028 if( tmpdata != NULL )
2029 {
2030#ifndef NDEBUG
2031 SCIP_VAR* res;
2032#endif
2033 if( transformed )
2034 {
2035 assert(tmpdata->cons != NULL);
2036 *andcons = tmpdata->cons;
2037
2038 assert(tmpdata->nuses > 0);
2039 /* increase usage of data object */
2040 ++(tmpdata->nuses);
2041 }
2042 else
2043 {
2044 assert(tmpdata->origcons != NULL);
2045 *andcons = tmpdata->origcons;
2046
2047 assert(tmpdata->noriguses > 0);
2048 /* increase usage of data object */
2049 ++(tmpdata->noriguses);
2050 }
2051 assert(*andcons != NULL);
2052
2053#ifndef NDEBUG
2054 res = SCIPgetResultantAnd(scip, *andcons);
2055 assert(res != NULL);
2056
2057 /* check that we already have added this resultant to and-constraint entry */
2058 assert(SCIPhashmapExists(conshdlrdata->hashmap, (void*)res));
2059#endif
2060 }
2061 else
2062 {
2063 /* create new and-constraint */
2064 SCIP_CONS* newcons;
2065 SCIP_VAR* resultant;
2066
2067 /* create auxiliary variable */
2068 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, ARTIFICIALVARNAMEPREFIX"%d", conshdlrdata->nallconsanddatas);
2069 SCIP_CALL( SCIPcreateVar(scip, &resultant, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY,
2070 TRUE, TRUE, NULL, NULL, NULL, NULL, NULL) );
2071
2072 /* @todo: branch on artificial variables, the test results show that it is of advantage */
2073 /* change branching priority of artificial variable to -1 */
2074 SCIP_CALL( SCIPchgVarBranchPriority(scip, resultant, -1) );
2075
2076 /* add auxiliary variable to the problem */
2077 SCIP_CALL( SCIPaddVar(scip, resultant) );
2078
2079 /* @todo: keep and-resultants defined to check debug solution */
2080#ifdef SCIP_DISABLED_CODE
2081#ifdef WITH_DEBUG_SOLUTION
2082 if( SCIPdebugIsMainscip(scip) )
2083 {
2084 SCIP_Real val;
2085 SCIP_Real debugsolval;
2086 int v;
2087
2088 for( v = nvars - 1; v >= 0; --v )
2089 {
2090 SCIP_CALL( SCIPdebugGetSolVal(scip, vars[v], &val) );
2091 assert(SCIPisFeasZero(scip, val) || SCIPisFeasEQ(scip, val, 1.0));
2092
2093 if( val < 0.5 )
2094 break;
2095 }
2096 val = ((val < 0.5) ? 0.0 : 1.0);
2097
2098 SCIP_CALL( SCIPdebugGetSolVal(scip, resultant, &debugsolval) );
2099 if( (SCIPvarIsOriginal(resultant) || SCIPvarIsTransformedOrigvar(resultant)) && !SCIPisFeasEQ(scip, debugsolval, val) )
2100 {
2101 SCIPerrorMessage("computed solution value %g for resultant <%s> violates debug solution value %g\n", val, SCIPvarGetName(resultant), debugsolval);
2102 SCIPABORT();
2103 return SCIP_ERROR; /*lint !e527*/
2104 }
2105 else if( !SCIPvarIsOriginal(resultant) && !SCIPvarIsTransformedOrigvar(resultant) )
2106 {
2107 SCIP_CALL( SCIPdebugAddSolVal(scip, resultant, val) );
2108 }
2109 }
2110#endif
2111#endif
2112
2113 SCIP_CALL( SCIPgetBoolParam(scip, "constraints/" CONSHDLR_NAME "/nlcseparate", &separate) );
2114 SCIP_CALL( SCIPgetBoolParam(scip, "constraints/" CONSHDLR_NAME "/nlcpropagate", &propagate) );
2115 SCIP_CALL( SCIPgetBoolParam(scip, "constraints/" CONSHDLR_NAME "/nlcremovable", &removable) );
2116
2117 /* we do not want to check the and constraints, so the check flag will be FALSE */
2118
2119 /* create and add "and" constraint for the multiplication of the binary variables */
2120 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "andcons_%d", conshdlrdata->nallconsanddatas);
2121 SCIP_CALL( SCIPcreateConsAnd(scip, &newcons, name, resultant, newdata->nvars, newdata->vars,
2122 initial, separate, enforce, check && FALSE, propagate,
2123 local, modifiable, dynamic, removable, stickingatnode) ); /*lint !e506*/
2124 SCIP_CALL( SCIPaddCons(scip, newcons) );
2125 SCIPdebugPrintCons(scip, newcons, NULL);
2126
2127 /* force all deriving constraint from this and constraint to be checked and not removable */
2130
2131 *andcons = newcons;
2132 assert(*andcons != NULL);
2133
2134 /* resize data for all and-constraints if necessary */
2135 if( conshdlrdata->nallconsanddatas == conshdlrdata->sallconsanddatas )
2136 {
2137 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &(conshdlrdata->allconsanddatas), &(conshdlrdata->sallconsanddatas), SCIPcalcMemGrowSize(scip, conshdlrdata->sallconsanddatas + 1)) );
2138 }
2139
2140 /* add new data object to global hash table */
2141 conshdlrdata->allconsanddatas[conshdlrdata->nallconsanddatas] = newdata;
2142 ++(conshdlrdata->nallconsanddatas);
2143
2144 if( transformed )
2145 {
2146 int v;
2147
2148 newdata->cons = newcons;
2149 SCIP_CALL( SCIPcaptureCons(scip, newdata->cons) );
2150
2151 /* initialize usage of data object */
2152 newdata->nuses = 1;
2153
2154 /* capture all variables */
2155 for( v = newdata->nvars - 1; v >= 0; --v )
2156 {
2157 SCIP_CALL( SCIPcaptureVar(scip, newdata->vars[v]) ); /*lint !e613*/
2158 }
2159 }
2160 else
2161 {
2162 newdata->origcons = newcons;
2163 SCIP_CALL( SCIPcaptureCons(scip, newdata->origcons) );
2164
2165 /* initialize usage of data object */
2166 newdata->noriguses = 1;
2167 }
2168
2169 /* no such and-constraint in current hash table: insert the new object into hash table */
2170 SCIP_CALL( SCIPhashtableInsert(conshdlrdata->hashtable, (void*)newdata) );
2171
2172 /* insert new mapping */
2173 assert(!SCIPhashmapExists(conshdlrdata->hashmap, (void*)resultant));
2174 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->hashmap, (void*)resultant, (void*)newdata) );
2175
2176 /* release and-resultant and -constraint */
2177 SCIP_CALL( SCIPreleaseVar(scip, &resultant) );
2178 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
2179
2180 return SCIP_OKAY;
2181 }
2182
2183 /* free memory */
2184 SCIPfreeBlockMemoryArray(scip, &(newdata->vars), newdata->svars);
2185 SCIPfreeBlockMemory(scip, &newdata);
2186
2187 return SCIP_OKAY;
2188}
2189
2190/** adds a term to the given pseudoboolean constraint */
2191static
2193 SCIP*const scip, /**< SCIP data structure */
2194 SCIP_CONS*const cons, /**< pseudoboolean constraint */
2195 SCIP_VAR**const vars, /**< variables of the nonlinear term */
2196 int const nvars, /**< number of variables of the nonlinear term */
2197 SCIP_Real const val /**< coefficient of constraint entry */
2198 )
2199{
2200 SCIP_CONSHDLR* conshdlr;
2201 SCIP_CONSHDLRDATA* conshdlrdata;
2202 SCIP_CONS* andcons;
2203 SCIP_CONSDATA* consdata;
2204 SCIP_VAR* res;
2205
2206 assert(scip != NULL);
2207 assert(cons != NULL);
2208 assert(nvars == 0 || vars != NULL);
2209
2210 if( nvars == 0 || SCIPisZero(scip, val) )
2211 return SCIP_OKAY;
2212
2213 consdata = SCIPconsGetData(cons);
2214 assert(consdata != NULL);
2215
2216 conshdlr = SCIPconsGetHdlr(cons);
2217 assert(conshdlr != NULL);
2218
2219 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2220 assert(conshdlrdata != NULL);
2221
2222 /* create (and add) and-constraint */
2223 SCIP_CALL( createAndAddAndCons(scip, conshdlr, vars, nvars,
2226 &andcons) );
2227 assert(andcons != NULL);
2228
2229 /* ensure memory size */
2230 if( consdata->nconsanddatas == consdata->sconsanddatas )
2231 {
2232 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &(consdata->consanddatas), &(consdata->sconsanddatas), consdata->sconsanddatas + 1) );
2233 }
2234
2235 res = SCIPgetResultantAnd(scip, andcons);
2236 assert(res != NULL);
2237 assert(SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)res) != NULL);
2238
2239 consdata->consanddatas[consdata->nconsanddatas] = (CONSANDDATA*) SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)res);
2240 ++(consdata->nconsanddatas);
2241
2242 /* add auxiliary variables to linear constraint */
2243 switch( consdata->linconstype )
2244 {
2246 SCIP_CALL( SCIPaddCoefLinear(scip, consdata->lincons, res, val) );
2247 break;
2249 if( !SCIPisEQ(scip, val, 1.0) )
2250 return SCIP_INVALIDDATA;
2251
2252 SCIP_CALL( SCIPaddCoefLogicor(scip, consdata->lincons, res) );
2253 break;
2255 if( !SCIPisIntegral(scip, val) || !SCIPisPositive(scip, val) )
2256 return SCIP_INVALIDDATA;
2257
2258 SCIP_CALL( SCIPaddCoefKnapsack(scip, consdata->lincons, res, (SCIP_Longint) val) );
2259 break;
2261 if( !SCIPisEQ(scip, val, 1.0) )
2262 return SCIP_INVALIDDATA;
2263
2264 SCIP_CALL( SCIPaddCoefSetppc(scip, consdata->lincons, res) );
2265 break;
2266#ifdef WITHEQKNAPSACK
2267 case SCIP_LINEARCONSTYPE_EQKNAPSACK:
2268 if( !SCIPisIntegral(scip, val) || !SCIPisPositive(scip, val) )
2269 return SCIP_INVALIDDATA;
2270
2271 SCIP_CALL( SCIPaddCoefEQKnapsack(scip, consdata->lincons, res, (SCIP_Longint) val) );
2272 break;
2273#endif
2275 default:
2276 SCIPerrorMessage("unknown linear constraint type\n");
2277 return SCIP_INVALIDDATA;
2278 }
2279
2280 /* install rounding locks for all new variable */
2281 SCIP_CALL( lockRoundingAndCons(scip, cons, consdata->consanddatas[consdata->nconsanddatas - 1], val, consdata->lhs, consdata->rhs) );
2282
2283 /* change flags */
2284 consdata->changed = TRUE;
2285 consdata->propagated = FALSE;
2286 consdata->presolved = FALSE;
2287 consdata->cliquesadded = FALSE;
2288 consdata->upgradetried = FALSE;
2289
2290 return SCIP_OKAY;
2291}
2292
2293/** changes left hand side of linear constraint */
2294static
2296 SCIP*const scip, /**< SCIP data structure */
2297 SCIP_CONS*const cons, /**< linear constraint */
2298 SCIP_LINEARCONSTYPE const constype, /**< linear constraint type */
2299 SCIP_Real const lhs /**< new left hand side of linear constraint */
2300 )
2301{
2302 switch( constype )
2303 {
2305 SCIP_CALL( SCIPchgLhsLinear(scip, cons, lhs) );
2306 break;
2310 SCIPerrorMessage("changing left hand side only allowed on standard lienar constraint \n");
2311 return SCIP_INVALIDDATA;
2312#ifdef WITHEQKNAPSACK
2313 case SCIP_LINEARCONSTYPE_EQKNAPSACK:
2314#endif
2316 default:
2317 SCIPerrorMessage("unknown linear constraint type\n");
2318 return SCIP_INVALIDDATA;
2319 }
2320
2321 return SCIP_OKAY;
2322}
2323
2324/** changes right hand side of linear constraint */
2325static
2327 SCIP*const scip, /**< SCIP data structure */
2328 SCIP_CONS*const cons, /**< linear constraint */
2329 SCIP_LINEARCONSTYPE const constype, /**< linear constraint type */
2330 SCIP_Real const rhs /**< new right hand side of linear constraint */
2331 )
2332{
2333 switch( constype )
2334 {
2336 SCIP_CALL( SCIPchgRhsLinear(scip, cons, rhs) );
2337 break;
2341 SCIPerrorMessage("changing left hand side only allowed on standard lienar constraint \n");
2342 return SCIP_INVALIDDATA;
2343#ifdef WITHEQKNAPSACK
2344 case SCIP_LINEARCONSTYPE_EQKNAPSACK:
2345#endif
2347 default:
2348 SCIPerrorMessage("unknown linear constraint type\n");
2349 return SCIP_INVALIDDATA;
2350 }
2351
2352 return SCIP_OKAY;
2353}
2354
2355/** sets left hand side of linear constraint */
2356static
2358 SCIP*const scip, /**< SCIP data structure */
2359 SCIP_CONS*const cons, /**< linear constraint */
2360 SCIP_Real lhs /**< new left hand side */
2361 )
2362{
2363 SCIP_CONSDATA* consdata;
2364 SCIP_VAR** vars;
2365 SCIP_Real* coefs;
2366 int nvars;
2367 SCIP_VAR** linvars;
2368 SCIP_Real* lincoefs;
2369 int nlinvars;
2370 SCIP_VAR** andress;
2371 SCIP_Real* andcoefs;
2372 SCIP_Bool* andnegs;
2373 int nandress;
2374 SCIP_Real oldlhs;
2375 SCIP_Real oldrhs;
2376
2377 assert(scip != NULL);
2378 assert(cons != NULL);
2380 assert(!SCIPisInfinity(scip, lhs));
2381
2382 /* adjust value to not be smaller than -inf */
2383 if ( SCIPisInfinity(scip, -lhs) )
2384 lhs = -SCIPinfinity(scip);
2385
2386 consdata = SCIPconsGetData(cons);
2387 assert(consdata != NULL);
2388
2389 /* get sides of linear constraint */
2390 SCIP_CALL( getLinearConsSides(scip, consdata->lincons, consdata->linconstype, &oldlhs, &oldrhs) );
2391 assert(!SCIPisInfinity(scip, oldlhs));
2392 assert(!SCIPisInfinity(scip, -oldrhs));
2393 assert(SCIPisLE(scip, oldlhs, oldrhs));
2394
2395 /* check whether the side is not changed */
2396 if( SCIPisEQ(scip, oldlhs, lhs) )
2397 return SCIP_OKAY;
2398
2399 /* gets number of variables in linear constraint */
2400 SCIP_CALL( getLinearConsNVars(scip, consdata->lincons, consdata->linconstype, &nvars) );
2401
2402 /* allocate temporary memory */
2403 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
2404 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
2405 SCIP_CALL( SCIPallocBufferArray(scip, &linvars, nvars) );
2406 SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, nvars) );
2407 SCIP_CALL( SCIPallocBufferArray(scip, &andress, nvars) );
2408 SCIP_CALL( SCIPallocBufferArray(scip, &andcoefs, nvars) );
2409 SCIP_CALL( SCIPallocBufferArray(scip, &andnegs, nvars) );
2410
2411 /* get variables and coefficient of linear constraint */
2412 SCIP_CALL( getLinearConsVarsData(scip, consdata->lincons, consdata->linconstype, vars, coefs, &nvars) );
2413 assert(nvars == 0 || (coefs != NULL));
2414
2415 /* calculate all not artificial linear variables and all artificial and-resultants */
2416 SCIP_CALL( getLinVarsAndAndRess(scip, cons, vars, coefs, nvars, linvars, lincoefs, &nlinvars, andress, andcoefs, andnegs, &nandress) );
2417 assert(consdata->nconsanddatas == nandress);
2418
2419 /* if necessary, update the rounding locks of variables */
2420 if( SCIPconsIsLocked(cons) )
2421 {
2422 SCIP_VAR** andvars;
2423 int nandvars;
2424 SCIP_Real val;
2425 int v;
2426 int c;
2427
2428 assert(SCIPconsIsTransformed(cons));
2429
2430 if( SCIPisInfinity(scip, -oldlhs) && !SCIPisInfinity(scip, -lhs) )
2431 {
2432 /* non-linear part */
2433 for( c = consdata->nconsanddatas - 1; c >= 0; --c )
2434 {
2435 CONSANDDATA* consanddata;
2436 SCIP_CONS* andcons;
2437
2438 consanddata = consdata->consanddatas[c];
2439 assert(consanddata != NULL);
2440
2441 andcons = consanddata->cons;
2442 assert(andcons != NULL);
2443
2444 andvars = SCIPgetVarsAnd(scip, andcons);
2445 nandvars = SCIPgetNVarsAnd(scip, andcons);
2446 val = andnegs[c] ? -andcoefs[c] : andcoefs[c];
2447
2448 /* lock variables */
2449 if( SCIPisPositive(scip, val) )
2450 {
2451 for( v = nandvars - 1; v >= 0; --v )
2452 {
2453 SCIP_CALL( SCIPlockVarCons(scip, andvars[v], cons, TRUE, FALSE) );
2454 }
2455 }
2456 else
2457 {
2458 for( v = nandvars - 1; v >= 0; --v )
2459 {
2460 SCIP_CALL( SCIPlockVarCons(scip, andvars[v], cons, FALSE, TRUE) );
2461 }
2462 }
2463 }
2464 }
2465 else if( !SCIPisInfinity(scip, -oldlhs) && SCIPisInfinity(scip, -lhs) )
2466 {
2467 /* non-linear part */
2468 for( c = consdata->nconsanddatas - 1; c >= 0; --c )
2469 {
2470 CONSANDDATA* consanddata;
2471 SCIP_CONS* andcons;
2472
2473 consanddata = consdata->consanddatas[c];
2474 assert(consanddata != NULL);
2475
2476 andcons = consanddata->cons;
2477 assert(andcons != NULL);
2478
2479 andvars = SCIPgetVarsAnd(scip, andcons);
2480 nandvars = SCIPgetNVarsAnd(scip, andcons);
2481 val = andnegs[c] ? -andcoefs[c] : andcoefs[c];
2482
2483 /* lock variables */
2484 if( SCIPisPositive(scip, val) )
2485 {
2486 for( v = nandvars - 1; v >= 0; --v )
2487 {
2488 SCIP_CALL( SCIPunlockVarCons(scip, andvars[v], cons, TRUE, FALSE) );
2489 }
2490 }
2491 else
2492 {
2493 for( v = nandvars - 1; v >= 0; --v )
2494 {
2495 SCIP_CALL( SCIPunlockVarCons(scip, andvars[v], cons, FALSE, TRUE) );
2496 }
2497 }
2498 }
2499 }
2500 }
2501
2502 /* 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 */
2503 if( SCIPisLT(scip, oldlhs, lhs) )
2504 {
2505 consdata->propagated = FALSE;
2506 }
2507
2508 /* set new left hand side and update constraint data */
2509 SCIP_CALL( chgLhsLinearCons(scip, consdata->lincons, consdata->linconstype, lhs) );
2510 consdata->lhs = lhs;
2511 consdata->presolved = FALSE;
2512 consdata->changed = TRUE;
2513
2514 /* free temporary memory */
2515 SCIPfreeBufferArray(scip, &andnegs);
2516 SCIPfreeBufferArray(scip, &andcoefs);
2517 SCIPfreeBufferArray(scip, &andress);
2518 SCIPfreeBufferArray(scip, &lincoefs);
2519 SCIPfreeBufferArray(scip, &linvars);
2520 SCIPfreeBufferArray(scip, &coefs);
2521 SCIPfreeBufferArray(scip, &vars);
2522
2523 return SCIP_OKAY;
2524}
2525
2526/** sets right hand side of pseudoboolean constraint */
2527static
2529 SCIP*const scip, /**< SCIP data structure */
2530 SCIP_CONS*const cons, /**< linear constraint */
2531 SCIP_Real rhs /**< new right hand side */
2532 )
2533{
2534 SCIP_CONSDATA* consdata;
2535 SCIP_VAR** vars;
2536 SCIP_Real* coefs;
2537 int nvars;
2538 SCIP_VAR** linvars;
2539 SCIP_Real* lincoefs;
2540 int nlinvars;
2541 SCIP_VAR** andress;
2542 SCIP_Real* andcoefs;
2543 SCIP_Bool* andnegs;
2544 int nandress;
2545 SCIP_Real oldlhs;
2546 SCIP_Real oldrhs;
2547
2548 assert(scip != NULL);
2549 assert(cons != NULL);
2551 assert(!SCIPisInfinity(scip, -rhs));
2552
2553 /* adjust value to not be larger than inf */
2554 if( SCIPisInfinity(scip, rhs) )
2555 rhs = SCIPinfinity(scip);
2556
2557 consdata = SCIPconsGetData(cons);
2558 assert(consdata != NULL);
2559
2560 /* get sides of linear constraint */
2561 SCIP_CALL( getLinearConsSides(scip, consdata->lincons, consdata->linconstype, &oldlhs, &oldrhs) );
2562 assert(!SCIPisInfinity(scip, oldlhs));
2563 assert(!SCIPisInfinity(scip, -oldrhs));
2564 assert(SCIPisLE(scip, oldlhs, oldrhs));
2565
2566 /* check whether the side is not changed */
2567 if( SCIPisEQ(scip, oldrhs, rhs) )
2568 return SCIP_OKAY;
2569
2570 /* gets number of variables in linear constraint */
2571 SCIP_CALL( getLinearConsNVars(scip, consdata->lincons, consdata->linconstype, &nvars) );
2572
2573 /* allocate temporary memory */
2574 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
2575 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
2576 SCIP_CALL( SCIPallocBufferArray(scip, &linvars, nvars) );
2577 SCIP_CALL( SCIPallocBufferArray(scip, &lincoefs, nvars) );
2578 SCIP_CALL( SCIPallocBufferArray(scip, &andress, nvars) );
2579 SCIP_CALL( SCIPallocBufferArray(scip, &andcoefs, nvars) );
2580 SCIP_CALL( SCIPallocBufferArray(scip, &andnegs, nvars) );
2581
2582 /* get variables and coefficient of linear constraint */
2583 SCIP_CALL( getLinearConsVarsData(scip, consdata->lincons, consdata->linconstype, vars, coefs, &nvars) );
2584 assert(nvars == 0 || (coefs != NULL));
2585
2586 /* calculate all not artificial linear variables and all artificial and-resultants */
2587 SCIP_CALL( getLinVarsAndAndRess(scip, cons, vars, coefs, nvars, linvars, lincoefs, &nlinvars, andress, andcoefs, andnegs, &nandress) );
2588 assert(consdata->nconsanddatas == nandress);
2589
2590 /* if necessary, update the rounding locks of variables */
2591 if( SCIPconsIsLocked(cons) )
2592 {
2593 SCIP_VAR** andvars;
2594 int nandvars;
2595 SCIP_Real val;
2596 int v;
2597 int c;
2598
2599 assert(SCIPconsIsTransformed(cons));
2600
2601 if( SCIPisInfinity(scip, oldrhs) && !SCIPisInfinity(scip, rhs) )
2602 {
2603 /* non-linear part */
2604 for( c = consdata->nconsanddatas - 1; c >= 0; --c )
2605 {
2606 CONSANDDATA* consanddata;
2607 SCIP_CONS* andcons;
2608
2609 consanddata = consdata->consanddatas[c];
2610 assert(consanddata != NULL);
2611
2612 andcons = consanddata->cons;
2613 assert(andcons != NULL);
2614
2615 andvars = SCIPgetVarsAnd(scip, andcons);
2616 nandvars = SCIPgetNVarsAnd(scip, andcons);
2617 val = andnegs[c] ? -andcoefs[c] : andcoefs[c];
2618
2619 /* lock variables */
2620 if( SCIPisPositive(scip, val) )
2621 {
2622 for( v = nandvars - 1; v >= 0; --v )
2623 {
2624 SCIP_CALL( SCIPlockVarCons(scip, andvars[v], cons, FALSE, TRUE) );
2625 }
2626 }
2627 else
2628 {
2629 for( v = nandvars - 1; v >= 0; --v )
2630 {
2631 SCIP_CALL( SCIPlockVarCons(scip, andvars[v], cons, TRUE, FALSE) );
2632 }
2633 }
2634 }
2635 }
2636 else if( !SCIPisInfinity(scip, oldrhs) && SCIPisInfinity(scip, rhs) )
2637 {
2638 /* non-linear part */
2639 for( c = consdata->nconsanddatas - 1; c >= 0; --c )
2640 {
2641 CONSANDDATA* consanddata;
2642 SCIP_CONS* andcons;
2643
2644 consanddata = consdata->consanddatas[c];
2645 assert(consanddata != NULL);
2646
2647 andcons = consanddata->cons;
2648 assert(andcons != NULL);
2649
2650 andvars = SCIPgetVarsAnd(scip, andcons);
2651 nandvars = SCIPgetNVarsAnd(scip, andcons);
2652 val = andnegs[c] ? -andcoefs[c] : andcoefs[c];
2653
2654 /* lock variables */
2655 if( SCIPisPositive(scip, val) )
2656 {
2657 for( v = nandvars - 1; v >= 0; --v )
2658 {
2659 SCIP_CALL( SCIPunlockVarCons(scip, andvars[v], cons, FALSE, TRUE) );
2660 }
2661 }
2662 else
2663 {
2664 for( v = nandvars - 1; v >= 0; --v )
2665 {
2666 SCIP_CALL( SCIPunlockVarCons(scip, andvars[v], cons, TRUE, FALSE) );
2667 }
2668 }
2669 }
2670 }
2671 }
2672
2673 /* 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 */
2674 if( SCIPisGT(scip, oldrhs, rhs) )
2675 {
2676 consdata->propagated = FALSE;
2677 }
2678
2679 /* set new right hand side and update constraint data */
2680 SCIP_CALL( chgRhsLinearCons(scip, consdata->lincons, consdata->linconstype, rhs) );
2681 consdata->rhs = rhs;
2682 consdata->presolved = FALSE;
2683 consdata->changed = TRUE;
2684
2685 /* free temporary memory */
2686 SCIPfreeBufferArray(scip, &andnegs);
2687 SCIPfreeBufferArray(scip, &andcoefs);
2688 SCIPfreeBufferArray(scip, &andress);
2689 SCIPfreeBufferArray(scip, &lincoefs);
2690 SCIPfreeBufferArray(scip, &linvars);
2691 SCIPfreeBufferArray(scip, &coefs);
2692 SCIPfreeBufferArray(scip, &vars);
2693
2694 return SCIP_OKAY;
2695}
2696
2697/** create and-constraints and get all and-resultants */
2698static
2700 SCIP*const scip, /**< SCIP data structure */
2701 SCIP_CONSHDLR*const conshdlr, /**< pseudoboolean constraint handler */
2702 SCIP_VAR**const*const terms, /**< array of term variables to get and-constraints for */
2703 SCIP_Real*const termcoefs, /**< array of coefficients for and-constraints */
2704 int const nterms, /**< number of terms to get and-constraints for */
2705 int const*const ntermvars, /**< array of number of variable in each term */
2706 SCIP_Bool const initial, /**< should the LP relaxation of constraint be in the initial LP?
2707 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
2708 SCIP_Bool const enforce, /**< should the constraint be enforced during node processing?
2709 * TRUE for model constraints, FALSE for additional, redundant
2710 * constraints. */
2711 SCIP_Bool const check, /**< should the constraint be checked for feasibility?
2712 * TRUE for model constraints, FALSE for additional, redundant
2713 * constraints. */
2714 SCIP_Bool const local, /**< is constraint only valid locally?
2715 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching
2716 * constraints. */
2717 SCIP_Bool const modifiable, /**< is constraint modifiable (subject to column generation)?
2718 * Usually set to FALSE. In column generation applications, set to TRUE
2719 * if pricing adds coefficients to this constraint. */
2720 SCIP_Bool const dynamic, /**< is constraint subject to aging?
2721 * Usually set to FALSE. Set to TRUE for own cuts which
2722 * are seperated as constraints. */
2723 SCIP_Bool const stickingatnode, /**< should the constraint always be kept at the node where it was added, even
2724 * if it may be moved to a more global node?
2725 * Usually set to FALSE. Set to TRUE to for constraints that represent
2726 * node data. */
2727 SCIP_CONS**const andconss, /**< array to store all created and-constraints for given terms */
2728 SCIP_Real*const andvals, /**< array to store all coefficients of and-constraints */
2729 SCIP_Bool*const andnegs, /**< array to store negation status of and-constraints */
2730 int*const nandconss /**< number of created and constraints */
2731 )
2732{
2733 int t;
2734
2735 assert(scip != NULL);
2736 assert(conshdlr != NULL);
2737 assert(nterms == 0 || (terms != NULL && ntermvars != NULL));
2738 assert(andconss != NULL);
2739 assert(andvals != NULL);
2740 assert(nandconss != NULL);
2741
2742 (*nandconss) = 0;
2743
2744 if( nterms == 0 )
2745 return SCIP_OKAY;
2746
2747 /* loop over all terms and create/get all and constraints */
2748 for( t = 0; t < nterms; ++t )
2749 {
2750 if( !SCIPisZero(scip, termcoefs[t]) && ntermvars[t] > 0 )
2751 {
2752 SCIP_CALL( createAndAddAndCons(scip, conshdlr, terms[t], ntermvars[t],
2753 initial, enforce, check, local, modifiable, dynamic, stickingatnode,
2754 &(andconss[*nandconss])) );
2755 assert(andconss[*nandconss] != NULL);
2756 andvals[*nandconss] = termcoefs[t];
2757 andnegs[*nandconss] = FALSE;
2758 ++(*nandconss);
2759 }
2760 }
2761
2762 return SCIP_OKAY;
2763}
2764
2765/** created linear constraint of pseudo boolean constraint */
2766static
2768 SCIP*const scip, /**< SCIP data structure */
2769 SCIP_CONSHDLR*const conshdlr, /**< pseudoboolean constraint handler */
2770 SCIP_VAR**const linvars, /**< linear variables */
2771 int const nlinvars, /**< number of linear variables */
2772 SCIP_Real*const linvals, /**< linear coefficients */
2773 SCIP_VAR**const andress, /**< and-resultant variables */
2774 int const nandress, /**< number of and-resultant variables */
2775 SCIP_Real const*const andvals, /**< and-resultant coefficients */
2776 SCIP_Bool*const andnegs, /**< and-resultant negation status */
2777 SCIP_Real*const lhs, /**< pointer to left hand side of linear constraint */
2778 SCIP_Real*const rhs, /**< pointer to right hand side of linear constraint */
2779 SCIP_Bool const issoftcons, /**< is this a soft constraint */
2780 SCIP_Bool const initial, /**< should the LP relaxation of constraint be in the initial LP?
2781 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
2782 SCIP_Bool const separate, /**< should the constraint be separated during LP processing?
2783 * Usually set to TRUE. */
2784 SCIP_Bool const enforce, /**< should the constraint be enforced during node processing?
2785 * TRUE for model constraints, FALSE for additional, redundant
2786 * constraints. */
2787 SCIP_Bool const check, /**< should the constraint be checked for feasibility?
2788 * TRUE for model constraints, FALSE for additional, redundant
2789 * constraints. */
2790 SCIP_Bool const propagate, /**< should the constraint be propagated during node processing?
2791 * Usually set to TRUE. */
2792 SCIP_Bool const local, /**< is constraint only valid locally?
2793 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching
2794 * constraints. */
2795 SCIP_Bool const modifiable, /**< is constraint modifiable (subject to column generation)?
2796 * Usually set to FALSE. In column generation applications, set to TRUE
2797 * if pricing adds coefficients to this constraint. */
2798 SCIP_Bool const dynamic, /**< is constraint subject to aging?
2799 * Usually set to FALSE. Set to TRUE for own cuts which
2800 * are seperated as constraints. */
2801 SCIP_Bool const removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
2802 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user
2803 * cuts'. */
2804 SCIP_Bool const stickingatnode, /**< should the constraint always be kept at the node where it was added, even
2805 * if it may be moved to a more global node?
2806 * Usually set to FALSE. Set to TRUE to for constraints that represent
2807 * node data. */
2808 SCIP_CONS**const lincons, /**< pointer to store created linear constraint */
2809 SCIP_LINEARCONSTYPE*const linconstype /**< pointer to store the type of the linear constraint */
2810 )
2811{
2812 SCIP_CONSHDLRDATA* conshdlrdata;
2813 SCIP_CONSHDLR* upgrconshdlr;
2814 SCIP_CONS* cons;
2815 char name[SCIP_MAXSTRLEN];
2816 int v;
2817 SCIP_Bool created;
2818 SCIP_Bool integral;
2819 int nzero;
2820 int ncoeffspone;
2821 int ncoeffsnone;
2822 int ncoeffspint;
2823 int ncoeffsnint;
2824
2825 assert(scip != NULL);
2826 assert(conshdlr != NULL);
2827 assert(nlinvars == 0 || (linvars != NULL && linvals != NULL));
2828 assert(nandress == 0 || (andress != NULL && andvals != NULL));
2829 assert(lhs != NULL);
2830 assert(rhs != NULL);
2831 assert(lincons != NULL);
2832 assert(linconstype != NULL);
2833 assert(nlinvars > 0 || nandress > 0);
2834
2835 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2836 assert(conshdlrdata != NULL);
2837
2838 (*linconstype) = SCIP_LINEARCONSTYPE_INVALIDCONS;
2839 (*lincons) = NULL;
2840 cons = NULL;
2841
2842 (void)SCIPsnprintf(name, SCIP_MAXSTRLEN, "pseudoboolean_linear%d", conshdlrdata->nlinconss);
2843 ++(conshdlrdata->nlinconss);
2844
2845 created = FALSE;
2846
2847 if( !modifiable )
2848 {
2849 SCIP_Real val;
2850 int nvars;
2851
2852 /* calculate some statistics for upgrading on linear constraint */
2853 nzero = 0;
2854 ncoeffspone = 0;
2855 ncoeffsnone = 0;
2856 ncoeffspint = 0;
2857 ncoeffsnint = 0;
2858 integral = TRUE;
2859 nvars = nlinvars + nandress;
2860
2861 /* calculate information over linear part */
2862 for( v = nlinvars - 1; v >= 0; --v )
2863 {
2864 val = linvals[v];
2865
2866 if( SCIPisZero(scip, val) )
2867 {
2868 ++nzero;
2869 continue;
2870 }
2871 if( SCIPisEQ(scip, val, 1.0) )
2872 ++ncoeffspone;
2873 else if( SCIPisEQ(scip, val, -1.0) )
2874 ++ncoeffsnone;
2875 else if( SCIPisIntegral(scip, val) )
2876 {
2877 if( SCIPisPositive(scip, val) )
2878 ++ncoeffspint;
2879 else
2880 ++ncoeffsnint;
2881 }
2882 else
2883 {
2884 integral = FALSE;
2885 break;
2886 }
2887 }
2888
2889 if( integral )
2890 {
2891 /* calculate information over and-resultants */
2892 for( v = nandress - 1; v >= 0; --v )
2893 {
2894 val = andvals[v];
2895
2896 if( SCIPisZero(scip, val) )
2897 {
2898 ++nzero;
2899 continue;
2900 }
2901 if( SCIPisEQ(scip, val, 1.0) )
2902 ++ncoeffspone;
2903 else if( SCIPisEQ(scip, val, -1.0) )
2904 ++ncoeffsnone;
2905 else if( SCIPisIntegral(scip, val) )
2906 {
2907 if( SCIPisPositive(scip, val) )
2908 ++ncoeffspint;
2909 else
2910 ++ncoeffsnint;
2911 }
2912 else
2913 {
2914 integral = FALSE;
2915 break;
2916 }
2917 }
2918 }
2919
2920 SCIPdebugMsg(scip, "While creating the linear constraint of the pseudoboolean constraint we found %d zero coefficients that were removed\n", nzero);
2921
2922 /* try to upgrade to a special linear constraint */
2923 if( integral )
2924 {
2925 upgrconshdlr = SCIPfindConshdlr(scip, "logicor");
2926
2927 /* check, if linear constraint can be upgraded to logic or constraint
2928 * - logic or constraints consist only of binary variables with a
2929 * coefficient of +1.0 or -1.0 (variables with -1.0 coefficients can be negated):
2930 * lhs <= x1 + ... + xp - y1 - ... - yn <= rhs
2931 * - negating all variables y = (1-Y) with negative coefficients gives:
2932 * lhs + n <= x1 + ... + xp + Y1 + ... + Yn <= rhs + n
2933 * - negating all variables x = (1-X) with positive coefficients and multiplying with -1 gives:
2934 * p - rhs <= X1 + ... + Xp + y1 + ... + yn <= p - lhs
2935 * - logic or constraints have left hand side of +1.0, and right hand side of +infinity: x(S) >= 1.0
2936 * -> without negations: (lhs == 1 - n and rhs == +inf) or (lhs == -inf and rhs = p - 1)
2937 */
2938 if( upgrconshdlr != NULL && nvars > 2 && ncoeffspone + ncoeffsnone == nvars
2939 && ((SCIPisEQ(scip, *lhs, 1.0 - ncoeffsnone) && SCIPisInfinity(scip, *rhs))
2940 || (SCIPisInfinity(scip, -*lhs) && SCIPisEQ(scip, *rhs, ncoeffspone - 1.0))) )
2941 {
2942 SCIP_VAR** transvars;
2943 int mult;
2944
2945 SCIPdebugMsg(scip, "linear constraint will be logic-or constraint\n");
2946
2947 /* check, if we have to multiply with -1 (negate the positive vars) or with +1 (negate the negative vars) */
2948 mult = SCIPisInfinity(scip, *rhs) ? +1 : -1;
2949
2950 /* get temporary memory */
2951 SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
2952
2953 /* negate positive or negative variables */
2954 for( v = 0; v < nlinvars; ++v )
2955 {
2956 if( mult * linvals[v] > 0.0 )
2957 transvars[v] = linvars[v];
2958 else
2959 {
2960 SCIP_CALL( SCIPgetNegatedVar(scip, linvars[v], &transvars[v]) );
2961 }
2962 assert(transvars[v] != NULL);
2963 }
2964
2965 /* negate positive or negative variables */
2966 for( v = 0; v < nandress; ++v )
2967 {
2968 if( mult * andvals[v] > 0.0 )
2969 transvars[nlinvars + v] = andress[v];
2970 else
2971 {
2972 SCIP_CALL( SCIPgetNegatedVar(scip, andress[v], &transvars[nlinvars + v]) );
2973 andnegs[v] = TRUE;
2974 }
2975 assert(transvars[nlinvars + v] != NULL);
2976 }
2977
2978 assert(!modifiable);
2979 /* create the constraint */
2980 SCIP_CALL( SCIPcreateConsLogicor(scip, &cons, name, nvars, transvars,
2981 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
2982
2983 created = TRUE;
2984 (*linconstype) = SCIP_LINEARCONSTYPE_LOGICOR;
2985
2986 /* free temporary memory */
2987 SCIPfreeBufferArray(scip, &transvars);
2988
2989 *lhs = 1.0;
2990 *rhs = SCIPinfinity(scip);
2991 }
2992
2993 upgrconshdlr = SCIPfindConshdlr(scip, "setppc");
2994
2995 /* check, if linear constraint can be upgraded to set partitioning, packing, or covering constraint
2996 * - all set partitioning / packing / covering constraints consist only of binary variables with a
2997 * coefficient of +1.0 or -1.0 (variables with -1.0 coefficients can be negated):
2998 * lhs <= x1 + ... + xp - y1 - ... - yn <= rhs
2999 * - negating all variables y = (1-Y) with negative coefficients gives:
3000 * lhs + n <= x1 + ... + xp + Y1 + ... + Yn <= rhs + n
3001 * - negating all variables x = (1-X) with positive coefficients and multiplying with -1 gives:
3002 * p - rhs <= X1 + ... + Xp + y1 + ... + yn <= p - lhs
3003 * - a set partitioning constraint has left hand side of +1.0, and right hand side of +1.0 : x(S) == 1.0
3004 * -> without negations: lhs == rhs == 1 - n or lhs == rhs == p - 1
3005 * - a set packing constraint has left hand side of -infinity, and right hand side of +1.0 : x(S) <= 1.0
3006 * -> without negations: (lhs == -inf and rhs == 1 - n) or (lhs == p - 1 and rhs = +inf)
3007 * - a set covering constraint has left hand side of +1.0, and right hand side of +infinity: x(S) >= 1.0
3008 * -> without negations: (lhs == 1 - n and rhs == +inf) or (lhs == -inf and rhs = p - 1)
3009 */
3010 if( upgrconshdlr != NULL && !created && ncoeffspone + ncoeffsnone == nvars )
3011 {
3012 SCIP_VAR** transvars;
3013 int mult;
3014
3015 if( SCIPisEQ(scip, *lhs, *rhs) && (SCIPisEQ(scip, *lhs, 1.0 - ncoeffsnone) || SCIPisEQ(scip, *lhs, ncoeffspone - 1.0)) )
3016 {
3017 SCIPdebugMsg(scip, "linear pseudoboolean constraint will be a set partitioning constraint\n");
3018
3019 /* check, if we have to multiply with -1 (negate the positive vars) or with +1 (negate the negative vars) */
3020 mult = SCIPisEQ(scip, *lhs, 1.0 - ncoeffsnone) ? +1 : -1;
3021
3022 /* get temporary memory */
3023 SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
3024
3025 /* negate positive or negative variables for linear variables */
3026 for( v = 0; v < nlinvars; ++v )
3027 {
3028 if( mult * linvals[v] > 0.0 )
3029 transvars[v] = linvars[v];
3030 else
3031 {
3032 SCIP_CALL( SCIPgetNegatedVar(scip, linvars[v], &transvars[v]) );
3033 }
3034 assert(transvars[v] != NULL);
3035 }
3036
3037 /* negate positive or negative variables for and-resultants */
3038 for( v = 0; v < nandress; ++v )
3039 {
3040 if( mult * andvals[v] > 0.0 )
3041 transvars[nlinvars + v] = andress[v];
3042 else
3043 {
3044 SCIP_CALL( SCIPgetNegatedVar(scip, andress[v], &transvars[nlinvars + v]) );
3045 andnegs[v] = TRUE;
3046 }
3047 assert(transvars[nlinvars + v] != NULL);
3048 }
3049
3050 /* create the constraint */
3051 assert(!modifiable);
3052 SCIP_CALL( SCIPcreateConsSetpart(scip, &cons, name, nvars, transvars,
3053 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
3054
3055 created = TRUE;
3056 (*linconstype) = SCIP_LINEARCONSTYPE_SETPPC;
3057
3058 /* release temporary memory */
3059 SCIPfreeBufferArray(scip, &transvars);
3060
3061 *lhs = 1.0;
3062 *rhs = 1.0;
3063 }
3064 else if( (SCIPisInfinity(scip, -*lhs) && SCIPisEQ(scip, *rhs, 1.0 - ncoeffsnone))
3065 || (SCIPisEQ(scip, *lhs, ncoeffspone - 1.0) && SCIPisInfinity(scip, *rhs)) )
3066 {
3067 SCIPdebugMsg(scip, "linear pseudoboolean constraint will be a set packing constraint\n");
3068
3069 /* check, if we have to multiply with -1 (negate the positive vars) or with +1 (negate the negative vars) */
3070 mult = SCIPisInfinity(scip, -*lhs) ? +1 : -1;
3071
3072 /* get temporary memory */
3073 SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
3074
3075 /* negate positive or negative variables for linear variables */
3076 for( v = 0; v < nlinvars; ++v )
3077 {
3078 if( mult * linvals[v] > 0.0 )
3079 transvars[v] = linvars[v];
3080 else
3081 {
3082 SCIP_CALL( SCIPgetNegatedVar(scip, linvars[v], &transvars[v]) );
3083 }
3084 assert(transvars[v] != NULL);
3085 }
3086
3087 /* negate positive or negative variables for and-resultants*/
3088 for( v = 0; v < nandress; ++v )
3089 {
3090 if( mult * andvals[v] > 0.0 )
3091 transvars[nlinvars + v] = andress[v];
3092 else
3093 {
3094 SCIP_CALL( SCIPgetNegatedVar(scip, andress[v], &transvars[nlinvars + v]) );
3095 andnegs[v] = TRUE;
3096 }
3097 assert(transvars[nlinvars + v] != NULL);
3098 }
3099
3100 /* create the constraint */
3101 assert(!modifiable);
3102 SCIP_CALL( SCIPcreateConsSetpack(scip, &cons, name, nvars, transvars,
3103 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
3104
3105 created = TRUE;
3106 (*linconstype) = SCIP_LINEARCONSTYPE_SETPPC;
3107
3108 /* release temporary memory */
3109 SCIPfreeBufferArray(scip, &transvars);
3110
3111 *lhs = -SCIPinfinity(scip);
3112 *rhs = 1.0;
3113 }
3114 else if( (SCIPisEQ(scip, *lhs, 1.0 - ncoeffsnone) && SCIPisInfinity(scip, *rhs))
3115 || (SCIPisInfinity(scip, -*lhs) && SCIPisEQ(scip, *rhs, ncoeffspone - 1.0)) )
3116 {
3117 if( nvars != 1 )
3118 {
3119 if( nvars == 2 )
3120 {
3121 SCIPwarningMessage(scip, "Does not expect this, because this constraint should be a set packing constraint.\n");
3122 }
3123 else
3124 {
3125 SCIPwarningMessage(scip, "Does not expect this, because this constraint should be a logicor constraint.\n");
3126 }
3127 }
3128 SCIPdebugMsg(scip, "linear pseudoboolean constraint will be a set covering constraint\n");
3129
3130 /* check, if we have to multiply with -1 (negate the positive vars) or with +1 (negate the negative vars) */
3131 mult = SCIPisInfinity(scip, *rhs) ? +1 : -1;
3132
3133 /* get temporary memory */
3134 SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
3135
3136 /* negate positive or negative variables for linear variables */
3137 for( v = 0; v < nlinvars; ++v )
3138 {
3139 if( mult * linvals[v] > 0.0 )
3140 transvars[v] = linvars[v];
3141 else
3142 {
3143 SCIP_CALL( SCIPgetNegatedVar(scip, linvars[v], &transvars[v]) );
3144 }
3145 assert(transvars[v] != NULL);
3146 }
3147
3148 /* negate positive or negative variables for and-resultants*/
3149 for( v = 0; v < nandress; ++v )
3150 {
3151 if( mult * andvals[v] > 0.0 )
3152 transvars[nlinvars + v] = andress[v];
3153 else
3154 {
3155 SCIP_CALL( SCIPgetNegatedVar(scip, andress[v], &transvars[nlinvars + v]) );
3156 andnegs[v] = TRUE;
3157 }
3158 assert(transvars[nlinvars + v] != NULL);
3159 }
3160
3161 /* create the constraint */
3162 assert(!modifiable);
3163 SCIP_CALL( SCIPcreateConsSetcover(scip, &cons, name, nvars, transvars,
3164 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
3165
3166 created = TRUE;
3167 (*linconstype) = SCIP_LINEARCONSTYPE_SETPPC;
3168
3169 /* release temporary memory */
3170 SCIPfreeBufferArray(scip, &transvars);
3171
3172 *lhs = 1.0;
3173 *rhs = SCIPinfinity(scip);
3174 }
3175 }
3176
3177 upgrconshdlr = SCIPfindConshdlr(scip, "knapsack");
3178
3179 /* check, if linear constraint can be upgraded to a knapsack constraint
3180 * - all variables must be binary
3181 * - all coefficients must be integral
3182 * - exactly one of the sides must be infinite
3183 */
3184 if( upgrconshdlr != NULL && !created && (ncoeffspone + ncoeffsnone + ncoeffspint + ncoeffsnint == nvars) && (SCIPisInfinity(scip, -*lhs) != SCIPisInfinity(scip, *rhs)) )
3185 {
3186 SCIP_VAR** transvars;
3187 SCIP_Longint* weights;
3188 SCIP_Longint capacity;
3189 SCIP_Longint weight;
3190 int mult;
3191
3192 SCIPdebugMsg(scip, "linear pseudoboolean constraint will be a knapsack constraint\n");
3193
3194 /* get temporary memory */
3195 SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
3196 SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
3197
3198 /* if the right hand side is non-infinite, we have to negate all variables with negative coefficient;
3199 * otherwise, we have to negate all variables with positive coefficient and multiply the row with -1
3200 */
3201 if( SCIPisInfinity(scip, *rhs) )
3202 {
3203 mult = -1;
3204 capacity = (SCIP_Longint)SCIPfeasFloor(scip, -*lhs);
3205 }
3206 else
3207 {
3208 mult = +1;
3209 capacity = (SCIP_Longint)SCIPfeasFloor(scip, *rhs);
3210 }
3211
3212 /* negate positive or negative variables for linear variables */
3213 for( v = 0; v < nlinvars; ++v )
3214 {
3215 assert(SCIPisFeasIntegral(scip, linvals[v]));
3216 weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, linvals[v]);
3217 if( weight > 0 )
3218 {
3219 transvars[v] = linvars[v];
3220 weights[v] = weight;
3221 }
3222 else
3223 {
3224 SCIP_CALL( SCIPgetNegatedVar(scip, linvars[v], &transvars[v]) );
3225 weights[v] = -weight;
3226 capacity -= weight;
3227 }
3228 assert(transvars[v] != NULL);
3229 }
3230 /* negate positive or negative variables for and-resultants */
3231 for( v = 0; v < nandress; ++v )
3232 {
3233 assert(SCIPisFeasIntegral(scip, andvals[v]));
3234 weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, andvals[v]);
3235 if( weight > 0 )
3236 {
3237 transvars[nlinvars + v] = andress[v];
3238 weights[nlinvars + v] = weight;
3239 }
3240 else
3241 {
3242 SCIP_CALL( SCIPgetNegatedVar(scip, andress[v], &transvars[nlinvars + v]) );
3243 andnegs[v] = TRUE;
3244 weights[nlinvars + v] = -weight;
3245 capacity -= weight;
3246 }
3247 assert(transvars[nlinvars + v] != NULL);
3248 }
3249
3250 /* create the constraint */
3251 SCIP_CALL( SCIPcreateConsKnapsack(scip, &cons, name, nvars, transvars, weights, capacity,
3252 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
3253
3254 created = TRUE;
3255 (*linconstype) = SCIP_LINEARCONSTYPE_KNAPSACK;
3256
3257 /* free temporary memory */
3258 SCIPfreeBufferArray(scip, &weights);
3259 SCIPfreeBufferArray(scip, &transvars);
3260
3261 *lhs = -SCIPinfinity(scip);
3262 *rhs = capacity;
3263 }
3264#ifdef WITHEQKNAPSACK
3265
3266 upgrconshdlr = SCIPfindConshdlr(scip, "eqknapsack");
3267
3268 /* check, if linear constraint can be upgraded to a knapsack constraint
3269 * - all variables must be binary
3270 * - all coefficients must be integral
3271 * - both sides must be infinite
3272 */
3273 if( upgrconshdlr != NULL && !created && (ncoeffspone + ncoeffsnone + ncoeffspint + ncoeffsnint == nvars) && SCIPisEQ(scip, *lhs, *rhs) )
3274 {
3275 SCIP_VAR** transvars;
3276 SCIP_Longint* weights;
3277 SCIP_Longint capacity;
3278 SCIP_Longint weight;
3279 int mult;
3280
3281 assert(!SCIPisInfinity(scip, *rhs));
3282
3283 SCIPdebugMsg(scip, "linear pseudoboolean constraint will be a equality-knapsack constraint\n");
3284
3285 /* get temporary memory */
3286 SCIP_CALL( SCIPallocBufferArray(scip, &transvars, nvars) );
3287 SCIP_CALL( SCIPallocBufferArray(scip, &weights, nvars) );
3288
3289 if( SCIPisPositive(scip, *rhs) )
3290 {
3291 mult = +1;
3292 capacity = (SCIP_Longint)SCIPfeasFloor(scip, *rhs);
3293 }
3294 else
3295 {
3296 mult = -1;
3297 capacity = (SCIP_Longint)SCIPfeasFloor(scip, -*rhs);
3298 }
3299
3300 /* negate positive or negative variables for linear variables */
3301 for( v = 0; v < nlinvars; ++v )
3302 {
3303 assert(SCIPisFeasIntegral(scip, linvals[v]));
3304 weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, linvals[v]);
3305 if( weight > 0 )
3306 {
3307 transvars[v] = linvars[v];
3308 weights[v] = weight;
3309 }
3310 else
3311 {
3312 SCIP_CALL( SCIPgetNegatedVar(scip, linvars[v], &transvars[v]) );
3313 weights[v] = -weight;
3314 capacity -= weight;
3315 }
3316 assert(transvars[v] != NULL);
3317 }
3318 /* negate positive or negative variables for and-resultants */
3319 for( v = 0; v < nandress; ++v )
3320 {
3321 assert(SCIPisFeasIntegral(scip, andvals[v]));
3322 weight = mult * (SCIP_Longint)SCIPfeasFloor(scip, andvals[v]);
3323 if( weight > 0 )
3324 {
3325 transvars[nlinvars + v] = andress[v];
3326 weights[nlinvars + v] = weight;
3327 }
3328 else
3329 {
3330 SCIP_CALL( SCIPgetNegatedVar(scip, andress[v], &transvars[nlinvars + v]) );
3331 andnegs[v] = TRUE;
3332 weights[nlinvars + v] = -weight;
3333 capacity -= weight;
3334 }
3335 assert(transvars[nlinvars + v] != NULL);
3336 }
3337
3338 /* create the constraint */
3339 SCIP_CALL( SCIPcreateConsEqKnapsack(scip, &cons, name, nvars, transvars, weights, capacity,
3340 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
3341
3342 created = TRUE;
3343 (*linconstype) = SCIP_LINEARCONSTYPE_EQKNAPSACK;
3344
3345 /* free temporary memory */
3346 SCIPfreeBufferArray(scip, &weights);
3347 SCIPfreeBufferArray(scip, &transvars);
3348
3349 *lhs = capacity;
3350 *rhs = capacity;
3351 }
3352#endif
3353 }
3354 }
3355
3356 upgrconshdlr = SCIPfindConshdlr(scip, "linear");
3357 assert(created || upgrconshdlr != NULL);
3358
3359 if( !created )
3360 {
3361 SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, nlinvars, linvars, linvals, *lhs, *rhs,
3362 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
3363
3364 (*linconstype) = SCIP_LINEARCONSTYPE_LINEAR;
3365
3366 /* add all and-resultants */
3367 for( v = 0; v < nandress; ++v )
3368 {
3369 assert(andress[v] != NULL);
3370
3371 /* add auxiliary variables to linear constraint */
3372 SCIP_CALL( SCIPaddCoefLinear(scip, cons, andress[v], andvals[v]) );
3373 }
3374 }
3375
3376 assert(cons != NULL && *linconstype > SCIP_LINEARCONSTYPE_INVALIDCONS);
3378 *lincons = cons;
3379
3380 /* @todo: add indicator variable */
3381 /* add hard constraint */
3382 if( !issoftcons )
3383 {
3384 SCIP_CALL( SCIPaddCons(scip, cons) );
3385
3386 /* mark linear constraint not to be upgraded - otherwise we loose control over it */
3387 SCIP_CALL( SCIPcaptureCons(scip, cons) );
3388 SCIPconsAddUpgradeLocks(cons, 1);
3389 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
3390 }
3391
3392 return SCIP_OKAY;
3393}
3394
3395/** checks one original pseudoboolean constraint for feasibility of given solution */
3396static
3398 SCIP*const scip, /**< SCIP data structure */
3399 SCIP_CONS*const cons, /**< pseudo boolean constraint */
3400 SCIP_SOL*const sol, /**< solution to be checked, or NULL for current solution */
3401 SCIP_Bool*const violated, /**< pointer to store whether the constraint is violated */
3402 SCIP_Bool const printreason /**< should violation of constraint be printed */
3403 )
3404{
3405 SCIP_CONSDATA* consdata;
3406 SCIP_CONSHDLR* conshdlr;
3407 SCIP_CONSHDLRDATA* conshdlrdata;
3408
3409 SCIP_VAR** vars;
3410 SCIP_Real* coefs;
3411 SCIP_Real lhs;
3412 SCIP_Real rhs;
3413 SCIP_Real activity;
3414 int nvars;
3415 int v;
3416
3417 SCIP_Real lhsviol;
3418 SCIP_Real rhsviol;
3419 SCIP_Real absviol;
3420 SCIP_Real relviol;
3421
3422 assert(scip != NULL);
3423 assert(cons != NULL);
3424 assert(SCIPconsIsOriginal(cons));
3425 assert(violated != NULL);
3426
3427 *violated = FALSE;
3428
3429 SCIPdebugMsg(scip, "checking original pseudo boolean constraint <%s>\n", SCIPconsGetName(cons));
3431
3432 consdata = SCIPconsGetData(cons);
3433 assert(consdata != NULL);
3434 assert(consdata->lincons != NULL);
3435 assert(consdata->linconstype > SCIP_LINEARCONSTYPE_INVALIDCONS);
3436 assert(SCIPconsIsOriginal(consdata->lincons));
3437
3438 /* gets number of variables in linear constraint */
3439 SCIP_CALL( getLinearConsNVars(scip, consdata->lincons, consdata->linconstype, &nvars) );
3440
3441 /* allocate temporary memory */
3442 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
3443 SCIP_CALL( SCIPallocBufferArray(scip, &coefs, nvars) );
3444
3445 /* get sides of linear constraint */
3446 SCIP_CALL( getLinearConsSides(scip, consdata->lincons, consdata->linconstype, &lhs, &rhs) );
3447 assert(!SCIPisInfinity(scip, lhs));
3448 assert(!SCIPisInfinity(scip, -rhs));
3449 assert(SCIPisLE(scip, lhs, rhs));
3450
3451 /* get variables and coefficient of linear constraint */
3452 SCIP_CALL( getLinearConsVarsData(scip, consdata->lincons, consdata->linconstype, vars, coefs, &nvars) );
3453 assert(nvars == 0 || (coefs != NULL));
3454
3455 /* every variable in the linear constraint is either a linear variable or a term variable
3456 * but there can be additional fixed or negation-paired and-resultants with relevant and-constraints
3457 * whose values are already resolved in the linear constraint
3458 */
3459 assert(consdata->nlinvars + consdata->nconsanddatas >= nvars);
3460
3461 conshdlr = SCIPconsGetHdlr(cons);
3462 assert(conshdlr != NULL);
3463
3464 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3465 assert(conshdlrdata != NULL);
3466 assert(conshdlrdata->hashmap != NULL);
3467
3468 activity = 0.0;
3469
3470 /* compute pseudoboolean activity */
3471 for( v = 0; v < nvars; ++v )
3472 {
3473 CONSANDDATA* consanddata = NULL;
3474 SCIP_VAR* var = vars[v];
3475 SCIP_Real solval;
3476
3477 /* find and-constraint to standard or negated and-resultant */
3478 do
3479 {
3480 consanddata = (CONSANDDATA*)SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)var);
3481
3482 if( consanddata != NULL )
3483 break;
3484
3485 var = var == vars[v] ? SCIPvarGetNegatedVar(var) : vars[v];
3486 }
3487 while( var != vars[v] );
3488
3489 /* get linear solution */
3490 if( consanddata == NULL )
3491 solval = SCIPgetSolVal(scip, sol, vars[v]);
3492 /* get term solution */
3493 else
3494 {
3495 SCIP_CONS* andcons = consanddata->origcons;
3496 SCIP_VAR** andvars;
3497 int nandvars;
3498 int i;
3499
3500 /* use transformed constraint if no original constraint exists */
3501 if( andcons == NULL )
3502 andcons = consanddata->cons;
3503
3504 assert(SCIPgetResultantAnd(scip, andcons) == var);
3505
3506 andvars = SCIPgetVarsAnd(scip, andcons);
3507 nandvars = SCIPgetNVarsAnd(scip, andcons);
3508 assert(nandvars == 0 || andvars != NULL);
3509
3510 solval = 1.0;
3511
3512 for( i = 0; i < nandvars; ++i )
3513 solval *= SCIPgetSolVal(scip, sol, andvars[i]);
3514
3515 if( var != vars[v] )
3516 solval = 1.0 - solval;
3517 }
3518
3519 /* add activity contribution */
3520 activity += coefs[v] * solval;
3521 }
3522
3523 SCIPdebugMsg(scip, "lhs = %g, activity = %g, rhs = %g\n", lhs, activity, rhs);
3524
3525 /* calculate absolute and relative violation */
3526 lhsviol = lhs - activity;
3527 rhsviol = activity - rhs;
3528
3529 if(lhsviol > rhsviol)
3530 {
3531 absviol = lhsviol;
3532 relviol = SCIPrelDiff(lhs, activity);
3533 }
3534 else
3535 {
3536 absviol = rhsviol;
3537 relviol = SCIPrelDiff(activity, rhs);
3538 }
3539
3540 /* update absolute and relative violation of the solution */
3541 if( sol != NULL )
3542 SCIPupdateSolConsViolation(scip, sol, absviol, relviol);
3543
3544 /* check left hand side for violation */
3545 if( SCIPisFeasLT(scip, activity, lhs) )
3546 {
3547 if( printreason )
3548 {
3549 SCIP_CALL( SCIPprintCons(scip, cons, NULL ) );
3550 SCIPinfoMessage(scip, NULL, ";\n");
3551 SCIPinfoMessage(scip, NULL, "violation: left hand side is violated by %.15g\n", lhs - activity);
3552
3553 /* print linear constraint in SCIP_DEBUG mode too */
3554 SCIPdebugPrintCons(scip, SCIPconsGetData(cons)->lincons, NULL);
3555 }
3556
3557 *violated = TRUE;
3558 }
3559
3560 /* check right hand side for violation */
3561 if( SCIPisFeasGT(scip, activity, rhs) )
3562 {
3563 if( printreason )
3564 {
3565 SCIP_CALL( SCIPprintCons(scip, cons, NULL ) );
3566 SCIPinfoMessage(scip, NULL, ";\n");
3567 SCIPinfoMessage(scip, NULL, "violation: right hand side is violated by %.15g\n", activity - rhs);
3568 }
3569
3570 *violated = TRUE;
3571 }
3572
3573 /* free temporary memory */
3574 SCIPfreeBufferArray(scip, &coefs);
3575 SCIPfreeBufferArray(scip, &vars);
3576
3577 return SCIP_OKAY;
3578}
3579
3580/** checks all and-constraints inside the pseudoboolean constraint handler for feasibility of given solution or current
3581 * solution
3582 */
3583static
3585 SCIP*const scip, /**< SCIP data structure */
3586 SCIP_CONSHDLR*const conshdlr, /**< pseudo boolean constraint handler */
3587 SCIP_SOL*const sol, /**< solution to be checked, or NULL for current solution */
3588 SCIP_Bool*const violated /**< pointer to store whether the constraint is violated */
3589 )
3590{
3591 SCIP_CONSHDLRDATA* conshdlrdata;
3592 SCIP_CONS* andcons;
3593 SCIP_VAR** vars;
3594 SCIP_VAR* res;
3595 int nvars;
3596 int c;
3597 int v;
3598
3599 assert(scip != NULL);
3600 assert(conshdlr != NULL);
3601 assert(violated != NULL);
3602
3603 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3604 assert(conshdlrdata != NULL);
3605
3606 *violated = FALSE;
3607
3608 for( c = conshdlrdata->nallconsanddatas - 1; c >= 0; --c )
3609 {
3610 SCIP_Real solval;
3611 SCIP_Real minsolval;
3612 SCIP_Real sumsolval;
3613 SCIP_Real viol;
3614
3615 if( !conshdlrdata->allconsanddatas[c]->istransformed )
3616 continue;
3617
3618 andcons = conshdlrdata->allconsanddatas[c]->cons;
3619
3620 /* need to check even locally deleted constraints */
3621 if( andcons == NULL ) /*|| !SCIPconsIsActive(andcons) )*/
3622 continue;
3623
3624 vars = SCIPgetVarsAnd(scip, andcons);
3625 nvars = SCIPgetNVarsAnd(scip, andcons);
3626 res = SCIPgetResultantAnd(scip, andcons);
3627 assert(nvars == 0 || (vars != NULL && res != NULL));
3628
3629 /* check if the and-constraint is violated */
3630 minsolval = 1.0;
3631 sumsolval = 0.0;
3632 for( v = nvars - 1; v >= 0; --v )
3633 {
3634 solval = SCIPgetSolVal(scip, sol, vars[v]);
3635
3636 if( solval < minsolval )
3637 minsolval = solval;
3638
3639 sumsolval += solval;
3640 }
3641
3642 /* the resultant must be at most as large as every operator
3643 * and at least as large as one minus the sum of negated operators
3644 */
3645 solval = SCIPgetSolVal(scip, sol, res);
3646 viol = MAX3(0.0, solval - minsolval, sumsolval - (nvars - 1.0 + solval));
3647
3648 if( SCIPisFeasPositive(scip, viol) )
3649 {
3650 /* only reset constraint age if we are in enforcement */
3651 if( sol == NULL )
3652 {
3653 SCIP_CALL( SCIPresetConsAge(scip, andcons) );
3654 }
3655
3656 *violated = TRUE;
3657 break;
3658 }
3659 else if( sol == NULL )
3660 {
3661 SCIP_CALL( SCIPincConsAge(scip, andcons) );
3662 }
3663 }
3664
3665 return SCIP_OKAY;
3666}
3667
3668/** creates by copying and captures a linear constraint */
3669static
3671 SCIP*const targetscip, /**< target SCIP data structure */
3672 SCIP_CONS** targetcons, /**< pointer to store the created target constraint */
3673 SCIP*const sourcescip, /**< source SCIP data structure */
3674 SCIP_CONS*const sourcecons, /**< source constraint which will be copied */
3675 const char* name, /**< name of constraint */
3676 SCIP_HASHMAP*const varmap, /**< a SCIP_HASHMAP mapping variables of the source SCIP to corresponding
3677 * variables of the target SCIP */
3678 SCIP_HASHMAP*const consmap, /**< a hashmap to store the mapping of source constraints to the corresponding
3679 * target constraints */
3680 SCIP_Bool const initial, /**< should the LP relaxation of constraint be in the initial LP? */
3681 SCIP_Bool const separate, /**< should the constraint be separated during LP processing? */
3682 SCIP_Bool const enforce, /**< should the constraint be enforced during node processing? */
3683 SCIP_Bool const check, /**< should the constraint be checked for feasibility? */
3684 SCIP_Bool const propagate, /**< should the constraint be propagated during node processing? */
3685 SCIP_Bool const local, /**< is constraint only valid locally? */
3686 SCIP_Bool const modifiable, /**< is constraint modifiable (subject to column generation)? */
3687 SCIP_Bool const dynamic, /**< is constraint subject to aging? */
3688 SCIP_Bool const removable, /**< should the relaxation be removed from the LP due to aging or cleanup? */
3689 SCIP_Bool const stickingatnode, /**< should the constraint always be kept at the node where it was added, even
3690 * if it may be moved to a more global node? */
3691 SCIP_Bool const global, /**< create a global or a local copy? */
3692 SCIP_Bool*const valid /**< pointer to store if the copying was valid */
3693 )
3694{
3695 SCIP_CONSDATA* sourceconsdata;
3696 SCIP_CONS* sourcelincons;
3697
3698 assert(targetscip != NULL);
3699 assert(targetcons != NULL);
3700 assert(sourcescip != NULL);
3701 assert(sourcecons != NULL);
3702 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(sourcecons)), CONSHDLR_NAME) == 0);
3703 assert(valid != NULL);
3704
3705 *valid = TRUE;
3706
3707 sourceconsdata = SCIPconsGetData(sourcecons);
3708 assert(sourceconsdata != NULL);
3709
3710 /* get linear constraint */
3711 sourcelincons = sourceconsdata->lincons;
3712 assert(sourcelincons != NULL);
3713
3714 /* get copied version of linear constraint */
3715 if( !SCIPconsIsDeleted(sourcelincons) )
3716 {
3717 SCIP_CONSHDLR* conshdlrlinear;
3718 SCIP_CONS* targetlincons;
3719 SCIP_CONS** targetandconss;
3720 SCIP_Real* targetandcoefs;
3721 int ntargetandconss;
3722 SCIP_LINEARCONSTYPE targetlinconstype;
3723
3724 targetlinconstype = sourceconsdata->linconstype;
3725
3726 switch( targetlinconstype )
3727 {
3729 conshdlrlinear = SCIPfindConshdlr(sourcescip, "linear");
3730 assert(conshdlrlinear != NULL);
3731 break;
3733 conshdlrlinear = SCIPfindConshdlr(sourcescip, "logicor");
3734 assert(conshdlrlinear != NULL);
3735 break;
3737 conshdlrlinear = SCIPfindConshdlr(sourcescip, "knapsack");
3738 assert(conshdlrlinear != NULL);
3739 break;
3741 conshdlrlinear = SCIPfindConshdlr(sourcescip, "setppc");
3742 assert(conshdlrlinear != NULL);
3743 break;
3744#ifdef WITHEQKNAPSACK
3745 case SCIP_LINEARCONSTYPE_EQKNAPSACK:
3746 conshdlrlinear = SCIPfindConshdlr(sourcescip, "eqknapsack");
3747 assert(conshdlrlinear != NULL);
3748 break;
3749#endif
3751 default:
3752 SCIPerrorMessage("unknown linear constraint type\n");
3753 return SCIP_INVALIDDATA;
3754 }
3755
3756 if( conshdlrlinear == NULL ) /*lint !e774*/
3757 {
3758 SCIPerrorMessage("linear constraint handler not found\n");
3759 return SCIP_INVALIDDATA;
3760 }
3761
3762 targetlincons = NULL;
3763
3764 /* copy linear constraint */
3765 SCIP_CALL( SCIPgetConsCopy(sourcescip, targetscip, sourcelincons, &targetlincons, conshdlrlinear, varmap, consmap, SCIPconsGetName(sourcelincons),
3766 SCIPconsIsInitial(sourcelincons), SCIPconsIsSeparated(sourcelincons), SCIPconsIsEnforced(sourcelincons), SCIPconsIsChecked(sourcelincons),
3767 SCIPconsIsPropagated(sourcelincons), SCIPconsIsLocal(sourcelincons), SCIPconsIsModifiable(sourcelincons), SCIPconsIsDynamic(sourcelincons),
3768 SCIPconsIsRemovable(sourcelincons), SCIPconsIsStickingAtNode(sourcelincons), global, valid) );
3769
3770 if( *valid )
3771 {
3772 assert(targetlincons != NULL);
3773 assert(SCIPconsGetHdlr(targetlincons) != NULL);
3774 /* @note due to copying special linear constraints, now leads only to simple linear constraints, we check that
3775 * our target constraint handler is the same as our source constraint handler of the linear constraint,
3776 * if copying was not valid
3777 */
3778 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(targetlincons)), "linear") == 0 )
3779 targetlinconstype = SCIP_LINEARCONSTYPE_LINEAR;
3780 }
3781
3782 targetandconss = NULL;
3783 targetandcoefs = NULL;
3784 ntargetandconss = 0;
3785
3786 if( *valid )
3787 {
3788 SCIP_CONSHDLR* conshdlrand;
3789 int c;
3790 int nsourceandconss;
3791 SCIP_HASHTABLE* linconsvarsmap;
3792 SCIP_VAR** targetlinvars;
3793 SCIP_Real* targetlincoefs;
3794 int ntargetlinvars;
3795
3796 conshdlrand = SCIPfindConshdlr(sourcescip, "and");
3797 assert(conshdlrand != NULL);
3798
3799 nsourceandconss = sourceconsdata->nconsanddatas;
3800
3801 /* allocate temporary memory */
3802 SCIP_CALL( SCIPallocBufferArray(sourcescip, &targetandconss, nsourceandconss) );
3803 SCIP_CALL( SCIPallocBufferArray(sourcescip, &targetandcoefs, nsourceandconss) );
3804
3805 /* get the number of vars in the copied linear constraint and allocate buffers
3806 * for the variables and the coefficients
3807 */
3808 SCIP_CALL( getLinearConsNVars(targetscip, targetlincons, targetlinconstype, &ntargetlinvars) );
3809 SCIP_CALL( SCIPallocBufferArray(sourcescip, &targetlinvars, ntargetlinvars) );
3810 SCIP_CALL( SCIPallocBufferArray(sourcescip, &targetlincoefs, ntargetlinvars) );
3811
3812 /* retrieve the variables of the copied linear constraint */
3813 SCIP_CALL( getLinearConsVarsData(targetscip, targetlincons, targetlinconstype,
3814 targetlinvars, targetlincoefs, &ntargetlinvars) );
3815
3816 /* now create a hashtable and insert the variables into it, so that it
3817 * can be checked in constant time if a variable was removed due to
3818 * compressed copying when looping over the and resultants
3819 */
3820 SCIP_CALL( SCIPhashtableCreate(&linconsvarsmap, SCIPblkmem(targetscip), ntargetlinvars, SCIPvarGetHashkey,
3821 SCIPvarIsHashkeyEq, SCIPvarGetHashkeyVal, NULL) );
3822
3823 for( c = 0 ; c < ntargetlinvars; ++c )
3824 {
3825 SCIP_CALL( SCIPhashtableInsert(linconsvarsmap, targetlinvars[c]) );
3826 }
3827
3828 /* free the buffer arrays that were only required for building the hastable */
3829 SCIPfreeBufferArray(sourcescip, &targetlincoefs);
3830 SCIPfreeBufferArray(sourcescip, &targetlinvars);
3831
3832 for( c = 0 ; c < nsourceandconss; ++c )
3833 {
3834 CONSANDDATA* consanddata;
3835 SCIP_CONS* oldcons;
3836 SCIP_VAR* targetandresultant;
3837 SCIP_Bool validand;
3838
3839 consanddata = sourceconsdata->consanddatas[c];
3840 assert(consanddata != NULL);
3841 oldcons = SCIPconsIsOriginal(sourcecons) ? consanddata->origcons : consanddata->cons;
3842 targetandresultant = (SCIP_VAR*) SCIPhashmapGetImage(varmap, SCIPgetResultantAnd(sourcescip, oldcons));
3843 assert(targetandresultant != NULL);
3844
3845 /* if compressed copying is active, the resultant might not have been copied by the linear
3846 * constraint and we don't need to add it to the pseudo boolean constraint in this case
3847 */
3848 if( !SCIPhashtableExists(linconsvarsmap, targetandresultant) )
3849 continue;
3850
3851 validand = TRUE;
3852
3853 targetandconss[ntargetandconss] = NULL;
3854
3855 /* copy and-constraints */
3856 SCIP_CALL( SCIPgetConsCopy(sourcescip, targetscip, oldcons, &targetandconss[ntargetandconss], conshdlrand, varmap, consmap, SCIPconsGetName(oldcons),
3857 SCIPconsIsInitial(oldcons), SCIPconsIsSeparated(oldcons), SCIPconsIsEnforced(oldcons), SCIPconsIsChecked(oldcons),
3858 SCIPconsIsPropagated(oldcons), SCIPconsIsLocal(oldcons), SCIPconsIsModifiable(oldcons), SCIPconsIsDynamic(oldcons),
3859 SCIPconsIsRemovable(oldcons), SCIPconsIsStickingAtNode(oldcons), global, &validand) );
3860
3861 *valid &= validand;
3862
3863 if( validand )
3864 {
3865 targetandcoefs[ntargetandconss] = sourceconsdata->andcoefs[c];
3866 ++ntargetandconss;
3867 }
3868 }
3869
3870 SCIPhashtableFree(&linconsvarsmap);
3871 assert(ntargetandconss <= ntargetlinvars);
3872 }
3873
3874 if( *valid )
3875 {
3876 SCIP_Real targetrhs;
3877 SCIP_Real targetlhs;
3878
3879 SCIP_VAR* intvar;
3880 SCIP_VAR* indvar;
3881 const char* consname;
3882
3883 /* third the indicator and artificial integer variable part */
3884 assert(sourceconsdata->issoftcons == (sourceconsdata->indvar != NULL));
3885 indvar = sourceconsdata->indvar;
3886 intvar = sourceconsdata->intvar;
3887
3888 /* copy indicator variable */
3889 if( indvar != NULL )
3890 {
3891 assert(*valid);
3892 SCIP_CALL( SCIPgetVarCopy(sourcescip, targetscip, indvar, &indvar, varmap, consmap, global, valid) );
3893 assert(!(*valid) || indvar != NULL);
3894 }
3895 /* copy artificial integer variable */
3896 if( intvar != NULL && *valid )
3897 {
3898 SCIP_CALL( SCIPgetVarCopy(sourcescip, targetscip, intvar, &intvar, varmap, consmap, global, valid) );
3899 assert(!(*valid) || intvar != NULL);
3900 }
3901
3902 if( *valid )
3903 {
3904 if( name != NULL )
3905 consname = name;
3906 else
3907 consname = SCIPconsGetName(sourcecons);
3908
3909 /* get new left and right hand sides of copied linear constraint since
3910 * they might have changed if compressed copying is used
3911 */
3912 SCIP_CALL( getLinearConsSides(targetscip, targetlincons, targetlinconstype, &targetlhs, &targetrhs) );
3913
3914 /* create new pseudoboolean constraint */
3915 /* coverity[var_deref_op] */
3916 /* coverity[var_deref_model] */
3917 /* Note that due to compression the and constraints might have disappeared in which case ntargetandconss == 0. */
3918 SCIP_CALL( SCIPcreateConsPseudobooleanWithConss(targetscip, targetcons, consname,
3919 targetlincons, targetlinconstype, targetandconss, targetandcoefs, ntargetandconss,
3920 indvar, sourceconsdata->weight, sourceconsdata->issoftcons, intvar, targetlhs, targetrhs,
3921 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
3922 }
3923 }
3924
3925 if( !(*valid) && !SCIPisConsCompressionEnabled(sourcescip) )
3926 {
3927 SCIPverbMessage(sourcescip, SCIP_VERBLEVEL_MINIMAL, NULL, "could not copy constraint <%s>\n", SCIPconsGetName(sourcecons));
3928 }
3929
3930 /* release copied linear constraint */
3931 if( targetlincons != NULL )
3932 {
3933 SCIP_CALL( SCIPreleaseCons(targetscip, &targetlincons) );
3934 }
3935
3936 /* release copied and constraint */
3937 if( targetandconss != NULL )
3938 {
3939 int c;
3940
3941 assert(ntargetandconss <= sourceconsdata->nconsanddatas);
3942
3943 for( c = 0 ; c < ntargetandconss; ++c )
3944 {
3945 if( targetandconss[c] != NULL )
3946 {
3947 SCIP_CALL( SCIPreleaseCons(targetscip, &targetandconss[c]) );
3948 }
3949 }
3950 }
3951
3952 /* free temporary memory */
3953 SCIPfreeBufferArrayNull(sourcescip, &targetandcoefs);
3954 SCIPfreeBufferArrayNull(sourcescip, &targetandconss);
3955 }
3956 else
3957 *valid = FALSE;
3958
3959 return SCIP_OKAY;
3960}
3961
3962/** compute all changes in consanddatas array */
3963static
3965 SCIP*const scip, /**< SCIP data structure */
3966 SCIP_CONSHDLRDATA*const conshdlrdata /**< pseudoboolean constraint handler data */
3967 )
3968{
3969 CONSANDDATA** allconsanddatas;
3970 CONSANDDATA* consanddata;
3971 int c;
3972
3973 assert(scip != NULL);
3974 assert(conshdlrdata != NULL);
3975
3976 allconsanddatas = conshdlrdata->allconsanddatas;
3977 assert(allconsanddatas != NULL);
3978 assert(conshdlrdata->nallconsanddatas >= 0);
3979 assert(conshdlrdata->nallconsanddatas <= conshdlrdata->sallconsanddatas);
3980
3981 for( c = conshdlrdata->nallconsanddatas - 1; c >= 0; --c )
3982 {
3983 SCIP_CONS* cons;
3984 SCIP_VAR** vars;
3985 int nvars;
3986 SCIP_VAR** newvars;
3987 int nnewvars;
3988 int v;
3989
3990 consanddata = allconsanddatas[c];
3991
3992 if( !consanddata->istransformed )
3993 continue;
3994
3995 if( consanddata->nuses == 0 )
3996 continue;
3997
3998 vars = consanddata->vars;
3999 nvars = consanddata->nvars;
4000 assert(nvars == 0 || vars != NULL);
4001 assert(consanddata->nnewvars == 0 && ((consanddata->snewvars > 0) == (consanddata->newvars != NULL)));
4002
4003 if( nvars == 0 )
4004 {
4005#ifndef NDEBUG
4006 /* if an old consanddata-object has no variables left there should be no new variables */
4007 if( consanddata->cons != NULL )
4008 assert(SCIPgetNVarsAnd(scip, consanddata->cons) == 0);
4009#endif
4010 continue;
4011 }
4012
4013 cons = consanddata->cons;
4014 assert(cons != NULL);
4015
4016 if( SCIPconsIsDeleted(cons) )
4017 continue;
4018
4019 /* sort and-variables */
4020 if( !SCIPisAndConsSorted(scip, consanddata->cons) )
4021 {
4022 SCIP_CALL( SCIPsortAndCons(scip, consanddata->cons) );
4023 assert(SCIPisAndConsSorted(scip, consanddata->cons));
4024 }
4025
4026 /* get new and-variables */
4027 nnewvars = SCIPgetNVarsAnd(scip, consanddata->cons);
4028 newvars = SCIPgetVarsAnd(scip, consanddata->cons);
4029
4030 /* stop if the constraint has no variables or there was an error (coverity issue) */
4031 if( nnewvars <= 0 )
4032 continue;
4033
4034#ifndef NDEBUG
4035 /* check that old variables are sorted */
4036 for( v = nvars - 1; v > 0; --v )
4037 assert(SCIPvarGetIndex(vars[v]) >= SCIPvarGetIndex(vars[v - 1]));
4038 /* check that new variables are sorted */
4039 for( v = nnewvars - 1; v > 0; --v )
4040 assert(SCIPvarGetIndex(newvars[v]) >= SCIPvarGetIndex(newvars[v - 1]));
4041#endif
4042
4043 /* check for changings, if and-constraint did not change we do not need to copy all variables */
4044 if( nvars == nnewvars )
4045 {
4046 SCIP_Bool changed;
4047
4048 changed = FALSE;
4049
4050 /* check each variable */
4051 for( v = nvars - 1; v >= 0; --v )
4052 {
4053 if( vars[v] != newvars[v] )
4054 {
4055 changed = TRUE;
4056 break;
4057 }
4058 }
4059
4060 if( !changed )
4061 continue;
4062 }
4063
4064 /* resize newvars array if necessary */
4065 if( nnewvars > consanddata->snewvars )
4066 {
4067 SCIP_CALL( SCIPensureBlockMemoryArray(scip, &(consanddata->newvars), &(consanddata->snewvars), nnewvars) );
4068 }
4069
4070 /* copy all variables */
4071 BMScopyMemoryArray(consanddata->newvars, newvars, nnewvars);
4072 consanddata->nnewvars = nnewvars;
4073
4074 /* capture all variables */
4075 for( v = consanddata->nnewvars - 1; v >= 0; --v )
4076 {
4077 /* in original problem the variables was already deleted */
4078 assert(consanddata->newvars[v] != NULL);
4079 SCIP_CALL( SCIPcaptureVar(scip, consanddata->newvars[v]) );
4080 }
4081 }
4082
4083 return SCIP_OKAY;
4084}
4085
4086/** remove old locks */
4087static
4089 SCIP*const scip, /**< SCIP data structure */
4090 SCIP_CONS*const cons, /**< pseudoboolean constraint */
4091 CONSANDDATA*const consanddata, /**< CONSANDDATA object for which we want to delete the locks and the
4092 * capture of the corresponding and-constraint */
4093 SCIP_Real const coef, /**< coefficient which led to old locks */
4094 SCIP_Real const lhs, /**< left hand side which led to old locks */
4095 SCIP_Real const rhs /**< right hand side which led to old locks */
4096 )
4097{
4098 assert(scip != NULL);
4099 assert(cons != NULL);
4100 assert(consanddata != NULL);
4101 assert(!SCIPisInfinity(scip, coef) && !SCIPisInfinity(scip, -coef));
4102 assert(!SCIPisInfinity(scip, lhs));
4103 assert(!SCIPisInfinity(scip, -rhs));
4104 assert(SCIPisLE(scip, lhs, rhs));
4105
4106 /* remove rounding locks */
4107 SCIP_CALL( unlockRoundingAndCons(scip, cons, consanddata, coef, lhs, rhs) );
4108
4109 assert(consanddata->cons != NULL);
4110
4111 return SCIP_OKAY;
4112}
4113
4114/** add new locks */
4115static
4117 SCIP*const scip, /**< SCIP data structure */
4118 SCIP_CONS*const cons, /**< pseudoboolean constraint */
4119 CONSANDDATA*const consanddata, /**< CONSANDDATA object for which we want to delete the locks and the
4120 * capture of the corresponding and-constraint */
4121 SCIP_Real const coef, /**< coefficient which lead to new locks */
4122 SCIP_Real const lhs, /**< left hand side which lead to new locks */
4123 SCIP_Real const rhs /**< right hand side which lead to new locks */
4124 )
4125{
4126 assert(scip != NULL);
4127 assert(cons != NULL);
4128 assert(consanddata != NULL);
4129 assert(!SCIPisInfinity(scip, coef) && !SCIPisInfinity(scip, -coef));
4130 assert(!SCIPisInfinity(scip, lhs));
4131 assert(!SCIPisInfinity(scip, -rhs));
4132 assert(SCIPisLE(scip, lhs, rhs));
4133
4134 /* add rounding locks due to old variables in consanddata object */
4135 SCIP_CALL( lockRoundingAndCons(scip, cons, consanddata, coef, lhs, rhs) );
4136
4137 assert(consanddata->cons != NULL);
4138
4139 return SCIP_OKAY;
4140}
4141
4142/** update all locks inside this constraint and all captures on all and-constraints */
4143static
4145 SCIP*const scip, /**< SCIP data structure */
4146 SCIP_CONS*const cons, /**< pseudoboolean constraint */
4147 SCIP_CONSHDLRDATA*const conshdlrdata, /**< pseudoboolean constraint handler data */
4148 SCIP_Real const newlhs, /**< new left hand side of pseudoboolean constraint */
4149 SCIP_Real const newrhs, /**< new right hand side of pseudoboolean constraint */
4150 SCIP_VAR**const andress, /**< new and-resultants in pseudoboolean constraint */
4151 SCIP_Real*const andcoefs, /**< new and-resultants-coeffcients in pseudoboolean constraint */
4152 SCIP_Bool*const andnegs, /**< new negation status of and-resultants in pseudoboolean constraint */
4153 int const nandress /**< number of current and-resultants in pseudoboolean constraint */
4154 )
4155{
4156 CONSANDDATA** newconsanddatas;
4157 int nnewconsanddatas;
4158 int snewconsanddatas;
4159 SCIP_Real* newandcoefs;
4160 SCIP_Real* oldandcoefs;
4161 SCIP_Bool* newandnegs;
4162 SCIP_Bool* oldandnegs;
4163 CONSANDDATA** consanddatas;
4164 int nconsanddatas;
4165 SCIP_CONSDATA* consdata;
4166 int oldnvars;
4167 int c;
4168 int c1;
4169
4170 assert(scip != NULL);
4171 assert(cons != NULL);
4172 assert(conshdlrdata != NULL);
4173 assert(conshdlrdata->hashmap != NULL);
4174 assert(nandress == 0 || (andress != NULL && andcoefs != NULL));
4175 assert(!SCIPisInfinity(scip, newlhs));
4176 assert(!SCIPisInfinity(scip, -newrhs));
4177 assert(SCIPisLE(scip, newlhs, newrhs));
4178
4179 consdata = SCIPconsGetData(cons);
4180 assert(consdata != NULL);
4181
4182 /* sort and-constraints by the problem indices of corresponding and-resultants */
4183 SCIPsortPtrRealBool((void**)(consdata->consanddatas), consdata->andcoefs, consdata->andnegs, resvarCompWithInactive, consdata->nconsanddatas);
4184
4185 /* sort and-resultants by their problem indices */
4186 SCIPsortPtrRealBool((void**)andress, andcoefs, andnegs, resvarComp, nandress);
4187
4188 consanddatas = consdata->consanddatas;
4189 oldandcoefs = consdata->andcoefs;
4190 oldandnegs = consdata->andnegs;
4191 nconsanddatas = consdata->nconsanddatas;
4192 assert(nconsanddatas == 0 || (consanddatas != NULL && oldandcoefs != NULL));
4193
4194 snewconsanddatas = nconsanddatas + nandress;
4195
4196 /* allocate new block memory arrays */
4197 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &newconsanddatas, snewconsanddatas) );
4198 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &newandcoefs, snewconsanddatas) );
4199 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &newandnegs, snewconsanddatas) );
4200
4201 nnewconsanddatas = 0;
4202
4203 /* collect new consanddata objects and update locks and captures */
4204 for( c = 0, c1 = 0; c < nconsanddatas && c1 < nandress; )
4205 {
4206 SCIP_CONS* andcons;
4207 SCIP_VAR* res1;
4208 SCIP_VAR* res2;
4209 int compval;
4210
4211 assert(consanddatas[c] != NULL);
4212
4213 /* consanddata object could have been deleted in the last presolving round */
4214 if( !consanddatas[c]->istransformed )
4215 {
4216 ++c;
4217 consdata->changed = TRUE;
4218 consdata->upgradetried = FALSE;
4219 continue;
4220 }
4221
4222 andcons = consanddatas[c]->cons;
4223 assert(andcons != NULL);
4224
4225 if( andcons == NULL ) /*lint !e774*/
4226 {
4227 ++c;
4228 consdata->changed = TRUE;
4229 consdata->upgradetried = FALSE;
4230 continue;
4231 }
4232 else if( SCIPconsIsDeleted(andcons) )
4233 {
4234 /* remove rounding locks, because the and constraint was deleted */
4235 SCIP_CALL( unlockRoundingAndCons(scip, cons, consanddatas[c],
4236 oldandnegs[c] ? -oldandcoefs[c] : oldandcoefs[c], consdata->lhs, consdata->rhs) );
4237 ++c;
4238 consdata->changed = TRUE;
4239 consdata->upgradetried = FALSE;
4240 continue;
4241 }
4242 assert(andcons != NULL);
4243
4244 /* get and-resultants of consanddata object in constraint data */
4245 res1 = SCIPgetResultantAnd(scip, andcons);
4246 assert(res1 != NULL);
4247 assert(SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)res1) == consanddatas[c]);
4248
4249 /* get and-resultants in new corresponding linear constraint */
4250 res2 = andress[c1];
4251 assert(res2 != NULL);
4252 assert(SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)res2) != NULL);
4253
4254 /* get comparison value */
4255 compval = resvarComp((void*)res1, (void*)res2);
4256
4257 /* collect new consanddata objects sorted with respect to the problem index of corresponding and-resultants */
4258 if( compval == -1 )
4259 {
4260 assert(!SCIPisZero(scip, oldandcoefs[c]));
4261 assert(consanddatas[c]->nuses > 0);
4262 --(consanddatas[c]->nuses);
4263
4264 /* remove old locks */
4265 SCIP_CALL( removeOldLocks(scip, cons, consanddatas[c], oldandnegs[c] ? -oldandcoefs[c] : oldandcoefs[c],
4266 consdata->lhs, consdata->rhs) );
4267 ++c;
4268 consdata->changed = TRUE;
4269 consdata->upgradetried = FALSE;
4270 consdata->propagated = FALSE;
4271 consdata->presolved = FALSE;
4272 }
4273 else if( compval == +1 )
4274 {
4275 assert(!SCIPisZero(scip, andcoefs[c1]));
4276 assert(SCIPhashmapExists(conshdlrdata->hashmap, (void*)res2));
4277 newconsanddatas[nnewconsanddatas] = (CONSANDDATA*) SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)res2);
4278 newandcoefs[nnewconsanddatas] = andcoefs[c1];
4279 newandnegs[nnewconsanddatas] = andnegs[c1];
4280 ++(newconsanddatas[nnewconsanddatas]->nuses);
4281
4282 /* add new locks */
4283 SCIP_CALL( addNewLocks(scip, cons, newconsanddatas[nnewconsanddatas], newandnegs[nnewconsanddatas] ?
4284 -newandcoefs[nnewconsanddatas] : newandcoefs[nnewconsanddatas], newlhs, newrhs) );
4285 ++c1;
4286 consdata->changed = TRUE;
4287 consdata->upgradetried = FALSE;
4288 consdata->cliquesadded = FALSE;
4289 consdata->propagated = FALSE;
4290 consdata->presolved = FALSE;
4291
4292 ++nnewconsanddatas;
4293 }
4294 else
4295 {
4296 SCIP_Bool coefsignchanged;
4297 SCIP_Bool lhschanged;
4298 SCIP_Bool rhschanged;
4299
4300 assert(!SCIPisZero(scip, oldandcoefs[c]));
4301 assert(!SCIPisZero(scip, andcoefs[c1]));
4302 assert(SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)res2) == consanddatas[c]);
4303
4304 /* copy old consanddata object and new coefficent */
4305 newconsanddatas[nnewconsanddatas] = consanddatas[c];
4306
4307 newandcoefs[nnewconsanddatas] = andcoefs[c1];
4308 newandnegs[nnewconsanddatas] = andnegs[c1];
4309
4310 if( ((oldandnegs[c] == andnegs[c1]) && !SCIPisEQ(scip, oldandcoefs[c], newandcoefs[c1]))
4311 || ((oldandnegs[c] != newandnegs[c1]) && !SCIPisEQ(scip, oldandcoefs[c], -newandcoefs[c1])) )
4312 consdata->upgradetried = FALSE;
4313
4314 coefsignchanged = (oldandnegs[c] == andnegs[c1]) &&
4315 ((oldandcoefs[c] < 0 && andcoefs[c1] > 0) || (oldandcoefs[c] > 0 && andcoefs[c1] < 0));
4316 coefsignchanged = coefsignchanged || ((oldandnegs[c] != andnegs[c1]) &&
4317 ((oldandcoefs[c] < 0 && andcoefs[c1] < 0) || (oldandcoefs[c] > 0 && andcoefs[c1] > 0)));
4318 lhschanged = (SCIPisInfinity(scip, -consdata->lhs) && !SCIPisInfinity(scip, -newlhs)) || (!SCIPisInfinity(scip, -consdata->lhs) && SCIPisInfinity(scip, -newlhs))
4319 || (consdata->lhs < 0 && newlhs > 0) || (consdata->lhs > 0 && newlhs < 0);
4320 rhschanged = (SCIPisInfinity(scip, consdata->rhs) && !SCIPisInfinity(scip, newrhs)) || (!SCIPisInfinity(scip, consdata->rhs) && SCIPisInfinity(scip, newrhs))
4321 || (consdata->rhs < 0 && newrhs > 0) || (consdata->rhs > 0 && newrhs < 0);
4322
4323 /* update or renew locks */
4324 if( coefsignchanged || lhschanged || rhschanged || newconsanddatas[nnewconsanddatas]->nnewvars > 0)
4325 {
4326 /* renew locks */
4327 SCIP_CALL( removeOldLocks(scip, cons, newconsanddatas[nnewconsanddatas], oldandnegs[c] ?
4328 -oldandcoefs[c] : oldandcoefs[c], consdata->lhs, consdata->rhs) );
4329 SCIP_CALL( addNewLocks(scip, cons, newconsanddatas[nnewconsanddatas], newandnegs[nnewconsanddatas] ?
4330 -newandcoefs[nnewconsanddatas] : newandcoefs[nnewconsanddatas], newlhs, newrhs) );
4331
4332 consdata->changed = TRUE;
4333 consdata->upgradetried = FALSE;
4334 consdata->cliquesadded = FALSE;
4335 consdata->propagated = FALSE;
4336 consdata->presolved = FALSE;
4337 }
4338
4339 ++c;
4340 ++c1;
4341 ++nnewconsanddatas;
4342 }
4343 }
4344
4345 /* add all remaining consanddatas and update locks and captures */
4346 if( c < nconsanddatas )
4347 {
4348 assert(c1 == nandress);
4349
4350 for( ; c < nconsanddatas; ++c )
4351 {
4352 SCIP_CONS* andcons;
4353#ifndef NDEBUG
4354 SCIP_VAR* res1;
4355
4356 assert(consanddatas[c] != NULL);
4357#endif
4358 andcons = consanddatas[c]->cons;
4359#ifndef NDEBUG
4360 if( andcons != NULL )
4361 {
4362 res1 = SCIPgetResultantAnd(scip, andcons);
4363 assert(res1 != NULL);
4364 assert(SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)res1) == consanddatas[c]);
4365 }
4366#endif
4367 if( andcons == NULL )
4368 {
4369 consdata->changed = TRUE;
4370 consdata->upgradetried = FALSE;
4371 continue;
4372 }
4373
4374 assert(consanddatas[c]->nuses > 0);
4375 --(consanddatas[c]->nuses);
4376
4377 /* remove old locks */
4378 SCIP_CALL( removeOldLocks(scip, cons, consanddatas[c], oldandnegs[c] ? -oldandcoefs[c] : oldandcoefs[c],
4379 consdata->lhs, consdata->rhs) );
4380 consdata->changed = TRUE;
4381 consdata->upgradetried = FALSE;
4382 consdata->propagated = FALSE;
4383 consdata->presolved = FALSE;
4384 }
4385 }
4386 else if( c1 < nandress )
4387 {
4388 for( ; c1 < nandress; ++c1 )
4389 {
4390 SCIP_VAR* res2;
4391
4392 res2 = andress[c1];
4393 assert(res2 != NULL);
4394 assert(SCIPhashmapExists(conshdlrdata->hashmap, (void*)res2));
4395 newconsanddatas[nnewconsanddatas] = (CONSANDDATA*) SCIPhashmapGetImage(conshdlrdata->hashmap, (void*)res2);
4396 newandcoefs[nnewconsanddatas] = andcoefs[c1];
4397 newandnegs[nnewconsanddatas] = andnegs[c1];
4398 ++(newconsanddatas[nnewconsanddatas]->nuses);
4399
4400 /* add new locks */
4401 SCIP_CALL( addNewLocks(scip, cons, newconsanddatas[nnewconsanddatas], newandnegs[nnewconsanddatas] ?
4402 -newandcoefs[nnewconsanddatas] : newandcoefs[nnewconsanddatas], newlhs, newrhs) );
4403
4404 ++nnewconsanddatas;
4405 consdata->changed = TRUE;
4406 consdata->upgradetried = FALSE;
4407 consdata->cliquesadded = FALSE;
4408 consdata->propagated = FALSE;
4409 consdata->presolved = FALSE;
4410 }
4411 }
4412 assert(c == nconsanddatas && c1 == nandress);
4413
4414 /* delete old and-coefficients and consanddata objects */
4415 SCIPfreeBlockMemoryArray(scip, &(consdata->andcoefs), consdata->sconsanddatas);
4416 SCIPfreeBlockMemoryArray(scip, &(consdata->andnegs), consdata->sconsanddatas);
4417 SCIPfreeBlockMemoryArray(scip, &(consdata->consanddatas), consdata->sconsanddatas);
4418
4419 if( !SCIPisEQ(scip, consdata->lhs, newlhs) || !SCIPisEQ(scip, consdata->rhs, newrhs) )
4420 {
4421 consdata->upgradetried = FALSE;
4422 consdata->lhs = newlhs;
4423 consdata->rhs = newrhs;
4424 }
4425
4426 consdata->consanddatas = newconsanddatas;
4427 consdata->andcoefs = newandcoefs;
4428 consdata->andnegs = newandnegs;
4429 consdata->nconsanddatas = nnewconsanddatas;
4430 consdata->sconsanddatas = snewconsanddatas;
4431
4432 oldnvars = consdata->nlinvars;
4433 /* update number of linear variables without and-resultants */
4434 SCIP_CALL( getLinearConsNVars(scip, consdata->lincons, consdata->linconstype, &(consdata->nlinvars)) );
4435 consdata->nlinvars -= nnewconsanddatas;
4436
4437 if( oldnvars != consdata->nlinvars )
4438 {
4439 consdata->changed = TRUE;
4440 consdata->upgradetried = FALSE;
4441 consdata->cliquesadded = FALSE;
4442 consdata->propagated = FALSE;
4443 consdata->presolved = FALSE;
4444 }
4445
4446#ifndef NDEBUG
4447 consanddatas = consdata->consanddatas;
4448 nconsanddatas = consdata->nconsanddatas;
4449 assert(nconsanddatas == 0 || consanddatas != NULL);
4450
4451 /* check that consanddata objects are sorted with respect to the problem index of the corresponding resultants */
4452 for( c = nconsanddatas - 1; c > 0; --c )
4453 {
4454 SCIP_VAR* res1;
4455 SCIP_VAR* res2;
4456 SCIP_Bool resneg1;
4457 SCIP_Bool resneg2;
4458 int resind1;
4459 int resind2;
4460
4461 assert(consanddatas[c] != NULL);
4462 assert(consanddatas[c]->cons != NULL);
4463 res1 = SCIPgetResultantAnd(scip, consanddatas[c]->cons);
4464 assert(res1 != NULL);
4465 assert(consanddatas[c - 1] != NULL);
4466 assert(consanddatas[c - 1]->cons != NULL);
4467 res2 = SCIPgetResultantAnd(scip, consanddatas[c - 1]->cons);
4468 assert(res2 != NULL);
4469 resneg1 = SCIPvarIsNegated(res1);
4470 if( resneg1 )
4471 {
4472 res1 = SCIPvarGetNegatedVar(res1);
4473 assert(res1 != NULL);
4474 }
4475 resneg2 = SCIPvarIsNegated(res2);
4476 if( resneg2 )
4477 {
4478 res2 = SCIPvarGetNegatedVar(res2);
4479 assert(res2 != NULL);
4480 }
4481 resind1 = SCIPvarGetProbindex(res1);
4482 resind2 = SCIPvarGetProbindex(res2);
4483 if( resind1 == -1 && resind2 == -1 )
4484 {
4485 resind1 = SCIPvarGetIndex(res1);
4486 resind2 = SCIPvarGetIndex(res2);
4487 }
4488
4489 if( resind1 <= resind2 )
4490 {
4491 assert(resind1 == resind2);
4492 assert(!resneg1);
4493 assert(resneg2);
4494 }
4495 }
4496#endif
4497
4498 return SCIP_OKAY;
4499}
4500
4501/** adds cliques of the pseudoboolean constraint to the global clique table */
4502static
4504 SCIP*const scip, /**< SCIP data structure */
4505 SCIP_CONS*const cons, /**< pseudoboolean constraint */
4506 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
4507 int*const naggrvars, /**< pointer to count the number of aggregated variables */
4508 int*const nchgbds /**< pointer to count the number of performed bound changes */
4509 )
4510{
4511 SCIP_CONSDATA* consdata;
4512 SCIP_VAR** vars;
4513 int nvars;
4514 SCIP_VAR** linvars;
4515 SCIP_VAR* andres;
4516 SCIP_VAR* andres2;
4517 int nlinvars;
4518 int nandress;
4519 int c;
4520 int v2;
4521 int v1;
4522 int nchgbdslocal;
4523
4524 assert(scip != NULL);
4525 assert(cons != NULL);
4526 assert(cutoff != NULL);
4527 assert(naggrvars != NULL);
4528 assert(nchgbds != NULL);
4529 assert(SCIPconsIsActive(cons));
4530
4531 *cutoff = FALSE;
4532
4533 consdata = SCIPconsGetData(cons);
4534 assert(consdata != NULL);
4535 /* if we have no and-constraints left, we should not be here and this constraint should be deleted (only the linaer should survive) */
4536 assert(consdata->nconsanddatas > 0);
4537
4538 /* check whether the cliques have already been added */
4539 if( consdata->cliquesadded )
4540 return SCIP_OKAY;
4541
4542 consdata->cliquesadded = TRUE;
4543
4545
4546 /* check standard pointers and sizes */
4547 assert(consdata->lincons != NULL);
4548 assert(SCIPconsIsActive(consdata->lincons));
4549 assert(consdata->linconstype > SCIP_LINEARCONSTYPE_INVALIDCONS);
4550 assert(consdata->consanddatas != NULL);
4551 assert(consdata->nconsanddatas > 0);
4552 assert(consdata->nconsanddatas <= consdata->sconsanddatas);
4553
4554 /* check number of linear variables */
4555 SCIP_CALL( getLinearConsNVars(scip, consdata->lincons, consdata->linconstype, &nvars) );
4556 assert(nvars == consdata->nlinvars + consdata->nconsanddatas);
4557
4558 /* get temporary memory */
4559 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
4560 SCIP_CALL( SCIPallocBufferArray(scip, &linvars, nvars) );
4561
4562 /* get variables and coefficients */
4563 SCIP_CALL( getLinearConsVarsData(scip, consdata->lincons, consdata->linconstype, vars, NULL, &nvars) );
4564
4565 /* calculate all not artificial linear variables and all artificial and-resultants
4566 * @todo should we take into accout the negation status of the cliques?
4567 */
4568 SCIP_CALL( getLinVarsAndAndRess(scip, cons, vars, NULL, nvars, linvars, NULL, &nlinvars,
4569 NULL, NULL, NULL, &nandress) );
4570
4571 assert(nandress == consdata->nconsanddatas);
4572 assert(consdata->consanddatas != NULL);
4573
4574 /* find cliques from linear variable to and-resultant */
4575 for( c = nandress - 1; c >= 0; --c )
4576 {
4577 CONSANDDATA* consanddata;
4578 SCIP_VAR** andvars;
4579 int nandvars;
4580
4581 consanddata = consdata->consanddatas[c];
4582 assert(consanddata != NULL);
4583
4584 andres = SCIPgetResultantAnd(scip, consanddata->cons);
4585
4586 /* choose correct variable array */
4587 if( consanddata->nnewvars > 0 )
4588 {
4589 andvars = consanddata->newvars;
4590 nandvars = consanddata->nnewvars;
4591 }
4592 else
4593 {
4594 andvars = consanddata->vars;
4595 nandvars = consanddata->nvars;
4596 }
4597
4598 for( v1 = nandvars - 1; v1 >= 0; --v1 )
4599 {
4600 SCIP_VAR* var1;
4601 SCIP_Bool values[2];
4602
4603 var1 = andvars[v1];
4604 if( !SCIPvarIsActive(var1) && (!SCIPvarIsNegated(var1) || !SCIPvarIsActive(SCIPvarGetNegationVar(var1))) )
4605 continue;
4606
4607 /* get active counterpart to check for common cliques */
4609 {
4610 var1 = SCIPvarGetNegationVar(var1);
4611 values[0] = FALSE;
4612 }
4613 else
4614 values[0] = TRUE;
4615
4616 for( v2 = nlinvars - 1; v2 >= 0; --v2 )
4617 {
4618 SCIP_VAR* var2;
4619
4620 var2 = linvars[v2];
4621 if( !SCIPvarIsActive(var2) && (!SCIPvarIsNegated(var2) || !SCIPvarIsActive(SCIPvarGetNegationVar(var2))) )
4622 continue;
4623
4624 /* get active counterpart to check for common cliques */
4626 {
4627 var2 = SCIPvarGetNegationVar(var2);
4628 values[1] = FALSE;
4629 }
4630 else
4631 values[1] = TRUE;
4632
4633 /* if variable in and-constraint1 is the negated variable of a normal linear variable, than we can add a
4634 * clique between the and-resultant and the normal linear variable, negated variables are not save in
4635 * cliquetables
4636 *
4637 * set r_1 = var1 * z; (z is some product)
4638 * var1 == ~var2
4639 *
4640 * if:
4641 * var1 + ~var1 <= 1; r_1
4642 * 0 + 1 <= 1 0 \
4643 * 1 + 0 <= 1 ==> 1 or 0 > ==> r_1 + var2 <= 1
4644 * 0 + 0 <= 1 0 /
4645 */
4646 if( values[0] != values[1] && var1 == var2 )
4647 {
4648 SCIP_CONS* newcons;
4649 SCIP_VAR* clqvars[2];
4650 char consname[SCIP_MAXSTRLEN];
4651
4652 clqvars[0] = andres;
4653 clqvars[1] = values[1] ? var2 : SCIPvarGetNegatedVar(var2);
4654 assert(clqvars[1] != NULL);
4655
4656 /* @todo: check whether it is better to only add the clique or to add the setppc constraint or do both */
4657
4658 /* add clique */
4659 SCIP_CALL( SCIPaddClique(scip, clqvars, NULL, 2, FALSE, cutoff, &nchgbdslocal) );
4660 if( *cutoff )
4661 goto TERMINATE;
4662
4663 *nchgbds += nchgbdslocal;
4664
4665 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_clq_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(clqvars[0]), SCIPvarGetName(clqvars[1]) );
4666 SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, consname, 2, clqvars,
4671
4672 SCIP_CALL( SCIPaddCons(scip, newcons) );
4673 SCIPdebugMsg(scip, "added a clique/setppc constraint <%s> \n", SCIPconsGetName(newcons));
4674 SCIPdebugPrintCons(scip, newcons, NULL);
4675
4676 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4677 }
4678 /* if a variable in an and-constraint is in a clique with another normal linear variable, we can add the
4679 * clique between the linear variable and the and-resultant
4680 *
4681 * set r_1 = var1 * z; (z is some product)
4682 *
4683 * if:
4684 * var1 + var2 <= 1; r_1
4685 * 0 + 1 <= 1 0 \
4686 * 1 + 0 <= 1 ==> 1 or 0 > ==> r_1 + var2 <= 1
4687 * 0 + 0 <= 1 0 /
4688 */
4689 if( (var1 != var2) && SCIPvarsHaveCommonClique(var1, values[0], var2, values[1], TRUE) )
4690 {
4691 SCIP_CONS* newcons;
4692 SCIP_VAR* clqvars[2];
4693 char consname[SCIP_MAXSTRLEN];
4694
4695 clqvars[0] = andres;
4696 clqvars[1] = values[1] ? var2 : SCIPvarGetNegatedVar(var2);
4697 assert(clqvars[1] != NULL);
4698
4699 /* @todo: check whether it is better to only add the clique or to add the setppc constraint or do both */
4700
4701 /* add clique */
4702 SCIP_CALL( SCIPaddClique(scip, clqvars, NULL, 2, FALSE, cutoff, &nchgbdslocal) );
4703 if( *cutoff )
4704 goto TERMINATE;
4705
4706 *nchgbds += nchgbdslocal;
4707
4708 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_clq_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(clqvars[0]), SCIPvarGetName(clqvars[1]) );
4709 SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, consname, 2, clqvars,
4714
4715 SCIP_CALL( SCIPaddCons(scip, newcons) );
4716 SCIPdebugMsg(scip, "added a clique/setppc constraint <%s> \n", SCIPconsGetName(newcons));
4717 SCIPdebugPrintCons(scip, newcons, NULL);
4718
4719 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4720 }
4721 }
4722 }
4723 }
4724
4725 /* find cliques over variables which are in different and-constraints */
4726 for( c = nandress - 1; c > 0; --c )
4727 {
4728 CONSANDDATA* consanddata1;
4729 CONSANDDATA* consanddata2;
4730 SCIP_VAR** andvars1;
4731 int nandvars1;
4732 SCIP_VAR** andvars2;
4733 int nandvars2;
4734
4735 consanddata1 = consdata->consanddatas[c];
4736 assert(consanddata1 != NULL);
4737 consanddata2 = consdata->consanddatas[c - 1];
4738 assert(consanddata2 != NULL);
4739
4740 andres = SCIPgetResultantAnd(scip, consanddata1->cons);
4741 andres2 = SCIPgetResultantAnd(scip, consanddata2->cons);
4742
4743 /* choose correct variable array of consanddata object 1 */
4744 if( consanddata1->nnewvars > 0 )
4745 {
4746 andvars1 = consanddata1->newvars;
4747 nandvars1 = consanddata1->nnewvars;
4748 }
4749 else
4750 {
4751 andvars1 = consanddata1->vars;
4752 nandvars1 = consanddata1->nvars;
4753 }
4754
4755 /* choose correct variable array of consanddata object 2 */
4756 if( consanddata2->nnewvars > 0 )
4757 {
4758 andvars2 = consanddata2->newvars;
4759 nandvars2 = consanddata2->nnewvars;
4760 }
4761 else
4762 {
4763 andvars2 = consanddata2->vars;
4764 nandvars2 = consanddata2->nvars;
4765 }
4766
4767 /* compare both terms for finding new aggregated variables and new cliques */
4768 for( v1 = nandvars1 - 1; v1 >= 0; --v1 )
4769 {
4770 SCIP_VAR* var1;
4771 SCIP_Bool values[2];
4772
4773 var1 = andvars1[v1];
4774 if( !SCIPvarIsActive(var1) && (!SCIPvarIsNegated(var1) || !SCIPvarIsActive(SCIPvarGetNegationVar(var1))) )
4775 continue;
4776
4777 /* get active counterpart to check for common cliques */
4779 {
4780 var1 = SCIPvarGetNegationVar(var1);
4781 values[0] = FALSE;
4782 }
4783 else
4784 values[0] = TRUE;
4785
4786 for( v2 = nandvars2 - 1; v2 >= 0; --v2 )
4787 {
4788 SCIP_VAR* var2;
4789
4790 var2 = andvars2[v2];
4791 if( !SCIPvarIsActive(var2) && (!SCIPvarIsNegated(var2) || !SCIPvarIsActive(SCIPvarGetNegationVar(var2))) )
4792 continue;
4793
4794 /* get active counterpart to check for common cliques */
4796 {
4797 var2 = SCIPvarGetNegationVar(var2);
4798 values[1] = FALSE;
4799 }
4800 else
4801 values[1] = TRUE;
4802
4803 /* if a variable in and-constraint1 is the negated variable of a variable in and-constraint2, than we can
4804 * add a clique between both and-resultants, negated variables are not save in cliquetables
4805 *
4806 * set r_1 = var1 * z_1; (z_1 is some product)
4807 * set r_2 = var2 * z_2; (z_2 is some product)
4808 * var1 == ~var2
4809 *
4810 * if:
4811 * var1 + ~var1 <= 1; r_1 r_2
4812 * 0 + 1 <= 1 0 1 or 0 \
4813 * 1 + 0 <= 1 ==> 1 or 0 0 > ==> r_1 + r_2 <= 1
4814 * 0 + 0 <= 1 0 0 /
4815 */
4816 if( values[0] != values[1] && var1 == var2 )
4817 {
4818 SCIP_CONS* newcons;
4819 SCIP_VAR* clqvars[2];
4820 char consname[SCIP_MAXSTRLEN];
4821
4822 clqvars[0] = andres;
4823 clqvars[1] = andres2;
4824
4825 /* @todo: check whether it is better to only add the clique or to add the setppc constraint or do both */
4826
4827 /* add clique */
4828 SCIP_CALL( SCIPaddClique(scip, clqvars, NULL, 2, FALSE, cutoff, &nchgbdslocal) );
4829 if( *cutoff )
4830 goto TERMINATE;
4831
4832 *nchgbds += nchgbdslocal;
4833
4834 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_clq_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(clqvars[0]), SCIPvarGetName(clqvars[1]) );
4835 SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, consname, 2, clqvars,
4840
4841 SCIP_CALL( SCIPaddCons(scip, newcons) );
4842 SCIPdebugMsg(scip, "added a clique/setppc constraint <%s> \n", SCIPconsGetName(newcons));
4843 SCIPdebugPrintCons(scip, newcons, NULL);
4844
4845 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4846 }
4847 /* if a variable in an and-constraint is in a clique with a variable in another and-constraint, we can add
4848 * the clique between both and-resultant
4849 *
4850 * let r_1 = var1 * z_1; (z_1 is some product)
4851 * let r_2 = var2 * z_2; (z_2 is some product)
4852 *
4853 * if:
4854 * var1 + var2 <= 1; r_1 r_2
4855 * 0 + 1 <= 1 0 1 or 0 \
4856 * 1 + 0 <= 1 ==> 1 or 0 0 > ==> r_1 + r_2 <= 1
4857 * 0 + 0 <= 1 0 0 /
4858 */
4859 else if( SCIPvarsHaveCommonClique(var1, values[0], var2, values[1], TRUE) && (var1 != var2) )
4860 {
4861 SCIP_CONS* newcons;
4862 SCIP_VAR* clqvars[2];
4863 char consname[SCIP_MAXSTRLEN];
4864
4865 clqvars[0] = andres;
4866 clqvars[1] = values[1] ? var2 : SCIPvarGetNegatedVar(var2);
4867 assert(clqvars[1] != NULL);
4868
4869 /* @todo: check whether it is better to only add the clique or to add the setppc constraint or do both */
4870
4871 /* add clique */
4872 SCIP_CALL( SCIPaddClique(scip, clqvars, NULL, 2, FALSE, cutoff, &nchgbdslocal) );
4873 if( *cutoff )
4874 goto TERMINATE;
4875
4876 *nchgbds += nchgbdslocal;
4877
4878 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_clq_%s_%s", SCIPconsGetName(cons), SCIPvarGetName(clqvars[0]), SCIPvarGetName(clqvars[1]) );
4879 SCIP_CALL( SCIPcreateConsSetpack(scip, &newcons, consname, 2, clqvars,
4884
4885 SCIP_CALL( SCIPaddCons(scip, newcons) );
4886 SCIPdebugMsg(scip, "added a clique/setppc constraint <%s> \n", SCIPconsGetName(newcons));
4887 SCIPdebugPrintCons(scip, newcons, NULL);
4888
4889 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4890 }
4891 }
4892 }
4893 }
4894
4895 TERMINATE:
4896 /* free temporary memory */
4897 SCIPfreeBufferArray(scip, &linvars);
4898 SCIPfreeBufferArray(scip, &vars);
4899
4900 return SCIP_OKAY;
4901}
4902
4903/** propagation method for pseudoboolean constraints */
4904static
4906 SCIP*const scip, /**< SCIP data structure */
4907 SCIP_CONS*const cons, /**< knapsack constraint */
4908 SCIP_Bool*const cutoff, /**< pointer to store whether the node can be cut off */
4909 int*const ndelconss /**< pointer to count number of deleted constraints */
4910 )
4911{
4912 SCIP_CONSDATA* consdata;
4913
4914 assert(scip != NULL);
4915 assert(cons != NULL);
4916 assert(cutoff != NULL);
4917 assert(ndelconss != NULL);
4918
4919 *cutoff = FALSE;
4920
4921 consdata = SCIPconsGetData(cons);
4922 assert(consdata != NULL);
4923 assert(consdata->lincons != NULL);
4924
4925 /* if linear constraint is redundant, than pseudoboolean constraint is redundant too */
4926 if( SCIPconsIsDeleted(consdata->lincons) )
4927 {
4929 ++(*ndelconss);
4930 }
4931
4932 /* check if the constraint was already propagated */
4933 if( consdata->propagated )
4934 return SCIP_OKAY;
4935
4936 /* mark the constraint propagated */
4937 consdata->propagated = TRUE;
4938
4939 return SCIP_OKAY;
4940}
4941
4942/** update and-constraint flags due to pseudoboolean constraint flags */
4943static
4945 SCIP*const scip, /**< SCIP data structure */
4946 SCIP_CONS*const cons /**< pseudoboolean constraint */
4947 )
4948{
4949 CONSANDDATA** consanddatas;
4950 int nconsanddatas;
4951 SCIP_CONSDATA* consdata;
4952 int c;
4953
4954 assert(scip != NULL);
4955 assert(cons != NULL);
4956
4957 consdata = SCIPconsGetData(cons);
4958 assert(consdata != NULL);
4959
4960 consanddatas = consdata->consanddatas;
4961 nconsanddatas = consdata->nconsanddatas;
4962 assert(nconsanddatas == 0 || consanddatas != NULL);
4963
4964 if( !SCIPconsIsActive(cons) )
4965 return SCIP_OKAY;
4966
4967 /* release and-constraints and change check flag of and-constraint */
4968 for( c = nconsanddatas - 1; c >= 0; --c )
4969 {
4970 SCIP_CONS* andcons;
4971
4972 assert(consanddatas[c] != NULL);
4973
4974 if( !consanddatas[c]->istransformed )
4975 continue;
4976
4977 andcons = consanddatas[c]->cons;
4978 assert(andcons != NULL);
4979
4981 }
4982
4983 return SCIP_OKAY;
4984}
4985
4986/** delete unused information in constraint handler data */
4987static
4989 SCIP*const scip, /**< SCIP data structure */
4990 SCIP_CONSHDLRDATA*const conshdlrdata, /**< pseudoboolean constraint handler data */
4991 int*const ndelconss /**< pointer to count number of deleted constraints */
4992 )
4993{
4994 CONSANDDATA** allconsanddatas;
4995 CONSANDDATA* consanddata;
4996 SCIP_VAR** fixedvars = SCIPgetFixedVars(scip);
4997 SCIP_VAR** activevars;
4998 SCIP_Real* activescalars;
4999 SCIP_Real activeconstant;
5000 int nvars = SCIPgetNVars(scip);
5001 int nfixedvars = SCIPgetNFixedVars(scip);
5002 int c;
5003
5004 assert(scip != NULL);
5005 assert(conshdlrdata != NULL);
5006 assert(ndelconss != NULL);
5007
5008 if( conshdlrdata->nallconsanddatas == 0 )
5009 return SCIP_OKAY;
5010
5011 allconsanddatas = conshdlrdata->allconsanddatas;
5012 assert(allconsanddatas != NULL);
5013 assert(conshdlrdata->nallconsanddatas >= 1);
5014 assert(conshdlrdata->nallconsanddatas <= conshdlrdata->sallconsanddatas);
5015
5016 if( nfixedvars >= 1 && nvars >= 1 )
5017 {
5018 SCIP_CALL( SCIPallocBufferArray(scip, &activevars, nvars) );
5019 SCIP_CALL( SCIPallocBufferArray(scip, &activescalars, nvars) );
5020 }
5021 else
5022 {
5023 activevars = NULL;
5024 activescalars = NULL;
5025 }
5026
5027 for( c = conshdlrdata->nallconsanddatas - 1; c >= 0; --c )
5028 {
5029 SCIP_VAR** tmpvars;
5030 int stmpvars;
5031 SCIP_CONS* cons;
5032 int v;
5033
5034 consanddata = allconsanddatas[c];
5035
5036 assert(consanddata->nvars == 0 || (consanddata->vars != NULL && consanddata->svars > 0));
5037 assert(consanddata->nnewvars == 0 || (consanddata->newvars != NULL && consanddata->snewvars > 0));
5038
5039 if( !consanddata->istransformed )
5040 {
5041 assert(consanddata->vars == NULL || consanddata->origcons != NULL);
5042 assert(consanddata->nvars == 0 || consanddata->origcons != NULL);
5043 assert(consanddata->svars == 0 || consanddata->origcons != NULL);
5044 assert(consanddata->newvars == NULL);
5045 assert(consanddata->nnewvars == 0);
5046 assert(consanddata->snewvars == 0);
5047
5048 continue;
5049 }
5050
5051 /* if no variables are left, delete variables arrays */
5052 if( consanddata->nvars == 0 )
5053 {
5054 SCIP_VAR* resvar = SCIPgetResultantAnd(scip, consanddata->cons);
5055
5056 /* if we have no old variables, than also no new variables */
5057 assert(consanddata->nnewvars == 0);
5058 assert(consanddata->nuses > 0);
5059 assert(resvar != NULL);
5060
5061 /* delete and-constraint */
5062 SCIP_CALL( SCIPdelCons(scip, consanddata->cons) );
5063 ++(*ndelconss);
5064
5065 SCIP_CALL( transformToOrig(scip, consanddata, conshdlrdata) );
5066
5067 /* release and-constraint */
5068 SCIP_CALL( SCIPreleaseCons(scip, &consanddata->cons) );
5069 consanddata->nuses = 0;
5070
5071 /* remove consanddata from hashtable, if it existed only in transformed space */
5072 if( consanddata->origcons == NULL )
5073 {
5074 assert(SCIPhashtableExists(conshdlrdata->hashtable, (void*)consanddata));
5075 SCIP_CALL( SCIPhashtableRemove(conshdlrdata->hashtable, (void*)consanddata) );
5076 }
5077 assert(SCIPhashmapExists(conshdlrdata->hashmap, (void*)resvar));
5078 SCIP_CALL( SCIPhashmapRemove(conshdlrdata->hashmap, (void*)resvar) );
5079
5080 continue;
5081 }
5082
5083 /* the consanddata object is not used anymore, so extract the and constraint and delete other data */
5084 if( consanddata->nuses == 0 )
5085 {
5086 SCIP_Bool looseorcolumn;
5087 SCIP_VARSTATUS varstatus;
5088
5089 if( consanddata->cons == NULL )
5090 {
5091 assert(!consanddata->istransformed || consanddata->noriguses > 0);
5092 assert((consanddata->noriguses > 0) == (consanddata->origcons != NULL));
5093 assert(consanddata->vars == NULL || consanddata->origcons != NULL);
5094 assert(consanddata->nvars == 0 || consanddata->origcons != NULL);
5095 assert(consanddata->svars == 0 || consanddata->origcons != NULL);
5096 assert(consanddata->newvars == NULL);
5097 assert(consanddata->nnewvars == 0);
5098 assert(consanddata->snewvars == 0);
5099
5100 continue;
5101 }
5102
5103 SCIP_CALL( transformToOrig(scip, consanddata, conshdlrdata) );
5104
5105 varstatus = SCIPvarGetStatus(SCIPgetResultantAnd(scip, consanddata->cons));
5106 looseorcolumn = (varstatus == SCIP_VARSTATUS_LOOSE || varstatus == SCIP_VARSTATUS_COLUMN);
5107
5108 /* @note due to aggregations or fixings the resultant may need to be propagated later on, so we can only
5109 * delete the and-constraint if the resultant is of column or loose status
5110 * and is not an active variable of another (multi-)aggregated/negated variable
5111 */
5112 if( looseorcolumn )
5113 {
5114 SCIP_VAR* resvar = SCIPgetResultantAnd(scip, consanddata->cons);
5115 SCIP_Bool del = TRUE;
5116 int w;
5117
5118 assert(nvars >= 1);
5119
5120 /* we need to check all active representatives */
5121 for( w = 0; w < nfixedvars && del; ++w )
5122 {
5123 int nactivevars;
5124 int requiredsize;
5125 int i;
5126
5127 assert(fixedvars != NULL);
5128 assert(activevars != NULL);
5129 assert(activescalars != NULL);
5130 activevars[0] = fixedvars[w];
5131 activescalars[0] = 1.0;
5132 activeconstant = 0.0;
5133 nactivevars = 1;
5134 SCIP_CALL( SCIPgetProbvarLinearSum(scip, activevars, activescalars, &nactivevars, nvars,
5135 &activeconstant, &requiredsize, TRUE) );
5136 assert(requiredsize <= nvars);
5137
5138 for( i = 0; i < nactivevars && del; ++i )
5139 {
5140 assert(SCIPvarGetStatus(activevars[i]) == SCIP_VARSTATUS_LOOSE || SCIPvarGetStatus(activevars[i]) == SCIP_VARSTATUS_COLUMN || SCIPvarGetStatus(activevars[i]) == SCIP_VARSTATUS_FIXED);
5141
5142 if( activevars[i] == resvar )
5143 del = FALSE;
5144 }
5145 }
5146
5147 if( del )
5148 {
5149 SCIP_CALL( SCIPdelCons(scip, consanddata->cons) );
5150 }
5151 }
5152
5153 if( !SCIPconsIsDeleted(consanddata->cons) )
5154 {
5155 /* change flags */
5156 if( !looseorcolumn )
5157 {
5158 SCIP_CALL( SCIPsetConsInitial(scip, consanddata->cons, FALSE) );
5159 }
5160 SCIP_CALL( SCIPsetConsChecked(scip, consanddata->cons, TRUE) );
5161 }
5162
5163 /* remove consanddata from hashtable, if it existed only in transformed space */
5164 if( consanddata->origcons == NULL )
5165 {
5166 assert(SCIPhashtableExists(conshdlrdata->hashtable, (void*)consanddata));
5167 SCIP_CALL( SCIPhashtableRemove(conshdlrdata->hashtable, (void*)consanddata) );
5168 }
5169 assert(SCIPhashmapExists(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddata->cons)));
5170 SCIP_CALL( SCIPhashmapRemove(conshdlrdata->hashmap, (void*)SCIPgetResultantAnd(scip, consanddata->cons)) );
5171
5172 SCIP_CALL( SCIPreleaseCons(scip, &(consanddata->cons)) );
5173 ++(*ndelconss);
5174
5175 continue;
5176 }
5177
5178 cons = consanddata->cons;
5179 assert(cons != NULL);
5180
5181 /* if and-constraint is deleted, delete variables arrays */
5182 if( SCIPconsIsDeleted(cons) )
5183 {
5184 SCIP_VAR* resvar = SCIPgetResultantAnd(scip, consanddata->cons);
5185
5186 assert(consanddata->nuses > 0);
5187 assert(resvar != NULL);
5188
5189 SCIP_CALL( transformToOrig(scip, consanddata, conshdlrdata) );
5190
5191 /* release and-constraint */
5192 SCIP_CALL( SCIPreleaseCons(scip, &consanddata->cons) );
5193 consanddata->nuses = 0;
5194
5195 /* remove consanddata from hashtable, if it existed only in transformed space */
5196 if( consanddata->origcons == NULL )
5197 {
5198 assert(SCIPhashtableExists(conshdlrdata->hashtable, (void*)consanddata));
5199 SCIP_CALL( SCIPhashtableRemove(conshdlrdata->hashtable, (void*)consanddata) );
5200 }
5201 assert(SCIPhashmapExists(conshdlrdata->hashmap, (void*)resvar));
5202 SCIP_CALL(