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