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