Scippy

SCIP

Solving Constraint Integer Programs

implics.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-2015 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 implics.c
17  * @brief methods for implications, variable bounds, and clique tables
18  * @author Tobias Achterberg
19  */
20 
21 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
22 
23 #include <stdlib.h>
24 #include <assert.h>
25 
26 #include "scip/def.h"
27 #include "scip/set.h"
28 #include "scip/stat.h"
29 #include "scip/event.h"
30 #include "scip/var.h"
31 #include "scip/implics.h"
32 #include "scip/pub_message.h"
33 #include "scip/pub_misc.h"
34 #include "scip/debug.h"
35 
36 #ifndef NDEBUG
37 #include "scip/struct_implics.h"
38 #endif
39 
40 
41 
42 /*
43  * methods for variable bounds
44  */
45 
46 /** creates a variable bounds data structure */
47 static
49  SCIP_VBOUNDS** vbounds, /**< pointer to store variable bounds data structure */
50  BMS_BLKMEM* blkmem /**< block memory */
51  )
52 {
53  assert(vbounds != NULL);
54 
55  SCIP_ALLOC( BMSallocBlockMemory(blkmem, vbounds) );
56  (*vbounds)->vars = NULL;
57  (*vbounds)->coefs = NULL;
58  (*vbounds)->constants = NULL;
59  (*vbounds)->len = 0;
60  (*vbounds)->size = 0;
61 
62  return SCIP_OKAY;
63 }
64 
65 /** frees a variable bounds data structure */
67  SCIP_VBOUNDS** vbounds, /**< pointer to store variable bounds data structure */
68  BMS_BLKMEM* blkmem /**< block memory */
69  )
70 {
71  assert(vbounds != NULL);
72 
73  if( *vbounds != NULL )
74  {
75  BMSfreeBlockMemoryArrayNull(blkmem, &(*vbounds)->vars, (*vbounds)->size);
76  BMSfreeBlockMemoryArrayNull(blkmem, &(*vbounds)->coefs, (*vbounds)->size);
77  BMSfreeBlockMemoryArrayNull(blkmem, &(*vbounds)->constants, (*vbounds)->size);
78  BMSfreeBlockMemory(blkmem, vbounds);
79  }
80 }
81 
82 /** ensures, that variable bounds arrays can store at least num entries */
83 static
85  SCIP_VBOUNDS** vbounds, /**< pointer to variable bounds data structure */
86  BMS_BLKMEM* blkmem, /**< block memory */
87  SCIP_SET* set, /**< global SCIP settings */
88  int num /**< minimum number of entries to store */
89  )
90 {
91  assert(vbounds != NULL);
92 
93  /* create variable bounds data structure, if not yet existing */
94  if( *vbounds == NULL )
95  {
96  SCIP_CALL( vboundsCreate(vbounds, blkmem) );
97  }
98  assert(*vbounds != NULL);
99  assert((*vbounds)->len <= (*vbounds)->size);
100 
101  if( num > (*vbounds)->size )
102  {
103  int newsize;
104 
105  newsize = SCIPsetCalcMemGrowSize(set, num);
106  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*vbounds)->vars, (*vbounds)->size, newsize) );
107  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*vbounds)->coefs, (*vbounds)->size, newsize) );
108  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*vbounds)->constants, (*vbounds)->size, newsize) );
109  (*vbounds)->size = newsize;
110  }
111  assert(num <= (*vbounds)->size);
112 
113  return SCIP_OKAY;
114 }
115 
116 /** binary searches the insertion position of the given variable in the vbounds data structure */
117 static
119  SCIP_VBOUNDS* vbounds, /**< variable bounds data structure, or NULL */
120  SCIP_VAR* var, /**< variable to search in vbounds data structure */
121  SCIP_Bool negativecoef, /**< is coefficient b negative? */
122  int* insertpos, /**< pointer to store position where to insert new entry */
123  SCIP_Bool* found /**< pointer to store whether the same variable was found at the returned pos */
124  )
125 {
126  SCIP_Bool exists;
127  int pos;
128 
129  assert(insertpos != NULL);
130  assert(found != NULL);
131 
132  /* check for empty vbounds data */
133  if( vbounds == NULL )
134  {
135  *insertpos = 0;
136  *found = FALSE;
137  return SCIP_OKAY;
138  }
139  assert(vbounds->len >= 0);
140 
141  /* binary search for the given variable */
142  exists = SCIPsortedvecFindPtr((void**)vbounds->vars, SCIPvarComp, var, vbounds->len, &pos);
143 
144  if( exists )
145  {
146  /* we found the variable: check if the sign of the coefficient matches */
147  assert(var == vbounds->vars[pos]);
148  if( (vbounds->coefs[pos] < 0.0) == negativecoef )
149  {
150  /* the variable exists with the same sign at the current position */
151  *insertpos = pos;
152  *found = TRUE;
153  }
154  else if( negativecoef )
155  {
156  assert(vbounds->coefs[pos] > 0.0);
157  if( pos+1 < vbounds->len && vbounds->vars[pos+1] == var )
158  {
159  /* the variable exists with the desired sign at the next position */
160  assert(vbounds->coefs[pos+1] < 0.0);
161  *insertpos = pos+1;
162  *found = TRUE;
163  }
164  else
165  {
166  /* the negative coefficient should be inserted to the right of the positive one */
167  *insertpos = pos+1;
168  *found = FALSE;
169  }
170  }
171  else
172  {
173  assert(vbounds->coefs[pos] < 0.0);
174  if( pos-1 >= 0 && vbounds->vars[pos-1] == var )
175  {
176  /* the variable exists with the desired sign at the previous position */
177  assert(vbounds->coefs[pos-1] > 0.0);
178  *insertpos = pos-1;
179  *found = TRUE;
180  }
181  else
182  {
183  /* the positive coefficient should be inserted to the left of the negative one */
184  *insertpos = pos;
185  *found = FALSE;
186  }
187  }
188  }
189  else
190  {
191  *insertpos = pos;
192  *found = FALSE;
193  }
194 
195  return SCIP_OKAY;
196 }
197 
198 /** adds a variable bound to the variable bounds data structure */
200  SCIP_VBOUNDS** vbounds, /**< pointer to variable bounds data structure */
201  BMS_BLKMEM* blkmem, /**< block memory */
202  SCIP_SET* set, /**< global SCIP settings */
203  SCIP_BOUNDTYPE vboundtype, /**< type of variable bound (LOWER or UPPER) */
204  SCIP_VAR* var, /**< variable z in x <= b*z + d or x >= b*z + d */
205  SCIP_Real coef, /**< coefficient b in x <= b*z + d or x >= b*z + d */
206  SCIP_Real constant, /**< constant d in x <= b*z + d or x >= b*z + d */
207  SCIP_Bool* added /**< pointer to store whether the variable bound was added */
208  )
209 {
210  int insertpos;
211  SCIP_Bool found;
212 
213  assert(vbounds != NULL);
214  assert(var != NULL);
216  assert(SCIPvarGetType(var) != SCIP_VARTYPE_CONTINUOUS);
217  assert(added != NULL);
218  assert(!SCIPsetIsZero(set, coef));
219 
220  *added = FALSE;
221 
222  /* identify insertion position of variable */
223  SCIP_CALL( vboundsSearchPos(*vbounds, var, (coef < 0.0), &insertpos, &found) );
224  if( found )
225  {
226  /* the same variable already exists in the vbounds data structure: use the better vbound */
227  assert(*vbounds != NULL);
228  assert(0 <= insertpos && insertpos < (*vbounds)->len);
229  assert((*vbounds)->vars[insertpos] == var);
230  assert(((*vbounds)->coefs[insertpos] < 0.0) == (coef < 0.0));
231 
232  if( vboundtype == SCIP_BOUNDTYPE_UPPER )
233  {
234  if( constant + MIN(coef, 0.0) < (*vbounds)->constants[insertpos] + MIN((*vbounds)->coefs[insertpos], 0.0) )
235  {
236  (*vbounds)->coefs[insertpos] = coef;
237  (*vbounds)->constants[insertpos] = constant;
238  *added = TRUE;
239  }
240  }
241  else
242  {
243  if( constant + MAX(coef, 0.0) > (*vbounds)->constants[insertpos] + MAX((*vbounds)->coefs[insertpos], 0.0) )
244  {
245  (*vbounds)->coefs[insertpos] = coef;
246  (*vbounds)->constants[insertpos] = constant;
247  *added = TRUE;
248  }
249  }
250  }
251  else
252  {
253  int i;
254 
255  /* the given variable does not yet exist in the vbounds */
256  SCIP_CALL( vboundsEnsureSize(vbounds, blkmem, set, *vbounds != NULL ? (*vbounds)->len+1 : 1) );
257  assert(*vbounds != NULL);
258  assert(0 <= insertpos && insertpos <= (*vbounds)->len);
259  assert(0 <= insertpos && insertpos < (*vbounds)->size);
260 
261  /* insert variable at the correct position */
262  for( i = (*vbounds)->len; i > insertpos; --i )
263  {
264  assert(!SCIPsetIsZero(set, (*vbounds)->coefs[i-1]));
265  (*vbounds)->vars[i] = (*vbounds)->vars[i-1];
266  (*vbounds)->coefs[i] = (*vbounds)->coefs[i-1];
267  (*vbounds)->constants[i] = (*vbounds)->constants[i-1];
268  }
269  assert(!SCIPsetIsZero(set, coef));
270  (*vbounds)->vars[insertpos] = var;
271  (*vbounds)->coefs[insertpos] = coef;
272  (*vbounds)->constants[insertpos] = constant;
273  (*vbounds)->len++;
274  *added = TRUE;
275  }
276 
277  return SCIP_OKAY;
278 }
279 
280 /** removes from variable x a variable bound x >=/<= b*z + d with binary or integer z */
282  SCIP_VBOUNDS** vbounds, /**< pointer to variable bounds data structure */
283  BMS_BLKMEM* blkmem, /**< block memory */
284  SCIP_VAR* vbdvar, /**< variable z in x >=/<= b*z + d */
285  SCIP_Bool negativecoef /**< is coefficient b negative? */
286  )
287 {
288  SCIP_Bool found;
289  int pos;
290  int i;
291 
292  assert(vbounds != NULL);
293  assert(*vbounds != NULL);
294 
295  /* searches for variable z in variable bounds of x */
296  SCIP_CALL( vboundsSearchPos(*vbounds, vbdvar, negativecoef, &pos, &found) );
297  if( !found )
298  return SCIP_OKAY;
299 
300  assert(0 <= pos && pos < (*vbounds)->len);
301  assert((*vbounds)->vars[pos] == vbdvar);
302  assert(((*vbounds)->coefs[pos] < 0.0) == negativecoef);
303 
304  /* removes z from variable bounds of x */
305  for( i = pos; i < (*vbounds)->len - 1; i++ )
306  {
307  (*vbounds)->vars[i] = (*vbounds)->vars[i+1];
308  (*vbounds)->coefs[i] = (*vbounds)->coefs[i+1];
309  (*vbounds)->constants[i] = (*vbounds)->constants[i+1];
310  }
311  (*vbounds)->len--;
312 
313 #ifndef NDEBUG
314  SCIP_CALL( vboundsSearchPos(*vbounds, vbdvar, negativecoef, &pos, &found) );
315  assert(!found);
316 #endif
317 
318  /* free vbounds data structure, if it is empty */
319  if( (*vbounds)->len == 0 )
320  SCIPvboundsFree(vbounds, blkmem);
321 
322  return SCIP_OKAY;
323 }
324 
325 /** reduces the number of variable bounds stored in the given variable bounds data structure */
327  SCIP_VBOUNDS** vbounds, /**< pointer to variable bounds data structure */
328  BMS_BLKMEM* blkmem, /**< block memory */
329  int newnvbds /**< new number of variable bounds */
330  )
331 {
332  assert(vbounds != NULL);
333  assert(*vbounds != NULL);
334  assert(newnvbds <= (*vbounds)->len);
335 
336  if( newnvbds == 0 )
337  SCIPvboundsFree(vbounds, blkmem);
338  else
339  (*vbounds)->len = newnvbds;
340 }
341 
342 
343 
344 
345 /*
346  * methods for implications
347  */
348 
349 #ifndef NDEBUG
350 /** comparator function for implication variables in the implication data structure */
351 static
353 { /*lint --e{715}*/
354  SCIP_VAR* var1;
355  SCIP_VAR* var2;
356  int var1idx;
357  int var2idx;
358 
359  var1 = (SCIP_VAR*)elem1;
360  var2 = (SCIP_VAR*)elem2;
361  assert(var1 != NULL);
362  assert(var2 != NULL);
363  var1idx = SCIPvarGetIndex(var1);
364  var2idx = SCIPvarGetIndex(var2);
365 
366  if( var1idx < var2idx )
367  return -1;
368  else if( var1idx > var2idx )
369  return +1;
370  else
371  return 0;
372 }
373 
374 /** performs integrity check on implications data structure */
375 static
377  SCIP_IMPLICS* implics /**< implications data structure */
378  )
379 {
380  SCIP_Bool varfixing;
381 
382  if( implics == NULL )
383  return;
384 
385  varfixing = FALSE;
386  do
387  {
388  SCIP_VAR** vars;
389  SCIP_BOUNDTYPE* types;
390  int nimpls;
391  int i;
392 
393  vars = implics->vars[varfixing];
394  types = implics->types[varfixing];
395  nimpls = implics->nimpls[varfixing];
396 
397  assert(0 <= nimpls && nimpls <= implics->size[varfixing]);
398  for( i = 1; i < nimpls; ++i )
399  {
400  int cmp;
401 
402  cmp = compVars(vars[i-1], vars[i]);
403  assert(cmp <= 0);
404  assert((cmp == 0) == (vars[i-1] == vars[i]));
405  assert(cmp < 0 || (types[i-1] == SCIP_BOUNDTYPE_LOWER && types[i] == SCIP_BOUNDTYPE_UPPER));
406  }
407 
408  varfixing = !varfixing;
409  }
410  while( varfixing == TRUE );
411 }
412 #else
413 #define checkImplics(implics) /**/
414 #endif
415 
416 /** creates an implications data structure */
417 static
419  SCIP_IMPLICS** implics, /**< pointer to store implications data structure */
420  BMS_BLKMEM* blkmem /**< block memory */
421  )
422 {
423  assert(implics != NULL);
424 
425  SCIP_ALLOC( BMSallocBlockMemory(blkmem, implics) );
426 
427  (*implics)->vars[0] = NULL;
428  (*implics)->types[0] = NULL;
429  (*implics)->bounds[0] = NULL;
430  (*implics)->ids[0] = NULL;
431  (*implics)->size[0] = 0;
432  (*implics)->nimpls[0] = 0;
433  (*implics)->vars[1] = NULL;
434  (*implics)->types[1] = NULL;
435  (*implics)->bounds[1] = NULL;
436  (*implics)->ids[1] = NULL;
437  (*implics)->size[1] = 0;
438  (*implics)->nimpls[1] = 0;
439 
440  return SCIP_OKAY;
441 }
442 
443 /** frees an implications data structure */
445  SCIP_IMPLICS** implics, /**< pointer of implications data structure to free */
446  BMS_BLKMEM* blkmem /**< block memory */
447  )
448 {
449  assert(implics != NULL);
450 
451  if( *implics != NULL )
452  {
453  BMSfreeBlockMemoryArrayNull(blkmem, &(*implics)->vars[0], (*implics)->size[0]);
454  BMSfreeBlockMemoryArrayNull(blkmem, &(*implics)->types[0], (*implics)->size[0]);
455  BMSfreeBlockMemoryArrayNull(blkmem, &(*implics)->bounds[0], (*implics)->size[0]);
456  BMSfreeBlockMemoryArrayNull(blkmem, &(*implics)->ids[0], (*implics)->size[0]);
457  BMSfreeBlockMemoryArrayNull(blkmem, &(*implics)->vars[1], (*implics)->size[1]);
458  BMSfreeBlockMemoryArrayNull(blkmem, &(*implics)->types[1], (*implics)->size[1]);
459  BMSfreeBlockMemoryArrayNull(blkmem, &(*implics)->bounds[1], (*implics)->size[1]);
460  BMSfreeBlockMemoryArrayNull(blkmem, &(*implics)->ids[1], (*implics)->size[1]);
461  BMSfreeBlockMemory(blkmem, implics);
462  }
463 }
464 
465 /** ensures, that arrays for x == 0 or x == 1 in implications data structure can store at least num entries */
466 static
468  SCIP_IMPLICS** implics, /**< pointer to implications data structure */
469  BMS_BLKMEM* blkmem, /**< block memory */
470  SCIP_SET* set, /**< global SCIP settings */
471  SCIP_Bool varfixing, /**< FALSE if size of arrays for x == 0 has to be ensured, TRUE for x == 1 */
472  int num /**< minimum number of entries to store */
473  )
474 {
475  assert(implics != NULL);
476 
477  /* create implications data structure, if not yet existing */
478  if( *implics == NULL )
479  {
480  SCIP_CALL( implicsCreate(implics, blkmem) );
481  }
482  assert(*implics != NULL);
483  assert((*implics)->nimpls[varfixing] <= (*implics)->size[varfixing]);
484 
485  if( num > (*implics)->size[varfixing] )
486  {
487  int newsize;
488 
489  newsize = SCIPsetCalcMemGrowSize(set, num);
490  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*implics)->vars[varfixing], (*implics)->size[varfixing],
491  newsize) ); /*lint !e866*/
492  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*implics)->types[varfixing], (*implics)->size[varfixing],
493  newsize) ); /*lint !e866*/
494  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*implics)->bounds[varfixing], (*implics)->size[varfixing],
495  newsize) ); /*lint !e866*/
496  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*implics)->ids[varfixing], (*implics)->size[varfixing],
497  newsize) ); /*lint !e866*/
498  (*implics)->size[varfixing] = newsize;
499  }
500  assert(num <= (*implics)->size[varfixing]);
501 
502  return SCIP_OKAY;
503 }
504 
505 /** gets the positions of the implications y >= l and y <= u in the implications data structure;
506  * if no lower or upper bound implication for y was found, -1 is returned
507  */
508 static
510  SCIP_IMPLICS* implics, /**< implications data structure */
511  SCIP_Bool varfixing, /**< FALSE if y is searched in implications for x == 0, TRUE for x == 1 */
512  SCIP_VAR* implvar, /**< variable y to search for */
513  int* poslower, /**< pointer to store position of y_lower (-1 if not found) */
514  int* posupper, /**< pointer to store position of y_upper (-1 if not found) */
515  int* posadd /**< pointer to store position of first y entry, or where a new y entry
516  * should be placed */
517  )
518 {
519  SCIP_Bool found;
520  int right;
521  int pos;
522 
523  assert(implics != NULL);
524  assert(poslower != NULL);
525  assert(posupper != NULL);
526  assert(posadd != NULL);
527 
528  if( implics->nimpls[varfixing] == 0 )
529  {
530  /* there are no implications with non-binary variable y */
531  *posadd = 0;
532  *poslower = -1;
533  *posupper = -1;
534  return;
535  }
536  right = implics->nimpls[varfixing] - 1;
537  assert(0 <= right);
538 
539  /* search for the position in the sorted array (via binary search) */
540  found = SCIPsortedvecFindPtr((void**)(&(implics->vars[varfixing][0])), SCIPvarComp, (void*)implvar, right + 1, &pos);
541 
542  if( !found )
543  {
544  /* y was not found */
545  assert(pos >= right || compVars((void*)implics->vars[varfixing][pos], (void*)implvar) > 0);
546  assert(pos == 0 || compVars((void*)implics->vars[varfixing][pos-1], (void*)implvar) < 0);
547  *poslower = -1;
548  *posupper = -1;
549  *posadd = pos;
550  }
551  else
552  {
553  /* y was found */
554  assert(implvar == implics->vars[varfixing][pos]);
555 
556  /* set poslower and posupper */
557  if( implics->types[varfixing][pos] == SCIP_BOUNDTYPE_LOWER )
558  {
559  /* y was found as y_lower (on position middle) */
560  *poslower = pos;
561  if( pos + 1 < implics->nimpls[varfixing] && implics->vars[varfixing][pos+1] == implvar )
562  {
563  assert(implics->types[varfixing][pos+1] == SCIP_BOUNDTYPE_UPPER);
564  *posupper = pos + 1;
565  }
566  else
567  *posupper = -1;
568  *posadd = pos;
569  }
570  else
571  {
572  /* y was found as y_upper (on position pos) */
573  *posupper = pos;
574  if( pos - 1 >= 0 && implics->vars[varfixing][pos-1] == implvar )
575  {
576  assert(implics->types[varfixing][pos-1] == SCIP_BOUNDTYPE_LOWER);
577  *poslower = pos - 1;
578  *posadd = pos - 1;
579  }
580  else
581  {
582  *poslower = -1;
583  *posadd = pos;
584  }
585  }
586  }
587 }
588 
589 /** returns whether variable y is already contained in implications for x == 0 or x == 1 with the given impltype
590  * y can be contained in structure with y >= b (y_lower) and y <= b (y_upper)
591  */
592 static
594  SCIP_IMPLICS* implics, /**< implications data structure */
595  SCIP_Bool varfixing, /**< FALSE if y is searched in implications for x == 0, TRUE for x == 1 */
596  SCIP_VAR* implvar, /**< variable y to search for */
597  SCIP_BOUNDTYPE impltype, /**< type of implication y <=/>= b to search for */
598  int* poslower, /**< pointer to store position of y_lower (inf if not found) */
599  int* posupper, /**< pointer to store position of y_upper (inf if not found) */
600  int* posadd /**< pointer to store correct position (with respect to impltype) to add y */
601  )
602 {
603  assert(implics != NULL);
604  assert(poslower != NULL);
605  assert(posupper != NULL);
606  assert(posadd != NULL);
607 
608  implicsSearchVar(implics, varfixing, implvar, poslower, posupper, posadd);
609  assert(*poslower == -1 || *posupper == -1 || *posupper == (*poslower)+1);
610  assert(*poslower == -1 || *posadd == *poslower);
611  assert(*poslower >= 0 || *posupper == -1 || *posadd == *posupper);
612  assert(0 <= *posadd && *posadd <= implics->nimpls[varfixing]);
613 
614  if( impltype == SCIP_BOUNDTYPE_LOWER )
615  return (*poslower >= 0);
616  else
617  {
618  if( *poslower >= 0 )
619  {
620  assert(*posadd == *poslower);
621  (*posadd)++;
622  }
623  return (*posupper >= 0);
624  }
625 }
626 
627 /** adds an implication x == 0/1 -> y <= b or y >= b to the implications data structure;
628  * the implication must be non-redundant
629  */
631  SCIP_IMPLICS** implics, /**< pointer to implications data structure */
632  BMS_BLKMEM* blkmem, /**< block memory */
633  SCIP_SET* set, /**< global SCIP settings */
634  SCIP_STAT* stat, /**< problem statistics */
635  SCIP_Bool varfixing, /**< FALSE if implication for x == 0 has to be added, TRUE for x == 1 */
636  SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */
637  SCIP_BOUNDTYPE impltype, /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */
638  SCIP_Real implbound, /**< bound b in implication y <= b or y >= b */
639  SCIP_Bool isshortcut, /**< is the implication a shortcut, i.e., added as part of the transitive closure of another implication? */
640  SCIP_Bool* conflict, /**< pointer to store whether implication causes a conflict for variable x */
641  SCIP_Bool* added /**< pointer to store whether the implication was added */
642  )
643 {
644  int poslower;
645  int posupper;
646  int posadd;
647  SCIP_Bool found;
648 #ifndef NDEBUG
649  int k;
650 #endif
651 
652  assert(implics != NULL);
653  assert(*implics == NULL || 0 <= (*implics)->nimpls[varfixing]);
654  assert(stat != NULL);
655  assert(SCIPvarIsActive(implvar));
657  assert((impltype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsFeasGT(set, implbound, SCIPvarGetLbGlobal(implvar)))
658  || (impltype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsFeasLT(set, implbound, SCIPvarGetUbGlobal(implvar))));
659  assert(conflict != NULL);
660  assert(added != NULL);
661 
662  SCIPdebugMessage("adding implication to implics %p [%u]: <%s> %s %g\n",
663  (void*)*implics, varfixing, SCIPvarGetName(implvar), impltype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", implbound);
664 
665  checkImplics(*implics);
666 
667  *conflict = FALSE;
668  *added = FALSE;
669 
670  /* check if variable is already contained in implications data structure */
671  if( *implics != NULL )
672  {
673  found = implicsSearchImplic(*implics, varfixing, implvar, impltype, &poslower, &posupper, &posadd);
674  assert(-1 <= poslower && poslower < (*implics)->nimpls[varfixing]);
675  assert(-1 <= posupper && posupper < (*implics)->nimpls[varfixing]);
676  assert(0 <= posadd && posadd <= (*implics)->nimpls[varfixing]);
677  assert(poslower == -1 || (*implics)->types[varfixing][poslower] == SCIP_BOUNDTYPE_LOWER);
678  assert(posupper == -1 || (*implics)->types[varfixing][posupper] == SCIP_BOUNDTYPE_UPPER);
679  }
680  else
681  {
682  found = FALSE;
683  poslower = -1;
684  posupper = -1;
685  posadd = 0;
686  }
687 
688  if( impltype == SCIP_BOUNDTYPE_LOWER )
689  {
690  assert(found == (poslower >= 0));
691 
692  /* check if y >= b is redundant */
693  if( poslower >= 0 && SCIPsetIsFeasLE(set, implbound, (*implics)->bounds[varfixing][poslower]) )
694  {
695  SCIPdebugMessage(" -> implication is redundant to <%s> >= %g\n",
696  SCIPvarGetName(implvar), (*implics)->bounds[varfixing][poslower]);
697  return SCIP_OKAY;
698  }
699 
700  /* check if y >= b causes conflict for x (i.e. y <= a (with a < b) is also valid) */
701  if( posupper >= 0 && SCIPsetIsFeasGT(set, implbound, (*implics)->bounds[varfixing][posupper]) )
702  {
703  SCIPdebugMessage(" -> implication is conflicting to <%s> <= %g\n",
704  SCIPvarGetName(implvar), (*implics)->bounds[varfixing][posupper]);
705  *conflict = TRUE;
706  return SCIP_OKAY;
707  }
708 
709  *added = TRUE;
710 
711  /* check if entry of the same type already exists */
712  if( found )
713  {
714  assert(poslower >= 0);
715  assert(posadd == poslower);
716 
717  /* add y >= b by changing old entry on poslower */
718  assert((*implics)->vars[varfixing][poslower] == implvar);
719  assert(SCIPsetIsFeasGT(set, implbound, (*implics)->bounds[varfixing][poslower]));
720  (*implics)->bounds[varfixing][poslower] = implbound;
721  }
722  else
723  {
724  assert(poslower == -1);
725 
726  /* add y >= b by creating a new entry on posadd */
727  SCIP_CALL( implicsEnsureSize(implics, blkmem, set, varfixing,
728  *implics != NULL ? (*implics)->nimpls[varfixing]+1 : 1) );
729  assert(*implics != NULL);
730 
731  if( (*implics)->nimpls[varfixing] - posadd > 0 )
732  {
733  int amount = ((*implics)->nimpls[varfixing] - posadd);
734 
735 #ifndef NDEBUG
736  for( k = (*implics)->nimpls[varfixing]; k > posadd; k-- )
737  {
738  assert(compVars((void*)(*implics)->vars[varfixing][k-1], (void*)implvar) >= 0);
739  }
740 #endif
741  BMSmoveMemoryArray(&((*implics)->types[varfixing][posadd+1]), &((*implics)->types[varfixing][posadd]), amount); /*lint !e866*/
742  BMSmoveMemoryArray(&((*implics)->ids[varfixing][posadd+1]), &((*implics)->ids[varfixing][posadd]), amount); /*lint !e866*/
743  BMSmoveMemoryArray(&((*implics)->vars[varfixing][posadd+1]), &((*implics)->vars[varfixing][posadd]), amount); /*lint !e866*/
744  BMSmoveMemoryArray(&((*implics)->bounds[varfixing][posadd+1]), &((*implics)->bounds[varfixing][posadd]), amount); /*lint !e866*/
745  }
746 
747  (*implics)->vars[varfixing][posadd] = implvar;
748  (*implics)->types[varfixing][posadd] = impltype;
749  (*implics)->bounds[varfixing][posadd] = implbound;
750  (*implics)->ids[varfixing][posadd] = (isshortcut ? -stat->nimplications : stat->nimplications);
751  (*implics)->nimpls[varfixing]++;
752 #ifndef NDEBUG
753  for( k = posadd-1; k >= 0; k-- )
754  assert(compVars((void*)(*implics)->vars[varfixing][k], (void*)implvar) <= 0);
755 #endif
756  stat->nimplications++;
757  }
758  }
759  else
760  {
761  assert(found == (posupper >= 0));
762 
763  /* check if y <= b is redundant */
764  if( posupper >= 0 && SCIPsetIsFeasGE(set, implbound, (*implics)->bounds[varfixing][posupper]) )
765  {
766  SCIPdebugMessage(" -> implication is redundant to <%s> <= %g\n",
767  SCIPvarGetName(implvar), (*implics)->bounds[varfixing][posupper]);
768  return SCIP_OKAY;
769  }
770 
771  /* check if y <= b causes conflict for x (i.e. y >= a (with a > b) is also valid) */
772  if( poslower >= 0 && SCIPsetIsFeasLT(set, implbound, (*implics)->bounds[varfixing][poslower]) )
773  {
774  SCIPdebugMessage(" -> implication is conflicting to <%s> >= %g\n",
775  SCIPvarGetName(implvar), (*implics)->bounds[varfixing][poslower]);
776  *conflict = TRUE;
777  return SCIP_OKAY;
778  }
779 
780  *added = TRUE;
781 
782  /* check if entry of the same type already exists */
783  if( found )
784  {
785  assert(posupper >= 0);
786  assert(posadd == posupper);
787 
788  /* add y <= b by changing old entry on posupper */
789  assert((*implics)->vars[varfixing][posupper] == implvar);
790  assert(SCIPsetIsFeasLT(set, implbound,(*implics)->bounds[varfixing][posupper]));
791  (*implics)->bounds[varfixing][posupper] = implbound;
792  }
793  else
794  {
795  /* add y <= b by creating a new entry on posadd */
796  assert(posupper == -1);
797 
798  SCIP_CALL( implicsEnsureSize(implics, blkmem, set, varfixing,
799  *implics != NULL ? (*implics)->nimpls[varfixing]+1 : 1) );
800  assert(*implics != NULL);
801 
802  if( (*implics)->nimpls[varfixing] - posadd > 0 )
803  {
804  int amount = ((*implics)->nimpls[varfixing] - posadd);
805 
806 #ifndef NDEBUG
807  for( k = (*implics)->nimpls[varfixing]; k > posadd; k-- )
808  {
809  assert(compVars((void*)(*implics)->vars[varfixing][k-1], (void*)implvar) >= 0);
810  }
811 #endif
812  BMSmoveMemoryArray(&((*implics)->types[varfixing][posadd+1]), &((*implics)->types[varfixing][posadd]), amount); /*lint !e866*/
813  BMSmoveMemoryArray(&((*implics)->ids[varfixing][posadd+1]), &((*implics)->ids[varfixing][posadd]), amount); /*lint !e866*/
814  BMSmoveMemoryArray(&((*implics)->vars[varfixing][posadd+1]), &((*implics)->vars[varfixing][posadd]), amount); /*lint !e866*/
815  BMSmoveMemoryArray(&((*implics)->bounds[varfixing][posadd+1]), &((*implics)->bounds[varfixing][posadd]), amount); /*lint !e866*/
816  }
817 
818  (*implics)->vars[varfixing][posadd] = implvar;
819  (*implics)->types[varfixing][posadd] = impltype;
820  (*implics)->bounds[varfixing][posadd] = implbound;
821  (*implics)->ids[varfixing][posadd] = (isshortcut ? -stat->nimplications : stat->nimplications);
822  (*implics)->nimpls[varfixing]++;
823 #ifndef NDEBUG
824  for( k = posadd-1; k >= 0; k-- )
825  assert(compVars((void*)(*implics)->vars[varfixing][k], (void*)implvar) <= 0);
826 #endif
827  stat->nimplications++;
828  }
829  }
830 
831  checkImplics(*implics);
832 
833  return SCIP_OKAY;
834 }
835 
836 /** removes the implication x <= 0 or x >= 1 ==> y <= b or y >= b from the implications data structure */
838  SCIP_IMPLICS** implics, /**< pointer to implications data structure */
839  BMS_BLKMEM* blkmem, /**< block memory */
840  SCIP_SET* set, /**< global SCIP settings */
841  SCIP_Bool varfixing, /**< FALSE if y should be removed from implications for x <= 0, TRUE for x >= 1 */
842  SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */
843  SCIP_BOUNDTYPE impltype /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */
844  )
845 { /*lint --e{715}*/
846  int poslower;
847  int posupper;
848  int posadd;
849  SCIP_Bool found;
850 
851  assert(implics != NULL);
852  assert(*implics != NULL);
853  assert(implvar != NULL);
854 
855  SCIPdebugMessage("deleting implication from implics %p [%u]: <%s> %s x\n",
856  (void*)*implics, varfixing, SCIPvarGetName(implvar), impltype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=");
857 
858  checkImplics(*implics);
859 
860  /* searches for y in implications of x */
861  found = implicsSearchImplic(*implics, varfixing, implvar, impltype, &poslower, &posupper, &posadd);
862  if( !found )
863  {
864  SCIPdebugMessage(" -> implication was not found\n");
865  return SCIP_OKAY;
866  }
867 
868  assert((impltype == SCIP_BOUNDTYPE_LOWER && poslower >= 0 && posadd == poslower)
869  || (impltype == SCIP_BOUNDTYPE_UPPER && posupper >= 0 && posadd == posupper));
870  assert(0 <= posadd && posadd < (*implics)->nimpls[varfixing]);
871  assert((*implics)->vars[varfixing][posadd] == implvar);
872  assert((*implics)->types[varfixing][posadd] == impltype);
873 
874  /* removes y from implications of x */
875  if( (*implics)->nimpls[varfixing] - posadd > 1 )
876  {
877  int amount = ((*implics)->nimpls[varfixing] - posadd - 1);
878 
879  BMSmoveMemoryArray(&((*implics)->types[varfixing][posadd]), &((*implics)->types[varfixing][posadd+1]), amount); /*lint !e866*/
880  BMSmoveMemoryArray(&((*implics)->vars[varfixing][posadd]), &((*implics)->vars[varfixing][posadd+1]), amount); /*lint !e866*/
881  BMSmoveMemoryArray(&((*implics)->bounds[varfixing][posadd]), &((*implics)->bounds[varfixing][posadd+1]), amount); /*lint !e866*/
882  }
883  (*implics)->nimpls[varfixing]--;
884 
885  /* free implics data structure, if it is empty */
886  if( (*implics)->nimpls[0] == 0 && (*implics)->nimpls[1] == 0 )
887  SCIPimplicsFree(implics, blkmem);
888 
889  checkImplics(*implics);
890 
891  return SCIP_OKAY;
892 }
893 
894 /** returns which implications on given variable y are contained in implications for x == 0 or x == 1 */
896  SCIP_IMPLICS* implics, /**< implications data structure */
897  SCIP_Bool varfixing, /**< FALSE if y should be searched in implications for x == 0, TRUE for x == 1 */
898  SCIP_VAR* implvar, /**< variable y to search for */
899  SCIP_Bool* haslowerimplic, /**< pointer to store whether there exists an implication y >= l */
900  SCIP_Bool* hasupperimplic /**< pointer to store whether there exists an implication y <= u */
901  )
902 {
903  int poslower;
904  int posupper;
905  int posadd;
906 
907  assert(haslowerimplic != NULL);
908  assert(hasupperimplic != NULL);
909 
910  implicsSearchVar(implics, varfixing, implvar, &poslower, &posupper, &posadd);
911 
912  *haslowerimplic = (poslower >= 0);
913  *hasupperimplic = (posupper >= 0);
914 }
915 
916 /** returns whether an implication y <= b or y >= b is contained in implications for x == 0 or x == 1 */
918  SCIP_IMPLICS* implics, /**< implications data structure */
919  SCIP_Bool varfixing, /**< FALSE if y should be searched in implications for x == 0, TRUE for x == 1 */
920  SCIP_VAR* implvar, /**< variable y to search for */
921  SCIP_BOUNDTYPE impltype /**< type of implication y <=/>= b to search for */
922  )
923 {
924  int poslower;
925  int posupper;
926  int posadd;
927 
928  return implicsSearchImplic(implics, varfixing, implvar, impltype, &poslower, &posupper, &posadd);
929 }
930 
931 
932 
933 
934 /*
935  * methods for cliques
936  */
937 
938 /* swaps cliques at positions first and second in cliques array of clique table */
939 static
941  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
942  int first, /**< first index */
943  int second /**< second index */
944  )
945 {
946  /* nothing to do if clique happens to be at the pole position of clean cliques */
947  if( first != second )
948  {
949  SCIP_CLIQUE* tmp;
950 
951  tmp = cliquetable->cliques[first];
952  assert(tmp->index == first);
953  assert(cliquetable->cliques[second]->index == second);
954 
955  cliquetable->cliques[first] = cliquetable->cliques[second];
956  cliquetable->cliques[second] = tmp;
957 
958  /* change the indices accordingly */
959  tmp->index = second;
960  cliquetable->cliques[first]->index = first;
961  }
962 }
963 
964 /* moves clique to the last position of currently dirty cliques */
965 static
967  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
968  SCIP_CLIQUE* clique /**< clique data structure */
969  )
970 {
971  assert(cliquetable->ndirtycliques <= clique->index);
972  assert(cliquetable->cliques[clique->index] == clique);
973  assert(cliquetable->ndirtycliques < cliquetable->ncliques);
974  assert(SCIPcliqueIsCleanedUp(cliquetable->cliques[cliquetable->ndirtycliques]));
975 
976  /* nothing to do if clique happens to be at the pole position of clean cliques */
977  if( clique->index > cliquetable->ndirtycliques )
978  {
979  cliquetableSwapCliques(cliquetable, clique->index, cliquetable->ndirtycliques);
980  }
981 
982  ++cliquetable->ndirtycliques;
983 }
984 
985 
986 /** creates a clique data structure with already created variables and values arrays in the size of 'size' */
987 static
989  SCIP_CLIQUE** clique, /**< pointer to store clique data structure */
990  BMS_BLKMEM* blkmem, /**< block memory */
991  int size, /**< initial size of clique */
992  SCIP_VAR** vars, /**< binary variables in the clique: at most one can be set to the given
993  * value */
994  SCIP_Bool* values, /**< values of the variables in the clique */
995  int nvars, /**< number of variables in the clique */
996  int id, /**< unique identifier of the clique */
997  SCIP_Bool isequation /**< is the clique an equation or an inequality? */
998  )
999 {
1000  assert(clique != NULL);
1001  assert(blkmem != NULL);
1002  assert(size >= nvars && nvars > 0);
1003  assert(vars != NULL);
1004  assert(values != NULL);
1005 
1006  SCIP_ALLOC( BMSallocBlockMemory(blkmem, clique) );
1007  (*clique)->vars = vars;
1008  (*clique)->values = values;
1009  (*clique)->nvars = nvars;
1010  (*clique)->size = size;
1011  (*clique)->startcleanup = -1;
1012  (*clique)->id = (unsigned int)id;
1013  (*clique)->eventsissued = FALSE;
1014  (*clique)->equation = isequation;
1015  (*clique)->index = -1;
1016 
1017  return SCIP_OKAY;
1018 }
1019 
1020 /** frees a clique data structure */
1021 static
1023  SCIP_CLIQUE** clique, /**< pointer to store clique data structure */
1024  BMS_BLKMEM* blkmem /**< block memory */
1025  )
1026 {
1027  assert(clique != NULL);
1028 
1029  if( *clique != NULL )
1030  {
1031  BMSfreeBlockMemoryArrayNull(blkmem, &(*clique)->vars, (*clique)->size);
1032  BMSfreeBlockMemoryArrayNull(blkmem, &(*clique)->values, (*clique)->size);
1033  BMSfreeBlockMemory(blkmem, clique);
1034  }
1035 }
1036 
1037 /** ensures, that clique arrays can store at least num entries */
1038 static
1040  SCIP_CLIQUE* clique, /**< clique data structure */
1041  BMS_BLKMEM* blkmem, /**< block memory */
1042  SCIP_SET* set, /**< global SCIP settings */
1043  int num /**< minimum number of entries to store */
1044  )
1045 {
1046  assert(clique != NULL);
1047 
1048  if( num > clique->size )
1049  {
1050  int newsize;
1051 
1052  newsize = SCIPsetCalcMemGrowSize(set, num);
1053  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &clique->vars, clique->size, newsize) );
1054  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &clique->values, clique->size, newsize) );
1055  clique->size = newsize;
1056  }
1057  assert(num <= clique->size);
1058 
1059  return SCIP_OKAY;
1060 }
1061 
1062 /** returns the position of the given variable/value pair in the clique; returns -1 if variable/value pair is not member
1063  * of the clique
1064  */
1066  SCIP_CLIQUE* clique, /**< clique data structure */
1067  SCIP_VAR* var, /**< variable to search for */
1068  SCIP_Bool value /**< value of the variable in the clique */
1069  )
1070 {
1071  int varidx;
1072  int left;
1073  int right;
1074 
1075  assert(clique != NULL);
1076 
1077  varidx = SCIPvarGetIndex(var);
1078  left = -1;
1079  right = clique->nvars;
1080  while( left < right-1 )
1081  {
1082  int middle;
1083  int idx;
1084 
1085  middle = (left+right)/2;
1086  idx = SCIPvarGetIndex(clique->vars[middle]);
1087  assert(idx >= 0);
1088  if( varidx < idx )
1089  right = middle;
1090  else if( varidx > idx )
1091  left = middle;
1092  else
1093  {
1094  assert(var == clique->vars[middle]);
1095 
1096  /* now watch out for the correct value */
1097  if( clique->values[middle] < value )
1098  {
1099  int i;
1100  for( i = middle+1; i < clique->nvars && clique->vars[i] == var; ++i )
1101  {
1102  if( clique->values[i] == value )
1103  return i;
1104  }
1105  return -1;
1106  }
1107  if( clique->values[middle] > value )
1108  {
1109  int i;
1110  for( i = middle-1; i >= 0 && clique->vars[i] == var; --i )
1111  {
1112  if( clique->values[i] == value )
1113  return i;
1114  }
1115  return -1;
1116  }
1117  return middle;
1118  }
1119  }
1120 
1121  return -1;
1122 }
1123 
1124 /** returns whether the given variable/value pair is member of the given clique */
1126  SCIP_CLIQUE* clique, /**< clique data structure */
1127  SCIP_VAR* var, /**< variable to remove from the clique */
1128  SCIP_Bool value /**< value of the variable in the clique */
1129  )
1130 {
1131  return (SCIPcliqueSearchVar(clique, var, value) >= 0);
1132 }
1133 
1134 /** adds a single variable to the given clique */
1136  SCIP_CLIQUE* clique, /**< clique data structure */
1137  BMS_BLKMEM* blkmem, /**< block memory */
1138  SCIP_SET* set, /**< global SCIP settings */
1139  SCIP_VAR* var, /**< variable to add to the clique */
1140  SCIP_Bool value, /**< value of the variable in the clique */
1141  SCIP_Bool* doubleentry, /**< pointer to store whether the variable and value occurs twice in the clique */
1142  SCIP_Bool* oppositeentry /**< pointer to store whether the variable with opposite value is in the clique */
1143  )
1144 {
1145  int pos;
1146  int i;
1147 
1148  assert(clique != NULL);
1150  assert(SCIPvarIsBinary(var));
1151  assert(doubleentry != NULL);
1152  assert(oppositeentry != NULL);
1153 
1154  SCIPdebugMessage("adding variable <%s> == %u to clique %u\n", SCIPvarGetName(var), value, clique->id);
1155 
1156  *doubleentry = FALSE;
1157  *oppositeentry = FALSE;
1158 
1159  /* allocate memory */
1160  SCIP_CALL( cliqueEnsureSize(clique, blkmem, set, clique->nvars+1) );
1161 
1162  /* search for insertion position by binary variable, note that first the entries are order after variable index and
1163  * second after the bool value of the corresponding variable
1164  */
1165  (void) SCIPsortedvecFindPtr((void**) clique->vars, SCIPvarComp, var, clique->nvars, &pos);
1166 
1167  assert(pos >= 0 && pos <= clique->nvars);
1168  /* remember insertion position for later, pos might change */
1169  i = pos;
1170 
1171  if( pos < clique->nvars )
1172  {
1173  const int amount = clique->nvars - pos;
1174 
1175  /* moving elements to correct position */
1176  BMSmoveMemoryArray(&(clique->vars[pos+1]), &(clique->vars[pos]), amount); /*lint !e866*/
1177  BMSmoveMemoryArray(&(clique->values[pos+1]), &(clique->values[pos]), amount); /*lint !e866*/
1178  clique->nvars++;
1179 
1180  /* insertion for a variable with cliquevalue FALSE */
1181  if( !value )
1182  {
1183  /* find last entry with the same variable and value behind the insertion position */
1184  for( ; pos < clique->nvars - 1 && clique->vars[pos + 1] == var && clique->values[pos + 1] == value; ++pos ); /*lint !e722*/
1185 
1186  /* check if the same variable with other value also exists */
1187  if( pos < clique->nvars - 1 && clique->vars[pos + 1] == var )
1188  {
1189  assert(clique->values[pos + 1] != value);
1190  *oppositeentry = TRUE;
1191  }
1192 
1193  /* check if we found the same variable with the same value more than once */
1194  if( pos != i )
1195  *doubleentry = TRUE;
1196  else
1197  {
1198  /* find last entry with the same variable and different value before the insertion position */
1199  for( ; pos > 0 && clique->vars[pos - 1] == var && clique->values[pos - 1] != value; --pos ); /*lint !e722*/
1200 
1201  /* check if we found the same variable with the same value more than once */
1202  if( pos > 0 && clique->vars[pos - 1] == var )
1203  {
1204  assert(clique->values[pos - 1] == value);
1205 
1206  *doubleentry = TRUE;
1207  }
1208  /* if we found the same variable with different value, we need to order them correctly */
1209  if( pos != i )
1210  {
1211  assert(clique->vars[pos] == var);
1212  assert(clique->values[pos] != value);
1213 
1214  clique->values[pos] = value;
1215  value = !value;
1216  }
1217  }
1218  }
1219  /* insertion for a variable with cliquevalue TRUE */
1220  else
1221  {
1222  /* find last entry with the same variable and different value behind the insertion position */
1223  for( ; pos < clique->nvars - 1 && clique->vars[pos + 1] == var && clique->values[pos + 1] != value; ++pos ); /*lint !e722*/
1224 
1225  /* check if the same variable with other value also exists */
1226  if( pos < clique->nvars - 1 && clique->vars[pos + 1] == var )
1227  {
1228  assert(clique->values[pos + 1] == value);
1229  *doubleentry = TRUE;
1230  }
1231 
1232  /* check if we found the same variable with different value */
1233  if( pos != i )
1234  {
1235  *oppositeentry = TRUE;
1236 
1237  /* if we found the same variable with different value, we need to order them correctly */
1238  assert(clique->vars[pos] == var);
1239  assert(clique->values[pos] != value);
1240 
1241  clique->values[pos] = value;
1242  value = !value;
1243  }
1244  else
1245  {
1246  /* find last entry with the same variable and value before the insertion position */
1247  for( ; pos > 0 && clique->vars[pos - 1] == var && clique->values[pos - 1] == value; --pos ); /*lint !e722*/
1248 
1249  if( pos != i )
1250  *doubleentry = TRUE;
1251 
1252  /* check if we found the same variable with different value up front */
1253  if( pos > 0 && clique->vars[pos - 1] == var && clique->values[pos - 1] != value )
1254  *oppositeentry = TRUE;
1255  }
1256  }
1257  }
1258  else
1259  clique->nvars++;
1260 
1261  clique->vars[i] = var;
1262  clique->values[i] = value;
1263  clique->eventsissued = FALSE;
1264 
1265  return SCIP_OKAY;
1266 }
1267 
1268 /** removes a single variable from the given clique */
1270  SCIP_CLIQUE* clique, /**< clique data structure */
1271  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
1272  SCIP_VAR* var, /**< variable to remove from the clique */
1273  SCIP_Bool value /**< value of the variable in the clique */
1274  )
1275 {
1276  int pos;
1277 
1278  assert(clique != NULL);
1279  assert(SCIPvarIsBinary(var));
1280  assert(cliquetable != NULL);
1281 
1282  /* if the clique is the leading clique during the cleanup step, we do not need to insert it again */
1283  if( cliquetable->incleanup && clique->index == 0 )
1284  return;
1285 
1286  SCIPdebugMessage("marking variable <%s> == %u from clique %u for deletion\n", SCIPvarGetName(var), value, clique->id);
1287 
1288  /* find variable in clique */
1289  pos = SCIPcliqueSearchVar(clique, var, value);
1290 
1291  assert(0 <= pos && pos < clique->nvars);
1292  assert(clique->vars[pos] == var);
1293  assert(clique->values[pos] == value);
1294 
1295  /* inform the clique table that this clique should be cleaned up */
1296  if( clique->startcleanup == -1 )
1297  cliquetableMarkCliqueForCleanup(cliquetable, clique);
1298 
1299  if( clique->startcleanup == -1 || pos < clique->startcleanup )
1300  clique->startcleanup = pos;
1301 
1302 #ifdef SCIP_MORE_DEBUG
1303  {
1304  int v;
1305  /* all variables prior to the one marked for startcleanup should be unfixed */
1306  for( v = clique->startcleanup - 1; v >= 0; --v )
1307  {
1308  assert(SCIPvarGetUbGlobal(clique->vars[v]) > 0.5);
1309  assert(SCIPvarGetLbGlobal(clique->vars[v]) < 0.5);
1310  }
1311  }
1312 #endif
1313 }
1314 
1315 /** gets the position of the given clique in the cliques array; returns -1 if clique is not member of cliques array */
1316 static
1318  SCIP_CLIQUE** cliques, /**< array of cliques */
1319  int ncliques, /**< number of cliques in the cliques array */
1320  SCIP_CLIQUE* clique /**< clique to search for */
1321  )
1322 {
1323  unsigned int cliqueid;
1324  int left;
1325  int right;
1326 
1327  assert(cliques != NULL || ncliques == 0);
1328  assert(clique != NULL);
1329 
1330  cliqueid = clique->id; /*lint !e732*/
1331  left = -1;
1332  right = ncliques;
1333  while( left < right-1 )
1334  {
1335  unsigned int id;
1336  int middle;
1337 
1338  assert(cliques != NULL);
1339  middle = (left+right)/2;
1340  id = cliques[middle]->id; /*lint !e732*/
1341  if( cliqueid < id )
1342  right = middle;
1343  else if( cliqueid > id )
1344  left = middle;
1345  else
1346  {
1347  assert(clique == cliques[middle]);
1348  return middle;
1349  }
1350  }
1351 
1352  return -1;
1353 }
1354 
1355 #ifndef NDEBUG
1356 /** checks whether clique appears in all clique lists of the involved variables */
1357 static
1359  SCIP_CLIQUE* clique /**< clique data structure */
1360  )
1361 {
1362  int i;
1363 
1364  assert(clique != NULL);
1365 
1366  for( i = 0; i < clique->nvars; ++i )
1367  {
1368  SCIP_CLIQUE** cliques;
1369  int ncliques;
1370  int pos;
1371  SCIP_VAR* var;
1372 
1373  var = clique->vars[i];
1374  assert(i == 0 || SCIPvarGetIndex(clique->vars[i-1]) <= SCIPvarGetIndex(var));
1375  assert(i == 0 || clique->vars[i-1] != var || clique->values[i-1] <= clique->values[i]);
1376  ncliques = SCIPvarGetNCliques(var, clique->values[i]);
1377 
1378  assert(SCIPvarIsActive(var) || ncliques == 0);
1379 
1380  /* cliquelist of inactive variables are already destroyed */
1381  if( ncliques == 0 )
1382  continue;
1383 
1384  cliques = SCIPvarGetCliques(var, clique->values[i]);
1385  pos = cliquesSearchClique(cliques, ncliques, clique);
1386 
1387  /* assert that the clique is correctly listed in all clique lists of unfixed variables. For fixed variables,
1388  * we require that a clean up has been correctly scheduled, but not yet been processed
1389  */
1390  if( SCIPvarGetUbGlobal(var) - SCIPvarGetLbGlobal(var) > 0.5 )
1391  {
1392  assert(0 <= pos && pos < ncliques);
1393  assert(cliques[pos] == clique);
1394  }
1395  else
1396  assert(0 <= clique->startcleanup && clique->startcleanup <= i);
1397  }
1398  assert(clique->index >= 0);
1399 }
1400 #else
1401 #define cliqueCheck(clique) /**/
1402 #endif
1403 
1404 /** creates a clique list data structure */
1405 static
1407  SCIP_CLIQUELIST** cliquelist, /**< pointer to store clique list data structure */
1408  BMS_BLKMEM* blkmem /**< block memory */
1409  )
1410 {
1411  assert(cliquelist != NULL);
1412 
1413  SCIP_ALLOC( BMSallocBlockMemory(blkmem, cliquelist) );
1414  (*cliquelist)->cliques[0] = NULL;
1415  (*cliquelist)->cliques[1] = NULL;
1416  (*cliquelist)->ncliques[0] = 0;
1417  (*cliquelist)->ncliques[1] = 0;
1418  (*cliquelist)->size[0] = 0;
1419  (*cliquelist)->size[1] = 0;
1420 
1421  return SCIP_OKAY;
1422 }
1423 
1424 /** frees a clique list data structure */
1426  SCIP_CLIQUELIST** cliquelist, /**< pointer to the clique list data structure */
1427  BMS_BLKMEM* blkmem /**< block memory */
1428  )
1429 {
1430  assert(cliquelist != NULL);
1431 
1432  if( *cliquelist != NULL )
1433  {
1434  BMSfreeBlockMemoryArrayNull(blkmem, &(*cliquelist)->cliques[0], (*cliquelist)->size[0]);
1435  BMSfreeBlockMemoryArrayNull(blkmem, &(*cliquelist)->cliques[1], (*cliquelist)->size[1]);
1436  BMSfreeBlockMemory(blkmem, cliquelist);
1437  }
1438 }
1439 
1440 /** ensures, that clique list arrays can store at least num entries */
1441 static
1443  SCIP_CLIQUELIST* cliquelist, /**< clique list data structure */
1444  BMS_BLKMEM* blkmem, /**< block memory */
1445  SCIP_SET* set, /**< global SCIP settings */
1446  SCIP_Bool value, /**< value of the variable for which the clique list should be extended */
1447  int num /**< minimum number of entries to store */
1448  )
1449 {
1450  assert(cliquelist != NULL);
1451 
1452  if( num > cliquelist->size[value] )
1453  {
1454  int newsize;
1455 
1456  newsize = SCIPsetCalcMemGrowSize(set, num);
1457  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &cliquelist->cliques[value], cliquelist->size[value], newsize) ); /*lint !e866*/
1458  cliquelist->size[value] = newsize;
1459  }
1460  assert(num <= cliquelist->size[value]);
1461 
1462  return SCIP_OKAY;
1463 }
1464 
1465 /** adds a clique to the clique list */
1467  SCIP_CLIQUELIST** cliquelist, /**< pointer to the clique list data structure */
1468  BMS_BLKMEM* blkmem, /**< block memory */
1469  SCIP_SET* set, /**< global SCIP settings */
1470  SCIP_Bool value, /**< value of the variable for which the clique list should be extended */
1471  SCIP_CLIQUE* clique /**< clique that should be added to the clique list */
1472  )
1473 {
1474  unsigned int id;
1475  int i = 0;
1476 
1477  assert(cliquelist != NULL);
1478 
1479  /* insert clique into list, sorted by clique id */
1480  id = clique->id; /*lint !e732*/
1481 
1482  /* allocate memory */
1483  if( *cliquelist == NULL )
1484  {
1485  SCIP_CALL( cliquelistCreate(cliquelist, blkmem) );
1486  }
1487  else
1488  {
1489  if( (*cliquelist)->cliques[value] != NULL )
1490  {
1491  for( i = (*cliquelist)->ncliques[value]; i > 0 && (*cliquelist)->cliques[value][i - 1]->id > id; --i ); /*lint !e574 !e722*/
1492  /* do not put the same clique twice in the cliquelist */
1493  if( i > 0 && (*cliquelist)->cliques[value][i - 1]->id == id )
1494  return SCIP_OKAY;
1495  }
1496  }
1497  SCIP_CALL( cliquelistEnsureSize(*cliquelist, blkmem, set, value, (*cliquelist)->ncliques[value] + 1) );
1498 
1499  SCIPdebugMessage("adding clique %u to cliquelist %p value %u (length: %d)\n",
1500  clique->id, (void*)*cliquelist, value, (*cliquelist)->ncliques[value]);
1501 
1502  BMSmoveMemoryArray(&((*cliquelist)->cliques[value][i+1]), &((*cliquelist)->cliques[value][i]), (*cliquelist)->ncliques[value] - i); /*lint !e866*/
1503 
1504  (*cliquelist)->cliques[value][i] = clique;
1505  (*cliquelist)->ncliques[value]++;
1506 
1507  return SCIP_OKAY;
1508 }
1509 
1510 /** removes a clique from the clique list */
1512  SCIP_CLIQUELIST** cliquelist, /**< pointer to the clique list data structure */
1513  BMS_BLKMEM* blkmem, /**< block memory */
1514  SCIP_Bool value, /**< value of the variable for which the clique list should be reduced */
1515  SCIP_CLIQUE* clique /**< clique that should be deleted from the clique list */
1516  )
1517 {
1518  int pos;
1519 
1520  assert(cliquelist != NULL);
1521 
1522  /* if a variable appeared twice in its last clique and is now removed both times, the cliquelist is already cleaned
1523  up after the first removal call of this "doubleton" */
1524  if( *cliquelist == NULL )
1525  return SCIP_OKAY;
1526 
1527  SCIPdebugMessage("deleting clique %u from cliquelist %p value %u (length: %d)\n",
1528  clique->id, (void*)*cliquelist, value, (*cliquelist)->ncliques[value]);
1529 
1530  pos = cliquesSearchClique((*cliquelist)->cliques[value], (*cliquelist)->ncliques[value], clique);
1531 
1532  /* clique does not exist in cliquelist, the clique should contain multiple entries of the same variable */
1533  if( pos < 0 )
1534  {
1535 #ifdef SCIP_MORE_DEBUG
1536  SCIP_VAR** clqvars;
1537  SCIP_Bool* clqvalues;
1538  int nclqvars = SCIPcliqueGetNVars(clique);
1539  int v;
1540 
1541  assert(nclqvars >= 2);
1542  assert(SCIPcliqueGetVars(clique) != NULL);
1543  assert(SCIPcliqueGetValues(clique) != NULL);
1544 
1545  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &clqvars, SCIPcliqueGetVars(clique), nclqvars) );
1546  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &clqvalues, SCIPcliqueGetValues(clique), nclqvars) );
1547 
1548  /* sort variables and corresponding clique values after variables indices */
1549  SCIPsortPtrBool((void**) clqvars, clqvalues, SCIPvarComp, nclqvars);
1550 
1551  for( v = nclqvars - 1; v > 0; --v )
1552  {
1553  if( clqvars[v] == clqvars[v - 1] )
1554  {
1555  if( clqvalues[v] == clqvalues[v - 1] || (v > 1 && clqvars[v] == clqvars[v - 2]) )
1556  break;
1557  }
1558  }
1559  assert(v > 0);
1560 
1561  BMSfreeBlockMemoryArray(blkmem, &clqvalues, nclqvars);
1562  BMSfreeBlockMemoryArray(blkmem, &clqvars, nclqvars);
1563 #endif
1564  return SCIP_OKAY;
1565  }
1566 
1567  assert(0 <= pos && pos < (*cliquelist)->ncliques[value]);
1568  assert((*cliquelist)->cliques[value][pos] == clique);
1569 
1570  /* remove clique from list */
1571  /* @todo maybe buffered deletion */
1572  (*cliquelist)->ncliques[value]--;
1573  if( pos < (*cliquelist)->ncliques[value] )
1574  {
1575  BMSmoveMemoryArray(&((*cliquelist)->cliques[value][pos]), &((*cliquelist)->cliques[value][pos+1]),
1576  (*cliquelist)->ncliques[value] - pos); /*lint !e866*/
1577  }
1578 
1579  /* free cliquelist if it is empty */
1580  if( (*cliquelist)->ncliques[0] == 0 && (*cliquelist)->ncliques[1] == 0 )
1581  SCIPcliquelistFree(cliquelist, blkmem);
1582 
1583  return SCIP_OKAY;
1584 }
1585 
1586 /** returns whether the given clique lists have a non-empty intersection, i.e. whether there is a clique that appears
1587  * in both lists
1588  */
1590  SCIP_CLIQUELIST* cliquelist1, /**< first clique list data structure */
1591  SCIP_Bool value1, /**< value of first variable */
1592  SCIP_CLIQUELIST* cliquelist2, /**< second clique list data structure */
1593  SCIP_Bool value2 /**< value of second variable */
1594  )
1595 {
1596  SCIP_CLIQUE** cliques1;
1597  SCIP_CLIQUE** cliques2;
1598  int ncliques1;
1599  int ncliques2;
1600  int i1;
1601  int i2;
1602 
1603  if( cliquelist1 == NULL || cliquelist2 == NULL )
1604  return FALSE;
1605 
1606  ncliques1 = cliquelist1->ncliques[value1];
1607  cliques1 = cliquelist1->cliques[value1];
1608  ncliques2 = cliquelist2->ncliques[value2];
1609  cliques2 = cliquelist2->cliques[value2];
1610 
1611  i1 = 0;
1612  i2 = 0;
1613 
1614  if( i1 < ncliques1 && i2 < ncliques2 )
1615  {
1616  int cliqueid;
1617 
1618  /* make the bigger clique the first one */
1619  if( ncliques2 > ncliques1 )
1620  {
1621  SCIP_CLIQUE** tmpc;
1622  int tmpi;
1623 
1624  tmpc = cliques1;
1625  tmpi = ncliques1;
1626  cliques1 = cliques2;
1627  ncliques1 = ncliques2;
1628  cliques2 = tmpc;
1629  ncliques2 = tmpi;
1630  }
1631 
1632  /* check whether both clique lists have a same clique */
1633  while( TRUE ) /*lint !e716*/
1634  {
1635  cliqueid = SCIPcliqueGetId(cliques2[i2]);
1636 
1637  /* if last item in clique1 has a smaller index than the actual clique in clique2, than cause of increasing order
1638  * there will be no same item and we can stop */
1639  if( SCIPcliqueGetId(cliques1[ncliques1 - 1]) < cliqueid )
1640  break;
1641 
1642  while( SCIPcliqueGetId(cliques1[i1]) < cliqueid )
1643  {
1644  ++i1;
1645  assert(i1 < ncliques1);
1646  }
1647  cliqueid = SCIPcliqueGetId(cliques1[i1]);
1648 
1649  /* if last item in clique2 has a smaller index than the actual clique in clique1, than cause of increasing order
1650  * there will be no same item and we can stop */
1651  if( SCIPcliqueGetId(cliques2[ncliques2 - 1]) < cliqueid )
1652  break;
1653 
1654  while( SCIPcliqueGetId(cliques2[i2]) < cliqueid )
1655  {
1656  ++i2;
1657  assert(i2 < ncliques2);
1658  }
1659  if( SCIPcliqueGetId(cliques2[i2]) == cliqueid )
1660  return TRUE;
1661  }
1662  }
1663  return FALSE;
1664 }
1665 
1666 /** removes all listed entries from the cliques */
1668  SCIP_CLIQUELIST* cliquelist, /**< clique list data structure */
1669  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
1670  SCIP_VAR* var, /**< active problem variable the clique list belongs to */
1671  SCIP_Bool irrelevantvar /**< has the variable become irrelevant, meaning that equality
1672  * cliques need to be relaxed? */
1673  )
1674 {
1675  assert(SCIPvarIsBinary(var));
1676 
1677  if( cliquelist != NULL )
1678  {
1679  int value;
1680 
1681  SCIPdebugMessage("removing variable <%s> from cliques (%d with value 0, %d with value 1)\n",
1682  SCIPvarGetName(var), cliquelist->ncliques[0], cliquelist->ncliques[1]);
1683 
1684  for( value = 0; value < 2; ++value )
1685  {
1686  int i;
1687 
1688  assert(SCIPvarGetCliques(var, (SCIP_Bool)value) == cliquelist->cliques[value]);
1689  assert(SCIPvarGetNCliques(var, (SCIP_Bool)value) == cliquelist->ncliques[value]);
1690 
1691  /* it is important to iterate from the end of the array because otherwise, each removal causes
1692  * a memory move of the entire array
1693  */
1694  for( i = cliquelist->ncliques[value] - 1; i >= 0; --i )
1695  {
1696  SCIP_CLIQUE* clique;
1697 
1698  clique = cliquelist->cliques[value][i];
1699  assert(clique != NULL);
1700 
1701  SCIPdebugMessage(" -> removing variable <%s> == %d from clique %u (size %d)\n",
1702  SCIPvarGetName(var), value, clique->id, clique->nvars);
1703 
1704  SCIPcliqueDelVar(clique, cliquetable, var, (SCIP_Bool)value);
1705 
1706  if( irrelevantvar )
1707  clique->equation = FALSE;
1708 
1709 #ifndef NDEBUG
1710  /* during the cleanup step, we skip the consistency check because clique may be temporarily inconsistent */
1711  if( ! cliquetable->incleanup || clique->index > 0 )
1712  {
1713  cliqueCheck(clique);
1714  }
1715 #endif
1716  }
1717  }
1718  }
1719 }
1720 
1721 /** gets the key of the given element */
1722 static
1723 SCIP_DECL_HASHGETKEY(hashgetkeyClique)
1724 { /*lint --e{715}*/
1725  return elem;
1726 }
1727 
1728 /** returns TRUE iff both keys are equal */
1729 static
1730 SCIP_DECL_HASHKEYEQ(hashkeyeqClique)
1731 { /*lint --e{715}*/
1732  SCIP_CLIQUE* clique1;
1733  SCIP_CLIQUE* clique2;
1734  int i;
1735 
1736  clique1 = (SCIP_CLIQUE*)key1;
1737  clique2 = (SCIP_CLIQUE*)key2;
1738  assert(clique1 != NULL);
1739  assert(clique2 != NULL);
1740 
1741  if( clique1->nvars != clique2->nvars )
1742  return FALSE;
1743 
1744  /* the variables are sorted: we can simply check the equality of each pair of variable/values */
1745  for( i = 0; i < clique1->nvars; ++i )
1746  {
1747  if( clique1->vars[i] != clique2->vars[i] || clique1->values[i] != clique2->values[i] )
1748  return FALSE;
1749  }
1750 
1751  return TRUE;
1752 }
1753 
1754 /** returns the hash value of the key */
1755 static
1756 SCIP_DECL_HASHKEYVAL(hashkeyvalClique)
1757 { /*lint --e{715}*/
1758  SCIP_CLIQUE* clique;
1759  unsigned int hashval;
1760  int i;
1761 
1762  clique = (SCIP_CLIQUE*)key;
1763  hashval = 0;
1764  for( i = 0; i < clique->nvars; ++i )
1765  {
1766  hashval *= 31;
1767  hashval += (unsigned int)(((size_t)clique->vars[i]) >> 1) + (unsigned int)clique->values[i];
1768  }
1769 
1770  return hashval;
1771 }
1772 
1773 #define HASHTABLE_CLIQUETABLE_SIZE 100
1774 
1775 /** creates a clique table data structure */
1777  SCIP_CLIQUETABLE** cliquetable, /**< pointer to store clique table data structure */
1778  SCIP_SET* set, /**< global SCIP settings */
1779  BMS_BLKMEM* blkmem /**< block memory */
1780  )
1781 {
1782  int hashtablesize;
1783 
1784  assert(cliquetable != NULL);
1785 
1786  SCIP_ALLOC( BMSallocMemory(cliquetable) );
1787 
1788  /* create hash table to test for multiple cliques */
1790  hashtablesize = MAX(hashtablesize, (set->misc_usesmalltables ? SCIP_HASHSIZE_CLIQUES_SMALL : SCIP_HASHSIZE_CLIQUES));
1791  SCIP_CALL( SCIPhashtableCreate(&((*cliquetable)->hashtable), blkmem, hashtablesize,
1792  hashgetkeyClique, hashkeyeqClique, hashkeyvalClique, NULL) );
1793 
1794  (*cliquetable)->cliques = NULL;
1795  (*cliquetable)->ncliques = 0;
1796  (*cliquetable)->size = 0;
1797  (*cliquetable)->ncreatedcliques = 0;
1798  (*cliquetable)->ncleanupfixedvars = 0;
1799  (*cliquetable)->ncleanupaggrvars = 0;
1800  (*cliquetable)->ndirtycliques = 0;
1801  (*cliquetable)->nentries = 0;
1802  (*cliquetable)->incleanup = FALSE;
1803 
1804  return SCIP_OKAY;
1805 }
1806 
1807 /** frees a clique table data structure */
1809  SCIP_CLIQUETABLE** cliquetable, /**< pointer to store clique table data structure */
1810  BMS_BLKMEM* blkmem /**< block memory */
1811  )
1812 {
1813  int i;
1814 
1815  assert(cliquetable != NULL);
1816  assert(*cliquetable != NULL);
1817 
1818  /* free all cliques */
1819  for( i = (*cliquetable)->ncliques - 1; i >= 0; --i )
1820  {
1821  cliqueFree(&(*cliquetable)->cliques[i], blkmem);
1822  }
1823 
1824  /* free clique table data */
1825  BMSfreeMemoryArrayNull(&(*cliquetable)->cliques);
1826 
1827  /* free hash table */
1828  SCIPhashtableFree(&((*cliquetable)->hashtable));
1829 
1830  BMSfreeMemory(cliquetable);
1831 
1832  return SCIP_OKAY;
1833 }
1834 
1835 /** ensures, that clique table arrays can store at least num entries */
1836 static
1838  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
1839  SCIP_SET* set, /**< global SCIP settings */
1840  int num /**< minimum number of entries to store */
1841  )
1842 {
1843  assert(cliquetable != NULL);
1844 
1845  if( num > cliquetable->size )
1846  {
1847  int newsize;
1848 
1849  newsize = SCIPsetCalcMemGrowSize(set, num);
1850  SCIP_ALLOC( BMSreallocMemoryArray(&cliquetable->cliques, newsize) );
1851  cliquetable->size = newsize;
1852  }
1853  assert(num <= cliquetable->size);
1854 
1855  return SCIP_OKAY;
1856 }
1857 
1858 /** sort variables regarding their index and remove multiple entries of the same variable */
1859 static
1861  SCIP_VAR** clqvars, /**< variables of a clique */
1862  SCIP_Bool* clqvalues, /**< clique values, active or negated, for the variables in a clique */
1863  int* nclqvars, /**< number of clique variables */
1864  SCIP_Bool* isequation, /**< do we have an equation clique at hand? */
1865  SCIP_CLIQUE* clique, /**< clique data structure or NULL */
1866  BMS_BLKMEM* blkmem, /**< block memory */
1867  SCIP_SET* set, /**< global SCIP settings */
1868  SCIP_STAT* stat, /**< problem statistics */
1869  SCIP_PROB* transprob, /**< transformed problem */
1870  SCIP_PROB* origprob, /**< original problem */
1871  SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
1872  SCIP_REOPT* reopt, /**< reoptimization data structure */
1873  SCIP_LP* lp, /**< current LP data */
1874  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
1875  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1876  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
1877  int* nbdchgs, /**< pointer to store number of fixed variables */
1878  SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
1879  )
1880 {
1881  SCIP_VAR* var;
1882  int noldbdchgs;
1883  int startidx;
1884 
1885  assert(nclqvars != NULL);
1886 
1887  SCIPdebugMessage("starting merging %d variables in clique %d\n", *nclqvars, (clique == NULL) ? -1 : (int) clique->id);
1888 
1889  if( *nclqvars <= 1 )
1890  return SCIP_OKAY;
1891 
1892  assert(clqvars != NULL);
1893  assert(clqvalues != NULL);
1894  assert(blkmem != NULL);
1895  assert(set != NULL);
1896  assert(stat != NULL);
1897  assert(transprob != NULL);
1898  assert(origprob != NULL);
1899  assert(tree != NULL);
1900  assert(eventqueue != NULL);
1901  assert(nbdchgs != NULL);
1902  assert(infeasible != NULL);
1903 
1904  /* sort variables and corresponding clique values regarding variables indices before merging multiples */
1905  SCIPsortPtrBool((void**) clqvars, clqvalues, SCIPvarComp, *nclqvars);
1906 
1907  var = NULL;
1908  noldbdchgs = *nbdchgs;
1909  /* check for multiple occurences or pairs of negations in the variable array, this should be very rare when creating a
1910  * new clique
1911  */
1912  startidx = *nclqvars - 1;
1913  while( startidx >= 0 )
1914  {
1915  int nones;
1916  int nzeros;
1917  int curr;
1918 
1919  var = clqvars[startidx];
1920  /* only column and loose variables can exist now */
1923  assert(SCIPvarIsBinary(var));
1924 
1925  /* the counters denote the occurrences of the variable var with value TRUE and FALSE as clqvalues, respectively */
1926  if( clqvalues[startidx] )
1927  {
1928  nones = 1;
1929  nzeros = 0;
1930  }
1931  else
1932  {
1933  nzeros = 1;
1934  nones = 0;
1935  }
1936  curr = startidx - 1;
1937 
1938  /* loop and increase the counter based on the clique value */
1939  while( curr >= 0 )
1940  {
1941  if( clqvars[curr] == var )
1942  {
1943  if( clqvalues[curr] )
1944  nones++;
1945  else
1946  nzeros++;
1947  }
1948  else
1949  /* var is different from variable pointed at by z */
1950  break;
1951 
1952  --curr;
1953  }
1954 
1955 
1956  /* single occurrence of the variable */
1957  if( nones + nzeros == 1 )
1958  {
1959  startidx = curr;
1960  continue;
1961  }
1962  /* at least two occurrences of both the variable and its negation; infeasible */
1963  if( nones >= 2 && nzeros >= 2 )
1964  {
1965  *infeasible = TRUE;
1966  break;
1967  }
1968 
1969  /* do we have the same variable with the same clique value twice? */
1970  if( nones >= 2 || nzeros >= 2 )
1971  {
1972  SCIP_Bool fixvalue;
1973 
1974  /* other cases should be handled as infeasible */
1975  assert(nones <= 1 || nzeros <= 1);
1976 
1977  /* ensure that the variable is removed from both clique lists before fixing it */
1978  if( clique != NULL )
1979  {
1980  if( nones >= 1 )
1981  {
1982  SCIP_CALL( SCIPvarDelCliqueFromList(var, blkmem, TRUE, clique) );
1983  }
1984  if( nzeros >= 1 )
1985  {
1986  SCIP_CALL( SCIPvarDelCliqueFromList(var, blkmem, FALSE, clique) );
1987  }
1988  }
1989 
1990  /* we fix the variable into the direction of less occurrences */
1991  fixvalue = nones >= 2 ? FALSE : TRUE;
1992 
1993  /* a variable multiple times in one clique forces this variable to be zero */
1994  SCIP_CALL( SCIPvarFixBinary(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
1995  cliquetable, fixvalue, infeasible, nbdchgs) );
1996 
1997  SCIPdebugMessage("same var %s twice in a clique with value %d fixed to %d (was %s)\n", SCIPvarGetName(var), fixvalue ? 0 : 1,
1998  fixvalue ? 1 : 0, *infeasible ? "infeasible" : "feasible");
1999 
2000  if( *infeasible )
2001  break;
2002  }
2003 
2004  /* do we have a pair of negated variables? */
2005  if( nones >= 1 && nzeros >= 1 )
2006  {
2007  SCIPdebugMessage("var %s is paired with its negation in one clique -> fix all other variables\n", SCIPvarGetName(var));
2008 
2009  /* a pair of negated variable in one clique forces all other variables in the clique to be zero */
2010  if( nzeros + nones < *nclqvars )
2011  {
2012  int w = *nclqvars - 1;
2013  while( w >= 0 )
2014  {
2015  /* skip all occurrences of variable var itself, these are between curr and startidx */
2016  if( w == startidx )
2017  {
2018  if( curr == -1 )
2019  break;
2020 
2021  w = curr;
2022  }
2023  assert(clqvars[w] != var);
2024 
2025  /* if one of the other variables occurs multiple times, we can
2026  * 1) deduce infeasibility if it occurs with different values
2027  * 2) wait for the last occurence to fix it
2028  */
2029  while( w > 0 && clqvars[w-1] == clqvars[w] )
2030  {
2031  if( clqvalues[w-1] != clqvalues[w] )
2032  {
2033  *infeasible = TRUE;
2034  break;
2035  }
2036  --w;
2037  }
2038 
2039  if( *infeasible )
2040  break;
2041 
2042  if( clique != NULL )
2043  {
2044  SCIP_CALL( SCIPvarDelCliqueFromList(clqvars[w], blkmem, clqvalues[w], clique) );
2045  }
2046  SCIP_CALL( SCIPvarFixBinary(clqvars[w], blkmem, set, stat, transprob, origprob, tree, reopt, lp,
2047  branchcand, eventqueue, cliquetable, !clqvalues[w], infeasible, nbdchgs) );
2048 
2049  SCIPdebugMessage("fixed var %s with value %u to %d (was %s)\n", SCIPvarGetName(clqvars[w]), clqvalues[w], clqvalues[w] ? 0 : 1, *infeasible ? "infeasible" : "feasible");
2050 
2051  if( *infeasible )
2052  break;
2053 
2054  --w;
2055  }
2056  }
2057  /* all variables except for var were fixed */
2058  if( clique != NULL )
2059  {
2060  SCIP_CALL( SCIPvarDelCliqueFromList(var, blkmem, TRUE, clique) );
2061  SCIP_CALL( SCIPvarDelCliqueFromList(var, blkmem, FALSE, clique) );
2062  }
2063  *nclqvars = 0;
2064  *isequation = FALSE;
2065  }
2066 
2067  /* otherwise, we would have an endless loop */
2068  assert(curr < startidx);
2069  startidx = curr;
2070  }
2071 
2072 
2073  /* we might have found an infeasibility or reduced the clique to size 0 */
2074  if( *infeasible || *nclqvars == 0 )
2075  return SCIP_OKAY;
2076 
2077  /* we fixed a variable because it appears at least twice, now we need to remove the fixings
2078  *
2079  * @note that if we are in probing or solving stage, the fixation on the variable might not be carried out yet,
2080  * because it was contradicting a local bound
2081  */
2082  if( *nbdchgs > noldbdchgs )
2083  {
2084  SCIP_VAR* onefixedvar;
2085  SCIP_Bool onefixedvalue;
2086  int w;
2087 
2088  /* we initialize the former value only to please gcc */
2089  onefixedvalue = TRUE;
2090  onefixedvar = NULL;
2091 
2092  /* remove all inactive variables, thereby checking for a variable that is fixed to one */
2093  startidx = 0;
2094  w = 0;
2095  while( startidx < *nclqvars )
2096  {
2097  var = clqvars[startidx];
2098 
2101 
2102  /* check if we have a variable fixed to one for this clique */
2103  if( (clqvalues[startidx] && SCIPvarGetLbGlobal(var) > 0.5) || (!clqvalues[startidx] && SCIPvarGetUbGlobal(var) < 0.5) )
2104  {
2105  if( onefixedvar != NULL )
2106  {
2107  *infeasible = TRUE;
2108 
2109  SCIPdebugMessage("two variables in clique %d fixed to one %s%s and %s%s\n", (clique != NULL) ? (int) clique->id : -1,
2110  onefixedvalue ? "" : "~", SCIPvarGetName(onefixedvar), clqvalues[startidx] ? "" : "~",
2111  SCIPvarGetName(clqvars[startidx]));
2112  return SCIP_OKAY;
2113  }
2114  onefixedvar = var;
2115  onefixedvalue = clqvalues[startidx];
2116  }
2117  /* only keep active variables */
2118  else if( SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5 )
2119  {
2120  /* we remove all fixed variables */
2121  if( startidx > w )
2122  {
2123  clqvars[w] = clqvars[startidx];
2124  clqvalues[w] = clqvalues[startidx];
2125  }
2126  ++w;
2127  }
2128  else
2129  {
2130  /* can we have some variable fixed to one? */
2131  assert((SCIPvarGetUbGlobal(var) < 0.5 && clqvalues[startidx]) || (SCIPvarGetLbGlobal(var) > 0.5 && !clqvalues[startidx]));
2132 
2133  if( clique != NULL )
2134  {
2135  SCIP_CALL( SCIPvarDelCliqueFromList(var, blkmem, clqvalues[startidx], clique) );
2136  }
2137  }
2138  ++startidx;
2139  }
2140 
2141  /* the clique has been reduced to w active (unfixed) variables */
2142  *nclqvars = w;
2143 
2144  /* in rare cases, a variable fixed to one is only detected in the merging step */
2145  if( onefixedvar != NULL )
2146  {
2147  SCIPdebugMessage("variable %s%s in clique %d fixed to one, fixing all other variables to zero\n",
2148  onefixedvalue ? "" : "~", SCIPvarGetName(onefixedvar), (clique != NULL) ? (int) clique->id : -1);
2149 
2150  /* handle all active variables by fixing them */
2151  for( startidx = *nclqvars; startidx >= 0; --startidx )
2152  {
2153  assert(SCIPvarGetStatus(clqvars[startidx]) == SCIP_VARSTATUS_COLUMN
2154  || SCIPvarGetStatus(clqvars[startidx]) == SCIP_VARSTATUS_LOOSE);
2155 
2156  /* delete the variable from its clique lists and fix it */
2157  if( onefixedvalue != clqvalues[startidx] || clqvars[startidx] != onefixedvar )
2158  {
2159  if( clique != NULL )
2160  {
2161  SCIP_CALL( SCIPvarDelCliqueFromList(clqvars[startidx], blkmem, clqvalues[startidx], clique) );
2162  }
2163 
2164  /* if one of the other variables occurs multiple times, we can
2165  * 1) deduce infeasibility if it occurs with different values
2166  * 2) wait for the last occurence to fix it
2167  */
2168  while( startidx > 0 && clqvars[startidx - 1] == clqvars[startidx] )
2169  {
2170  if( clqvalues[startidx - 1] != clqvalues[startidx] )
2171  {
2172  *infeasible = TRUE;
2173  return SCIP_OKAY;
2174  }
2175  --startidx;
2176  }
2177 
2178  SCIPdebugMessage("fixing variable %s in clique %d to %d\n", SCIPvarGetName(clqvars[startidx]), (clique != NULL) ? (int) clique->id : -1,
2179  clqvalues[startidx] ? 0 : 1);
2180 
2181  /* note that the variable status will remain unchanged */
2182  SCIP_CALL( SCIPvarFixBinary(clqvars[startidx], blkmem, set, stat, transprob, origprob, tree, reopt, lp,
2183  branchcand, eventqueue, cliquetable, !clqvalues[startidx], infeasible, nbdchgs) );
2184 
2185  if( *infeasible )
2186  return SCIP_OKAY;
2187  }
2188  }
2189 
2190  /* delete clique from onefixedvars clique list */
2191  if( clique != NULL ) /*lint !e850*/
2192  {
2193  SCIP_CALL( SCIPvarDelCliqueFromList(onefixedvar, blkmem, onefixedvalue, clique) );
2194  }
2195 
2196  *nclqvars = 0;
2197  *isequation = FALSE;
2198  }
2199  }
2200 
2201  assert(!(*infeasible));
2202 
2203  if( *isequation )
2204  {
2205  if( *nclqvars == 0 )
2206  {
2207  SCIPdebugMessage("empty equation clique left over -> infeasible\n");
2208 
2209  *infeasible = TRUE;
2210  }
2211  else if( *nclqvars == 1 )
2212  {
2213  assert(SCIPvarGetStatus(clqvars[0]) == SCIP_VARSTATUS_COLUMN
2214  || SCIPvarGetStatus(clqvars[0]) == SCIP_VARSTATUS_LOOSE);
2215  /* clearing data and removing variable from its clique list */
2216  if( clique != NULL )
2217  {
2218  SCIP_CALL( SCIPvarDelCliqueFromList(clqvars[0], blkmem, clqvalues[0], clique) );
2219  }
2220  SCIP_CALL( SCIPvarFixBinary(clqvars[0], blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
2221  eventqueue, cliquetable, clqvalues[0], infeasible, nbdchgs) );
2222 
2223  SCIPdebugMessage("fixed last clique var %s with value %u to %d (was %s)\n", SCIPvarGetName(clqvars[0]), clqvalues[0], clqvalues[0] ? 1 : 0, *infeasible ? "infeasible" : "feasible");
2224 
2225  *nclqvars = 0;
2226  *isequation = FALSE;
2227  }
2228  }
2229 
2230  return SCIP_OKAY;
2231 }
2232 
2233 
2234 /** adds a clique to the clique table, using the given values for the given variables;
2235  * performs implications if the clique contains the same variable twice
2236  */
2238  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
2239  BMS_BLKMEM* blkmem, /**< block memory */
2240  SCIP_SET* set, /**< global SCIP settings */
2241  SCIP_STAT* stat, /**< problem statistics */
2242  SCIP_PROB* transprob, /**< transformed problem */
2243  SCIP_PROB* origprob, /**< original problem */
2244  SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
2245  SCIP_REOPT* reopt, /**< reoptimization data structure */
2246  SCIP_LP* lp, /**< current LP data */
2247  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
2248  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2249  SCIP_VAR** vars, /**< binary variables in the clique: at most one can be set to the given value */
2250  SCIP_Bool* values, /**< values of the variables in the clique; NULL to use TRUE for all vars */
2251  int nvars, /**< number of variables in the clique */
2252  SCIP_Bool isequation, /**< is the clique an equation or an inequality? */
2253  SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
2254  int* nbdchgs /**< pointer to count the number of performed bound changes, or NULL */
2255  )
2256 {
2257  SCIP_VAR** clqvars;
2258  SCIP_Bool* clqvalues;
2259  SCIP_CLIQUE* clique;
2260  SCIP_VAR* var;
2261  int size;
2262  int nlocalbdchgs = 0;
2263  int v;
2264  int w;
2265 
2266  assert(cliquetable != NULL);
2267  assert(vars != NULL);
2268 
2269  SCIPdebugMessage("trying to add clique %d with %d vars to clique table\n", cliquetable->ncliques, nvars);
2270 
2271  /* check clique on debugging solution */
2272  SCIP_CALL( SCIPdebugCheckClique(set, vars, values, nvars) ); /*lint !e506 !e774*/
2273 
2274  *infeasible = FALSE;
2275  size = nvars;
2276 
2277  /* copy clique data */
2278  if( values == NULL )
2279  {
2280  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &clqvalues, size) );
2281 
2282  /* initialize clique values data */
2283  for( v = nvars - 1; v >= 0; --v )
2284  clqvalues[v] = TRUE;
2285  }
2286  else
2287  {
2288  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &clqvalues, values, size) );
2289  }
2290  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &clqvars, vars, size) );
2291 
2292  /* get active variables */
2293  SCIP_CALL( SCIPvarsGetProbvarBinary(&clqvars, &clqvalues, nvars) );
2294 
2295  /* remove all inactive vars */
2296  for( v = nvars - 1; v >= 0; --v )
2297  {
2298  var = clqvars[v];
2299 
2304  assert(SCIPvarIsBinary(var));
2305 
2306  /* if we have a variables already fixed to one in the clique, fix all other to zero */
2308  ((clqvalues[v] && SCIPvarGetLbGlobal(var) > 0.5) || (!clqvalues[v] && SCIPvarGetUbGlobal(var) < 0.5)) )
2309  {
2310  SCIPdebugMessage("in a clique var %s with value %u is fixed to %d -> fix the rest\n", SCIPvarGetName(var), clqvalues[v], clqvalues[v] ? 1 : 0);
2311 
2312  for( w = nvars - 1; w >= 0; --w )
2313  {
2314  SCIP_VAR* clqvar = clqvars[w];
2315 
2316  /* the rare case where the same variable appears several times is handled later during sort and merge */
2317  if( clqvar != var )
2318  {
2319  SCIP_Bool clqval = clqvalues[w];
2320 
2321  /* check if variable is fixed already and terminate with infeasible if this fixing contradicts the clique info */
2322  if( SCIPvarGetLbGlobal(clqvar) > SCIPvarGetUbGlobal(clqvar) - 0.5 )
2323  {
2324 
2325  /* check if fixing contradicts clique constraint */
2326  if( (clqval && SCIPvarGetLbGlobal(clqvar) > 0.5)
2327  || (! clqval && SCIPvarGetUbGlobal(clqvar) < 0.5) )
2328  {
2329  *infeasible = TRUE;
2330 
2331  return SCIP_OKAY;
2332  }
2333 
2334  continue;
2335  }
2336 
2337 /* the following piece of code is disabled because it assumes the clqvars to be sorted which they aren't until the method
2338  * sortAndMergeClique() is called
2339  */
2340 #ifdef SCIP_DISABLED_CODE
2341  /* if one of the other variables occurs multiple times, we can
2342  * 1) deduce infeasibility if it occurs with different values
2343  * 2) wait for the last occurence to fix it
2344  */
2345  while( w > 0 && clqvars[w - 1] == clqvars[w] )
2346  {
2347  if( clqvalues[w - 1] != clqvalues[w] )
2348  {
2349  *infeasible = TRUE;
2350  return SCIP_OKAY;
2351  }
2352  --w;
2353  }
2354 #endif
2355 
2356  /* fix the variable */
2357  SCIP_CALL( SCIPvarFixBinary(clqvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
2358  branchcand, eventqueue, cliquetable, !clqval, infeasible, &nlocalbdchgs) );
2359 
2360  SCIPdebugMessage("fixed var %s with value %u to %d (was %s)\n", SCIPvarGetName(clqvar), clqval, clqval ? 0 : 1, *infeasible ? "infeasible" : "feasible");
2361 
2362  if( *infeasible )
2363  break;
2364  }
2365  }
2366 
2367  /* all variables are fixed so we can stop */
2368  break; /*lint !e850*/
2369  }
2370 
2371  /* only unfixed column and loose variables may be member of a clique */
2372  if( SCIPvarGetUbGlobal(var) - SCIPvarGetLbGlobal(var) < 0.5 ||
2375  {
2376  --nvars;
2377  clqvars[v] = clqvars[nvars];
2378  clqvalues[v] = clqvalues[nvars];
2379  isequation = isequation && !(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR) && ! SCIPvarIsMarkedDeleteGlobalStructures(var);
2380  }
2381  }
2382 
2383  if( nbdchgs != NULL )
2384  *nbdchgs += nlocalbdchgs;
2385 
2386  /* did we fix all variables or are we infeasible? */
2387  if( v >= 0 )
2388  {
2389  BMSfreeBlockMemoryArray(blkmem, &clqvars, size);
2390  BMSfreeBlockMemoryArray(blkmem, &clqvalues, size);
2391 
2392  return SCIP_OKAY;
2393  }
2394  assert(!*infeasible);
2395 
2396  /* check if only one or less variables are left */
2397  if( v < 0 && nvars <= 1)
2398  {
2399  if( isequation )
2400  {
2401  if( nvars == 1 )
2402  {
2403  nlocalbdchgs = 0;
2404 
2405  SCIP_CALL( SCIPvarFixBinary(clqvars[0], blkmem, set, stat, transprob, origprob, tree, reopt, lp,
2406  branchcand, eventqueue, cliquetable, clqvalues[0], infeasible, &nlocalbdchgs) );
2407 
2408  SCIPdebugMessage("fixed last clique var %s with value %u to %d (was %s)\n", SCIPvarGetName(clqvars[0]), clqvalues[0], clqvalues[0] ? 1 : 0, *infeasible ? "infeasible" : "feasible");
2409 
2410  if( nbdchgs != NULL )
2411  *nbdchgs += nlocalbdchgs;
2412  }
2413  else if( nvars == 0 )
2414  {
2415  SCIPdebugMessage("empty equation clique left over -> infeasible\n");
2416 
2417  *infeasible = TRUE;
2418  }
2419  }
2420 
2421  BMSfreeBlockMemoryArray(blkmem, &clqvars, size);
2422  BMSfreeBlockMemoryArray(blkmem, &clqvalues, size);
2423 
2424  return SCIP_OKAY;
2425  }
2426 
2427  nlocalbdchgs = 0;
2428 
2429  /* sort the variables and values and remove multiple entries of the same variable */
2430  SCIP_CALL( sortAndMergeClique(clqvars, clqvalues, &nvars, &isequation, NULL, blkmem, set, stat, transprob, origprob, tree,
2431  reopt, lp, branchcand, eventqueue, cliquetable, &nlocalbdchgs, infeasible) );
2432 
2433  if( nbdchgs != NULL )
2434  *nbdchgs += nlocalbdchgs;
2435 
2436  /* did we stop early due to a pair of negated variables? */
2437  if( nvars == 0 || *infeasible )
2438  {
2439  BMSfreeBlockMemoryArray(blkmem, &clqvars, size);
2440  BMSfreeBlockMemoryArray(blkmem, &clqvalues, size);
2441 
2442  return SCIP_OKAY;
2443  }
2444 
2445  /* if less than two variables are left over, the clique is redundant */
2446  if( nvars > 1 )
2447  {
2448  SCIP_CLIQUE* sameclique;
2449 
2450  /* @todo check if we can aggregate variables if( clique->equation && clique->nvars == 2 ) */
2451 
2452  /* create the clique data structure */
2453  SCIP_CALL( cliqueCreateWithData(&clique, blkmem, size, clqvars, clqvalues, nvars, cliquetable->ncreatedcliques, isequation) );
2454 
2455  sameclique = SCIPhashtableRetrieve(cliquetable->hashtable, (void*)clique);
2456 
2457  if( sameclique == NULL )
2458  {
2459  SCIPdebugMessage("adding clique %u with %d vars to clique table\n", clique->id, nvars);
2460 
2461  cliquetable->ncreatedcliques++;
2462 
2463  /* add clique to clique table */
2464  SCIP_CALL( cliquetableEnsureSize(cliquetable, set, cliquetable->ncliques+1) );
2465  cliquetable->cliques[cliquetable->ncliques] = clique;
2466  clique->index = cliquetable->ncliques;
2467  cliquetable->ncliques++;
2468  cliquetable->nentries += nvars;
2469 
2470  SCIP_CALL( SCIPhashtableInsert(cliquetable->hashtable, (void*)clique) );
2471 
2472  /* add filled clique to the cliquelists of all corresponding variables */
2473  SCIP_CALL( SCIPvarsAddClique(clqvars, clqvalues, nvars, blkmem, set, clique) );
2474  }
2475  else
2476  {
2477  SCIPdebugMessage("same clique %p already found in cliquetable -> discard new one\n", (void*) sameclique);
2478 
2479  /* update equation status of clique */
2480  /* @note if we might change the order of the clique, e.g. put the equations up front, we should rather remove
2481  * the sameclique from the hashmap while adding the new clique
2482  */
2483  if( !sameclique->equation && clique->equation )
2484  sameclique->equation = TRUE;
2485 
2486  cliqueFree(&clique, blkmem);
2487  return SCIP_OKAY;
2488  }
2489  }
2490  else
2491  {
2492  assert(!isequation);
2493  assert(nvars == 1);
2494 
2495  BMSfreeBlockMemoryArray(blkmem, &clqvars, size);
2496  BMSfreeBlockMemoryArray(blkmem, &clqvalues, size);
2497 
2498  return SCIP_OKAY;
2499  }
2500  cliqueCheck(clique);
2501 
2502  return SCIP_OKAY;
2503 }
2504 
2505 /** clean up given clique by removing fixed variables */
2506 static
2508  SCIP_CLIQUE* clique, /**< clique data structure */
2509  BMS_BLKMEM* blkmem, /**< block memory */
2510  SCIP_SET* set, /**< global SCIP settings */
2511  SCIP_STAT* stat, /**< problem statistics */
2512  SCIP_PROB* transprob, /**< transformed problem */
2513  SCIP_PROB* origprob, /**< original problem */
2514  SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
2515  SCIP_REOPT* reopt, /**< reoptimization data structure */
2516  SCIP_LP* lp, /**< current LP data */
2517  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
2518  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2519  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
2520  int* nchgbds, /**< pointer to store number of fixed variables */
2521  SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
2522  )
2523 {
2524  assert(clique != NULL);
2525  assert(blkmem != NULL);
2526  assert(set != NULL);
2527  assert(nchgbds != NULL);
2528  assert(infeasible != NULL);
2529 
2530  /* do we need to clean up fixed variables? */
2531  if( !SCIPcliqueIsCleanedUp(clique) )
2532  {
2533  SCIP_VAR* onefixedvar = NULL;
2534  SCIP_Bool onefixedvalue;
2535  SCIP_Bool needsorting = FALSE;
2536  int v;
2537  int w;
2538 
2539  w = clique->startcleanup;
2540  /* exchange inactive by active variables */
2541  for( v = w; v < clique->nvars; ++v )
2542  {
2543  SCIP_Bool addvartoclique; /* has the variable status changed such that it needs to be replaced by an active representative? */
2544 
2545  addvartoclique = FALSE;
2547  || SCIPvarGetStatus(clique->vars[v]) == SCIP_VARSTATUS_NEGATED
2548  || SCIPvarGetStatus(clique->vars[v]) == SCIP_VARSTATUS_MULTAGGR )
2549  {
2550  needsorting = TRUE;
2551 
2552  SCIP_CALL( SCIPvarGetProbvarBinary(&(clique->vars[v]), &(clique->values[v])) );
2553  if( SCIPvarGetStatus(clique->vars[v]) == SCIP_VARSTATUS_NEGATED )
2554  {
2555  clique->vars[v] = SCIPvarGetNegationVar(clique->vars[v]);
2556  clique->values[v] = !clique->values[v];
2557  }
2558  else if( SCIPvarGetStatus(clique->vars[v]) == SCIP_VARSTATUS_MULTAGGR )
2559  {
2560  clique->equation = FALSE;
2561  continue;
2562  }
2563 
2564  addvartoclique = TRUE;
2565  }
2566 
2567  assert(SCIPvarGetStatus(clique->vars[v]) == SCIP_VARSTATUS_COLUMN
2568  || SCIPvarGetStatus(clique->vars[v]) == SCIP_VARSTATUS_LOOSE
2569  || SCIPvarGetStatus(clique->vars[v]) == SCIP_VARSTATUS_FIXED);
2570 
2571  /* check for variables that are either fixed to zero or marked for deletion from global structures */
2572  if( (clique->values[v] && SCIPvarGetUbGlobal(clique->vars[v]) < 0.5) ||
2573  (!clique->values[v] && SCIPvarGetLbGlobal(clique->vars[v]) > 0.5) ||
2575  {
2576  /* the variable will be overwritten by subsequent active variables */
2577  continue;
2578  }
2579 
2580  /* check for a variable fixed to one in the clique */
2581  else if( (clique->values[v] && SCIPvarGetLbGlobal(clique->vars[v]) > 0.5)
2582  || (!clique->values[v] && SCIPvarGetUbGlobal(clique->vars[v]) < 0.5) )
2583  {
2584  if( onefixedvar != NULL )
2585  {
2586  *infeasible = TRUE;
2587 
2588  SCIPdebugMessage("two variables in clique %u fixed to one %s%s and %s%s\n", clique->id,
2589  onefixedvalue ? "" : "~", SCIPvarGetName(onefixedvar), clique->values[v] ? "" : "~",
2590  SCIPvarGetName(clique->vars[v])); /*lint !e530*/
2591  return SCIP_OKAY;
2592  }
2593  onefixedvar = clique->vars[v];
2594  onefixedvalue = clique->values[v];
2595  }
2596  else
2597  {
2598  assert(SCIPvarGetStatus(clique->vars[v]) != SCIP_VARSTATUS_FIXED);
2599  assert(w <= v);
2600 
2601  if( w < v )
2602  {
2603  clique->vars[w] = clique->vars[v];
2604  clique->values[w] = clique->values[v];
2605  }
2606 
2607  /* add clique to active variable if it replaced a aggregated or negated var */
2608  if( addvartoclique )
2609  {
2610  SCIP_CALL( SCIPvarAddCliqueToList(clique->vars[w], blkmem, set, clique->values[w], clique) );
2611  }
2612  /* increase indexer of last active, i.e. unfixed, variable in clique */
2613  ++w;
2614  }
2615 
2616  }
2617  clique->nvars = w;
2618 
2619  if( onefixedvar != NULL )
2620  {
2621  SCIPdebugMessage("variable %s%s in clique %u fixed to one, fixing all other variables to zero\n",
2622  onefixedvalue ? "" : "~", SCIPvarGetName(onefixedvar), clique->id);
2623 
2624  for( v = 0; v < clique->nvars ; ++v )
2625  {
2626  SCIP_VAR* clqvar = clique->vars[v];
2627  SCIP_Bool clqval = clique->values[v];
2628 
2629  assert(SCIPvarGetStatus(clqvar) == SCIP_VARSTATUS_COLUMN
2630  || SCIPvarGetStatus(clqvar) == SCIP_VARSTATUS_LOOSE);
2631 
2632  if( onefixedvalue != clqval || clqvar != onefixedvar )
2633  {
2634  /* the variable could have been fixed already because it appears more than once in the clique */
2635  if( SCIPvarGetLbGlobal(clqvar) > SCIPvarGetUbGlobal(clqvar) - 0.5 )
2636  {
2637  /* the fixing must have occurred previously inside this loop. It may happen that
2638  * the variable occurs together with its negation in that clique, which is usually
2639  * handled during the merge step, but leads to a direct infeasibility because it
2640  * contradicts any other variable fixed to one in this clique
2641  */
2642  if( (clqval && SCIPvarGetLbGlobal(clqvar) > 0.5)
2643  || (! clqval && SCIPvarGetUbGlobal(clqvar) < 0.5) )
2644  {
2645  /* impossible because we would have detected this in the previous cleanup loop */
2646  assert(clqvar != onefixedvar);
2647  *infeasible = TRUE;
2648 
2649  return SCIP_OKAY;
2650  }
2651  continue;
2652  }
2653 
2654  SCIP_CALL( SCIPvarDelCliqueFromList(clqvar, blkmem, clqval, clique) );
2655 
2656 /* the following piece of code is wrong at this point because it assumes sorted variables. can be enabled if sorting
2657  * of variables is performed earlier than it is now
2658  */
2659 #ifdef SCIP_DISABLED_CODE
2660  /* if one of the other variables occurs multiple times, we can
2661  * 1) deduce infeasibility if it occurs with different values
2662  * 2) wait for the last occurence to fix it
2663  */
2664  while( v < clique->nvars - 1 && clique->vars[v + 1] == clqvar )
2665  {
2666  if( clique->values[v + 1] != clique->values[v] )
2667  {
2668  *infeasible = TRUE;
2669  return SCIP_OKAY;
2670  }
2671  ++v;
2672  }
2673 #endif
2674  SCIPdebugMessage("fixing variable %s in clique %u to %d\n", SCIPvarGetName(clqvar), clique->id,
2675  clqval ? 0 : 1);
2676 
2677  SCIP_CALL( SCIPvarFixBinary(clqvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
2678  eventqueue, cliquetable, !clqval, infeasible, nchgbds) );
2679 
2680  if( *infeasible )
2681  return SCIP_OKAY;
2682  }
2683  }
2684 
2685  if( SCIPvarGetStatus(onefixedvar) == SCIP_VARSTATUS_COLUMN /*lint !e850*/
2686  || SCIPvarGetStatus(onefixedvar) == SCIP_VARSTATUS_LOOSE )
2687  {
2688  SCIP_CALL( SCIPvarDelCliqueFromList(onefixedvar, blkmem, onefixedvalue, clique) );
2689  }
2690 
2691  clique->nvars = 0;
2692  clique->equation = FALSE;
2693  clique->startcleanup = -1;
2694 
2695  return SCIP_OKAY;
2696  }
2697 
2698  if( clique->equation )
2699  {
2700  if( clique->nvars == 0 )
2701  {
2702  *infeasible = TRUE;
2703  return SCIP_OKAY;
2704  }
2705  else if( clique->nvars == 1 )
2706  {
2707  assert(SCIPvarGetStatus(clique->vars[0]) == SCIP_VARSTATUS_COLUMN
2708  || SCIPvarGetStatus(clique->vars[0]) == SCIP_VARSTATUS_LOOSE);
2709 
2710  /* clearing data and removing variable from its clique list */
2711  SCIP_CALL( SCIPvarDelCliqueFromList(clique->vars[0], blkmem, clique->values[0], clique) );
2712 
2713  SCIPdebugMessage("fixing last variable %s in clique %u to %d\n", SCIPvarGetName(clique->vars[0]), clique->id,
2714  clique->values[0] ? 1 : 0);
2715 
2716  SCIP_CALL( SCIPvarFixBinary(clique->vars[0], blkmem, set, stat, transprob, origprob, tree, reopt, lp,
2717  branchcand, eventqueue, cliquetable, clique->values[0], infeasible, nchgbds) );
2718 
2719  clique->nvars = 0;
2720  clique->equation = FALSE;
2721  clique->startcleanup = -1;
2722 
2723  return SCIP_OKAY;
2724  }
2725  }
2726 
2727  if( needsorting )
2728  {
2729  SCIP_Bool isequation = clique->equation;
2730 
2731  /* remove multiple entries of the same variable */
2732  SCIP_CALL( sortAndMergeClique(clique->vars, clique->values, &(clique->nvars), &isequation, clique, blkmem, set, stat,
2733  transprob, origprob, tree, reopt, lp, branchcand, eventqueue, cliquetable, nchgbds, infeasible) );
2734 
2735  clique->equation = isequation;
2736  }
2737 
2738  /* @todo check if we can aggregate variables if( clique->equation && clique->nvars == 2 ) */
2739 
2740  clique->startcleanup = -1;
2741  }
2742  assert(SCIPcliqueIsCleanedUp(clique));
2743 
2744  return SCIP_OKAY;
2745 }
2746 
2747 #ifdef SCIP_MORE_DEBUG
2748 /** checks whether clique appears in all clique lists of the involved variables */
2749 static
2751  SCIP_CLIQUETABLE* cliquetable /**< clique table data structure */
2752  )
2753 {
2754  SCIP_Longint nentries = 0;
2755  int c;
2756 
2757  assert(cliquetable != NULL);
2758 
2759  for( c = cliquetable->ncliques - 1; c >= 0; --c )
2760  nentries += cliquetable->cliques[c]->nvars;
2761 
2762  return (nentries == cliquetable->nentries);
2763 }
2764 #else
2765 #define checkNEntries(cliquetable) TRUE
2766 #endif
2767 
2768 /** removes all empty and single variable cliques from the clique table; removes double entries from the clique table
2769  *
2770  * @note cliques can be processed several times by this method
2771  *
2772  * @todo try to detect infeasible implications, e.g., x = 1 => (y = 0 && y = 1)
2773  */
2775  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
2776  BMS_BLKMEM* blkmem, /**< block memory */
2777  SCIP_SET* set, /**< global SCIP settings */
2778  SCIP_STAT* stat, /**< problem statistics */
2779  SCIP_PROB* transprob, /**< transformed problem */
2780  SCIP_PROB* origprob, /**< original problem */
2781  SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
2782  SCIP_REOPT* reopt, /**< reoptimization data structure */
2783  SCIP_LP* lp, /**< current LP data */
2784  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
2785  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2786  int* nchgbds, /**< pointer to store number of fixed variables */
2787  SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
2788  )
2789 {
2790  assert(cliquetable != NULL);
2791  assert(stat != NULL);
2792  assert(infeasible != NULL);
2793 
2794  *infeasible = FALSE;
2795 
2796  /* check if we have anything to do */
2797  if( stat->npresolfixedvars == cliquetable->ncleanupfixedvars
2798  && stat->npresolaggrvars == cliquetable->ncleanupaggrvars
2799  && cliquetable->ndirtycliques == 0 )
2800  return SCIP_OKAY;
2801 
2802  SCIPdebugMessage("cleaning up clique table with %d cliques (with %" SCIP_LONGINT_FORMAT " entries)\n", cliquetable->ncliques, cliquetable->nentries);
2803 
2804  /* delay events */
2805  SCIP_CALL( SCIPeventqueueDelay(eventqueue) );
2806 
2807  cliquetable->incleanup = TRUE;
2808  while( cliquetable->ndirtycliques > 0 && !(*infeasible) )
2809  {
2810  SCIP_CLIQUE* clique;
2811  SCIP_CLIQUE* sameclique;
2812 
2813  clique = cliquetable->cliques[0];
2814 
2815  assert(!SCIPcliqueIsCleanedUp(clique));
2816 
2817  /* remove not clean up clique from hastable */
2818  SCIP_CALL( SCIPhashtableRemove(cliquetable->hashtable, (void*)clique) );
2819  cliquetable->nentries -= clique->nvars;
2820  assert(cliquetable->nentries >= 0);
2821 
2822  SCIP_CALL( cliqueCleanup(clique, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
2823  cliquetable, nchgbds, infeasible) );
2824 
2825  if( *infeasible )
2826  break;
2827 
2828  assert(SCIPcliqueIsCleanedUp(clique));
2829 
2830  /* swap freshly cleaned clique with last dirty clique */
2831  cliquetable->ndirtycliques--;
2832  cliquetableSwapCliques(cliquetable, 0, cliquetable->ndirtycliques);
2833  cliqueCheck(clique);
2834 
2835  /* @todo check if we can aggregate variables if( clique->equation && clique->nvars == 2 && SCIPsetGetStage(set) == SCIP_STAGE_PRESOLVING */
2836 #if 0
2837  if( clique->nvars == 2 && clique->equation && SCIPsetGetStage(set) == SCIP_STAGE_PRESOLVING )
2838  {
2839  SCIP_VAR* var0;
2840  SCIP_VAR* var1;
2841  SCIP_Real scalarx;
2842  SCIP_Real scalary;
2843  SCIP_Real rhs = 1.0;
2844  SCIP_Bool aggregated;
2845 
2846  printf("aggr vars, clique %d\n", clique->id);
2847 
2848  if( SCIPvarGetType(clique->vars[0]) >= SCIPvarGetType(clique->vars[1]) )
2849  {
2850  var0 = clique->vars[0];
2851  var1 = clique->vars[1];
2852 
2853  if( !clique->values[0] )
2854  {
2855  scalarx = -1.0;
2856  rhs -= 1.0;
2857  }
2858  else
2859  scalarx = 1.0;
2860 
2861  if( !clique->values[1] )
2862  {
2863  scalary = -1.0;
2864  rhs -= 1.0;
2865  }
2866  else
2867  scalary = 1.0;
2868  }
2869  else
2870  {
2871  var0 = clique->vars[1];
2872  var1 = clique->vars[0];
2873 
2874  if( !clique->values[0] )
2875  {
2876  scalary = -1.0;
2877  rhs -= 1.0;
2878  }
2879  else
2880  scalary = 1.0;
2881 
2882  if( !clique->values[1] )
2883  {
2884  scalarx = -1.0;
2885  rhs -= 1.0;
2886  }
2887  else
2888  scalarx = 1.0;
2889  }
2890 
2893 
2894  /* aggregate the variable */
2895  SCIP_CALL( SCIPvarTryAggregateVars(set, blkmem, stat, transprob, origprob, primal,
2896  tree, lp, cliquetable, branchcand, eventfilter, eventqueue,
2897  var0, var1, scalarx, scalary, rhs, infeasible, &aggregated) );
2898 
2899  assert(aggregated || *infeasible);
2900  }
2901 #endif
2902 
2903  sameclique = SCIPhashtableRetrieve(cliquetable->hashtable, (void*)clique);
2904 
2905  /* check if the clique is already contained in the clique table, or if it is redundant (too small) */
2906  if( clique->nvars <= 1 || sameclique != NULL )
2907  {
2908  int j;
2909 
2910  /* infeasible or fixing should be performed already on trivial clique */
2911  assert(clique->nvars > 1 || !clique->equation);
2912 
2913  /* if the clique which is already in the hashtable is an inequality and the current clique is an equation, we
2914  * update the equation status of the old one
2915  */
2916  if( clique->nvars > 1 && clique->equation && !sameclique->equation )
2917  {
2918  assert(sameclique->nvars >= 2);
2919 
2920  /* @note if we might change the order of the clique, e.g. put the equations up front, we should rather remove
2921  * the sameclique from the hashmap while adding the new clique
2922  */
2923  sameclique->equation = TRUE;
2924  }
2925 
2926  /* delete the clique from the variables' clique lists */
2927  for( j = 0; j < clique->nvars; ++j )
2928  {
2929  SCIP_CALL( SCIPvarDelCliqueFromList(clique->vars[j], blkmem, clique->values[j], clique) );
2930  }
2931 
2932  /* free clique and remove it from clique table */
2933  cliqueFree(&clique, blkmem);
2934  cliquetable->ncliques--;
2935  /* insert a clean clique from the end of the array */
2936  if( cliquetable->ndirtycliques < cliquetable->ncliques )
2937  {
2938  assert(SCIPcliqueIsCleanedUp(cliquetable->cliques[cliquetable->ncliques]));
2939  cliquetable->cliques[cliquetable->ndirtycliques] = cliquetable->cliques[cliquetable->ncliques];
2940  cliquetable->cliques[cliquetable->ndirtycliques]->index = cliquetable->ndirtycliques;
2941  }
2942  }
2943  else
2944  {
2945  cliquetable->nentries += clique->nvars;
2946 
2947  SCIP_CALL( SCIPhashtableInsert(cliquetable->hashtable, (void*)clique) );
2948  if( !clique->eventsissued )
2949  {
2950  int j;
2951 
2952  /* issue IMPLADDED event on each variable in the clique */
2953  for( j = 0; j < clique->nvars; ++j )
2954  {
2955  SCIP_EVENT* event;
2956 
2957  SCIP_CALL( SCIPeventCreateImplAdded(&event, blkmem, clique->vars[j]) );
2958  SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) );
2959  }
2960  clique->eventsissued = TRUE;
2961  }
2962  }
2963  }
2964  cliquetable->incleanup = FALSE;
2965 
2966  /* remember the number of fixed variables and cliques in order to avoid unnecessary cleanups */
2967  cliquetable->ncleanupfixedvars = stat->npresolfixedvars;
2968  cliquetable->ncleanupaggrvars = stat->npresolaggrvars;
2969  assert(*infeasible || cliquetable->ndirtycliques == 0);
2970 
2971  assert(*infeasible || checkNEntries(cliquetable));
2972 
2973  SCIPdebugMessage("cleaned up clique table has %d cliques left (with %" SCIP_LONGINT_FORMAT " entries)\n", cliquetable->ncliques, cliquetable->nentries);
2974 
2975  /* process events */
2976  SCIP_CALL( SCIPeventqueueProcess(eventqueue, blkmem, set, NULL, lp, branchcand, NULL) );
2977 
2978  return SCIP_OKAY;
2979 }
2980 
2981 
2982 /*
2983  * simple functions implemented as defines
2984  */
2985 
2986 /* In debug mode, the following methods are implemented as function calls to ensure
2987  * type validity.
2988  * In optimized mode, the methods are implemented as defines to improve performance.
2989  * However, we want to have them in the library anyways, so we have to undef the defines.
2990  */
2991 
2992 #undef SCIPvboundsGetNVbds
2993 #undef SCIPvboundsGetVars
2994 #undef SCIPvboundsGetCoefs
2995 #undef SCIPvboundsGetConstants
2996 #undef SCIPimplicsGetNImpls
2997 #undef SCIPimplicsGetVars
2998 #undef SCIPimplicsGetTypes
2999 #undef SCIPimplicsGetBounds
3000 #undef SCIPimplicsGetIds
3001 #undef SCIPcliqueGetNVars
3002 #undef SCIPcliqueGetVars
3003 #undef SCIPcliqueGetValues
3004 #undef SCIPcliqueGetId
3005 #undef SCIPcliqueIsCleanedUp
3006 #undef SCIPcliqueIsEquation
3007 #undef SCIPcliquelistGetNCliques
3008 #undef SCIPcliquelistGetCliques
3009 #undef SCIPcliquelistCheck
3010 #undef SCIPcliquetableGetNCliques
3011 #undef SCIPcliquetableGetCliques
3012 #undef SCIPcliquetableGetNEntries
3013 
3014 /** gets number of variable bounds contained in given variable bounds data structure */
3016  SCIP_VBOUNDS* vbounds /**< variable bounds data structure */
3017  )
3018 {
3019  return vbounds != NULL ? vbounds->len : 0;
3020 }
3021 
3022 /** gets array of variables contained in given variable bounds data structure */
3024  SCIP_VBOUNDS* vbounds /**< variable bounds data structure */
3025  )
3026 {
3027  return vbounds != NULL ? vbounds->vars : NULL;
3028 }
3029 
3030 /** gets array of coefficients contained in given variable bounds data structure */
3032  SCIP_VBOUNDS* vbounds /**< variable bounds data structure */
3033  )
3034 {
3035  return vbounds != NULL ? vbounds->coefs : NULL;
3036 }
3037 
3038 /** gets array of constants contained in given variable bounds data structure */
3040  SCIP_VBOUNDS* vbounds /**< variable bounds data structure */
3041  )
3042 {
3043  return vbounds != NULL ? vbounds->constants : NULL;
3044 }
3045 
3046 /** gets number of implications for a given binary variable fixing */
3048  SCIP_IMPLICS* implics, /**< implication data */
3049  SCIP_Bool varfixing /**< should the implications on var == FALSE or var == TRUE be returned? */
3050  )
3051 {
3052  return implics != NULL ? implics->nimpls[varfixing] : 0;
3053 }
3054 
3055 /** gets array with implied variables for a given binary variable fixing */
3057  SCIP_IMPLICS* implics, /**< implication data */
3058  SCIP_Bool varfixing /**< should the implications on var == FALSE or var == TRUE be returned? */
3059  )
3060 {
3061  return implics != NULL ? implics->vars[varfixing] : NULL;
3062 }
3063 
3064 /** gets array with implication types for a given binary variable fixing */
3066  SCIP_IMPLICS* implics, /**< implication data */
3067  SCIP_Bool varfixing /**< should the implications on var == FALSE or var == TRUE be returned? */
3068  )
3069 {
3070  return implics != NULL ? implics->types[varfixing] : NULL;
3071 }
3072 
3073 /** gets array with implication bounds for a given binary variable fixing */
3075  SCIP_IMPLICS* implics, /**< implication data */
3076  SCIP_Bool varfixing /**< should the implications on var == FALSE or var == TRUE be returned? */
3077  )
3078 {
3079  return implics != NULL ? implics->bounds[varfixing] : NULL;
3080 }
3081 
3082 /** Gets array with unique implication identifiers for a given binary variable fixing.
3083  * If an implication is a shortcut, i.e., it was added as part of the transitive closure of another implication,
3084  * its id is negative, otherwise it is nonnegative.
3085  */
3087  SCIP_IMPLICS* implics, /**< implication data */
3088  SCIP_Bool varfixing /**< should the implications on var == FALSE or var == TRUE be returned? */
3089  )
3090 {
3091  return implics != NULL ? implics->ids[varfixing] : NULL;
3092 }
3093 
3094 /** gets number of variables in the cliques */
3096  SCIP_CLIQUE* clique /**< clique data structure */
3097  )
3098 {
3099  assert(clique != NULL);
3100 
3101  return clique->nvars;
3102 }
3103 
3104 /** gets array of active problem variables in the cliques */
3106  SCIP_CLIQUE* clique /**< clique data structure */
3107  )
3108 {
3109  assert(clique != NULL);
3110 
3111  return clique->vars;
3112 }
3113 
3114 /** gets array of values of active problem variables in the cliques, i.e. whether the variable is fixed to FALSE or
3115  * to TRUE in the clique
3116  */
3118  SCIP_CLIQUE* clique /**< clique data structure */
3119  )
3120 {
3121  assert(clique != NULL);
3122 
3123  return clique->values;
3124 }
3125 
3126 /** gets unique identifier of the clique */
3128  SCIP_CLIQUE* clique /**< clique data structure */
3129  )
3130 {
3131  assert(clique != NULL);
3132 
3133  return (int) clique->id;
3134 }
3135 
3136 /** gets unique identifier of the clique */
3138  SCIP_CLIQUE* clique /**< clique data structure */
3139  )
3140 {
3141  assert(clique != NULL);
3142 
3143  return (clique->startcleanup == -1);
3144 }
3145 
3146 /** return whether the given clique is an equation */
3148  SCIP_CLIQUE* clique /**< clique data structure */
3149  )
3150 {
3151  assert(clique != NULL);
3152 
3153  return (SCIP_Bool)(clique->equation); /*lint !e571*/
3154 }
3155 
3156 /** returns the number of cliques stored in the clique list */
3158  SCIP_CLIQUELIST* cliquelist, /**< clique list data structure */
3159  SCIP_Bool value /**< value of the variable for which the cliques should be returned */
3160  )
3161 {
3162  return cliquelist != NULL ? cliquelist->ncliques[value] : 0;
3163 }
3164 
3165 /** returns the cliques stored in the clique list, or NULL if the clique list is empty */
3167  SCIP_CLIQUELIST* cliquelist, /**< clique list data structure */
3168  SCIP_Bool value /**< value of the variable for which the cliques should be returned */
3169  )
3170 {
3171  return cliquelist != NULL ? cliquelist->cliques[value] : NULL;
3172 }
3173 
3174 /** checks whether variable is contained in all cliques of the cliquelist */
3176  SCIP_CLIQUELIST* cliquelist, /**< clique list data structure */
3177  SCIP_VAR* var /**< variable, the clique list belongs to */
3178  )
3179 {
3180  /* @todo might need to change ifndef NDEBUG to ifdef SCIP_MORE_DEBUG because it can take at lot of time to check for
3181  * correctness
3182  */
3183 #ifndef NDEBUG
3184  int value;
3185 
3186  assert(SCIPvarGetNCliques(var, FALSE) == SCIPcliquelistGetNCliques(cliquelist, FALSE));
3187  assert(SCIPvarGetCliques(var, FALSE) == SCIPcliquelistGetCliques(cliquelist, FALSE));
3188  assert(SCIPvarGetNCliques(var, TRUE) == SCIPcliquelistGetNCliques(cliquelist, TRUE));
3189  assert(SCIPvarGetCliques(var, TRUE) == SCIPcliquelistGetCliques(cliquelist, TRUE));
3190 
3191  for( value = 0; value < 2; ++value )
3192  {
3193  SCIP_CLIQUE** cliques;
3194  int ncliques;
3195  int i;
3196 
3197  ncliques = SCIPcliquelistGetNCliques(cliquelist, (SCIP_Bool)value);
3198  cliques = SCIPcliquelistGetCliques(cliquelist, (SCIP_Bool)value);
3199  for( i = 0; i < ncliques; ++i )
3200  {
3201  SCIP_CLIQUE* clique;
3202  int pos;
3203 
3204  clique = cliques[i];
3205  assert(clique != NULL);
3206 
3207  pos = SCIPcliqueSearchVar(clique, var, (SCIP_Bool)value);
3208  assert(0 <= pos && pos < clique->nvars);
3209  assert(clique->vars[pos] == var);
3210  assert(clique->values[pos] == (SCIP_Bool)value);
3211  }
3212  }
3213 #endif
3214 }
3215 
3216 /** gets the number of cliques stored in the clique table */
3218  SCIP_CLIQUETABLE* cliquetable /**< clique table data structure */
3219  )
3220 {
3221  assert(cliquetable != NULL);
3222 
3223  return cliquetable->ncliques;
3224 }
3225 
3226 /** gets the array of cliques stored in the clique table */
3228  SCIP_CLIQUETABLE* cliquetable /**< clique table data structure */
3229  )
3230 {
3231  assert(cliquetable != NULL);
3232 
3233  return cliquetable->cliques;
3234 }
3235 
3236 /** gets the number of entries in the whole clique table */
3238  SCIP_CLIQUETABLE* cliquetable /**< clique table data structure */
3239  )
3240 {
3241  assert(cliquetable != NULL);
3242 
3243  return cliquetable->nentries;
3244 }
SCIP_CLIQUE ** cliques
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
SCIP_VAR * SCIPvarGetNegationVar(SCIP_VAR *var)
Definition: var.c:16781
void SCIPcliquelistRemoveFromCliques(SCIP_CLIQUELIST *cliquelist, SCIP_CLIQUETABLE *cliquetable, SCIP_VAR *var, SCIP_Bool irrelevantvar)
Definition: implics.c:1667
#define HASHTABLE_CLIQUETABLE_SIZE
Definition: implics.c:1773
#define BMSfreeBlockMemoryArrayNull(mem, ptr, num)
Definition: memory.h:422
internal methods for managing events
SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
Definition: implics.c:3105
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16341
static SCIP_Bool implicsSearchImplic(SCIP_IMPLICS *implics, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_BOUNDTYPE impltype, int *poslower, int *posupper, int *posadd)
Definition: implics.c:593
#define BMSfreeMemoryArrayNull(ptr)
Definition: memory.h:103
static void cliqueCheck(SCIP_CLIQUE *clique)
Definition: implics.c:1358
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:1562
void SCIPimplicsGetVarImplics(SCIP_IMPLICS *implics, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_Bool *haslowerimplic, SCIP_Bool *hasupperimplic)
Definition: implics.c:895
SCIP_RETCODE SCIPeventqueueProcess(SCIP_EVENTQUEUE *eventqueue, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_PRIMAL *primal, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTFILTER *eventfilter)
Definition: event.c:2307
SCIP_HASHTABLE * hashtable
SCIP_Longint SCIPcliquetableGetNEntries(SCIP_CLIQUETABLE *cliquetable)
Definition: implics.c:3237
SCIP_RETCODE SCIPcliqueAddVar(SCIP_CLIQUE *clique, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_VAR *var, SCIP_Bool value, SCIP_Bool *doubleentry, SCIP_Bool *oppositeentry)
Definition: implics.c:1135
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:16521
methods for implications, variable bounds, and cliques
SCIP_RETCODE SCIPeventqueueAdd(SCIP_EVENTQUEUE *eventqueue, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_PRIMAL *primal, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTFILTER *eventfilter, SCIP_EVENT **event)
Definition: event.c:2057
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17318
SCIP_Real * constants
#define SCIP_HASHSIZE_CLIQUES_SMALL
Definition: def.h:213
SCIP_RETCODE SCIPeventCreateImplAdded(SCIP_EVENT **event, BMS_BLKMEM *blkmem, SCIP_VAR *var)
Definition: event.c:724
SCIP_VAR ** SCIPimplicsGetVars(SCIP_IMPLICS *implics, SCIP_Bool varfixing)
Definition: implics.c:3056
int npresolaggrvars
Definition: struct_stat.h:194
#define NULL
Definition: lpi_spx.cpp:130
static SCIP_RETCODE cliquetableEnsureSize(SCIP_CLIQUETABLE *cliquetable, SCIP_SET *set, int num)
Definition: implics.c:1837
int npresolfixedvars
Definition: struct_stat.h:193
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:16965
int SCIPcliquelistGetNCliques(SCIP_CLIQUELIST *cliquelist, SCIP_Bool value)
Definition: implics.c:3157
SCIP_VAR ** SCIPvboundsGetVars(SCIP_VBOUNDS *vbounds)
Definition: implics.c:3023
#define SCIPdebugCheckClique(set, vars, values, nvars)
Definition: debug.h:241
SCIP_Bool SCIPcliqueHasVar(SCIP_CLIQUE *clique, SCIP_VAR *var, SCIP_Bool value)
Definition: implics.c:1125
static SCIP_RETCODE cliqueCleanup(SCIP_CLIQUE *clique, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_CLIQUETABLE *cliquetable, int *nchgbds, SCIP_Bool *infeasible)
Definition: implics.c:2507
#define FALSE
Definition: def.h:53
static SCIP_RETCODE implicsEnsureSize(SCIP_IMPLICS **implics, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_Bool varfixing, int num)
Definition: implics.c:467
static SCIP_DECL_HASHKEYVAL(hashkeyvalClique)
Definition: implics.c:1756
SCIP_Bool SCIPsetIsZero(SCIP_SET *set, SCIP_Real val)
Definition: set.c:5143
SCIP_RETCODE SCIPeventqueueDelay(SCIP_EVENTQUEUE *eventqueue)
Definition: event.c:2292
SCIP_RETCODE SCIPvboundsDel(SCIP_VBOUNDS **vbounds, BMS_BLKMEM *blkmem, SCIP_VAR *vbdvar, SCIP_Bool negativecoef)
Definition: implics.c:281
#define TRUE
Definition: def.h:52
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
SCIP_Bool SCIPcliqueIsEquation(SCIP_CLIQUE *clique)
Definition: implics.c:3147
SCIP_RETCODE SCIPcliquetableCreate(SCIP_CLIQUETABLE **cliquetable, SCIP_SET *set, BMS_BLKMEM *blkmem)
Definition: implics.c:1776
#define checkNEntries(cliquetable)
Definition: implics.c:2765
static SCIP_RETCODE cliquelistCreate(SCIP_CLIQUELIST **cliquelist, BMS_BLKMEM *blkmem)
Definition: implics.c:1406
SCIP_RETCODE SCIPcliquetableCleanup(SCIP_CLIQUETABLE *cliquetable, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, int *nchgbds, SCIP_Bool *infeasible)
Definition: implics.c:2774
int SCIPsetCalcMemGrowSize(SCIP_SET *set, int num)
Definition: set.c:4626
unsigned int eventsissued
SCIP_RETCODE SCIPimplicsDel(SCIP_IMPLICS **implics, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_BOUNDTYPE impltype)
Definition: implics.c:837
SCIP_RETCODE SCIPcliquetableFree(SCIP_CLIQUETABLE **cliquetable, BMS_BLKMEM *blkmem)
Definition: implics.c:1808
#define SCIPdebugMessage
Definition: pub_message.h:77
SCIP_CLIQUE ** SCIPcliquelistGetCliques(SCIP_CLIQUELIST *cliquelist, SCIP_Bool value)
Definition: implics.c:3166
SCIP_VAR ** vars[2]
SCIP_RETCODE SCIPcliquelistAdd(SCIP_CLIQUELIST **cliquelist, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_Bool value, SCIP_CLIQUE *clique)
Definition: implics.c:1466
#define BMSfreeMemory(ptr)
Definition: memory.h:100
SCIP_Real * coefs
static void implicsSearchVar(SCIP_IMPLICS *implics, SCIP_Bool varfixing, SCIP_VAR *implvar, int *poslower, int *posupper, int *posadd)
Definition: implics.c:509
static void cliquetableSwapCliques(SCIP_CLIQUETABLE *cliquetable, int first, int second)
Definition: implics.c:940
SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
Definition: misc.c:1475
static void cliquetableMarkCliqueForCleanup(SCIP_CLIQUETABLE *cliquetable, SCIP_CLIQUE *clique)
Definition: implics.c:966
SCIP_RETCODE SCIPvboundsAdd(SCIP_VBOUNDS **vbounds, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_BOUNDTYPE vboundtype, SCIP_VAR *var, SCIP_Real coef, SCIP_Real constant, SCIP_Bool *added)
Definition: implics.c:199
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16460
static SCIP_RETCODE cliqueCreateWithData(SCIP_CLIQUE **clique, BMS_BLKMEM *blkmem, int size, SCIP_VAR **vars, SCIP_Bool *values, int nvars, int id, SCIP_Bool isequation)
Definition: implics.c:988
int * ids[2]
#define SCIP_HASHSIZE_CLIQUES
Definition: def.h:210
void SCIPcliquelistFree(SCIP_CLIQUELIST **cliquelist, BMS_BLKMEM *blkmem)
Definition: implics.c:1425
int SCIPcliqueSearchVar(SCIP_CLIQUE *clique, SCIP_VAR *var, SCIP_Bool value)
Definition: implics.c:1065
int SCIPcliquetableGetNCliques(SCIP_CLIQUETABLE *cliquetable)
Definition: implics.c:3217
SCIP_RETCODE SCIPvarsGetProbvarBinary(SCIP_VAR ***vars, SCIP_Bool **negatedarr, int nvars)
Definition: var.c:11541
#define BMSduplicateBlockMemoryArray(mem, ptr, source, num)
Definition: memory.h:416
SCIP_BOUNDTYPE * SCIPimplicsGetTypes(SCIP_IMPLICS *implics, SCIP_Bool varfixing)
Definition: implics.c:3065
void SCIPcliqueDelVar(SCIP_CLIQUE *clique, SCIP_CLIQUETABLE *cliquetable, SCIP_VAR *var, SCIP_Bool value)
Definition: implics.c:1269
SCIP_Bool SCIPimplicsContainsImpl(SCIP_IMPLICS *implics, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_BOUNDTYPE impltype)
Definition: implics.c:917
SCIP_RETCODE SCIPimplicsAdd(SCIP_IMPLICS **implics, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_BOUNDTYPE impltype, SCIP_Real implbound, SCIP_Bool isshortcut, SCIP_Bool *conflict, SCIP_Bool *added)
Definition: implics.c:630
void SCIPsortPtrBool(void **ptrarray, SCIP_Bool *boolarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
static SCIP_DECL_HASHGETKEY(hashgetkeyClique)
Definition: implics.c:1723
int SCIPcalcHashtableSize(int minsize)
Definition: misc.c:1152
#define BMSmoveMemoryArray(ptr, source, num)
Definition: memory.h:93
SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
static int cliquesSearchClique(SCIP_CLIQUE **cliques, int ncliques, SCIP_CLIQUE *clique)
Definition: implics.c:1317
SCIP_Real * SCIPvboundsGetCoefs(SCIP_VBOUNDS *vbounds)
Definition: implics.c:3031
SCIP_RETCODE SCIPvarGetProbvarBinary(SCIP_VAR **var, SCIP_Bool *negated)
Definition: var.c:11573
SCIP_Bool incleanup
internal methods for global SCIP settings
#define SCIP_CALL(x)
Definition: def.h:263
static void checkImplics(SCIP_IMPLICS *implics)
Definition: implics.c:376
SCIP_Bool SCIPsetIsFeasGE(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:5517
SCIP_RETCODE SCIPhashtableRemove(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:1714
SCIP_VAR ** vars
SCIP_Real * SCIPvboundsGetConstants(SCIP_VBOUNDS *vbounds)
Definition: implics.c:3039
unsigned int equation
SCIP_Bool SCIPcliquelistsHaveCommonClique(SCIP_CLIQUELIST *cliquelist1, SCIP_Bool value1, SCIP_CLIQUELIST *cliquelist2, SCIP_Bool value2)
Definition: implics.c:1589
SCIP_Bool SCIPsetIsFeasLE(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:5473
void SCIPvboundsShrink(SCIP_VBOUNDS **vbounds, BMS_BLKMEM *blkmem, int newnvbds)
Definition: implics.c:326
#define BMSfreeBlockMemory(mem, ptr)
Definition: memory.h:419
SCIP_Bool * values
internal methods for problem variables
SCIP_Real * bounds[2]
SCIP_RETCODE SCIPvarTryAggregateVars(SCIP_SET *set, BMS_BLKMEM *blkmem, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_PRIMAL *primal, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_CLIQUETABLE *cliquetable, SCIP_BRANCHCAND *branchcand, SCIP_EVENTFILTER *eventfilter, SCIP_EVENTQUEUE *eventqueue, SCIP_VAR *varx, SCIP_VAR *vary, SCIP_Real scalarx, SCIP_Real scalary, SCIP_Real rhs, SCIP_Bool *infeasible, SCIP_Bool *aggregated)
Definition: var.c:4914
datastructures for implications, variable bounds, and cliques
public data structures and miscellaneous methods
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:16638
#define SCIP_Bool
Definition: def.h:50
#define BMSallocBlockMemoryArray(mem, ptr, num)
Definition: memory.h:408
#define BMSfreeBlockMemoryArray(mem, ptr, num)
Definition: memory.h:421
int * SCIPimplicsGetIds(SCIP_IMPLICS *implics, SCIP_Bool varfixing)
Definition: implics.c:3086
#define MAX(x, y)
Definition: tclique_def.h:75
int SCIPimplicsGetNImpls(SCIP_IMPLICS *implics, SCIP_Bool varfixing)
Definition: implics.c:3047
methods for debugging
SCIP_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
Definition: implics.c:3117
SCIP_RETCODE SCIPvarAddCliqueToList(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_Bool value, SCIP_CLIQUE *clique)
Definition: var.c:10660
static SCIP_DECL_HASHKEYEQ(hashkeyeqClique)
Definition: implics.c:1730
SCIP_BOUNDTYPE * types[2]
SCIP_VAR ** vars
SCIP_RETCODE SCIPvarFixBinary(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_CLIQUETABLE *cliquetable, SCIP_Bool value, SCIP_Bool *infeasible, int *nbdchgs)
Definition: var.c:10446
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:1622
SCIP_Bool SCIPsetIsFeasLT(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:5451
SCIP_RETCODE SCIPcliquetableAdd(SCIP_CLIQUETABLE *cliquetable, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_VAR **vars, SCIP_Bool *values, int nvars, SCIP_Bool isequation, SCIP_Bool *infeasible, int *nbdchgs)
Definition: implics.c:2237
static SCIP_RETCODE vboundsCreate(SCIP_VBOUNDS **vbounds, BMS_BLKMEM *blkmem)
Definition: implics.c:48
int SCIPvboundsGetNVbds(SCIP_VBOUNDS *vbounds)
Definition: implics.c:3015
static void cliqueFree(SCIP_CLIQUE **clique, BMS_BLKMEM *blkmem)
Definition: implics.c:1022
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:1505
static SCIP_RETCODE cliqueEnsureSize(SCIP_CLIQUE *clique, BMS_BLKMEM *blkmem, SCIP_SET *set, int num)
Definition: implics.c:1039
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:16506
static SCIP_RETCODE vboundsSearchPos(SCIP_VBOUNDS *vbounds, SCIP_VAR *var, SCIP_Bool negativecoef, int *insertpos, SCIP_Bool *found)
Definition: implics.c:118
static SCIP_RETCODE sortAndMergeClique(SCIP_VAR **clqvars, SCIP_Bool *clqvalues, int *nclqvars, SCIP_Bool *isequation, SCIP_CLIQUE *clique, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_STAT *stat, SCIP_PROB *transprob, SCIP_PROB *origprob, SCIP_TREE *tree, SCIP_REOPT *reopt, SCIP_LP *lp, SCIP_BRANCHCAND *branchcand, SCIP_EVENTQUEUE *eventqueue, SCIP_CLIQUETABLE *cliquetable, int *nbdchgs, SCIP_Bool *infeasible)
Definition: implics.c:1860
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:16955
static SCIP_DECL_SORTPTRCOMP(compVars)
Definition: implics.c:352
static SCIP_RETCODE vboundsEnsureSize(SCIP_VBOUNDS **vbounds, BMS_BLKMEM *blkmem, SCIP_SET *set, int num)
Definition: implics.c:84
SCIP_Bool misc_usesmalltables
Definition: struct_set.h:311
unsigned int id
public methods for message output
void SCIPcliquelistCheck(SCIP_CLIQUELIST *cliquelist, SCIP_VAR *var)
Definition: implics.c:3175
SCIP_CLIQUE ** cliques[2]
#define SCIP_Real
Definition: def.h:124
internal methods for problem statistics
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17307
#define MIN(x, y)
Definition: memory.c:63
#define BMSallocMemory(ptr)
Definition: memory.h:74
#define BMSreallocMemoryArray(ptr, num)
Definition: memory.h:82
#define SCIP_Longint
Definition: def.h:109
SCIP_Bool SCIPsetIsFeasGT(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:5495
static SCIP_RETCODE cliquelistEnsureSize(SCIP_CLIQUELIST *cliquelist, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_Bool value, int num)
Definition: implics.c:1442
SCIP_STAGE SCIPsetGetStage(SCIP_SET *set)
Definition: set.c:2283
SCIP_Bool SCIPvarIsMarkedDeleteGlobalStructures(SCIP_VAR *var)
Definition: var.c:16608
SCIP_Bool SCIPcliqueIsCleanedUp(SCIP_CLIQUE *clique)
Definition: implics.c:3137
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:16628
int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
Definition: implics.c:3095
#define BMSallocBlockMemory(mem, ptr)
Definition: memory.h:406
common defines and data types used in all packages of SCIP
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:392
SCIP_Real * SCIPimplicsGetBounds(SCIP_IMPLICS *implics, SCIP_Bool varfixing)
Definition: implics.c:3074
#define SCIP_ALLOC(x)
Definition: def.h:274
static SCIP_RETCODE implicsCreate(SCIP_IMPLICS **implics, BMS_BLKMEM *blkmem)
Definition: implics.c:418
void SCIPvboundsFree(SCIP_VBOUNDS **vbounds, BMS_BLKMEM *blkmem)
Definition: implics.c:66
SCIP_RETCODE SCIPvarsAddClique(SCIP_VAR **vars, SCIP_Bool *values, int nvars, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_CLIQUE *clique)
Definition: var.c:10622
#define BMSreallocBlockMemoryArray(mem, ptr, oldnum, newnum)
Definition: memory.h:412
SCIP_CLIQUE ** SCIPcliquetableGetCliques(SCIP_CLIQUETABLE *cliquetable)
Definition: implics.c:3227
void SCIPimplicsFree(SCIP_IMPLICS **implics, BMS_BLKMEM *blkmem)
Definition: implics.c:444
SCIP_RETCODE SCIPcliquelistDel(SCIP_CLIQUELIST **cliquelist, BMS_BLKMEM *blkmem, SCIP_Bool value, SCIP_CLIQUE *clique)
Definition: implics.c:1511
SCIP_Longint nentries
int nimplications
Definition: struct_stat.h:188
int SCIPcliqueGetId(SCIP_CLIQUE *clique)
Definition: implics.c:3127
SCIP_RETCODE SCIPvarDelCliqueFromList(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_Bool value, SCIP_CLIQUE *clique)
Definition: var.c:10682