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-2016 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  startidx = *nclqvars - 1;
1912  while( startidx >= 0 )
1913  {
1914  int nones;
1915  int nzeros;
1916  int curr;
1917 
1918  var = clqvars[startidx];
1919  /* only column and loose variables can exist now */
1921  assert(SCIPvarIsBinary(var));
1922 
1923  /* the counters denote the occurrences of the variable var with value TRUE and FALSE as clqvalues, respectively */
1924  if( clqvalues[startidx] )
1925  {
1926  nones = 1;
1927  nzeros = 0;
1928  }
1929  else
1930  {
1931  nzeros = 1;
1932  nones = 0;
1933  }
1934  curr = startidx - 1;
1935 
1936  /* loop and increase the counter based on the clique value */
1937  while( curr >= 0 )
1938  {
1939  if( clqvars[curr] == var )
1940  {
1941  if( clqvalues[curr] )
1942  nones++;
1943  else
1944  nzeros++;
1945  }
1946  else
1947  /* var is different from variable at index curr */
1948  break;
1949 
1950  --curr;
1951  }
1952  assert(nzeros + nones <= *nclqvars);
1953 
1954  /* single occurrence of the variable */
1955  if( nones + nzeros == 1 )
1956  {
1957  startidx = curr;
1958  continue;
1959  }
1960  /* at least two occurrences of both the variable and its negation; infeasible */
1961  if( nones >= 2 && nzeros >= 2 )
1962  {
1963  *infeasible = TRUE;
1964  break;
1965  }
1966 
1967  /* do we have the same variable with the same clique value twice? */
1968  if( nones >= 2 || nzeros >= 2 )
1969  {
1970  SCIP_Bool fixvalue;
1971 
1972  /* other cases should be handled as infeasible */
1973  assert(nones <= 1 || nzeros <= 1);
1974 
1975  /* ensure that the variable is removed from both clique lists before fixing it */
1976  if( clique != NULL )
1977  {
1978  if( nones >= 1 )
1979  {
1980  SCIP_CALL( SCIPvarDelCliqueFromList(var, blkmem, TRUE, clique) );
1981  }
1982  if( nzeros >= 1 )
1983  {
1984  SCIP_CALL( SCIPvarDelCliqueFromList(var, blkmem, FALSE, clique) );
1985  }
1986  }
1987 
1988  /* we fix the variable into the direction of fewer occurrences */
1989  fixvalue = nones >= 2 ? FALSE : TRUE;
1990 
1991  /* a variable multiple times in one clique forces this variable to be zero */
1992  SCIP_CALL( SCIPvarFixBinary(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
1993  cliquetable, fixvalue, infeasible, nbdchgs) );
1994 
1995  SCIPdebugMessage("same var %s twice in a clique with value %d fixed to %d (was %s)\n", SCIPvarGetName(var), fixvalue ? 0 : 1,
1996  fixvalue ? 1 : 0, *infeasible ? "infeasible" : "feasible");
1997 
1998  if( *infeasible )
1999  break;
2000  }
2001 
2002  /* do we have a pair of negated variables? */
2003  if( nones >= 1 && nzeros >= 1 )
2004  {
2005  SCIPdebugMessage("var %s is paired with its negation in one clique -> fix all other variables\n", SCIPvarGetName(var));
2006 
2007  /* a pair of negated variables in one clique forces all other variables in the clique to be zero */
2008  if( nzeros + nones < *nclqvars )
2009  {
2010  int w;
2011 
2012  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  /* break main loop */
2067  break;
2068  }
2069 
2070  /* otherwise, we would have an endless loop */
2071  assert(curr < startidx);
2072  startidx = curr;
2073  }
2074 
2075 
2076  /* we might have found an infeasibility or reduced the clique to size 0 */
2077  if( *infeasible || *nclqvars == 0 )
2078  return SCIP_OKAY;
2079 
2080  /* we fixed a variable because it appears at least twice, now we need to remove the fixings
2081  *
2082  * @note that if we are in probing or solving stage, the fixation on the variable might not be carried out yet,
2083  * because it was contradicting a local bound
2084  */
2085  if( *nbdchgs > noldbdchgs )
2086  {
2087  SCIP_VAR* onefixedvar;
2088  SCIP_Bool onefixedvalue;
2089  int w;
2090 
2091  /* we initialize the former value only to please gcc */
2092  onefixedvalue = TRUE;
2093  onefixedvar = NULL;
2094 
2095  /* remove all inactive variables, thereby checking for a variable that is fixed to one */
2096  startidx = 0;
2097  w = 0;
2098  while( startidx < *nclqvars )
2099  {
2100  var = clqvars[startidx];
2101 
2104 
2105  /* check if we have a variable fixed to one for this clique */
2106  if( (clqvalues[startidx] && SCIPvarGetLbGlobal(var) > 0.5) || (!clqvalues[startidx] && SCIPvarGetUbGlobal(var) < 0.5) )
2107  {
2108  if( onefixedvar != NULL )
2109  {
2110  *infeasible = TRUE;
2111 
2112  SCIPdebugMessage("two variables in clique %d fixed to one %s%s and %s%s\n", (clique != NULL) ? (int) clique->id : -1,
2113  onefixedvalue ? "" : "~", SCIPvarGetName(onefixedvar), clqvalues[startidx] ? "" : "~",
2114  SCIPvarGetName(clqvars[startidx]));
2115  return SCIP_OKAY;
2116  }
2117  onefixedvar = var;
2118  onefixedvalue = clqvalues[startidx];
2119  }
2120  /* only keep active variables */
2121  else if( SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5 )
2122  {
2123  /* we remove all fixed variables */
2124  if( startidx > w )
2125  {
2126  clqvars[w] = clqvars[startidx];
2127  clqvalues[w] = clqvalues[startidx];
2128  }
2129  ++w;
2130  }
2131  else
2132  {
2133  /* can we have some variable fixed to one? */
2134  assert((SCIPvarGetUbGlobal(var) < 0.5 && clqvalues[startidx]) || (SCIPvarGetLbGlobal(var) > 0.5 && !clqvalues[startidx]));
2135 
2136  if( clique != NULL )
2137  {
2138  SCIP_CALL( SCIPvarDelCliqueFromList(var, blkmem, clqvalues[startidx], clique) );
2139  }
2140  }
2141  ++startidx;
2142  }
2143 
2144  /* the clique has been reduced to w active (unfixed) variables */
2145  *nclqvars = w;
2146 
2147  /* in rare cases, a variable fixed to one is only detected in the merging step */
2148  if( onefixedvar != NULL )
2149  {
2150  SCIPdebugMessage("variable %s%s in clique %d fixed to one, fixing all other variables to zero\n",
2151  onefixedvalue ? "" : "~", SCIPvarGetName(onefixedvar), (clique != NULL) ? (int) clique->id : -1);
2152 
2153  /* handle all active variables by fixing them */
2154  for( startidx = *nclqvars; startidx >= 0; --startidx )
2155  {
2156  assert(SCIPvarGetStatus(clqvars[startidx]) == SCIP_VARSTATUS_COLUMN
2157  || SCIPvarGetStatus(clqvars[startidx]) == SCIP_VARSTATUS_LOOSE);
2158 
2159  /* delete the variable from its clique lists and fix it */
2160  if( onefixedvalue != clqvalues[startidx] || clqvars[startidx] != onefixedvar )
2161  {
2162  if( clique != NULL )
2163  {
2164  SCIP_CALL( SCIPvarDelCliqueFromList(clqvars[startidx], blkmem, clqvalues[startidx], clique) );
2165  }
2166 
2167  /* if one of the other variables occurs multiple times, we can
2168  * 1) deduce infeasibility if it occurs with different values
2169  * 2) wait for the last occurence to fix it
2170  */
2171  while( startidx > 0 && clqvars[startidx - 1] == clqvars[startidx] )
2172  {
2173  if( clqvalues[startidx - 1] != clqvalues[startidx] )
2174  {
2175  *infeasible = TRUE;
2176  return SCIP_OKAY;
2177  }
2178  --startidx;
2179  }
2180 
2181  SCIPdebugMessage("fixing variable %s in clique %d to %d\n", SCIPvarGetName(clqvars[startidx]), (clique != NULL) ? (int) clique->id : -1,
2182  clqvalues[startidx] ? 0 : 1);
2183 
2184  /* note that the variable status will remain unchanged */
2185  SCIP_CALL( SCIPvarFixBinary(clqvars[startidx], blkmem, set, stat, transprob, origprob, tree, reopt, lp,
2186  branchcand, eventqueue, cliquetable, !clqvalues[startidx], infeasible, nbdchgs) );
2187 
2188  if( *infeasible )
2189  return SCIP_OKAY;
2190  }
2191  }
2192 
2193  /* delete clique from onefixedvars clique list */
2194  if( clique != NULL ) /*lint !e850*/
2195  {
2196  SCIP_CALL( SCIPvarDelCliqueFromList(onefixedvar, blkmem, onefixedvalue, clique) );
2197  }
2198 
2199  *nclqvars = 0;
2200  *isequation = FALSE;
2201  }
2202  }
2203 
2204  assert(!(*infeasible));
2205 
2206  if( *isequation )
2207  {
2208  if( *nclqvars == 0 )
2209  {
2210  SCIPdebugMessage("empty equation clique left over -> infeasible\n");
2211 
2212  *infeasible = TRUE;
2213  }
2214  else if( *nclqvars == 1 )
2215  {
2216  assert(SCIPvarGetStatus(clqvars[0]) == SCIP_VARSTATUS_COLUMN
2217  || SCIPvarGetStatus(clqvars[0]) == SCIP_VARSTATUS_LOOSE);
2218  /* clearing data and removing variable from its clique list */
2219  if( clique != NULL )
2220  {
2221  SCIP_CALL( SCIPvarDelCliqueFromList(clqvars[0], blkmem, clqvalues[0], clique) );
2222  }
2223  SCIP_CALL( SCIPvarFixBinary(clqvars[0], blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
2224  eventqueue, cliquetable, clqvalues[0], infeasible, nbdchgs) );
2225 
2226  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");
2227 
2228  *nclqvars = 0;
2229  *isequation = FALSE;
2230  }
2231  }
2232 
2233  return SCIP_OKAY;
2234 }
2235 
2236 
2237 /** adds a clique to the clique table, using the given values for the given variables;
2238  * performs implications if the clique contains the same variable twice
2239  */
2241  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
2242  BMS_BLKMEM* blkmem, /**< block memory */
2243  SCIP_SET* set, /**< global SCIP settings */
2244  SCIP_STAT* stat, /**< problem statistics */
2245  SCIP_PROB* transprob, /**< transformed problem */
2246  SCIP_PROB* origprob, /**< original problem */
2247  SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
2248  SCIP_REOPT* reopt, /**< reoptimization data structure */
2249  SCIP_LP* lp, /**< current LP data */
2250  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
2251  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2252  SCIP_VAR** vars, /**< binary variables in the clique: at most one can be set to the given value */
2253  SCIP_Bool* values, /**< values of the variables in the clique; NULL to use TRUE for all vars */
2254  int nvars, /**< number of variables in the clique */
2255  SCIP_Bool isequation, /**< is the clique an equation or an inequality? */
2256  SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
2257  int* nbdchgs /**< pointer to count the number of performed bound changes, or NULL */
2258  )
2259 {
2260  SCIP_VAR** clqvars;
2261  SCIP_Bool* clqvalues;
2262  SCIP_CLIQUE* clique;
2263  SCIP_VAR* var;
2264  int size;
2265  int nlocalbdchgs = 0;
2266  int v;
2267  int w;
2268 
2269  assert(cliquetable != NULL);
2270  assert(vars != NULL);
2271 
2272  SCIPdebugMessage("trying to add clique %d with %d vars to clique table\n", cliquetable->ncliques, nvars);
2273 
2274  /* check clique on debugging solution */
2275  SCIP_CALL( SCIPdebugCheckClique(set, vars, values, nvars) ); /*lint !e506 !e774*/
2276 
2277  *infeasible = FALSE;
2278  size = nvars;
2279 
2280  /* copy clique data */
2281  if( values == NULL )
2282  {
2283  SCIP_ALLOC( BMSallocBlockMemoryArray(blkmem, &clqvalues, size) );
2284 
2285  /* initialize clique values data */
2286  for( v = nvars - 1; v >= 0; --v )
2287  clqvalues[v] = TRUE;
2288  }
2289  else
2290  {
2291  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &clqvalues, values, size) );
2292  }
2293  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &clqvars, vars, size) );
2294 
2295  /* get active variables */
2296  SCIP_CALL( SCIPvarsGetProbvarBinary(&clqvars, &clqvalues, nvars) );
2297 
2298  /* remove all inactive vars */
2299  for( v = nvars - 1; v >= 0; --v )
2300  {
2301  var = clqvars[v];
2302 
2307  assert(SCIPvarIsBinary(var));
2308 
2309  /* if we have a variables already fixed to one in the clique, fix all other to zero */
2311  ((clqvalues[v] && SCIPvarGetLbGlobal(var) > 0.5) || (!clqvalues[v] && SCIPvarGetUbGlobal(var) < 0.5)) )
2312  {
2313  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);
2314 
2315  for( w = nvars - 1; w >= 0; --w )
2316  {
2317  SCIP_VAR* clqvar = clqvars[w];
2318 
2319  /* the rare case where the same variable appears several times is handled later during sort and merge */
2320  if( clqvar != var )
2321  {
2322  SCIP_Bool clqval = clqvalues[w];
2323 
2324  /* check if variable is fixed already and terminate with infeasible if this fixing contradicts the clique info */
2325  if( SCIPvarGetLbGlobal(clqvar) > SCIPvarGetUbGlobal(clqvar) - 0.5 )
2326  {
2327 
2328  /* check if fixing contradicts clique constraint */
2329  if( (clqval && SCIPvarGetLbGlobal(clqvar) > 0.5)
2330  || (! clqval && SCIPvarGetUbGlobal(clqvar) < 0.5) )
2331  {
2332  *infeasible = TRUE;
2333 
2334  return SCIP_OKAY;
2335  }
2336 
2337  continue;
2338  }
2339 
2340 /* the following piece of code is disabled because it assumes the clqvars to be sorted which they aren't until the method
2341  * sortAndMergeClique() is called
2342  */
2343 #ifdef SCIP_DISABLED_CODE
2344  /* if one of the other variables occurs multiple times, we can
2345  * 1) deduce infeasibility if it occurs with different values
2346  * 2) wait for the last occurence to fix it
2347  */
2348  while( w > 0 && clqvars[w - 1] == clqvars[w] )
2349  {
2350  if( clqvalues[w - 1] != clqvalues[w] )
2351  {
2352  *infeasible = TRUE;
2353  return SCIP_OKAY;
2354  }
2355  --w;
2356  }
2357 #endif
2358 
2359  /* fix the variable */
2360  SCIP_CALL( SCIPvarFixBinary(clqvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
2361  branchcand, eventqueue, cliquetable, !clqval, infeasible, &nlocalbdchgs) );
2362 
2363  SCIPdebugMessage("fixed var %s with value %u to %d (was %s)\n", SCIPvarGetName(clqvar), clqval, clqval ? 0 : 1, *infeasible ? "infeasible" : "feasible");
2364 
2365  if( *infeasible )
2366  break;
2367  }
2368  }
2369 
2370  /* all variables are fixed so we can stop */
2371  break; /*lint !e850*/
2372  }
2373 
2374  /* only unfixed column and loose variables may be member of a clique */
2375  if( SCIPvarGetUbGlobal(var) - SCIPvarGetLbGlobal(var) < 0.5 ||
2378  {
2379  --nvars;
2380  clqvars[v] = clqvars[nvars];
2381  clqvalues[v] = clqvalues[nvars];
2382  isequation = isequation && !(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR) && ! SCIPvarIsMarkedDeleteGlobalStructures(var);
2383  }
2384  }
2385 
2386  if( nbdchgs != NULL )
2387  *nbdchgs += nlocalbdchgs;
2388 
2389  /* did we fix all variables or are we infeasible? */
2390  if( v >= 0 )
2391  {
2392  BMSfreeBlockMemoryArray(blkmem, &clqvars, size);
2393  BMSfreeBlockMemoryArray(blkmem, &clqvalues, size);
2394 
2395  return SCIP_OKAY;
2396  }
2397  assert(!*infeasible);
2398 
2399  /* check if only one or less variables are left */
2400  if( v < 0 && nvars <= 1)
2401  {
2402  if( isequation )
2403  {
2404  if( nvars == 1 )
2405  {
2406  nlocalbdchgs = 0;
2407 
2408  SCIP_CALL( SCIPvarFixBinary(clqvars[0], blkmem, set, stat, transprob, origprob, tree, reopt, lp,
2409  branchcand, eventqueue, cliquetable, clqvalues[0], infeasible, &nlocalbdchgs) );
2410 
2411  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");
2412 
2413  if( nbdchgs != NULL )
2414  *nbdchgs += nlocalbdchgs;
2415  }
2416  else if( nvars == 0 )
2417  {
2418  SCIPdebugMessage("empty equation clique left over -> infeasible\n");
2419 
2420  *infeasible = TRUE;
2421  }
2422  }
2423 
2424  BMSfreeBlockMemoryArray(blkmem, &clqvars, size);
2425  BMSfreeBlockMemoryArray(blkmem, &clqvalues, size);
2426 
2427  return SCIP_OKAY;
2428  }
2429 
2430  nlocalbdchgs = 0;
2431 
2432  /* sort the variables and values and remove multiple entries of the same variable */
2433  SCIP_CALL( sortAndMergeClique(clqvars, clqvalues, &nvars, &isequation, NULL, blkmem, set, stat, transprob, origprob, tree,
2434  reopt, lp, branchcand, eventqueue, cliquetable, &nlocalbdchgs, infeasible) );
2435 
2436  if( nbdchgs != NULL )
2437  *nbdchgs += nlocalbdchgs;
2438 
2439  /* did we stop early due to a pair of negated variables? */
2440  if( nvars == 0 || *infeasible )
2441  {
2442  BMSfreeBlockMemoryArray(blkmem, &clqvars, size);
2443  BMSfreeBlockMemoryArray(blkmem, &clqvalues, size);
2444 
2445  return SCIP_OKAY;
2446  }
2447 
2448  /* if less than two variables are left over, the clique is redundant */
2449  if( nvars > 1 )
2450  {
2451  SCIP_CLIQUE* sameclique;
2452 
2453  /* @todo check if we can aggregate variables if( clique->equation && clique->nvars == 2 ) */
2454 
2455  /* create the clique data structure */
2456  SCIP_CALL( cliqueCreateWithData(&clique, blkmem, size, clqvars, clqvalues, nvars, cliquetable->ncreatedcliques, isequation) );
2457 
2458  sameclique = (SCIP_CLIQUE*)SCIPhashtableRetrieve(cliquetable->hashtable, (void*)clique);
2459 
2460  if( sameclique == NULL )
2461  {
2462  SCIPdebugMessage("adding clique %u with %d vars to clique table\n", clique->id, nvars);
2463 
2464  cliquetable->ncreatedcliques++;
2465 
2466  /* add clique to clique table */
2467  SCIP_CALL( cliquetableEnsureSize(cliquetable, set, cliquetable->ncliques+1) );
2468  cliquetable->cliques[cliquetable->ncliques] = clique;
2469  clique->index = cliquetable->ncliques;
2470  cliquetable->ncliques++;
2471  cliquetable->nentries += nvars;
2472 
2473  SCIP_CALL( SCIPhashtableInsert(cliquetable->hashtable, (void*)clique) );
2474 
2475  /* add filled clique to the cliquelists of all corresponding variables */
2476  SCIP_CALL( SCIPvarsAddClique(clqvars, clqvalues, nvars, blkmem, set, clique) );
2477  }
2478  else
2479  {
2480  SCIPdebugMessage("same clique %p already found in cliquetable -> discard new one\n", (void*) sameclique);
2481 
2482  /* update equation status of clique */
2483  /* @note if we might change the order of the clique, e.g. put the equations up front, we should rather remove
2484  * the sameclique from the hashmap while adding the new clique
2485  */
2486  if( !sameclique->equation && clique->equation )
2487  sameclique->equation = TRUE;
2488 
2489  cliqueFree(&clique, blkmem);
2490  return SCIP_OKAY;
2491  }
2492  }
2493  else
2494  {
2495  assert(!isequation);
2496  assert(nvars == 1);
2497 
2498  BMSfreeBlockMemoryArray(blkmem, &clqvars, size);
2499  BMSfreeBlockMemoryArray(blkmem, &clqvalues, size);
2500 
2501  return SCIP_OKAY;
2502  }
2503  cliqueCheck(clique);
2504 
2505  return SCIP_OKAY;
2506 }
2507 
2508 /** clean up given clique by removing fixed variables */
2509 static
2511  SCIP_CLIQUE* clique, /**< clique data structure */
2512  BMS_BLKMEM* blkmem, /**< block memory */
2513  SCIP_SET* set, /**< global SCIP settings */
2514  SCIP_STAT* stat, /**< problem statistics */
2515  SCIP_PROB* transprob, /**< transformed problem */
2516  SCIP_PROB* origprob, /**< original problem */
2517  SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
2518  SCIP_REOPT* reopt, /**< reoptimization data structure */
2519  SCIP_LP* lp, /**< current LP data */
2520  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
2521  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2522  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
2523  int* nchgbds, /**< pointer to store number of fixed variables */
2524  SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
2525  )
2526 {
2527  assert(clique != NULL);
2528  assert(blkmem != NULL);
2529  assert(set != NULL);
2530  assert(nchgbds != NULL);
2531  assert(infeasible != NULL);
2532 
2533  /* do we need to clean up fixed variables? */
2534  if( !SCIPcliqueIsCleanedUp(clique) )
2535  {
2536  SCIP_VAR* onefixedvar = NULL;
2537  SCIP_Bool onefixedvalue;
2538  SCIP_Bool needsorting = FALSE;
2539  int v;
2540  int w;
2541 
2542  w = clique->startcleanup;
2543 
2544  SCIPdebugMessage("Starting clean up of clique %d (size %d) from position %d\n", clique->id, clique->nvars, w);
2545 
2546  /* exchange inactive by active variables */
2547  for( v = w; v < clique->nvars; ++v )
2548  {
2549  SCIP_Bool addvartoclique; /* has the variable status changed such that it needs to be replaced by an active representative? */
2550 
2551  addvartoclique = FALSE;
2553  || SCIPvarGetStatus(clique->vars[v]) == SCIP_VARSTATUS_NEGATED
2554  || SCIPvarGetStatus(clique->vars[v]) == SCIP_VARSTATUS_MULTAGGR )
2555  {
2556  needsorting = TRUE;
2557 
2558  SCIP_CALL( SCIPvarGetProbvarBinary(&(clique->vars[v]), &(clique->values[v])) );
2559  if( SCIPvarGetStatus(clique->vars[v]) == SCIP_VARSTATUS_NEGATED )
2560  {
2561  clique->vars[v] = SCIPvarGetNegationVar(clique->vars[v]);
2562  clique->values[v] = !clique->values[v];
2563  }
2564  else if( SCIPvarGetStatus(clique->vars[v]) == SCIP_VARSTATUS_MULTAGGR )
2565  {
2566  clique->equation = FALSE;
2567  continue;
2568  }
2569 
2570  addvartoclique = TRUE;
2571  }
2572 
2573  assert(SCIPvarGetStatus(clique->vars[v]) == SCIP_VARSTATUS_COLUMN
2574  || SCIPvarGetStatus(clique->vars[v]) == SCIP_VARSTATUS_LOOSE
2575  || SCIPvarGetStatus(clique->vars[v]) == SCIP_VARSTATUS_FIXED);
2576 
2577  /* check for variables that are either fixed to zero or marked for deletion from global structures */
2578  if( (clique->values[v] && SCIPvarGetUbGlobal(clique->vars[v]) < 0.5) ||
2579  (!clique->values[v] && SCIPvarGetLbGlobal(clique->vars[v]) > 0.5) ||
2581  {
2582  /* the variable will be overwritten by subsequent active variables */
2583  continue;
2584  }
2585 
2586  /* check for a variable fixed to one in the clique */
2587  else if( (clique->values[v] && SCIPvarGetLbGlobal(clique->vars[v]) > 0.5)
2588  || (!clique->values[v] && SCIPvarGetUbGlobal(clique->vars[v]) < 0.5) )
2589  {
2590  if( onefixedvar != NULL )
2591  {
2592  *infeasible = TRUE;
2593 
2594  SCIPdebugMessage("two variables in clique %u fixed to one %s%s and %s%s\n", clique->id,
2595  onefixedvalue ? "" : "~", SCIPvarGetName(onefixedvar), clique->values[v] ? "" : "~",
2596  SCIPvarGetName(clique->vars[v])); /*lint !e530*/
2597  return SCIP_OKAY;
2598  }
2599  onefixedvar = clique->vars[v];
2600  onefixedvalue = clique->values[v];
2601  }
2602  else
2603  {
2604  assert(SCIPvarGetStatus(clique->vars[v]) != SCIP_VARSTATUS_FIXED);
2605  assert(w <= v);
2606 
2607  if( w < v )
2608  {
2609  clique->vars[w] = clique->vars[v];
2610  clique->values[w] = clique->values[v];
2611  }
2612 
2613  /* add clique to active variable if it replaced a aggregated or negated var */
2614  if( addvartoclique )
2615  {
2616  SCIP_CALL( SCIPvarAddCliqueToList(clique->vars[w], blkmem, set, clique->values[w], clique) );
2617  }
2618  /* increase indexer of last active, i.e. unfixed, variable in clique */
2619  ++w;
2620  }
2621 
2622  }
2623  clique->nvars = w;
2624 
2625  if( onefixedvar != NULL )
2626  {
2627  SCIPdebugMessage("variable %s%s in clique %u fixed to one, fixing all other variables to zero\n",
2628  onefixedvalue ? "" : "~", SCIPvarGetName(onefixedvar), clique->id);
2629 
2630  for( v = 0; v < clique->nvars ; ++v )
2631  {
2632  SCIP_VAR* clqvar = clique->vars[v];
2633  SCIP_Bool clqval = clique->values[v];
2634 
2635  assert(SCIPvarGetStatus(clqvar) == SCIP_VARSTATUS_COLUMN
2636  || SCIPvarGetStatus(clqvar) == SCIP_VARSTATUS_LOOSE);
2637 
2638  if( onefixedvalue != clqval || clqvar != onefixedvar )
2639  {
2640  /* the variable could have been fixed already because it appears more than once in the clique */
2641  if( SCIPvarGetLbGlobal(clqvar) > SCIPvarGetUbGlobal(clqvar) - 0.5 )
2642  {
2643  /* the fixing must have occurred previously inside this loop. It may happen that
2644  * the variable occurs together with its negation in that clique, which is usually
2645  * handled during the merge step, but leads to a direct infeasibility because it
2646  * contradicts any other variable fixed to one in this clique
2647  */
2648  if( (clqval && SCIPvarGetLbGlobal(clqvar) > 0.5)
2649  || (! clqval && SCIPvarGetUbGlobal(clqvar) < 0.5) )
2650  {
2651  /* impossible because we would have detected this in the previous cleanup loop */
2652  assert(clqvar != onefixedvar);
2653  *infeasible = TRUE;
2654 
2655  return SCIP_OKAY;
2656  }
2657  continue;
2658  }
2659 
2660  SCIP_CALL( SCIPvarDelCliqueFromList(clqvar, blkmem, clqval, clique) );
2661 
2662 /* the following piece of code is wrong at this point because it assumes sorted variables. can be enabled if sorting
2663  * of variables is performed earlier than it is now
2664  */
2665 #ifdef SCIP_DISABLED_CODE
2666  /* if one of the other variables occurs multiple times, we can
2667  * 1) deduce infeasibility if it occurs with different values
2668  * 2) wait for the last occurence to fix it
2669  */
2670  while( v < clique->nvars - 1 && clique->vars[v + 1] == clqvar )
2671  {
2672  if( clique->values[v + 1] != clique->values[v] )
2673  {
2674  *infeasible = TRUE;
2675  return SCIP_OKAY;
2676  }
2677  ++v;
2678  }
2679 #endif
2680  SCIPdebugMessage("fixing variable %s in clique %u to %d\n", SCIPvarGetName(clqvar), clique->id,
2681  clqval ? 0 : 1);
2682 
2683  SCIP_CALL( SCIPvarFixBinary(clqvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
2684  eventqueue, cliquetable, !clqval, infeasible, nchgbds) );
2685 
2686  if( *infeasible )
2687  return SCIP_OKAY;
2688  }
2689  }
2690 
2691  if( SCIPvarGetStatus(onefixedvar) == SCIP_VARSTATUS_COLUMN /*lint !e850*/
2692  || SCIPvarGetStatus(onefixedvar) == SCIP_VARSTATUS_LOOSE )
2693  {
2694  SCIP_CALL( SCIPvarDelCliqueFromList(onefixedvar, blkmem, onefixedvalue, clique) );
2695  }
2696 
2697  clique->nvars = 0;
2698  clique->equation = FALSE;
2699  clique->startcleanup = -1;
2700 
2701  return SCIP_OKAY;
2702  }
2703 
2704  if( clique->equation )
2705  {
2706  if( clique->nvars == 0 )
2707  {
2708  *infeasible = TRUE;
2709  return SCIP_OKAY;
2710  }
2711  else if( clique->nvars == 1 )
2712  {
2713  assert(SCIPvarGetStatus(clique->vars[0]) == SCIP_VARSTATUS_COLUMN
2714  || SCIPvarGetStatus(clique->vars[0]) == SCIP_VARSTATUS_LOOSE);
2715 
2716  /* clearing data and removing variable from its clique list */
2717  SCIP_CALL( SCIPvarDelCliqueFromList(clique->vars[0], blkmem, clique->values[0], clique) );
2718 
2719  SCIPdebugMessage("fixing last variable %s in clique %u to %d\n", SCIPvarGetName(clique->vars[0]), clique->id,
2720  clique->values[0] ? 1 : 0);
2721 
2722  SCIP_CALL( SCIPvarFixBinary(clique->vars[0], blkmem, set, stat, transprob, origprob, tree, reopt, lp,
2723  branchcand, eventqueue, cliquetable, clique->values[0], infeasible, nchgbds) );
2724 
2725  clique->nvars = 0;
2726  clique->equation = FALSE;
2727  clique->startcleanup = -1;
2728 
2729  return SCIP_OKAY;
2730  }
2731  }
2732 
2733  if( needsorting )
2734  {
2735  SCIP_Bool isequation = clique->equation;
2736 
2737  /* remove multiple entries of the same variable */
2738  SCIP_CALL( sortAndMergeClique(clique->vars, clique->values, &(clique->nvars), &isequation, clique, blkmem, set, stat,
2739  transprob, origprob, tree, reopt, lp, branchcand, eventqueue, cliquetable, nchgbds, infeasible) );
2740 
2741  clique->equation = isequation;
2742  }
2743 
2744  /* @todo check if we can aggregate variables if( clique->equation && clique->nvars == 2 ) */
2745 
2746  clique->startcleanup = -1;
2747  }
2748  assert(SCIPcliqueIsCleanedUp(clique));
2749 
2750  return SCIP_OKAY;
2751 }
2752 
2753 #ifdef SCIP_MORE_DEBUG
2754 /** checks whether clique appears in all clique lists of the involved variables */
2755 static
2757  SCIP_CLIQUETABLE* cliquetable /**< clique table data structure */
2758  )
2759 {
2760  SCIP_Longint nentries = 0;
2761  int c;
2762 
2763  assert(cliquetable != NULL);
2764 
2765  for( c = cliquetable->ncliques - 1; c >= 0; --c )
2766  nentries += cliquetable->cliques[c]->nvars;
2767 
2768  return (nentries == cliquetable->nentries);
2769 }
2770 #else
2771 #define checkNEntries(cliquetable) TRUE
2772 #endif
2773 
2774 /** removes all empty and single variable cliques from the clique table; removes double entries from the clique table
2775  *
2776  * @note cliques can be processed several times by this method
2777  *
2778  * @todo try to detect infeasible implications, e.g., x = 1 => (y = 0 && y = 1)
2779  */
2781  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
2782  BMS_BLKMEM* blkmem, /**< block memory */
2783  SCIP_SET* set, /**< global SCIP settings */
2784  SCIP_STAT* stat, /**< problem statistics */
2785  SCIP_PROB* transprob, /**< transformed problem */
2786  SCIP_PROB* origprob, /**< original problem */
2787  SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
2788  SCIP_REOPT* reopt, /**< reoptimization data structure */
2789  SCIP_LP* lp, /**< current LP data */
2790  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
2791  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2792  int* nchgbds, /**< pointer to store number of fixed variables */
2793  SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
2794  )
2795 {
2796  assert(cliquetable != NULL);
2797  assert(stat != NULL);
2798  assert(infeasible != NULL);
2799 
2800  *infeasible = FALSE;
2801 
2802  /* check if we have anything to do */
2803  if( stat->npresolfixedvars == cliquetable->ncleanupfixedvars
2804  && stat->npresolaggrvars == cliquetable->ncleanupaggrvars
2805  && cliquetable->ndirtycliques == 0 )
2806  return SCIP_OKAY;
2807 
2808  SCIPdebugMessage("cleaning up clique table with %d cliques (with %" SCIP_LONGINT_FORMAT " entries)\n", cliquetable->ncliques, cliquetable->nentries);
2809 
2810  /* delay events */
2811  SCIP_CALL( SCIPeventqueueDelay(eventqueue) );
2812 
2813  cliquetable->incleanup = TRUE;
2814  while( cliquetable->ndirtycliques > 0 && !(*infeasible) )
2815  {
2816  SCIP_CLIQUE* clique;
2817  SCIP_CLIQUE* sameclique;
2818 
2819  clique = cliquetable->cliques[0];
2820 
2821  assert(!SCIPcliqueIsCleanedUp(clique));
2822 
2823  /* remove not clean up clique from hastable */
2824  SCIP_CALL( SCIPhashtableRemove(cliquetable->hashtable, (void*)clique) );
2825  cliquetable->nentries -= clique->nvars;
2826  assert(cliquetable->nentries >= 0);
2827 
2828  SCIP_CALL( cliqueCleanup(clique, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
2829  cliquetable, nchgbds, infeasible) );
2830 
2831  if( *infeasible )
2832  break;
2833 
2834  assert(SCIPcliqueIsCleanedUp(clique));
2835 
2836  /* swap freshly cleaned clique with last dirty clique */
2837  cliquetable->ndirtycliques--;
2838  cliquetableSwapCliques(cliquetable, 0, cliquetable->ndirtycliques);
2839  cliqueCheck(clique);
2840 
2841  /* @todo check if we can aggregate variables if( clique->equation && clique->nvars == 2 && SCIPsetGetStage(set) == SCIP_STAGE_PRESOLVING */
2842 #if 0
2843  if( clique->nvars == 2 && clique->equation && SCIPsetGetStage(set) == SCIP_STAGE_PRESOLVING )
2844  {
2845  SCIP_VAR* var0;
2846  SCIP_VAR* var1;
2847  SCIP_Real scalarx;
2848  SCIP_Real scalary;
2849  SCIP_Real rhs = 1.0;
2850  SCIP_Bool aggregated;
2851 
2852  printf("aggr vars, clique %d\n", clique->id);
2853 
2854  if( SCIPvarGetType(clique->vars[0]) >= SCIPvarGetType(clique->vars[1]) )
2855  {
2856  var0 = clique->vars[0];
2857  var1 = clique->vars[1];
2858 
2859  if( !clique->values[0] )
2860  {
2861  scalarx = -1.0;
2862  rhs -= 1.0;
2863  }
2864  else
2865  scalarx = 1.0;
2866 
2867  if( !clique->values[1] )
2868  {
2869  scalary = -1.0;
2870  rhs -= 1.0;
2871  }
2872  else
2873  scalary = 1.0;
2874  }
2875  else
2876  {
2877  var0 = clique->vars[1];
2878  var1 = clique->vars[0];
2879 
2880  if( !clique->values[0] )
2881  {
2882  scalary = -1.0;
2883  rhs -= 1.0;
2884  }
2885  else
2886  scalary = 1.0;
2887 
2888  if( !clique->values[1] )
2889  {
2890  scalarx = -1.0;
2891  rhs -= 1.0;
2892  }
2893  else
2894  scalarx = 1.0;
2895  }
2896 
2899 
2900  /* aggregate the variable */
2901  SCIP_CALL( SCIPvarTryAggregateVars(set, blkmem, stat, transprob, origprob, primal,
2902  tree, lp, cliquetable, branchcand, eventfilter, eventqueue,
2903  var0, var1, scalarx, scalary, rhs, infeasible, &aggregated) );
2904 
2905  assert(aggregated || *infeasible);
2906  }
2907 #endif
2908 
2909  sameclique = (SCIP_CLIQUE*)SCIPhashtableRetrieve(cliquetable->hashtable, (void*)clique);
2910 
2911  /* check if the clique is already contained in the clique table, or if it is redundant (too small) */
2912  if( clique->nvars <= 1 || sameclique != NULL )
2913  {
2914  int j;
2915 
2916  /* infeasible or fixing should be performed already on trivial clique */
2917  assert(clique->nvars > 1 || !clique->equation);
2918 
2919  /* if the clique which is already in the hashtable is an inequality and the current clique is an equation, we
2920  * update the equation status of the old one
2921  */
2922  if( clique->nvars > 1 && clique->equation && !sameclique->equation )
2923  {
2924  assert(sameclique->nvars >= 2);
2925 
2926  /* @note if we might change the order of the clique, e.g. put the equations up front, we should rather remove
2927  * the sameclique from the hashmap while adding the new clique
2928  */
2929  sameclique->equation = TRUE;
2930  }
2931 
2932  /* delete the clique from the variables' clique lists */
2933  for( j = 0; j < clique->nvars; ++j )
2934  {
2935  SCIP_CALL( SCIPvarDelCliqueFromList(clique->vars[j], blkmem, clique->values[j], clique) );
2936  }
2937 
2938  /* free clique and remove it from clique table */
2939  cliqueFree(&clique, blkmem);
2940  cliquetable->ncliques--;
2941  /* insert a clean clique from the end of the array */
2942  if( cliquetable->ndirtycliques < cliquetable->ncliques )
2943  {
2944  assert(SCIPcliqueIsCleanedUp(cliquetable->cliques[cliquetable->ncliques]));
2945  cliquetable->cliques[cliquetable->ndirtycliques] = cliquetable->cliques[cliquetable->ncliques];
2946  cliquetable->cliques[cliquetable->ndirtycliques]->index = cliquetable->ndirtycliques;
2947  }
2948  }
2949  else
2950  {
2951  cliquetable->nentries += clique->nvars;
2952 
2953  SCIP_CALL( SCIPhashtableInsert(cliquetable->hashtable, (void*)clique) );
2954  if( !clique->eventsissued )
2955  {
2956  int j;
2957 
2958  /* issue IMPLADDED event on each variable in the clique */
2959  for( j = 0; j < clique->nvars; ++j )
2960  {
2961  SCIP_EVENT* event;
2962 
2963  SCIP_CALL( SCIPeventCreateImplAdded(&event, blkmem, clique->vars[j]) );
2964  SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) );
2965  }
2966  clique->eventsissued = TRUE;
2967  }
2968  }
2969  }
2970  cliquetable->incleanup = FALSE;
2971 
2972  /* remember the number of fixed variables and cliques in order to avoid unnecessary cleanups */
2973  cliquetable->ncleanupfixedvars = stat->npresolfixedvars;
2974  cliquetable->ncleanupaggrvars = stat->npresolaggrvars;
2975  assert(*infeasible || cliquetable->ndirtycliques == 0);
2976 
2977  assert(*infeasible || checkNEntries(cliquetable));
2978 
2979  SCIPdebugMessage("cleaned up clique table has %d cliques left (with %" SCIP_LONGINT_FORMAT " entries)\n", cliquetable->ncliques, cliquetable->nentries);
2980 
2981  /* process events */
2982  SCIP_CALL( SCIPeventqueueProcess(eventqueue, blkmem, set, NULL, lp, branchcand, NULL) );
2983 
2984  return SCIP_OKAY;
2985 }
2986 
2987 
2988 /*
2989  * simple functions implemented as defines
2990  */
2991 
2992 /* In debug mode, the following methods are implemented as function calls to ensure
2993  * type validity.
2994  * In optimized mode, the methods are implemented as defines to improve performance.
2995  * However, we want to have them in the library anyways, so we have to undef the defines.
2996  */
2997 
2998 #undef SCIPvboundsGetNVbds
2999 #undef SCIPvboundsGetVars
3000 #undef SCIPvboundsGetCoefs
3001 #undef SCIPvboundsGetConstants
3002 #undef SCIPimplicsGetNImpls
3003 #undef SCIPimplicsGetVars
3004 #undef SCIPimplicsGetTypes
3005 #undef SCIPimplicsGetBounds
3006 #undef SCIPimplicsGetIds
3007 #undef SCIPcliqueGetNVars
3008 #undef SCIPcliqueGetVars
3009 #undef SCIPcliqueGetValues
3010 #undef SCIPcliqueGetId
3011 #undef SCIPcliqueIsCleanedUp
3012 #undef SCIPcliqueIsEquation
3013 #undef SCIPcliquelistGetNCliques
3014 #undef SCIPcliquelistGetCliques
3015 #undef SCIPcliquelistCheck
3016 #undef SCIPcliquetableGetNCliques
3017 #undef SCIPcliquetableGetCliques
3018 #undef SCIPcliquetableGetNEntries
3019 
3020 /** gets number of variable bounds contained in given variable bounds data structure */
3022  SCIP_VBOUNDS* vbounds /**< variable bounds data structure */
3023  )
3024 {
3025  return vbounds != NULL ? vbounds->len : 0;
3026 }
3027 
3028 /** gets array of variables contained in given variable bounds data structure */
3030  SCIP_VBOUNDS* vbounds /**< variable bounds data structure */
3031  )
3032 {
3033  return vbounds != NULL ? vbounds->vars : NULL;
3034 }
3035 
3036 /** gets array of coefficients contained in given variable bounds data structure */
3038  SCIP_VBOUNDS* vbounds /**< variable bounds data structure */
3039  )
3040 {
3041  return vbounds != NULL ? vbounds->coefs : NULL;
3042 }
3043 
3044 /** gets array of constants contained in given variable bounds data structure */
3046  SCIP_VBOUNDS* vbounds /**< variable bounds data structure */
3047  )
3048 {
3049  return vbounds != NULL ? vbounds->constants : NULL;
3050 }
3051 
3052 /** gets number of implications for a given binary variable fixing */
3054  SCIP_IMPLICS* implics, /**< implication data */
3055  SCIP_Bool varfixing /**< should the implications on var == FALSE or var == TRUE be returned? */
3056  )
3057 {
3058  return implics != NULL ? implics->nimpls[varfixing] : 0;
3059 }
3060 
3061 /** gets array with implied variables for a given binary variable fixing */
3063  SCIP_IMPLICS* implics, /**< implication data */
3064  SCIP_Bool varfixing /**< should the implications on var == FALSE or var == TRUE be returned? */
3065  )
3066 {
3067  return implics != NULL ? implics->vars[varfixing] : NULL;
3068 }
3069 
3070 /** gets array with implication types for a given binary variable fixing */
3072  SCIP_IMPLICS* implics, /**< implication data */
3073  SCIP_Bool varfixing /**< should the implications on var == FALSE or var == TRUE be returned? */
3074  )
3075 {
3076  return implics != NULL ? implics->types[varfixing] : NULL;
3077 }
3078 
3079 /** gets array with implication bounds for a given binary variable fixing */
3081  SCIP_IMPLICS* implics, /**< implication data */
3082  SCIP_Bool varfixing /**< should the implications on var == FALSE or var == TRUE be returned? */
3083  )
3084 {
3085  return implics != NULL ? implics->bounds[varfixing] : NULL;
3086 }
3087 
3088 /** Gets array with unique implication identifiers for a given binary variable fixing.
3089  * If an implication is a shortcut, i.e., it was added as part of the transitive closure of another implication,
3090  * its id is negative, otherwise it is nonnegative.
3091  */
3093  SCIP_IMPLICS* implics, /**< implication data */
3094  SCIP_Bool varfixing /**< should the implications on var == FALSE or var == TRUE be returned? */
3095  )
3096 {
3097  return implics != NULL ? implics->ids[varfixing] : NULL;
3098 }
3099 
3100 /** gets number of variables in the cliques */
3102  SCIP_CLIQUE* clique /**< clique data structure */
3103  )
3104 {
3105  assert(clique != NULL);
3106 
3107  return clique->nvars;
3108 }
3109 
3110 /** gets array of active problem variables in the cliques */
3112  SCIP_CLIQUE* clique /**< clique data structure */
3113  )
3114 {
3115  assert(clique != NULL);
3116 
3117  return clique->vars;
3118 }
3119 
3120 /** gets array of values of active problem variables in the cliques, i.e. whether the variable is fixed to FALSE or
3121  * to TRUE in the clique
3122  */
3124  SCIP_CLIQUE* clique /**< clique data structure */
3125  )
3126 {
3127  assert(clique != NULL);
3128 
3129  return clique->values;
3130 }
3131 
3132 /** gets unique identifier of the clique */
3134  SCIP_CLIQUE* clique /**< clique data structure */
3135  )
3136 {
3137  assert(clique != NULL);
3138 
3139  return (int) clique->id;
3140 }
3141 
3142 /** gets unique identifier of the clique */
3144  SCIP_CLIQUE* clique /**< clique data structure */
3145  )
3146 {
3147  assert(clique != NULL);
3148 
3149  return (clique->startcleanup == -1);
3150 }
3151 
3152 /** return whether the given clique is an equation */
3154  SCIP_CLIQUE* clique /**< clique data structure */
3155  )
3156 {
3157  assert(clique != NULL);
3158 
3159  return (SCIP_Bool)(clique->equation); /*lint !e571*/
3160 }
3161 
3162 /** returns the number of cliques stored in the clique list */
3164  SCIP_CLIQUELIST* cliquelist, /**< clique list data structure */
3165  SCIP_Bool value /**< value of the variable for which the cliques should be returned */
3166  )
3167 {
3168  return cliquelist != NULL ? cliquelist->ncliques[value] : 0;
3169 }
3170 
3171 /** returns the cliques stored in the clique list, or NULL if the clique list is empty */
3173  SCIP_CLIQUELIST* cliquelist, /**< clique list data structure */
3174  SCIP_Bool value /**< value of the variable for which the cliques should be returned */
3175  )
3176 {
3177  return cliquelist != NULL ? cliquelist->cliques[value] : NULL;
3178 }
3179 
3180 /** checks whether variable is contained in all cliques of the cliquelist */
3182  SCIP_CLIQUELIST* cliquelist, /**< clique list data structure */
3183  SCIP_VAR* var /**< variable, the clique list belongs to */
3184  )
3185 {
3186  /* @todo might need to change ifndef NDEBUG to ifdef SCIP_MORE_DEBUG because it can take at lot of time to check for
3187  * correctness
3188  */
3189 #ifndef NDEBUG
3190  int value;
3191 
3192  assert(SCIPvarGetNCliques(var, FALSE) == SCIPcliquelistGetNCliques(cliquelist, FALSE));
3193  assert(SCIPvarGetCliques(var, FALSE) == SCIPcliquelistGetCliques(cliquelist, FALSE));
3194  assert(SCIPvarGetNCliques(var, TRUE) == SCIPcliquelistGetNCliques(cliquelist, TRUE));
3195  assert(SCIPvarGetCliques(var, TRUE) == SCIPcliquelistGetCliques(cliquelist, TRUE));
3196 
3197  for( value = 0; value < 2; ++value )
3198  {
3199  SCIP_CLIQUE** cliques;
3200  int ncliques;
3201  int i;
3202 
3203  ncliques = SCIPcliquelistGetNCliques(cliquelist, (SCIP_Bool)value);
3204  cliques = SCIPcliquelistGetCliques(cliquelist, (SCIP_Bool)value);
3205  for( i = 0; i < ncliques; ++i )
3206  {
3207  SCIP_CLIQUE* clique;
3208  int pos;
3209 
3210  clique = cliques[i];
3211  assert(clique != NULL);
3212 
3213  pos = SCIPcliqueSearchVar(clique, var, (SCIP_Bool)value);
3214  assert(0 <= pos && pos < clique->nvars);
3215  assert(clique->vars[pos] == var);
3216  assert(clique->values[pos] == (SCIP_Bool)value);
3217  }
3218  }
3219 #endif
3220 }
3221 
3222 /** gets the number of cliques stored in the clique table */
3224  SCIP_CLIQUETABLE* cliquetable /**< clique table data structure */
3225  )
3226 {
3227  assert(cliquetable != NULL);
3228 
3229  return cliquetable->ncliques;
3230 }
3231 
3232 /** gets the array of cliques stored in the clique table */
3234  SCIP_CLIQUETABLE* cliquetable /**< clique table data structure */
3235  )
3236 {
3237  assert(cliquetable != NULL);
3238 
3239  return cliquetable->cliques;
3240 }
3241 
3242 /** gets the number of entries in the whole clique table */
3244  SCIP_CLIQUETABLE* cliquetable /**< clique table data structure */
3245  )
3246 {
3247  assert(cliquetable != NULL);
3248 
3249  return cliquetable->nentries;
3250 }
SCIP_CLIQUE ** cliques
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
SCIP_VAR * SCIPvarGetNegationVar(SCIP_VAR *var)
Definition: var.c:16883
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 BMSallocBlockMemory(mem, ptr)
Definition: memory.h:406
#define BMSfreeBlockMemoryArrayNull(mem, ptr, num)
Definition: memory.h:422
internal methods for managing events
SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
Definition: implics.c:3111
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16443
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
static void cliqueCheck(SCIP_CLIQUE *clique)
Definition: implics.c:1358
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:1567
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:3243
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:16623
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:17420
SCIP_Real * constants
#define SCIP_HASHSIZE_CLIQUES_SMALL
Definition: def.h:216
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:3062
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:17067
int SCIPcliquelistGetNCliques(SCIP_CLIQUELIST *cliquelist, SCIP_Bool value)
Definition: implics.c:3163
SCIP_VAR ** SCIPvboundsGetVars(SCIP_VBOUNDS *vbounds)
Definition: implics.c:3029
#define SCIPdebugCheckClique(set, vars, values, nvars)
Definition: debug.h:259
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:2510
#define FALSE
Definition: def.h:56
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:5292
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:55
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
SCIP_Bool SCIPcliqueIsEquation(SCIP_CLIQUE *clique)
Definition: implics.c:3153
SCIP_RETCODE SCIPcliquetableCreate(SCIP_CLIQUETABLE **cliquetable, SCIP_SET *set, BMS_BLKMEM *blkmem)
Definition: implics.c:1776
#define SCIP_CALL(x)
Definition: def.h:266
#define checkNEntries(cliquetable)
Definition: implics.c:2771
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:2780
int SCIPsetCalcMemGrowSize(SCIP_SET *set, int num)
Definition: set.c:4766
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:3172
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
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:1480
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:16562
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:213
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:3223
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:3071
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:1157
#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
#define BMSallocMemory(ptr)
Definition: memory.h:74
SCIP_Real * SCIPvboundsGetCoefs(SCIP_VBOUNDS *vbounds)
Definition: implics.c:3037
SCIP_RETCODE SCIPvarGetProbvarBinary(SCIP_VAR **var, SCIP_Bool *negated)
Definition: var.c:11573
SCIP_Bool incleanup
internal methods for global SCIP settings
static void checkImplics(SCIP_IMPLICS *implics)
Definition: implics.c:376
#define BMSreallocMemoryArray(ptr, num)
Definition: memory.h:82
SCIP_Bool SCIPsetIsFeasGE(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:5666
#define BMSfreeMemory(ptr)
Definition: memory.h:100
SCIP_RETCODE SCIPhashtableRemove(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:1719
SCIP_VAR ** vars
SCIP_Real * SCIPvboundsGetConstants(SCIP_VBOUNDS *vbounds)
Definition: implics.c:3045
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:5622
void SCIPvboundsShrink(SCIP_VBOUNDS **vbounds, BMS_BLKMEM *blkmem, int newnvbds)
Definition: implics.c:326
#define BMSfreeMemoryArrayNull(ptr)
Definition: memory.h:103
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:16740
#define SCIP_Bool
Definition: def.h:53
#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:3092
#define MAX(x, y)
Definition: tclique_def.h:75
int SCIPimplicsGetNImpls(SCIP_IMPLICS *implics, SCIP_Bool varfixing)
Definition: implics.c:3053
methods for debugging
SCIP_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
Definition: implics.c:3123
#define BMSfreeBlockMemory(mem, ptr)
Definition: memory.h:419
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:1627
SCIP_Bool SCIPsetIsFeasLT(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:5600
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:2240
static SCIP_RETCODE vboundsCreate(SCIP_VBOUNDS **vbounds, BMS_BLKMEM *blkmem)
Definition: implics.c:48
int SCIPvboundsGetNVbds(SCIP_VBOUNDS *vbounds)
Definition: implics.c:3021
static void cliqueFree(SCIP_CLIQUE **clique, BMS_BLKMEM *blkmem)
Definition: implics.c:1022
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:1510
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:16608
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:17057
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
unsigned int id
public methods for message output
void SCIPcliquelistCheck(SCIP_CLIQUELIST *cliquelist, SCIP_VAR *var)
Definition: implics.c:3181
SCIP_CLIQUE ** cliques[2]
#define SCIP_Real
Definition: def.h:127
internal methods for problem statistics
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17409
#define MIN(x, y)
Definition: memory.c:67
#define SCIP_Longint
Definition: def.h:112
SCIP_Bool SCIPsetIsFeasGT(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:5644
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:2423
SCIP_Bool SCIPvarIsMarkedDeleteGlobalStructures(SCIP_VAR *var)
Definition: var.c:16710
SCIP_Bool SCIPcliqueIsCleanedUp(SCIP_CLIQUE *clique)
Definition: implics.c:3143
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:16730
int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
Definition: implics.c:3101
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:3080
#define SCIP_ALLOC(x)
Definition: def.h:277
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:3233
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:3133
SCIP_RETCODE SCIPvarDelCliqueFromList(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_Bool value, SCIP_CLIQUE *clique)
Definition: var.c:10682