Scippy

SCIP

Solving Constraint Integer Programs

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