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-2017 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], newsize) ); /*lint !e866*/
491  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*implics)->types[varfixing], (*implics)->size[varfixing], newsize) ); /*lint !e866*/
492  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*implics)->bounds[varfixing], (*implics)->size[varfixing], newsize) ); /*lint !e866*/
493  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &(*implics)->ids[varfixing], (*implics)->size[varfixing], newsize) ); /*lint !e866*/
494  (*implics)->size[varfixing] = newsize;
495  }
496  assert(num <= (*implics)->size[varfixing]);
497 
498  return SCIP_OKAY;
499 }
500 
501 /** gets the positions of the implications y >= l and y <= u in the implications data structure;
502  * if no lower or upper bound implication for y was found, -1 is returned
503  */
504 static
506  SCIP_IMPLICS* implics, /**< implications data structure */
507  SCIP_Bool varfixing, /**< FALSE if y is searched in implications for x == 0, TRUE for x == 1 */
508  SCIP_VAR* implvar, /**< variable y to search for */
509  int* poslower, /**< pointer to store position of y_lower (-1 if not found) */
510  int* posupper, /**< pointer to store position of y_upper (-1 if not found) */
511  int* posadd /**< pointer to store position of first y entry, or where a new y entry
512  * should be placed */
513  )
514 {
515  SCIP_Bool found;
516  int right;
517  int pos;
518 
519  assert(implics != NULL);
520  assert(poslower != NULL);
521  assert(posupper != NULL);
522  assert(posadd != NULL);
523 
524  if( implics->nimpls[varfixing] == 0 )
525  {
526  /* there are no implications with non-binary variable y */
527  *posadd = 0;
528  *poslower = -1;
529  *posupper = -1;
530  return;
531  }
532  right = implics->nimpls[varfixing] - 1;
533  assert(0 <= right);
534 
535  /* search for the position in the sorted array (via binary search) */
536  found = SCIPsortedvecFindPtr((void**)(&(implics->vars[varfixing][0])), SCIPvarComp, (void*)implvar, right + 1, &pos);
537 
538  if( !found )
539  {
540  /* y was not found */
541  assert(pos >= right || compVars((void*)implics->vars[varfixing][pos], (void*)implvar) > 0);
542  assert(pos == 0 || compVars((void*)implics->vars[varfixing][pos-1], (void*)implvar) < 0);
543  *poslower = -1;
544  *posupper = -1;
545  *posadd = pos;
546  }
547  else
548  {
549  /* y was found */
550  assert(implvar == implics->vars[varfixing][pos]);
551 
552  /* set poslower and posupper */
553  if( implics->types[varfixing][pos] == SCIP_BOUNDTYPE_LOWER )
554  {
555  /* y was found as y_lower (on position middle) */
556  *poslower = pos;
557  if( pos + 1 < implics->nimpls[varfixing] && implics->vars[varfixing][pos+1] == implvar )
558  {
559  assert(implics->types[varfixing][pos+1] == SCIP_BOUNDTYPE_UPPER);
560  *posupper = pos + 1;
561  }
562  else
563  *posupper = -1;
564  *posadd = pos;
565  }
566  else
567  {
568  /* y was found as y_upper (on position pos) */
569  *posupper = pos;
570  if( pos - 1 >= 0 && implics->vars[varfixing][pos-1] == implvar )
571  {
572  assert(implics->types[varfixing][pos-1] == SCIP_BOUNDTYPE_LOWER);
573  *poslower = pos - 1;
574  *posadd = pos - 1;
575  }
576  else
577  {
578  *poslower = -1;
579  *posadd = pos;
580  }
581  }
582  }
583 }
584 
585 /** returns whether variable y is already contained in implications for x == 0 or x == 1 with the given impltype
586  * y can be contained in structure with y >= b (y_lower) and y <= b (y_upper)
587  */
588 static
590  SCIP_IMPLICS* implics, /**< implications data structure */
591  SCIP_Bool varfixing, /**< FALSE if y is searched in implications for x == 0, TRUE for x == 1 */
592  SCIP_VAR* implvar, /**< variable y to search for */
593  SCIP_BOUNDTYPE impltype, /**< type of implication y <=/>= b to search for */
594  int* poslower, /**< pointer to store position of y_lower (inf if not found) */
595  int* posupper, /**< pointer to store position of y_upper (inf if not found) */
596  int* posadd /**< pointer to store correct position (with respect to impltype) to add y */
597  )
598 {
599  assert(implics != NULL);
600  assert(poslower != NULL);
601  assert(posupper != NULL);
602  assert(posadd != NULL);
603 
604  implicsSearchVar(implics, varfixing, implvar, poslower, posupper, posadd);
605  assert(*poslower == -1 || *posupper == -1 || *posupper == (*poslower)+1);
606  assert(*poslower == -1 || *posadd == *poslower);
607  assert(*poslower >= 0 || *posupper == -1 || *posadd == *posupper);
608  assert(0 <= *posadd && *posadd <= implics->nimpls[varfixing]);
609 
610  if( impltype == SCIP_BOUNDTYPE_LOWER )
611  return (*poslower >= 0);
612  else
613  {
614  if( *poslower >= 0 )
615  {
616  assert(*posadd == *poslower);
617  (*posadd)++;
618  }
619  return (*posupper >= 0);
620  }
621 }
622 
623 /** adds an implication x == 0/1 -> y <= b or y >= b to the implications data structure;
624  * the implication must be non-redundant
625  */
627  SCIP_IMPLICS** implics, /**< pointer to implications data structure */
628  BMS_BLKMEM* blkmem, /**< block memory */
629  SCIP_SET* set, /**< global SCIP settings */
630  SCIP_STAT* stat, /**< problem statistics */
631  SCIP_Bool varfixing, /**< FALSE if implication for x == 0 has to be added, TRUE for x == 1 */
632  SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */
633  SCIP_BOUNDTYPE impltype, /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */
634  SCIP_Real implbound, /**< bound b in implication y <= b or y >= b */
635  SCIP_Bool isshortcut, /**< is the implication a shortcut, i.e., added as part of the transitive closure of another implication? */
636  SCIP_Bool* conflict, /**< pointer to store whether implication causes a conflict for variable x */
637  SCIP_Bool* added /**< pointer to store whether the implication was added */
638  )
639 {
640  int poslower;
641  int posupper;
642  int posadd;
643  SCIP_Bool found;
644 #ifndef NDEBUG
645  int k;
646 #endif
647 
648  assert(implics != NULL);
649  assert(*implics == NULL || 0 <= (*implics)->nimpls[varfixing]);
650  assert(stat != NULL);
651  assert(SCIPvarIsActive(implvar));
653  assert((impltype == SCIP_BOUNDTYPE_LOWER && SCIPsetIsFeasGT(set, implbound, SCIPvarGetLbGlobal(implvar)))
654  || (impltype == SCIP_BOUNDTYPE_UPPER && SCIPsetIsFeasLT(set, implbound, SCIPvarGetUbGlobal(implvar))));
655  assert(conflict != NULL);
656  assert(added != NULL);
657 
658  SCIPsetDebugMsg(set, "adding implication to implics %p [%u]: <%s> %s %g\n",
659  (void*)*implics, varfixing, SCIPvarGetName(implvar), impltype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=", implbound);
660 
661  checkImplics(*implics);
662 
663  *conflict = FALSE;
664  *added = FALSE;
665 
666  /* check if variable is already contained in implications data structure */
667  if( *implics != NULL )
668  {
669  found = implicsSearchImplic(*implics, varfixing, implvar, impltype, &poslower, &posupper, &posadd);
670  assert(-1 <= poslower && poslower < (*implics)->nimpls[varfixing]);
671  assert(-1 <= posupper && posupper < (*implics)->nimpls[varfixing]);
672  assert(0 <= posadd && posadd <= (*implics)->nimpls[varfixing]);
673  assert(poslower == -1 || (*implics)->types[varfixing][poslower] == SCIP_BOUNDTYPE_LOWER);
674  assert(posupper == -1 || (*implics)->types[varfixing][posupper] == SCIP_BOUNDTYPE_UPPER);
675  }
676  else
677  {
678  found = FALSE;
679  poslower = -1;
680  posupper = -1;
681  posadd = 0;
682  }
683 
684  if( impltype == SCIP_BOUNDTYPE_LOWER )
685  {
686  assert(found == (poslower >= 0));
687 
688  /* check if y >= b is redundant */
689  if( poslower >= 0 && SCIPsetIsFeasLE(set, implbound, (*implics)->bounds[varfixing][poslower]) )
690  {
691  SCIPsetDebugMsg(set, " -> implication is redundant to <%s> >= %g\n", SCIPvarGetName(implvar), (*implics)->bounds[varfixing][poslower]);
692  return SCIP_OKAY;
693  }
694 
695  /* check if y >= b causes conflict for x (i.e. y <= a (with a < b) is also valid) */
696  if( posupper >= 0 && SCIPsetIsFeasGT(set, implbound, (*implics)->bounds[varfixing][posupper]) )
697  {
698  SCIPsetDebugMsg(set, " -> implication is conflicting to <%s> <= %g\n", SCIPvarGetName(implvar), (*implics)->bounds[varfixing][posupper]);
699  *conflict = TRUE;
700  return SCIP_OKAY;
701  }
702 
703  *added = TRUE;
704 
705  /* check if entry of the same type already exists */
706  if( found )
707  {
708  assert(poslower >= 0);
709  assert(posadd == poslower);
710 
711  /* add y >= b by changing old entry on poslower */
712  assert((*implics)->vars[varfixing][poslower] == implvar);
713  assert(SCIPsetIsFeasGT(set, implbound, (*implics)->bounds[varfixing][poslower]));
714  (*implics)->bounds[varfixing][poslower] = implbound;
715  }
716  else
717  {
718  assert(poslower == -1);
719 
720  /* add y >= b by creating a new entry on posadd */
721  SCIP_CALL( implicsEnsureSize(implics, blkmem, set, varfixing,
722  *implics != NULL ? (*implics)->nimpls[varfixing]+1 : 1) );
723  assert(*implics != NULL);
724 
725  if( (*implics)->nimpls[varfixing] - posadd > 0 )
726  {
727  int amount = ((*implics)->nimpls[varfixing] - posadd);
728 
729 #ifndef NDEBUG
730  for( k = (*implics)->nimpls[varfixing]; k > posadd; k-- )
731  {
732  assert(compVars((void*)(*implics)->vars[varfixing][k-1], (void*)implvar) >= 0);
733  }
734 #endif
735  BMSmoveMemoryArray(&((*implics)->types[varfixing][posadd+1]), &((*implics)->types[varfixing][posadd]), amount); /*lint !e866*/
736  BMSmoveMemoryArray(&((*implics)->ids[varfixing][posadd+1]), &((*implics)->ids[varfixing][posadd]), amount); /*lint !e866*/
737  BMSmoveMemoryArray(&((*implics)->vars[varfixing][posadd+1]), &((*implics)->vars[varfixing][posadd]), amount); /*lint !e866*/
738  BMSmoveMemoryArray(&((*implics)->bounds[varfixing][posadd+1]), &((*implics)->bounds[varfixing][posadd]), amount); /*lint !e866*/
739  }
740 
741  (*implics)->vars[varfixing][posadd] = implvar;
742  (*implics)->types[varfixing][posadd] = impltype;
743  (*implics)->bounds[varfixing][posadd] = implbound;
744  (*implics)->ids[varfixing][posadd] = (isshortcut ? -stat->nimplications : stat->nimplications);
745  (*implics)->nimpls[varfixing]++;
746 #ifndef NDEBUG
747  for( k = posadd-1; k >= 0; k-- )
748  assert(compVars((void*)(*implics)->vars[varfixing][k], (void*)implvar) <= 0);
749 #endif
750  stat->nimplications++;
751  }
752  }
753  else
754  {
755  assert(found == (posupper >= 0));
756 
757  /* check if y <= b is redundant */
758  if( posupper >= 0 && SCIPsetIsFeasGE(set, implbound, (*implics)->bounds[varfixing][posupper]) )
759  {
760  SCIPsetDebugMsg(set, " -> implication is redundant to <%s> <= %g\n", SCIPvarGetName(implvar), (*implics)->bounds[varfixing][posupper]);
761  return SCIP_OKAY;
762  }
763 
764  /* check if y <= b causes conflict for x (i.e. y >= a (with a > b) is also valid) */
765  if( poslower >= 0 && SCIPsetIsFeasLT(set, implbound, (*implics)->bounds[varfixing][poslower]) )
766  {
767  SCIPsetDebugMsg(set, " -> implication is conflicting to <%s> >= %g\n", SCIPvarGetName(implvar), (*implics)->bounds[varfixing][poslower]);
768  *conflict = TRUE;
769  return SCIP_OKAY;
770  }
771 
772  *added = TRUE;
773 
774  /* check if entry of the same type already exists */
775  if( found )
776  {
777  assert(posupper >= 0);
778  assert(posadd == posupper);
779 
780  /* add y <= b by changing old entry on posupper */
781  assert((*implics)->vars[varfixing][posupper] == implvar);
782  assert(SCIPsetIsFeasLT(set, implbound,(*implics)->bounds[varfixing][posupper]));
783  (*implics)->bounds[varfixing][posupper] = implbound;
784  }
785  else
786  {
787  /* add y <= b by creating a new entry on posadd */
788  assert(posupper == -1);
789 
790  SCIP_CALL( implicsEnsureSize(implics, blkmem, set, varfixing,
791  *implics != NULL ? (*implics)->nimpls[varfixing]+1 : 1) );
792  assert(*implics != NULL);
793 
794  if( (*implics)->nimpls[varfixing] - posadd > 0 )
795  {
796  int amount = ((*implics)->nimpls[varfixing] - posadd);
797 
798 #ifndef NDEBUG
799  for( k = (*implics)->nimpls[varfixing]; k > posadd; k-- )
800  {
801  assert(compVars((void*)(*implics)->vars[varfixing][k-1], (void*)implvar) >= 0);
802  }
803 #endif
804  BMSmoveMemoryArray(&((*implics)->types[varfixing][posadd+1]), &((*implics)->types[varfixing][posadd]), amount); /*lint !e866*/
805  BMSmoveMemoryArray(&((*implics)->ids[varfixing][posadd+1]), &((*implics)->ids[varfixing][posadd]), amount); /*lint !e866*/
806  BMSmoveMemoryArray(&((*implics)->vars[varfixing][posadd+1]), &((*implics)->vars[varfixing][posadd]), amount); /*lint !e866*/
807  BMSmoveMemoryArray(&((*implics)->bounds[varfixing][posadd+1]), &((*implics)->bounds[varfixing][posadd]), amount); /*lint !e866*/
808  }
809 
810  (*implics)->vars[varfixing][posadd] = implvar;
811  (*implics)->types[varfixing][posadd] = impltype;
812  (*implics)->bounds[varfixing][posadd] = implbound;
813  (*implics)->ids[varfixing][posadd] = (isshortcut ? -stat->nimplications : stat->nimplications);
814  (*implics)->nimpls[varfixing]++;
815 #ifndef NDEBUG
816  for( k = posadd-1; k >= 0; k-- )
817  assert(compVars((void*)(*implics)->vars[varfixing][k], (void*)implvar) <= 0);
818 #endif
819  stat->nimplications++;
820  }
821  }
822 
823  checkImplics(*implics);
824 
825  return SCIP_OKAY;
826 }
827 
828 /** removes the implication x <= 0 or x >= 1 ==> y <= b or y >= b from the implications data structure */
830  SCIP_IMPLICS** implics, /**< pointer to implications data structure */
831  BMS_BLKMEM* blkmem, /**< block memory */
832  SCIP_SET* set, /**< global SCIP settings */
833  SCIP_Bool varfixing, /**< FALSE if y should be removed from implications for x <= 0, TRUE for x >= 1 */
834  SCIP_VAR* implvar, /**< variable y in implication y <= b or y >= b */
835  SCIP_BOUNDTYPE impltype /**< type of implication y <= b (SCIP_BOUNDTYPE_UPPER) or y >= b (SCIP_BOUNDTYPE_LOWER) */
836  )
837 { /*lint --e{715}*/
838  int poslower;
839  int posupper;
840  int posadd;
841  SCIP_Bool found;
842 
843  assert(implics != NULL);
844  assert(*implics != NULL);
845  assert(implvar != NULL);
846 
847  SCIPsetDebugMsg(set, "deleting implication from implics %p [%u]: <%s> %s x\n",
848  (void*)*implics, varfixing, SCIPvarGetName(implvar), impltype == SCIP_BOUNDTYPE_LOWER ? ">=" : "<=");
849 
850  checkImplics(*implics);
851 
852  /* searches for y in implications of x */
853  found = implicsSearchImplic(*implics, varfixing, implvar, impltype, &poslower, &posupper, &posadd);
854  if( !found )
855  {
856  SCIPsetDebugMsg(set, " -> implication was not found\n");
857  return SCIP_OKAY;
858  }
859 
860  assert((impltype == SCIP_BOUNDTYPE_LOWER && poslower >= 0 && posadd == poslower)
861  || (impltype == SCIP_BOUNDTYPE_UPPER && posupper >= 0 && posadd == posupper));
862  assert(0 <= posadd && posadd < (*implics)->nimpls[varfixing]);
863  assert((*implics)->vars[varfixing][posadd] == implvar);
864  assert((*implics)->types[varfixing][posadd] == impltype);
865 
866  /* removes y from implications of x */
867  if( (*implics)->nimpls[varfixing] - posadd > 1 )
868  {
869  int amount = ((*implics)->nimpls[varfixing] - posadd - 1);
870 
871  BMSmoveMemoryArray(&((*implics)->types[varfixing][posadd]), &((*implics)->types[varfixing][posadd+1]), amount); /*lint !e866*/
872  BMSmoveMemoryArray(&((*implics)->vars[varfixing][posadd]), &((*implics)->vars[varfixing][posadd+1]), amount); /*lint !e866*/
873  BMSmoveMemoryArray(&((*implics)->bounds[varfixing][posadd]), &((*implics)->bounds[varfixing][posadd+1]), amount); /*lint !e866*/
874  }
875  (*implics)->nimpls[varfixing]--;
876 
877  /* free implics data structure, if it is empty */
878  if( (*implics)->nimpls[0] == 0 && (*implics)->nimpls[1] == 0 )
879  SCIPimplicsFree(implics, blkmem);
880 
881  checkImplics(*implics);
882 
883  return SCIP_OKAY;
884 }
885 
886 /** returns which implications on given variable y are contained in implications for x == 0 or x == 1 */
888  SCIP_IMPLICS* implics, /**< implications data structure */
889  SCIP_Bool varfixing, /**< FALSE if y should be searched in implications for x == 0, TRUE for x == 1 */
890  SCIP_VAR* implvar, /**< variable y to search for */
891  SCIP_Bool* haslowerimplic, /**< pointer to store whether there exists an implication y >= l */
892  SCIP_Bool* hasupperimplic /**< pointer to store whether there exists an implication y <= u */
893  )
894 {
895  int poslower;
896  int posupper;
897  int posadd;
898 
899  assert(haslowerimplic != NULL);
900  assert(hasupperimplic != NULL);
901 
902  implicsSearchVar(implics, varfixing, implvar, &poslower, &posupper, &posadd);
903 
904  *haslowerimplic = (poslower >= 0);
905  *hasupperimplic = (posupper >= 0);
906 }
907 
908 /** returns whether an implication y <= b or y >= b is contained in implications for x == 0 or x == 1 */
910  SCIP_IMPLICS* implics, /**< implications data structure */
911  SCIP_Bool varfixing, /**< FALSE if y should be searched in implications for x == 0, TRUE for x == 1 */
912  SCIP_VAR* implvar, /**< variable y to search for */
913  SCIP_BOUNDTYPE impltype /**< type of implication y <=/>= b to search for */
914  )
915 {
916  int poslower;
917  int posupper;
918  int posadd;
919 
920  return implicsSearchImplic(implics, varfixing, implvar, impltype, &poslower, &posupper, &posadd);
921 }
922 
923 
924 
925 
926 /*
927  * methods for cliques
928  */
929 
930 /* swaps cliques at positions first and second in cliques array of clique table */
931 static
933  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
934  int first, /**< first index */
935  int second /**< second index */
936  )
937 {
938  /* nothing to do if clique happens to be at the pole position of clean cliques */
939  if( first != second )
940  {
941  SCIP_CLIQUE* tmp;
942 
943  tmp = cliquetable->cliques[first];
944  assert(tmp->index == first);
945  assert(cliquetable->cliques[second]->index == second);
946 
947  cliquetable->cliques[first] = cliquetable->cliques[second];
948  cliquetable->cliques[second] = tmp;
949 
950  /* change the indices accordingly */
951  tmp->index = second;
952  cliquetable->cliques[first]->index = first;
953  }
954 }
955 
956 /* moves clique to the last position of currently dirty cliques */
957 static
959  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
960  SCIP_CLIQUE* clique /**< clique data structure */
961  )
962 {
963  assert(cliquetable->ndirtycliques <= clique->index);
964  assert(cliquetable->cliques[clique->index] == clique);
965  assert(cliquetable->ndirtycliques < cliquetable->ncliques);
966  assert(SCIPcliqueIsCleanedUp(cliquetable->cliques[cliquetable->ndirtycliques]));
967 
968  /* nothing to do if clique happens to be at the pole position of clean cliques */
969  if( clique->index > cliquetable->ndirtycliques )
970  {
971  cliquetableSwapCliques(cliquetable, clique->index, cliquetable->ndirtycliques);
972  }
973 
974  ++cliquetable->ndirtycliques;
975 }
976 
977 
978 /** creates a clique data structure with already created variables and values arrays in the size of 'size' */
979 static
981  SCIP_CLIQUE** clique, /**< pointer to store clique data structure */
982  BMS_BLKMEM* blkmem, /**< block memory */
983  int size, /**< initial size of clique */
984  SCIP_VAR** vars, /**< binary variables in the clique: at most one can be set to the given
985  * value */
986  SCIP_Bool* values, /**< values of the variables in the clique */
987  int nvars, /**< number of variables in the clique */
988  int id, /**< unique identifier of the clique */
989  SCIP_Bool isequation /**< is the clique an equation or an inequality? */
990  )
991 {
992  assert(clique != NULL);
993  assert(blkmem != NULL);
994  assert(size >= nvars && nvars > 0);
995  assert(vars != NULL);
996  assert(values != NULL);
997 
998  SCIP_ALLOC( BMSallocBlockMemory(blkmem, clique) );
999  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*clique)->vars, vars, size) );
1000  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &(*clique)->values, values, size) );
1001  (*clique)->nvars = nvars;
1002  (*clique)->size = size;
1003  (*clique)->startcleanup = -1;
1004  (*clique)->id = (unsigned int)id;
1005  (*clique)->eventsissued = FALSE;
1006  (*clique)->equation = isequation;
1007  (*clique)->index = -1;
1008 
1009  return SCIP_OKAY;
1010 }
1011 
1012 /** frees a clique data structure */
1013 static
1015  SCIP_CLIQUE** clique, /**< pointer to store clique data structure */
1016  BMS_BLKMEM* blkmem /**< block memory */
1017  )
1018 {
1019  assert(clique != NULL);
1020 
1021  if( *clique != NULL )
1022  {
1023  BMSfreeBlockMemoryArrayNull(blkmem, &(*clique)->vars, (*clique)->size);
1024  BMSfreeBlockMemoryArrayNull(blkmem, &(*clique)->values, (*clique)->size);
1025  BMSfreeBlockMemory(blkmem, clique);
1026  }
1027 }
1028 
1029 /** ensures, that clique arrays can store at least num entries */
1030 static
1032  SCIP_CLIQUE* clique, /**< clique data structure */
1033  BMS_BLKMEM* blkmem, /**< block memory */
1034  SCIP_SET* set, /**< global SCIP settings */
1035  int num /**< minimum number of entries to store */
1036  )
1037 {
1038  assert(clique != NULL);
1039 
1040  if( num > clique->size )
1041  {
1042  int newsize;
1043 
1044  newsize = SCIPsetCalcMemGrowSize(set, num);
1045  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &clique->vars, clique->size, newsize) );
1046  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &clique->values, clique->size, newsize) );
1047  clique->size = newsize;
1048  }
1049  assert(num <= clique->size);
1050 
1051  return SCIP_OKAY;
1052 }
1053 
1054 /** returns the position of the given variable/value pair in the clique; returns -1 if variable/value pair is not member
1055  * of the clique
1056  */
1058  SCIP_CLIQUE* clique, /**< clique data structure */
1059  SCIP_VAR* var, /**< variable to search for */
1060  SCIP_Bool value /**< value of the variable in the clique */
1061  )
1062 {
1063  int varidx;
1064  int left;
1065  int right;
1066 
1067  assert(clique != NULL);
1068 
1069  varidx = SCIPvarGetIndex(var);
1070  left = -1;
1071  right = clique->nvars;
1072  while( left < right-1 )
1073  {
1074  int middle;
1075  int idx;
1076 
1077  middle = (left+right)/2;
1078  idx = SCIPvarGetIndex(clique->vars[middle]);
1079  assert(idx >= 0);
1080  if( varidx < idx )
1081  right = middle;
1082  else if( varidx > idx )
1083  left = middle;
1084  else
1085  {
1086  assert(var == clique->vars[middle]);
1087 
1088  /* now watch out for the correct value */
1089  if( clique->values[middle] < value )
1090  {
1091  int i;
1092  for( i = middle+1; i < clique->nvars && clique->vars[i] == var; ++i )
1093  {
1094  if( clique->values[i] == value )
1095  return i;
1096  }
1097  return -1;
1098  }
1099  if( clique->values[middle] > value )
1100  {
1101  int i;
1102  for( i = middle-1; i >= 0 && clique->vars[i] == var; --i )
1103  {
1104  if( clique->values[i] == value )
1105  return i;
1106  }
1107  return -1;
1108  }
1109  return middle;
1110  }
1111  }
1112 
1113  return -1;
1114 }
1115 
1116 /** returns whether the given variable/value pair is member of the given clique */
1118  SCIP_CLIQUE* clique, /**< clique data structure */
1119  SCIP_VAR* var, /**< variable to remove from the clique */
1120  SCIP_Bool value /**< value of the variable in the clique */
1121  )
1122 {
1123  return (SCIPcliqueSearchVar(clique, var, value) >= 0);
1124 }
1125 
1126 /** adds a single variable to the given clique */
1128  SCIP_CLIQUE* clique, /**< clique data structure */
1129  BMS_BLKMEM* blkmem, /**< block memory */
1130  SCIP_SET* set, /**< global SCIP settings */
1131  SCIP_VAR* var, /**< variable to add to the clique */
1132  SCIP_Bool value, /**< value of the variable in the clique */
1133  SCIP_Bool* doubleentry, /**< pointer to store whether the variable and value occurs twice in the clique */
1134  SCIP_Bool* oppositeentry /**< pointer to store whether the variable with opposite value is in the clique */
1135  )
1136 {
1137  int pos;
1138  int i;
1139 
1140  assert(clique != NULL);
1142  assert(SCIPvarIsBinary(var));
1143  assert(doubleentry != NULL);
1144  assert(oppositeentry != NULL);
1145 
1146  SCIPsetDebugMsg(set, "adding variable <%s> == %u to clique %u\n", SCIPvarGetName(var), value, clique->id);
1147 
1148  *doubleentry = FALSE;
1149  *oppositeentry = FALSE;
1150 
1151  /* allocate memory */
1152  SCIP_CALL( cliqueEnsureSize(clique, blkmem, set, clique->nvars+1) );
1153 
1154  /* search for insertion position by binary variable, note that first the entries are order after variable index and
1155  * second after the bool value of the corresponding variable
1156  */
1157  (void) SCIPsortedvecFindPtr((void**) clique->vars, SCIPvarComp, var, clique->nvars, &pos);
1158 
1159  assert(pos >= 0 && pos <= clique->nvars);
1160  /* remember insertion position for later, pos might change */
1161  i = pos;
1162 
1163  if( pos < clique->nvars )
1164  {
1165  const int amount = clique->nvars - pos;
1166 
1167  /* moving elements to correct position */
1168  BMSmoveMemoryArray(&(clique->vars[pos+1]), &(clique->vars[pos]), amount); /*lint !e866*/
1169  BMSmoveMemoryArray(&(clique->values[pos+1]), &(clique->values[pos]), amount); /*lint !e866*/
1170  clique->nvars++;
1171 
1172  /* insertion for a variable with cliquevalue FALSE */
1173  if( !value )
1174  {
1175  /* find last entry with the same variable and value behind the insertion position */
1176  for( ; pos < clique->nvars - 1 && clique->vars[pos + 1] == var && clique->values[pos + 1] == value; ++pos ); /*lint !e722*/
1177 
1178  /* check if the same variable with other value also exists */
1179  if( pos < clique->nvars - 1 && clique->vars[pos + 1] == var )
1180  {
1181  assert(clique->values[pos + 1] != value);
1182  *oppositeentry = TRUE;
1183  }
1184 
1185  /* check if we found the same variable with the same value more than once */
1186  if( pos != i )
1187  *doubleentry = TRUE;
1188  else
1189  {
1190  /* find last entry with the same variable and different value before the insertion position */
1191  for( ; pos > 0 && clique->vars[pos - 1] == var && clique->values[pos - 1] != value; --pos ); /*lint !e722*/
1192 
1193  /* check if we found the same variable with the same value more than once */
1194  if( pos > 0 && clique->vars[pos - 1] == var )
1195  {
1196  assert(clique->values[pos - 1] == value);
1197 
1198  *doubleentry = TRUE;
1199  }
1200  /* if we found the same variable with different value, we need to order them correctly */
1201  if( pos != i )
1202  {
1203  assert(clique->vars[pos] == var);
1204  assert(clique->values[pos] != value);
1205 
1206  clique->values[pos] = value;
1207  value = !value;
1208  }
1209  }
1210  }
1211  /* insertion for a variable with cliquevalue TRUE */
1212  else
1213  {
1214  /* find last entry with the same variable and different value behind the insertion position */
1215  for( ; pos < clique->nvars - 1 && clique->vars[pos + 1] == var && clique->values[pos + 1] != value; ++pos ); /*lint !e722*/
1216 
1217  /* check if the same variable with other value also exists */
1218  if( pos < clique->nvars - 1 && clique->vars[pos + 1] == var )
1219  {
1220  assert(clique->values[pos + 1] == value);
1221  *doubleentry = TRUE;
1222  }
1223 
1224  /* check if we found the same variable with different value */
1225  if( pos != i )
1226  {
1227  *oppositeentry = TRUE;
1228 
1229  /* if we found the same variable with different value, we need to order them correctly */
1230  assert(clique->vars[pos] == var);
1231  assert(clique->values[pos] != value);
1232 
1233  clique->values[pos] = value;
1234  value = !value;
1235  }
1236  else
1237  {
1238  /* find last entry with the same variable and value before the insertion position */
1239  for( ; pos > 0 && clique->vars[pos - 1] == var && clique->values[pos - 1] == value; --pos ); /*lint !e722*/
1240 
1241  if( pos != i )
1242  *doubleentry = TRUE;
1243 
1244  /* check if we found the same variable with different value up front */
1245  if( pos > 0 && clique->vars[pos - 1] == var && clique->values[pos - 1] != value )
1246  *oppositeentry = TRUE;
1247  }
1248  }
1249  }
1250  else
1251  clique->nvars++;
1252 
1253  clique->vars[i] = var;
1254  clique->values[i] = value;
1255  clique->eventsissued = FALSE;
1256 
1257  return SCIP_OKAY;
1258 }
1259 
1260 /** removes a single variable from the given clique */
1262  SCIP_CLIQUE* clique, /**< clique data structure */
1263  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
1264  SCIP_VAR* var, /**< variable to remove from the clique */
1265  SCIP_Bool value /**< value of the variable in the clique */
1266  )
1267 {
1268  int pos;
1269 
1270  assert(clique != NULL);
1271  assert(SCIPvarIsBinary(var));
1272  assert(cliquetable != NULL);
1273 
1274  /* if the clique is the leading clique during the cleanup step, we do not need to insert it again */
1275  if( cliquetable->incleanup && clique->index == 0 )
1276  return;
1277 
1278  SCIPdebugMessage("marking variable <%s> == %u from clique %u for deletion\n", SCIPvarGetName(var), value, clique->id);
1279 
1280  /* find variable in clique */
1281  pos = SCIPcliqueSearchVar(clique, var, value);
1282 
1283  assert(0 <= pos && pos < clique->nvars);
1284  assert(clique->vars[pos] == var);
1285  assert(clique->values[pos] == value);
1286 
1287  /* inform the clique table that this clique should be cleaned up */
1288  if( clique->startcleanup == -1 )
1289  cliquetableMarkCliqueForCleanup(cliquetable, clique);
1290 
1291  if( clique->startcleanup == -1 || pos < clique->startcleanup )
1292  clique->startcleanup = pos;
1293 
1294 #ifdef SCIP_MORE_DEBUG
1295  {
1296  int v;
1297  /* all variables prior to the one marked for startcleanup should be unfixed */
1298  for( v = clique->startcleanup - 1; v >= 0; --v )
1299  {
1300  assert(SCIPvarGetUbGlobal(clique->vars[v]) > 0.5);
1301  assert(SCIPvarGetLbGlobal(clique->vars[v]) < 0.5);
1302  }
1303  }
1304 #endif
1305 }
1306 
1307 /** gets the position of the given clique in the cliques array; returns -1 if clique is not member of cliques array */
1308 static
1310  SCIP_CLIQUE** cliques, /**< array of cliques */
1311  int ncliques, /**< number of cliques in the cliques array */
1312  SCIP_CLIQUE* clique /**< clique to search for */
1313  )
1314 {
1315  unsigned int cliqueid;
1316  int left;
1317  int right;
1318 
1319  assert(cliques != NULL || ncliques == 0);
1320  assert(clique != NULL);
1321 
1322  cliqueid = clique->id; /*lint !e732*/
1323  left = -1;
1324  right = ncliques;
1325  while( left < right-1 )
1326  {
1327  unsigned int id;
1328  int middle;
1329 
1330  assert(cliques != NULL);
1331  middle = (left+right)/2;
1332  id = cliques[middle]->id; /*lint !e732*/
1333  if( cliqueid < id )
1334  right = middle;
1335  else if( cliqueid > id )
1336  left = middle;
1337  else
1338  {
1339  assert(clique == cliques[middle]);
1340  return middle;
1341  }
1342  }
1343 
1344  return -1;
1345 }
1346 
1347 #ifdef SCIP_MORE_DEBUG
1348 /** checks whether clique appears in all clique lists of the involved variables */
1349 static
1350 void cliqueCheck(
1351  SCIP_CLIQUE* clique /**< clique data structure */
1352  )
1353 {
1354  int i;
1355 
1356  assert(clique != NULL);
1357 
1358  for( i = 0; i < clique->nvars; ++i )
1359  {
1360  SCIP_CLIQUE** cliques;
1361  int ncliques;
1362  int pos;
1363  SCIP_VAR* var;
1364 
1365  var = clique->vars[i];
1366  assert(i == 0 || SCIPvarGetIndex(clique->vars[i-1]) <= SCIPvarGetIndex(var));
1367  assert(i == 0 || clique->vars[i-1] != var || clique->values[i-1] <= clique->values[i]);
1368  ncliques = SCIPvarGetNCliques(var, clique->values[i]);
1369 
1370  assert(SCIPvarIsActive(var) || ncliques == 0);
1371 
1372  /* cliquelist of inactive variables are already destroyed */
1373  if( ncliques == 0 )
1374  continue;
1375 
1376  cliques = SCIPvarGetCliques(var, clique->values[i]);
1377  pos = cliquesSearchClique(cliques, ncliques, clique);
1378 
1379  /* assert that the clique is correctly listed in all clique lists of unfixed variables. For fixed variables,
1380  * we require that a clean up has been correctly scheduled, but not yet been processed
1381  */
1382  if( SCIPvarGetUbGlobal(var) - SCIPvarGetLbGlobal(var) > 0.5 )
1383  {
1384  assert(0 <= pos && pos < ncliques);
1385  assert(cliques[pos] == clique);
1386  }
1387  else
1388  assert(0 <= clique->startcleanup && clique->startcleanup <= i);
1389  }
1390  assert(clique->index >= 0);
1391 }
1392 #else
1393 #define cliqueCheck(clique) /**/
1394 #endif
1395 
1396 /** creates a clique list data structure */
1397 static
1399  SCIP_CLIQUELIST** cliquelist, /**< pointer to store clique list data structure */
1400  BMS_BLKMEM* blkmem /**< block memory */
1401  )
1402 {
1403  assert(cliquelist != NULL);
1404 
1405  SCIP_ALLOC( BMSallocBlockMemory(blkmem, cliquelist) );
1406  (*cliquelist)->cliques[0] = NULL;
1407  (*cliquelist)->cliques[1] = NULL;
1408  (*cliquelist)->ncliques[0] = 0;
1409  (*cliquelist)->ncliques[1] = 0;
1410  (*cliquelist)->size[0] = 0;
1411  (*cliquelist)->size[1] = 0;
1412 
1413  return SCIP_OKAY;
1414 }
1415 
1416 /** frees a clique list data structure */
1418  SCIP_CLIQUELIST** cliquelist, /**< pointer to the clique list data structure */
1419  BMS_BLKMEM* blkmem /**< block memory */
1420  )
1421 {
1422  assert(cliquelist != NULL);
1423 
1424  if( *cliquelist != NULL )
1425  {
1426  BMSfreeBlockMemoryArrayNull(blkmem, &(*cliquelist)->cliques[0], (*cliquelist)->size[0]);
1427  BMSfreeBlockMemoryArrayNull(blkmem, &(*cliquelist)->cliques[1], (*cliquelist)->size[1]);
1428  BMSfreeBlockMemory(blkmem, cliquelist);
1429  }
1430 }
1431 
1432 /** ensures, that clique list arrays can store at least num entries */
1433 static
1435  SCIP_CLIQUELIST* cliquelist, /**< clique list data structure */
1436  BMS_BLKMEM* blkmem, /**< block memory */
1437  SCIP_SET* set, /**< global SCIP settings */
1438  SCIP_Bool value, /**< value of the variable for which the clique list should be extended */
1439  int num /**< minimum number of entries to store */
1440  )
1441 {
1442  assert(cliquelist != NULL);
1443 
1444  if( num > cliquelist->size[value] )
1445  {
1446  int newsize;
1447 
1448  newsize = SCIPsetCalcMemGrowSize(set, num);
1449  SCIP_ALLOC( BMSreallocBlockMemoryArray(blkmem, &cliquelist->cliques[value], cliquelist->size[value], newsize) ); /*lint !e866*/
1450  cliquelist->size[value] = newsize;
1451  }
1452  assert(num <= cliquelist->size[value]);
1453 
1454  return SCIP_OKAY;
1455 }
1456 
1457 /** adds a clique to the clique list */
1459  SCIP_CLIQUELIST** cliquelist, /**< pointer to the clique list data structure */
1460  BMS_BLKMEM* blkmem, /**< block memory */
1461  SCIP_SET* set, /**< global SCIP settings */
1462  SCIP_Bool value, /**< value of the variable for which the clique list should be extended */
1463  SCIP_CLIQUE* clique /**< clique that should be added to the clique list */
1464  )
1465 {
1466  unsigned int id;
1467  int i = 0;
1468 
1469  assert(cliquelist != NULL);
1470 
1471  /* insert clique into list, sorted by clique id */
1472  id = clique->id; /*lint !e732*/
1473 
1474  /* allocate memory */
1475  if( *cliquelist == NULL )
1476  {
1477  SCIP_CALL( cliquelistCreate(cliquelist, blkmem) );
1478  }
1479  else
1480  {
1481  if( (*cliquelist)->cliques[value] != NULL )
1482  {
1483  for( i = (*cliquelist)->ncliques[value]; i > 0 && (*cliquelist)->cliques[value][i - 1]->id > id; --i ); /*lint !e574 !e722*/
1484  /* do not put the same clique twice in the cliquelist */
1485  if( i > 0 && (*cliquelist)->cliques[value][i - 1]->id == id )
1486  return SCIP_OKAY;
1487  }
1488  }
1489  SCIP_CALL( cliquelistEnsureSize(*cliquelist, blkmem, set, value, (*cliquelist)->ncliques[value] + 1) );
1490 
1491  SCIPsetDebugMsg(set, "adding clique %u to cliquelist %p value %u (length: %d)\n",
1492  clique->id, (void*)*cliquelist, value, (*cliquelist)->ncliques[value]);
1493 
1494  BMSmoveMemoryArray(&((*cliquelist)->cliques[value][i+1]), &((*cliquelist)->cliques[value][i]), (*cliquelist)->ncliques[value] - i); /*lint !e866*/
1495 
1496  (*cliquelist)->cliques[value][i] = clique;
1497  (*cliquelist)->ncliques[value]++;
1498 
1499  return SCIP_OKAY;
1500 }
1501 
1502 /** removes a clique from the clique list */
1504  SCIP_CLIQUELIST** cliquelist, /**< pointer to the clique list data structure */
1505  BMS_BLKMEM* blkmem, /**< block memory */
1506  SCIP_Bool value, /**< value of the variable for which the clique list should be reduced */
1507  SCIP_CLIQUE* clique /**< clique that should be deleted from the clique list */
1508  )
1509 {
1510  int pos;
1511 
1512  assert(cliquelist != NULL);
1513 
1514  /* if a variable appeared twice in its last clique and is now removed both times, the cliquelist is already cleaned
1515  up after the first removal call of this "doubleton" */
1516  if( *cliquelist == NULL )
1517  return SCIP_OKAY;
1518 
1519  SCIPdebugMessage("deleting clique %u from cliquelist %p value %u (length: %d)\n",
1520  clique->id, (void*)*cliquelist, value, (*cliquelist)->ncliques[value]);
1521 
1522  pos = cliquesSearchClique((*cliquelist)->cliques[value], (*cliquelist)->ncliques[value], clique);
1523 
1524  /* clique does not exist in cliquelist, the clique should contain multiple entries of the same variable */
1525  if( pos < 0 )
1526  {
1527 #ifdef SCIP_MORE_DEBUG
1528  SCIP_VAR** clqvars;
1529  SCIP_Bool* clqvalues;
1530  int nclqvars = SCIPcliqueGetNVars(clique);
1531  int v;
1532 
1533  assert(nclqvars >= 2);
1534  assert(SCIPcliqueGetVars(clique) != NULL);
1535  assert(SCIPcliqueGetValues(clique) != NULL);
1536 
1537  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &clqvars, SCIPcliqueGetVars(clique), nclqvars) );
1538  SCIP_ALLOC( BMSduplicateBlockMemoryArray(blkmem, &clqvalues, SCIPcliqueGetValues(clique), nclqvars) );
1539 
1540  /* sort variables and corresponding clique values after variables indices */
1541  SCIPsortPtrBool((void**) clqvars, clqvalues, SCIPvarComp, nclqvars);
1542 
1543  for( v = nclqvars - 1; v > 0; --v )
1544  {
1545  if( clqvars[v] == clqvars[v - 1] )
1546  {
1547  if( clqvalues[v] == clqvalues[v - 1] || (v > 1 && clqvars[v] == clqvars[v - 2]) )
1548  break;
1549  }
1550  }
1551  assert(v > 0);
1552 
1553  BMSfreeBlockMemoryArray(blkmem, &clqvalues, nclqvars);
1554  BMSfreeBlockMemoryArray(blkmem, &clqvars, nclqvars);
1555 #endif
1556  return SCIP_OKAY;
1557  }
1558 
1559  assert(0 <= pos && pos < (*cliquelist)->ncliques[value]);
1560  assert((*cliquelist)->cliques[value][pos] == clique);
1561 
1562  /* remove clique from list */
1563  /* @todo maybe buffered deletion */
1564  (*cliquelist)->ncliques[value]--;
1565  if( pos < (*cliquelist)->ncliques[value] )
1566  {
1567  BMSmoveMemoryArray(&((*cliquelist)->cliques[value][pos]), &((*cliquelist)->cliques[value][pos+1]),
1568  (*cliquelist)->ncliques[value] - pos); /*lint !e866*/
1569  }
1570 
1571  /* free cliquelist if it is empty */
1572  if( (*cliquelist)->ncliques[0] == 0 && (*cliquelist)->ncliques[1] == 0 )
1573  SCIPcliquelistFree(cliquelist, blkmem);
1574 
1575  return SCIP_OKAY;
1576 }
1577 
1578 /** returns whether the given clique lists have a non-empty intersection, i.e. whether there is a clique that appears
1579  * in both lists
1580  */
1582  SCIP_CLIQUELIST* cliquelist1, /**< first clique list data structure */
1583  SCIP_Bool value1, /**< value of first variable */
1584  SCIP_CLIQUELIST* cliquelist2, /**< second clique list data structure */
1585  SCIP_Bool value2 /**< value of second variable */
1586  )
1587 {
1588  SCIP_CLIQUE** cliques1;
1589  SCIP_CLIQUE** cliques2;
1590  int ncliques1;
1591  int ncliques2;
1592  int i1;
1593  int i2;
1594 
1595  if( cliquelist1 == NULL || cliquelist2 == NULL )
1596  return FALSE;
1597 
1598  ncliques1 = cliquelist1->ncliques[value1];
1599  cliques1 = cliquelist1->cliques[value1];
1600  ncliques2 = cliquelist2->ncliques[value2];
1601  cliques2 = cliquelist2->cliques[value2];
1602 
1603  i1 = 0;
1604  i2 = 0;
1605 
1606  if( i1 < ncliques1 && i2 < ncliques2 )
1607  {
1608  int cliqueid;
1609 
1610  /* make the bigger clique the first one */
1611  if( ncliques2 > ncliques1 )
1612  {
1613  SCIP_CLIQUE** tmpc;
1614  int tmpi;
1615 
1616  tmpc = cliques1;
1617  tmpi = ncliques1;
1618  cliques1 = cliques2;
1619  ncliques1 = ncliques2;
1620  cliques2 = tmpc;
1621  ncliques2 = tmpi;
1622  }
1623 
1624  /* check whether both clique lists have a same clique */
1625  while( TRUE ) /*lint !e716*/
1626  {
1627  cliqueid = SCIPcliqueGetId(cliques2[i2]);
1628 
1629  /* if last item in clique1 has a smaller index than the actual clique in clique2, than cause of increasing order
1630  * there will be no same item and we can stop */
1631  if( SCIPcliqueGetId(cliques1[ncliques1 - 1]) < cliqueid )
1632  break;
1633 
1634  while( SCIPcliqueGetId(cliques1[i1]) < cliqueid )
1635  {
1636  ++i1;
1637  assert(i1 < ncliques1);
1638  }
1639  cliqueid = SCIPcliqueGetId(cliques1[i1]);
1640 
1641  /* if last item in clique2 has a smaller index than the actual clique in clique1, than cause of increasing order
1642  * there will be no same item and we can stop */
1643  if( SCIPcliqueGetId(cliques2[ncliques2 - 1]) < cliqueid )
1644  break;
1645 
1646  while( SCIPcliqueGetId(cliques2[i2]) < cliqueid )
1647  {
1648  ++i2;
1649  assert(i2 < ncliques2);
1650  }
1651  if( SCIPcliqueGetId(cliques2[i2]) == cliqueid )
1652  return TRUE;
1653  }
1654  }
1655  return FALSE;
1656 }
1657 
1658 /** removes all listed entries from the cliques */
1660  SCIP_CLIQUELIST* cliquelist, /**< clique list data structure */
1661  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
1662  SCIP_VAR* var, /**< active problem variable the clique list belongs to */
1663  SCIP_Bool irrelevantvar /**< has the variable become irrelevant, meaning that equality
1664  * cliques need to be relaxed? */
1665  )
1666 {
1667  assert(SCIPvarIsBinary(var));
1668 
1669  if( cliquelist != NULL )
1670  {
1671  int value;
1672 
1673  SCIPdebugMessage("removing variable <%s> from cliques (%d with value 0, %d with value 1)\n",
1674  SCIPvarGetName(var), cliquelist->ncliques[0], cliquelist->ncliques[1]);
1675 
1676  for( value = 0; value < 2; ++value )
1677  {
1678  int i;
1679 
1680  assert(SCIPvarGetCliques(var, (SCIP_Bool)value) == cliquelist->cliques[value]);
1681  assert(SCIPvarGetNCliques(var, (SCIP_Bool)value) == cliquelist->ncliques[value]);
1682 
1683  /* it is important to iterate from the end of the array because otherwise, each removal causes
1684  * a memory move of the entire array
1685  */
1686  for( i = cliquelist->ncliques[value] - 1; i >= 0; --i )
1687  {
1688  SCIP_CLIQUE* clique;
1689 
1690  clique = cliquelist->cliques[value][i];
1691  assert(clique != NULL);
1692 
1693  SCIPdebugMessage(" -> removing variable <%s> == %d from clique %u (size %d)\n",
1694  SCIPvarGetName(var), value, clique->id, clique->nvars);
1695 
1696  SCIPcliqueDelVar(clique, cliquetable, var, (SCIP_Bool)value);
1697 
1698  if( irrelevantvar )
1699  clique->equation = FALSE;
1700 
1701 #ifdef SCIP_MORE_DEBUG
1702  /* during the cleanup step, we skip the consistency check because clique may be temporarily inconsistent */
1703  if( ! cliquetable->incleanup || clique->index > 0 )
1704  {
1705  cliqueCheck(clique);
1706  }
1707 #endif
1708  }
1709  }
1710  }
1711 }
1712 
1713 /** gets the key of the given element */
1714 static
1715 SCIP_DECL_HASHGETKEY(hashgetkeyClique)
1716 { /*lint --e{715}*/
1717  return elem;
1718 }
1719 
1720 /** returns TRUE iff both keys are equal */
1721 static
1722 SCIP_DECL_HASHKEYEQ(hashkeyeqClique)
1723 { /*lint --e{715}*/
1724  SCIP_CLIQUE* clique1;
1725  SCIP_CLIQUE* clique2;
1726  int i;
1727 
1728  clique1 = (SCIP_CLIQUE*)key1;
1729  clique2 = (SCIP_CLIQUE*)key2;
1730  assert(clique1 != NULL);
1731  assert(clique2 != NULL);
1732 
1733  if( clique1->nvars != clique2->nvars )
1734  return FALSE;
1735 
1736  /* the variables are sorted: we can simply check the equality of each pair of variable/values */
1737  for( i = 0; i < clique1->nvars; ++i )
1738  {
1739  if( clique1->vars[i] != clique2->vars[i] || clique1->values[i] != clique2->values[i] )
1740  return FALSE;
1741  }
1742 
1743  return TRUE;
1744 }
1745 
1746 /** returns the hash value of the key */
1747 static
1748 SCIP_DECL_HASHKEYVAL(hashkeyvalClique)
1749 { /*lint --e{715}*/
1750  SCIP_CLIQUE* clique;
1751 
1752  clique = (SCIP_CLIQUE*)key;
1753 
1754  return clique->nvars == 0 ? 0 : SCIPhashTwo(SCIPcombineTwoInt(SCIPvarGetIndex(clique->vars[0]), \
1755  SCIPvarGetIndex(clique->vars[clique->nvars-1])), \
1756  SCIPcombineThreeInt(clique->nvars, \
1757  clique->values[0], \
1758  clique->values[clique->nvars-1]));
1759 }
1760 
1761 #define HASHTABLE_CLIQUETABLE_SIZE 100
1762 
1763 /** creates a clique table data structure */
1765  SCIP_CLIQUETABLE** cliquetable, /**< pointer to store clique table data structure */
1766  SCIP_SET* set, /**< global SCIP settings */
1767  BMS_BLKMEM* blkmem /**< block memory */
1768  )
1769 {
1770  int hashtablesize;
1771 
1772  assert(cliquetable != NULL);
1773 
1774  SCIP_ALLOC( BMSallocMemory(cliquetable) );
1775 
1776  /* create hash table to test for multiple cliques */
1777  hashtablesize = HASHTABLE_CLIQUETABLE_SIZE;
1778  hashtablesize = MAX(hashtablesize, (set->misc_usesmalltables ? SCIP_HASHSIZE_CLIQUES_SMALL : SCIP_HASHSIZE_CLIQUES));
1779  SCIP_CALL( SCIPhashtableCreate(&((*cliquetable)->hashtable), blkmem, hashtablesize,
1780  hashgetkeyClique, hashkeyeqClique, hashkeyvalClique, NULL) );
1781 
1782  (*cliquetable)->cliques = NULL;
1783  (*cliquetable)->ncliques = 0;
1784  (*cliquetable)->size = 0;
1785  (*cliquetable)->ncreatedcliques = 0;
1786  (*cliquetable)->ncleanupfixedvars = 0;
1787  (*cliquetable)->ncleanupaggrvars = 0;
1788  (*cliquetable)->ndirtycliques = 0;
1789  (*cliquetable)->nentries = 0;
1790  (*cliquetable)->incleanup = FALSE;
1791  (*cliquetable)->componentupdate = FALSE;
1792  (*cliquetable)->ncliquecomponents = -1;
1793 
1794  return SCIP_OKAY;
1795 }
1796 
1797 /** frees a clique table data structure */
1799  SCIP_CLIQUETABLE** cliquetable, /**< pointer to store clique table data structure */
1800  BMS_BLKMEM* blkmem /**< block memory */
1801  )
1802 {
1803  int i;
1804 
1805  assert(cliquetable != NULL);
1806  assert(*cliquetable != NULL);
1807 
1808  /* free all cliques */
1809  for( i = (*cliquetable)->ncliques - 1; i >= 0; --i )
1810  {
1811  cliqueFree(&(*cliquetable)->cliques[i], blkmem);
1812  }
1813 
1814  /* free clique table data */
1815  BMSfreeMemoryArrayNull(&(*cliquetable)->cliques);
1816 
1817  /* free hash table */
1818  SCIPhashtableFree(&((*cliquetable)->hashtable));
1819 
1820  BMSfreeMemory(cliquetable);
1821 
1822  return SCIP_OKAY;
1823 }
1824 
1825 /** ensures, that clique table arrays can store at least num entries */
1826 static
1828  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
1829  SCIP_SET* set, /**< global SCIP settings */
1830  int num /**< minimum number of entries to store */
1831  )
1832 {
1833  assert(cliquetable != NULL);
1834 
1835  if( num > cliquetable->size )
1836  {
1837  int newsize;
1838 
1839  newsize = SCIPsetCalcMemGrowSize(set, num);
1840  SCIP_ALLOC( BMSreallocMemoryArray(&cliquetable->cliques, newsize) );
1841  cliquetable->size = newsize;
1842  }
1843  assert(num <= cliquetable->size);
1844 
1845  return SCIP_OKAY;
1846 }
1847 
1848 /** sort variables regarding their index and remove multiple entries of the same variable */
1849 static
1851  SCIP_VAR** clqvars, /**< variables of a clique */
1852  SCIP_Bool* clqvalues, /**< clique values, active or negated, for the variables in a clique */
1853  int* nclqvars, /**< number of clique variables */
1854  SCIP_Bool* isequation, /**< do we have an equation clique at hand? */
1855  SCIP_CLIQUE* clique, /**< clique data structure or NULL */
1856  BMS_BLKMEM* blkmem, /**< block memory */
1857  SCIP_SET* set, /**< global SCIP settings */
1858  SCIP_STAT* stat, /**< problem statistics */
1859  SCIP_PROB* transprob, /**< transformed problem */
1860  SCIP_PROB* origprob, /**< original problem */
1861  SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
1862  SCIP_REOPT* reopt, /**< reoptimization data structure */
1863  SCIP_LP* lp, /**< current LP data */
1864  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
1865  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
1866  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
1867  int* nbdchgs, /**< pointer to store number of fixed variables */
1868  SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
1869  )
1870 {
1871  SCIP_VAR* var;
1872  int noldbdchgs;
1873  int startidx;
1874 
1875  assert(nclqvars != NULL);
1876 
1877  SCIPsetDebugMsg(set, "starting merging %d variables in clique %d\n", *nclqvars, (clique == NULL) ? -1 : (int) clique->id);
1878 
1879  if( *nclqvars <= 1 )
1880  return SCIP_OKAY;
1881 
1882  assert(clqvars != NULL);
1883  assert(clqvalues != NULL);
1884  assert(blkmem != NULL);
1885  assert(set != NULL);
1886  assert(stat != NULL);
1887  assert(transprob != NULL);
1888  assert(origprob != NULL);
1889  assert(tree != NULL);
1890  assert(eventqueue != NULL);
1891  assert(nbdchgs != NULL);
1892  assert(infeasible != NULL);
1893 
1894  /* sort variables and corresponding clique values regarding variables indices before merging multiples */
1895  SCIPsortPtrBool((void**) clqvars, clqvalues, SCIPvarComp, *nclqvars);
1896 
1897  var = NULL;
1898  noldbdchgs = *nbdchgs;
1899  /* check for multiple occurences or pairs of negations in the variable array, this should be very rare when creating a
1900  * new clique */
1901  startidx = *nclqvars - 1;
1902  while( startidx >= 0 )
1903  {
1904  int nones;
1905  int nzeros;
1906  int curr;
1907 
1908  var = clqvars[startidx];
1909  /* only column and loose variables can exist now */
1911  assert(SCIPvarIsBinary(var));
1912 
1913  /* the counters denote the occurrences of the variable var with value TRUE and FALSE as clqvalues, respectively */
1914  if( clqvalues[startidx] )
1915  {
1916  nones = 1;
1917  nzeros = 0;
1918  }
1919  else
1920  {
1921  nzeros = 1;
1922  nones = 0;
1923  }
1924  curr = startidx - 1;
1925 
1926  /* loop and increase the counter based on the clique value */
1927  while( curr >= 0 )
1928  {
1929  if( clqvars[curr] == var )
1930  {
1931  if( clqvalues[curr] )
1932  nones++;
1933  else
1934  nzeros++;
1935  }
1936  else
1937  /* var is different from variable at index curr */
1938  break;
1939 
1940  --curr;
1941  }
1942  assert(nzeros + nones <= *nclqvars);
1943 
1944  /* single occurrence of the variable */
1945  if( nones + nzeros == 1 )
1946  {
1947  startidx = curr;
1948  continue;
1949  }
1950  /* at least two occurrences of both the variable and its negation; infeasible */
1951  if( nones >= 2 && nzeros >= 2 )
1952  {
1953  *infeasible = TRUE;
1954  break;
1955  }
1956 
1957  /* do we have the same variable with the same clique value twice? */
1958  if( nones >= 2 || nzeros >= 2 )
1959  {
1960  SCIP_Bool fixvalue;
1961 
1962  /* other cases should be handled as infeasible */
1963  assert(nones <= 1 || nzeros <= 1);
1964 
1965  /* ensure that the variable is removed from both clique lists before fixing it */
1966  if( clique != NULL )
1967  {
1968  if( nones >= 1 )
1969  {
1970  SCIP_CALL( SCIPvarDelCliqueFromList(var, blkmem, TRUE, clique) );
1971  }
1972  if( nzeros >= 1 )
1973  {
1974  SCIP_CALL( SCIPvarDelCliqueFromList(var, blkmem, FALSE, clique) );
1975  }
1976  }
1977 
1978  /* we fix the variable into the direction of fewer occurrences */
1979  fixvalue = nones >= 2 ? FALSE : TRUE;
1980 
1981  /* a variable multiple times in one clique forces this variable to be zero */
1982  SCIP_CALL( SCIPvarFixBinary(var, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
1983  cliquetable, fixvalue, infeasible, nbdchgs) );
1984 
1985  SCIPsetDebugMsg(set, "same var %s twice in a clique with value %d fixed to %d (was %s)\n", SCIPvarGetName(var), fixvalue ? 0 : 1,
1986  fixvalue ? 1 : 0, *infeasible ? "infeasible" : "feasible");
1987 
1988  if( *infeasible )
1989  break;
1990  }
1991 
1992  /* do we have a pair of negated variables? */
1993  if( nones >= 1 && nzeros >= 1 )
1994  {
1995  SCIPsetDebugMsg(set, "var %s is paired with its negation in one clique -> fix all other variables\n", SCIPvarGetName(var));
1996 
1997  /* a pair of negated variables in one clique forces all other variables in the clique to be zero */
1998  if( nzeros + nones < *nclqvars )
1999  {
2000  int w;
2001 
2002  w = *nclqvars - 1;
2003  while( w >= 0 )
2004  {
2005  /* skip all occurrences of variable var itself, these are between curr and startidx */
2006  if( w == startidx )
2007  {
2008  if( curr == -1 )
2009  break;
2010 
2011  w = curr;
2012  }
2013  assert(clqvars[w] != var);
2014 
2015  /* if one of the other variables occurs multiple times, we can
2016  * 1) deduce infeasibility if it occurs with different values
2017  * 2) wait for the last occurence to fix it
2018  */
2019  while( w > 0 && clqvars[w-1] == clqvars[w] )
2020  {
2021  if( clqvalues[w-1] != clqvalues[w] )
2022  {
2023  *infeasible = TRUE;
2024  break;
2025  }
2026  --w;
2027  }
2028 
2029  if( *infeasible )
2030  break;
2031 
2032  if( clique != NULL )
2033  {
2034  SCIP_CALL( SCIPvarDelCliqueFromList(clqvars[w], blkmem, clqvalues[w], clique) );
2035  }
2036  SCIP_CALL( SCIPvarFixBinary(clqvars[w], blkmem, set, stat, transprob, origprob, tree, reopt, lp,
2037  branchcand, eventqueue, cliquetable, !clqvalues[w], infeasible, nbdchgs) );
2038 
2039  SCIPsetDebugMsg(set, "fixed var %s with value %u to %d (was %s)\n", SCIPvarGetName(clqvars[w]), clqvalues[w],
2040  clqvalues[w] ? 0 : 1, *infeasible ? "infeasible" : "feasible");
2041 
2042  if( *infeasible )
2043  break;
2044 
2045  --w;
2046  }
2047  }
2048  /* all variables except for var were fixed */
2049  if( clique != NULL )
2050  {
2051  SCIP_CALL( SCIPvarDelCliqueFromList(var, blkmem, TRUE, clique) );
2052  SCIP_CALL( SCIPvarDelCliqueFromList(var, blkmem, FALSE, clique) );
2053  }
2054  *nclqvars = 0;
2055  *isequation = FALSE;
2056 
2057  /* break main loop */
2058  break;
2059  }
2060 
2061  /* otherwise, we would have an endless loop */
2062  assert(curr < startidx);
2063  startidx = curr;
2064  }
2065 
2066 
2067  /* we might have found an infeasibility or reduced the clique to size 0 */
2068  if( *infeasible || *nclqvars == 0 )
2069  return SCIP_OKAY;
2070 
2071  /* we fixed a variable because it appears at least twice, now we need to remove the fixings
2072  *
2073  * @note that if we are in probing or solving stage, the fixation on the variable might not be carried out yet,
2074  * because it was contradicting a local bound
2075  */
2076  if( *nbdchgs > noldbdchgs )
2077  {
2078  SCIP_VAR* onefixedvar;
2079  SCIP_Bool onefixedvalue;
2080  int w;
2081 
2082  /* we initialize the former value only to please gcc */
2083  onefixedvalue = TRUE;
2084  onefixedvar = NULL;
2085 
2086  /* remove all inactive variables, thereby checking for a variable that is fixed to one */
2087  startidx = 0;
2088  w = 0;
2089  while( startidx < *nclqvars )
2090  {
2091  var = clqvars[startidx];
2092 
2095 
2096  /* check if we have a variable fixed to one for this clique */
2097  if( (clqvalues[startidx] && SCIPvarGetLbGlobal(var) > 0.5) || (!clqvalues[startidx] && SCIPvarGetUbGlobal(var) < 0.5) )
2098  {
2099  if( onefixedvar != NULL )
2100  {
2101  *infeasible = TRUE;
2102 
2103  SCIPsetDebugMsg(set, "two variables in clique %d fixed to one %s%s and %s%s\n", (clique != NULL) ? (int) clique->id : -1,
2104  onefixedvalue ? "" : "~", SCIPvarGetName(onefixedvar), clqvalues[startidx] ? "" : "~", SCIPvarGetName(clqvars[startidx]));
2105  return SCIP_OKAY;
2106  }
2107  onefixedvar = var;
2108  onefixedvalue = clqvalues[startidx];
2109  }
2110  /* only keep active variables */
2111  else if( SCIPvarGetLbGlobal(var) < 0.5 && SCIPvarGetUbGlobal(var) > 0.5 )
2112  {
2113  /* we remove all fixed variables */
2114  if( startidx > w )
2115  {
2116  clqvars[w] = clqvars[startidx];
2117  clqvalues[w] = clqvalues[startidx];
2118  }
2119  ++w;
2120  }
2121  else
2122  {
2123  /* can we have some variable fixed to one? */
2124  assert((SCIPvarGetUbGlobal(var) < 0.5 && clqvalues[startidx]) || (SCIPvarGetLbGlobal(var) > 0.5 && !clqvalues[startidx]));
2125 
2126  if( clique != NULL )
2127  {
2128  SCIP_CALL( SCIPvarDelCliqueFromList(var, blkmem, clqvalues[startidx], clique) );
2129  }
2130  }
2131  ++startidx;
2132  }
2133 
2134  /* the clique has been reduced to w active (unfixed) variables */
2135  *nclqvars = w;
2136 
2137  /* in rare cases, a variable fixed to one is only detected in the merging step */
2138  if( onefixedvar != NULL )
2139  {
2140  SCIPsetDebugMsg(set, "variable %s%s in clique %d fixed to one, fixing all other variables to zero\n",
2141  onefixedvalue ? "" : "~", SCIPvarGetName(onefixedvar), (clique != NULL) ? (int) clique->id : -1);
2142 
2143  /* handle all active variables by fixing them */
2144  for( startidx = *nclqvars; startidx >= 0; --startidx )
2145  {
2146  assert(SCIPvarGetStatus(clqvars[startidx]) == SCIP_VARSTATUS_COLUMN
2147  || SCIPvarGetStatus(clqvars[startidx]) == SCIP_VARSTATUS_LOOSE);
2148 
2149  /* delete the variable from its clique lists and fix it */
2150  if( onefixedvalue != clqvalues[startidx] || clqvars[startidx] != onefixedvar )
2151  {
2152  if( clique != NULL )
2153  {
2154  SCIP_CALL( SCIPvarDelCliqueFromList(clqvars[startidx], blkmem, clqvalues[startidx], clique) );
2155  }
2156 
2157  /* if one of the other variables occurs multiple times, we can
2158  * 1) deduce infeasibility if it occurs with different values
2159  * 2) wait for the last occurence to fix it
2160  */
2161  while( startidx > 0 && clqvars[startidx - 1] == clqvars[startidx] )
2162  {
2163  if( clqvalues[startidx - 1] != clqvalues[startidx] )
2164  {
2165  *infeasible = TRUE;
2166  return SCIP_OKAY;
2167  }
2168  --startidx;
2169  }
2170 
2171  SCIPsetDebugMsg(set, "fixing variable %s in clique %d to %d\n", SCIPvarGetName(clqvars[startidx]), (clique != NULL) ? (int) clique->id : -1,
2172  clqvalues[startidx] ? 0 : 1);
2173 
2174  /* note that the variable status will remain unchanged */
2175  SCIP_CALL( SCIPvarFixBinary(clqvars[startidx], blkmem, set, stat, transprob, origprob, tree, reopt, lp,
2176  branchcand, eventqueue, cliquetable, !clqvalues[startidx], infeasible, nbdchgs) );
2177 
2178  if( *infeasible )
2179  return SCIP_OKAY;
2180  }
2181  }
2182 
2183  /* delete clique from onefixedvars clique list */
2184  if( clique != NULL ) /*lint !e850*/
2185  {
2186  SCIP_CALL( SCIPvarDelCliqueFromList(onefixedvar, blkmem, onefixedvalue, clique) );
2187  }
2188 
2189  *nclqvars = 0;
2190  *isequation = FALSE;
2191  }
2192  }
2193 
2194  assert(!(*infeasible));
2195 
2196  if( *isequation )
2197  {
2198  if( *nclqvars == 0 )
2199  {
2200  SCIPsetDebugMsg(set, "empty equation clique left over -> infeasible\n");
2201 
2202  *infeasible = TRUE;
2203  }
2204  else if( *nclqvars == 1 )
2205  {
2206  assert(SCIPvarGetStatus(clqvars[0]) == SCIP_VARSTATUS_COLUMN
2207  || SCIPvarGetStatus(clqvars[0]) == SCIP_VARSTATUS_LOOSE);
2208  /* clearing data and removing variable from its clique list */
2209  if( clique != NULL )
2210  {
2211  SCIP_CALL( SCIPvarDelCliqueFromList(clqvars[0], blkmem, clqvalues[0], clique) );
2212  }
2213  SCIP_CALL( SCIPvarFixBinary(clqvars[0], blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
2214  eventqueue, cliquetable, clqvalues[0], infeasible, nbdchgs) );
2215 
2216  SCIPsetDebugMsg(set, "fixed last clique var %s with value %u to %d (was %s)\n", SCIPvarGetName(clqvars[0]), clqvalues[0],
2217  clqvalues[0] ? 1 : 0, *infeasible ? "infeasible" : "feasible");
2218 
2219  *nclqvars = 0;
2220  *isequation = FALSE;
2221  }
2222  }
2223 
2224  return SCIP_OKAY;
2225 }
2226 
2227 /** checks if current connected components information will get outdated after adding this new clique */
2228 static
2230  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
2231  SCIP_CLIQUE* clique /**< clique that should be added */
2232  )
2233 {
2234  int i;
2235  assert(cliquetable != NULL);
2236  assert(clique != NULL);
2237 
2238  /* check if last variable was a single component so far */
2239  if( SCIPvarGetCliqueComponentIdx(clique->vars[clique->nvars - 1]) == -1 )
2240  {
2241  cliquetable->componentupdate = TRUE;
2242  return;
2243  }
2244 
2245  /* check if this clique connects two previously disconnected components of the clique graph */
2246  for( i = 0; i < clique->nvars - 1 && !cliquetable->componentupdate; ++i )
2247  {
2248  if( SCIPvarGetCliqueComponentIdx(clique->vars[i]) == -1 ||
2249  SCIPvarGetCliqueComponentIdx(clique->vars[i]) != SCIPvarGetCliqueComponentIdx(clique->vars[i + 1]) )
2250  {
2251  cliquetable->componentupdate = TRUE;
2252  break;
2253  }
2254  }
2255 }
2256 
2257 /** adds a clique to the clique table, using the given values for the given variables;
2258  * performs implications if the clique contains the same variable twice
2259  */
2261  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
2262  BMS_BLKMEM* blkmem, /**< block memory */
2263  SCIP_SET* set, /**< global SCIP settings */
2264  SCIP_STAT* stat, /**< problem statistics */
2265  SCIP_PROB* transprob, /**< transformed problem */
2266  SCIP_PROB* origprob, /**< original problem */
2267  SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
2268  SCIP_REOPT* reopt, /**< reoptimization data structure */
2269  SCIP_LP* lp, /**< current LP data */
2270  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
2271  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2272  SCIP_VAR** vars, /**< binary variables in the clique: at most one can be set to the given value */
2273  SCIP_Bool* values, /**< values of the variables in the clique; NULL to use TRUE for all vars */
2274  int nvars, /**< number of variables in the clique */
2275  SCIP_Bool isequation, /**< is the clique an equation or an inequality? */
2276  SCIP_Bool* infeasible, /**< pointer to store whether an infeasibility was detected */
2277  int* nbdchgs /**< pointer to count the number of performed bound changes, or NULL */
2278  )
2279 {
2280  SCIP_VAR** clqvars;
2281  SCIP_Bool* clqvalues;
2282  SCIP_CLIQUE* clique;
2283  SCIP_VAR* var;
2284  int size;
2285  int nlocalbdchgs = 0;
2286  int v;
2287  int w;
2288 
2289  assert(cliquetable != NULL);
2290  assert(vars != NULL);
2291 
2292  SCIPsetDebugMsg(set, "trying to add clique %d with %d vars to clique table\n", cliquetable->ncliques, nvars);
2293 
2294  /* check clique on debugging solution */
2295  SCIP_CALL( SCIPdebugCheckClique(set, vars, values, nvars) ); /*lint !e506 !e774*/
2296 
2297  *infeasible = FALSE;
2298  size = nvars;
2299 
2300  /* copy clique data */
2301  if( values == NULL )
2302  {
2303  SCIP_CALL( SCIPsetAllocBufferArray(set, &clqvalues, size) );
2304 
2305  /* initialize clique values data */
2306  for( v = nvars - 1; v >= 0; --v )
2307  clqvalues[v] = TRUE;
2308  }
2309  else
2310  {
2311  SCIP_CALL( SCIPsetDuplicateBufferArray(set, &clqvalues, values, size) );
2312  }
2313  SCIP_CALL( SCIPsetDuplicateBufferArray(set, &clqvars, vars, size) );
2314 
2315  /* get active variables */
2316  SCIP_CALL( SCIPvarsGetProbvarBinary(&clqvars, &clqvalues, nvars) );
2317 
2318  /* remove all inactive vars */
2319  for( v = nvars - 1; v >= 0; --v )
2320  {
2321  var = clqvars[v];
2322 
2327  assert(SCIPvarIsBinary(var));
2328 
2329  /* if we have a variables already fixed to one in the clique, fix all other to zero */
2331  ((clqvalues[v] && SCIPvarGetLbGlobal(var) > 0.5) || (!clqvalues[v] && SCIPvarGetUbGlobal(var) < 0.5)) )
2332  {
2333  SCIPsetDebugMsg(set, "in a clique var %s with value %u is fixed to %d -> fix the rest\n", SCIPvarGetName(var), clqvalues[v], clqvalues[v] ? 1 : 0);
2334 
2335  for( w = nvars - 1; w >= 0; --w )
2336  {
2337  SCIP_VAR* clqvar = clqvars[w];
2338 
2339  /* the rare case where the same variable appears several times is handled later during sort and merge */
2340  if( clqvar != var )
2341  {
2342  SCIP_Bool clqval = clqvalues[w];
2343 
2344  /* check if variable is fixed already and terminate with infeasible if this fixing contradicts the clique info */
2345  if( SCIPvarGetLbGlobal(clqvar) > SCIPvarGetUbGlobal(clqvar) - 0.5 )
2346  {
2347 
2348  /* check if fixing contradicts clique constraint */
2349  if( (clqval && SCIPvarGetLbGlobal(clqvar) > 0.5)
2350  || (! clqval && SCIPvarGetUbGlobal(clqvar) < 0.5) )
2351  {
2352  *infeasible = TRUE;
2353 
2354  goto FREEMEM;
2355  }
2356 
2357  continue;
2358  }
2359 
2360 /* the following piece of code is disabled because it assumes the clqvars to be sorted which they aren't until the method
2361  * sortAndMergeClique() is called
2362  */
2363 #ifdef SCIP_DISABLED_CODE
2364  /* if one of the other variables occurs multiple times, we can
2365  * 1) deduce infeasibility if it occurs with different values
2366  * 2) wait for the last occurence to fix it
2367  */
2368  while( w > 0 && clqvars[w - 1] == clqvars[w] )
2369  {
2370  if( clqvalues[w - 1] != clqvalues[w] )
2371  {
2372  *infeasible = TRUE;
2373  return SCIP_OKAY;
2374  }
2375  --w;
2376  }
2377 #endif
2378 
2379  /* fix the variable */
2380  SCIP_CALL( SCIPvarFixBinary(clqvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp,
2381  branchcand, eventqueue, cliquetable, !clqval, infeasible, &nlocalbdchgs) );
2382 
2383  SCIPsetDebugMsg(set, "fixed var %s with value %u to %d (was %s)\n", SCIPvarGetName(clqvar), clqval,
2384  clqval ? 0 : 1, *infeasible ? "infeasible" : "feasible");
2385 
2386  if( *infeasible )
2387  break;
2388  }
2389  }
2390 
2391  /* all variables are fixed so we can stop */
2392  break; /*lint !e850*/
2393  }
2394 
2395  /* only unfixed column and loose variables may be member of a clique */
2396  if( SCIPvarGetUbGlobal(var) - SCIPvarGetLbGlobal(var) < 0.5 ||
2399  {
2400  --nvars;
2401  clqvars[v] = clqvars[nvars];
2402  clqvalues[v] = clqvalues[nvars];
2403  isequation = isequation && !(SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR) && ! SCIPvarIsMarkedDeleteGlobalStructures(var);
2404  }
2405  }
2406 
2407  if( nbdchgs != NULL )
2408  *nbdchgs += nlocalbdchgs;
2409 
2410  /* did we fix all variables or are we infeasible? */
2411  if( v >= 0 )
2412  goto FREEMEM;
2413 
2414  assert(!*infeasible);
2415 
2416  /* check if only one or less variables are left */
2417  if( v < 0 && nvars <= 1)
2418  {
2419  if( isequation )
2420  {
2421  if( nvars == 1 )
2422  {
2423  nlocalbdchgs = 0;
2424 
2425  SCIP_CALL( SCIPvarFixBinary(clqvars[0], blkmem, set, stat, transprob, origprob, tree, reopt, lp,
2426  branchcand, eventqueue, cliquetable, clqvalues[0], infeasible, &nlocalbdchgs) );
2427 
2428  SCIPsetDebugMsg(set, "fixed last clique var %s with value %u to %d (was %s)\n", SCIPvarGetName(clqvars[0]), clqvalues[0],
2429  clqvalues[0] ? 1 : 0, *infeasible ? "infeasible" : "feasible");
2430 
2431  if( nbdchgs != NULL )
2432  *nbdchgs += nlocalbdchgs;
2433  }
2434  else if( nvars == 0 )
2435  {
2436  SCIPsetDebugMsg(set, "empty equation clique left over -> infeasible\n");
2437 
2438  *infeasible = TRUE;
2439  }
2440  }
2441 
2442  goto FREEMEM;
2443  }
2444 
2445  nlocalbdchgs = 0;
2446 
2447  /* sort the variables and values and remove multiple entries of the same variable */
2448  SCIP_CALL( sortAndMergeClique(clqvars, clqvalues, &nvars, &isequation, NULL, blkmem, set, stat, transprob, origprob, tree,
2449  reopt, lp, branchcand, eventqueue, cliquetable, &nlocalbdchgs, infeasible) );
2450 
2451  if( nbdchgs != NULL )
2452  *nbdchgs += nlocalbdchgs;
2453 
2454  /* did we stop early due to a pair of negated variables? */
2455  if( nvars == 0 || *infeasible )
2456  goto FREEMEM;
2457 
2458  /* if less than two variables are left over, the clique is redundant */
2459  if( nvars > 1 )
2460  {
2461  SCIP_CLIQUE* sameclique;
2462 
2463  /* @todo check if we can aggregate variables if( clique->equation && clique->nvars == 2 ) */
2464 
2465  /* create the clique data structure */
2466  SCIP_CALL( cliqueCreateWithData(&clique, blkmem, nvars, clqvars, clqvalues, nvars, cliquetable->ncreatedcliques, isequation) );
2467 
2468  sameclique = (SCIP_CLIQUE*)SCIPhashtableRetrieve(cliquetable->hashtable, (void*)clique);
2469 
2470  if( sameclique == NULL )
2471  {
2472  SCIPsetDebugMsg(set, "adding clique %u with %d vars to clique table\n", clique->id, nvars);
2473 
2474  cliquetable->ncreatedcliques++;
2475 
2476  /* add clique to clique table */
2477  SCIP_CALL( cliquetableEnsureSize(cliquetable, set, cliquetable->ncliques+1) );
2478  cliquetable->cliques[cliquetable->ncliques] = clique;
2479  clique->index = cliquetable->ncliques;
2480  cliquetable->ncliques++;
2481  cliquetable->nentries += nvars;
2482  cliquetableCheckComponentUpdate(cliquetable, clique);
2483 
2484  SCIP_CALL( SCIPhashtableInsert(cliquetable->hashtable, (void*)clique) );
2485 
2486  /* add filled clique to the cliquelists of all corresponding variables */
2487  SCIP_CALL( SCIPvarsAddClique(clqvars, clqvalues, nvars, blkmem, set, clique) );
2488  }
2489  else
2490  {
2491  SCIPsetDebugMsg(set, "same clique %p (id: %d) already found in cliquetable -> discard new one\n", (void*) sameclique, sameclique->id);
2492 
2493  /* update equation status of clique */
2494  /* @note if we might change the order of the clique, e.g. put the equations up front, we should rather remove
2495  * the sameclique from the hashmap while adding the new clique
2496  */
2497  if( !sameclique->equation && clique->equation )
2498  sameclique->equation = TRUE;
2499 
2500  cliqueFree(&clique, blkmem);
2501 
2502  goto FREEMEM;
2503  }
2504  }
2505  else
2506  {
2507  assert(!isequation);
2508  assert(nvars == 1);
2509 
2510  goto FREEMEM;
2511  }
2512  cliqueCheck(clique);
2513 
2514  FREEMEM:
2515  SCIPsetFreeBufferArray(set, &clqvalues);
2516  SCIPsetFreeBufferArray(set, &clqvars);
2517 
2518  return SCIP_OKAY;
2519 }
2520 
2521 /** clean up given clique by removing fixed variables */
2522 static
2524  SCIP_CLIQUE* clique, /**< clique data structure */
2525  BMS_BLKMEM* blkmem, /**< block memory */
2526  SCIP_SET* set, /**< global SCIP settings */
2527  SCIP_STAT* stat, /**< problem statistics */
2528  SCIP_PROB* transprob, /**< transformed problem */
2529  SCIP_PROB* origprob, /**< original problem */
2530  SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
2531  SCIP_REOPT* reopt, /**< reoptimization data structure */
2532  SCIP_LP* lp, /**< current LP data */
2533  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
2534  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2535  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
2536  int* nchgbds, /**< pointer to store number of fixed variables */
2537  SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
2538  )
2539 {
2540  assert(clique != NULL);
2541  assert(blkmem != NULL);
2542  assert(set != NULL);
2543  assert(nchgbds != NULL);
2544  assert(infeasible != NULL);
2545 
2546  /* do we need to clean up fixed variables? */
2547  if( !SCIPcliqueIsCleanedUp(clique) )
2548  {
2549  SCIP_VAR* onefixedvar = NULL;
2550  SCIP_Bool onefixedvalue;
2551  SCIP_Bool needsorting = FALSE;
2552  int v;
2553  int w;
2554 
2555  w = clique->startcleanup;
2556 
2557  SCIPsetDebugMsg(set, "Starting clean up of clique %u (size %d) from position %d\n", clique->id, clique->nvars, w);
2558 
2559  /* exchange inactive by active variables */
2560  for( v = w; v < clique->nvars; ++v )
2561  {
2562  SCIP_Bool addvartoclique; /* has the variable status changed such that it needs to be replaced by an active representative? */
2563 
2564  addvartoclique = FALSE;
2566  || SCIPvarGetStatus(clique->vars[v]) == SCIP_VARSTATUS_NEGATED
2567  || SCIPvarGetStatus(clique->vars[v]) == SCIP_VARSTATUS_MULTAGGR )
2568  {
2569  needsorting = TRUE;
2570 
2571  SCIP_CALL( SCIPvarGetProbvarBinary(&(clique->vars[v]), &(clique->values[v])) );
2572  if( SCIPvarGetStatus(clique->vars[v]) == SCIP_VARSTATUS_NEGATED )
2573  {
2574  clique->vars[v] = SCIPvarGetNegationVar(clique->vars[v]);
2575  clique->values[v] = !clique->values[v];
2576  }
2577  else if( SCIPvarGetStatus(clique->vars[v]) == SCIP_VARSTATUS_MULTAGGR )
2578  {
2579  clique->equation = FALSE;
2580  continue;
2581  }
2582 
2583  addvartoclique = TRUE;
2584  }
2585 
2586  assert(SCIPvarGetStatus(clique->vars[v]) == SCIP_VARSTATUS_COLUMN
2587  || SCIPvarGetStatus(clique->vars[v]) == SCIP_VARSTATUS_LOOSE
2588  || SCIPvarGetStatus(clique->vars[v]) == SCIP_VARSTATUS_FIXED);
2589 
2590  /* check for variables that are either fixed to zero or marked for deletion from global structures */
2591  if( (clique->values[v] && SCIPvarGetUbGlobal(clique->vars[v]) < 0.5) ||
2592  (!clique->values[v] && SCIPvarGetLbGlobal(clique->vars[v]) > 0.5) ||
2594  {
2595  if( clique->equation && SCIPvarIsMarkedDeleteGlobalStructures(clique->vars[v]) )
2596  clique->equation = FALSE;
2597 
2598  /* the variable will be overwritten by subsequent active variables */
2599  continue;
2600  }
2601 
2602  /* check for a variable fixed to one in the clique */
2603  else if( (clique->values[v] && SCIPvarGetLbGlobal(clique->vars[v]) > 0.5)
2604  || (!clique->values[v] && SCIPvarGetUbGlobal(clique->vars[v]) < 0.5) )
2605  {
2606  if( onefixedvar != NULL )
2607  {
2608  *infeasible = TRUE;
2609 
2610  SCIPsetDebugMsg(set, "two variables in clique %u fixed to one %s%s and %s%s\n", clique->id,
2611  onefixedvalue ? "" : "~", SCIPvarGetName(onefixedvar), clique->values[v] ? "" : "~",
2612  SCIPvarGetName(clique->vars[v])); /*lint !e530*/
2613  return SCIP_OKAY;
2614  }
2615  onefixedvar = clique->vars[v];
2616  onefixedvalue = clique->values[v];
2617  }
2618  else
2619  {
2620  assert(SCIPvarGetStatus(clique->vars[v]) != SCIP_VARSTATUS_FIXED);
2621  assert(w <= v);
2622 
2623  if( w < v )
2624  {
2625  clique->vars[w] = clique->vars[v];
2626  clique->values[w] = clique->values[v];
2627  }
2628 
2629  /* add clique to active variable if it replaced a aggregated or negated var */
2630  if( addvartoclique )
2631  {
2632  SCIP_CALL( SCIPvarAddCliqueToList(clique->vars[w], blkmem, set, clique->values[w], clique) );
2633  }
2634  /* increase indexer of last active, i.e. unfixed, variable in clique */
2635  ++w;
2636  }
2637 
2638  }
2639  clique->nvars = w;
2640 
2641  if( onefixedvar != NULL )
2642  {
2643  SCIPsetDebugMsg(set, "variable %s%s in clique %u fixed to one, fixing all other variables to zero\n",
2644  onefixedvalue ? "" : "~", SCIPvarGetName(onefixedvar), clique->id);
2645 
2646  for( v = 0; v < clique->nvars ; ++v )
2647  {
2648  SCIP_VAR* clqvar = clique->vars[v];
2649  SCIP_Bool clqval = clique->values[v];
2650 
2651  assert(SCIPvarGetStatus(clqvar) == SCIP_VARSTATUS_COLUMN
2652  || SCIPvarGetStatus(clqvar) == SCIP_VARSTATUS_LOOSE);
2653 
2654  if( onefixedvalue != clqval || clqvar != onefixedvar )
2655  {
2656  /* the variable could have been fixed already because it appears more than once in the clique */
2657  if( SCIPvarGetLbGlobal(clqvar) > SCIPvarGetUbGlobal(clqvar) - 0.5 )
2658  {
2659  /* the fixing must have occurred previously inside this loop. It may happen that
2660  * the variable occurs together with its negation in that clique, which is usually
2661  * handled during the merge step, but leads to a direct infeasibility because it
2662  * contradicts any other variable fixed to one in this clique
2663  */
2664  if( (clqval && SCIPvarGetLbGlobal(clqvar) > 0.5)
2665  || (! clqval && SCIPvarGetUbGlobal(clqvar) < 0.5) )
2666  {
2667  /* impossible because we would have detected this in the previous cleanup loop */
2668  assert(clqvar != onefixedvar);
2669  *infeasible = TRUE;
2670 
2671  return SCIP_OKAY;
2672  }
2673  continue;
2674  }
2675 
2676  SCIP_CALL( SCIPvarDelCliqueFromList(clqvar, blkmem, clqval, clique) );
2677 
2678 /* the following piece of code is wrong at this point because it assumes sorted variables. can be enabled if sorting
2679  * of variables is performed earlier than it is now
2680  */
2681 #ifdef SCIP_DISABLED_CODE
2682  /* if one of the other variables occurs multiple times, we can
2683  * 1) deduce infeasibility if it occurs with different values
2684  * 2) wait for the last occurence to fix it
2685  */
2686  while( v < clique->nvars - 1 && clique->vars[v + 1] == clqvar )
2687  {
2688  if( clique->values[v + 1] != clique->values[v] )
2689  {
2690  *infeasible = TRUE;
2691  return SCIP_OKAY;
2692  }
2693  ++v;
2694  }
2695 #endif
2696  SCIPsetDebugMsg(set, "fixing variable %s in clique %u to %d\n", SCIPvarGetName(clqvar), clique->id, clqval ? 0 : 1);
2697 
2698  SCIP_CALL( SCIPvarFixBinary(clqvar, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand,
2699  eventqueue, cliquetable, !clqval, infeasible, nchgbds) );
2700 
2701  if( *infeasible )
2702  return SCIP_OKAY;
2703  }
2704  }
2705 
2706  if( SCIPvarGetStatus(onefixedvar) == SCIP_VARSTATUS_COLUMN /*lint !e850*/
2707  || SCIPvarGetStatus(onefixedvar) == SCIP_VARSTATUS_LOOSE )
2708  {
2709  SCIP_CALL( SCIPvarDelCliqueFromList(onefixedvar, blkmem, onefixedvalue, clique) );
2710  }
2711 
2712  clique->nvars = 0;
2713  clique->equation = FALSE;
2714  clique->startcleanup = -1;
2715 
2716  return SCIP_OKAY;
2717  }
2718 
2719  if( clique->equation )
2720  {
2721  if( clique->nvars == 0 )
2722  {
2723  *infeasible = TRUE;
2724  return SCIP_OKAY;
2725  }
2726  else if( clique->nvars == 1 )
2727  {
2728  assert(SCIPvarGetStatus(clique->vars[0]) == SCIP_VARSTATUS_COLUMN
2729  || SCIPvarGetStatus(clique->vars[0]) == SCIP_VARSTATUS_LOOSE);
2730 
2731  /* clearing data and removing variable from its clique list */
2732  SCIP_CALL( SCIPvarDelCliqueFromList(clique->vars[0], blkmem, clique->values[0], clique) );
2733 
2734  SCIPsetDebugMsg(set, "fixing last variable %s in clique %u to %d\n", SCIPvarGetName(clique->vars[0]), clique->id,
2735  clique->values[0] ? 1 : 0);
2736 
2737  SCIP_CALL( SCIPvarFixBinary(clique->vars[0], blkmem, set, stat, transprob, origprob, tree, reopt, lp,
2738  branchcand, eventqueue, cliquetable, clique->values[0], infeasible, nchgbds) );
2739 
2740  clique->nvars = 0;
2741  clique->equation = FALSE;
2742  clique->startcleanup = -1;
2743 
2744  return SCIP_OKAY;
2745  }
2746  }
2747 
2748  if( needsorting )
2749  {
2750  SCIP_Bool isequation = clique->equation;
2751 
2752  /* remove multiple entries of the same variable */
2753  SCIP_CALL( sortAndMergeClique(clique->vars, clique->values, &(clique->nvars), &isequation, clique, blkmem, set, stat,
2754  transprob, origprob, tree, reopt, lp, branchcand, eventqueue, cliquetable, nchgbds, infeasible) );
2755 
2756  clique->equation = isequation;
2757  }
2758 
2759  /* @todo check if we can aggregate variables if( clique->equation && clique->nvars == 2 ) */
2760 
2761  clique->startcleanup = -1;
2762  }
2763  assert(SCIPcliqueIsCleanedUp(clique));
2764 
2765  return SCIP_OKAY;
2766 }
2767 
2768 #ifdef SCIP_MORE_DEBUG
2769 /** checks whether clique appears in all clique lists of the involved variables */
2770 static
2772  SCIP_CLIQUETABLE* cliquetable /**< clique table data structure */
2773  )
2774 {
2775  SCIP_Longint nentries = 0;
2776  int c;
2777 
2778  assert(cliquetable != NULL);
2779 
2780  for( c = cliquetable->ncliques - 1; c >= 0; --c )
2781  nentries += cliquetable->cliques[c]->nvars;
2782 
2783  return (nentries == cliquetable->nentries);
2784 }
2785 #else
2786 #define checkNEntries(cliquetable) TRUE
2787 #endif
2788 
2789 /** removes all empty and single variable cliques from the clique table; removes double entries from the clique table
2790  *
2791  * @note cliques can be processed several times by this method
2792  *
2793  * @todo try to detect infeasible implications, e.g., x = 1 => (y = 0 && y = 1)
2794  */
2796  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
2797  BMS_BLKMEM* blkmem, /**< block memory */
2798  SCIP_SET* set, /**< global SCIP settings */
2799  SCIP_STAT* stat, /**< problem statistics */
2800  SCIP_PROB* transprob, /**< transformed problem */
2801  SCIP_PROB* origprob, /**< original problem */
2802  SCIP_TREE* tree, /**< branch and bound tree if in solving stage */
2803  SCIP_REOPT* reopt, /**< reoptimization data structure */
2804  SCIP_LP* lp, /**< current LP data */
2805  SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */
2806  SCIP_EVENTQUEUE* eventqueue, /**< event queue */
2807  int* nchgbds, /**< pointer to store number of fixed variables */
2808  SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
2809  )
2810 {
2811  assert(cliquetable != NULL);
2812  assert(stat != NULL);
2813  assert(infeasible != NULL);
2814 
2815  *infeasible = FALSE;
2816 
2817  /* check if we have anything to do */
2818  if( stat->npresolfixedvars == cliquetable->ncleanupfixedvars
2819  && stat->npresolaggrvars == cliquetable->ncleanupaggrvars
2820  && cliquetable->ndirtycliques == 0 )
2821  return SCIP_OKAY;
2822 
2823  SCIPsetDebugMsg(set, "cleaning up clique table with %d cliques (with %" SCIP_LONGINT_FORMAT " entries)\n", cliquetable->ncliques, cliquetable->nentries);
2824 
2825  /* delay events */
2826  SCIP_CALL( SCIPeventqueueDelay(eventqueue) );
2827 
2828  cliquetable->incleanup = TRUE;
2829  while( cliquetable->ndirtycliques > 0 && !(*infeasible) )
2830  {
2831  SCIP_CLIQUE* clique;
2832  SCIP_CLIQUE* sameclique;
2833 
2834  clique = cliquetable->cliques[0];
2835 
2836  assert(!SCIPcliqueIsCleanedUp(clique));
2837 
2838  /* remove not clean up clique from hastable */
2839  SCIP_CALL( SCIPhashtableRemove(cliquetable->hashtable, (void*)clique) );
2840  cliquetable->nentries -= clique->nvars;
2841  assert(cliquetable->nentries >= 0);
2842 
2843  SCIP_CALL( cliqueCleanup(clique, blkmem, set, stat, transprob, origprob, tree, reopt, lp, branchcand, eventqueue,
2844  cliquetable, nchgbds, infeasible) );
2845 
2846  if( *infeasible )
2847  break;
2848 
2849  assert(SCIPcliqueIsCleanedUp(clique));
2850 
2851  /* swap freshly cleaned clique with last dirty clique */
2852  cliquetable->ndirtycliques--;
2853  cliquetableSwapCliques(cliquetable, 0, cliquetable->ndirtycliques);
2854  cliqueCheck(clique);
2855 
2856  /* @todo check if we can aggregate variables if( clique->equation && clique->nvars == 2 && SCIPsetGetStage(set) == SCIP_STAGE_PRESOLVING */
2857 #if 0
2858  if( clique->nvars == 2 && clique->equation && SCIPsetGetStage(set) == SCIP_STAGE_PRESOLVING )
2859  {
2860  SCIP_VAR* var0;
2861  SCIP_VAR* var1;
2862  SCIP_Real scalarx;
2863  SCIP_Real scalary;
2864  SCIP_Real rhs = 1.0;
2865  SCIP_Bool aggregated;
2866 
2867  printf("aggr vars, clique %d\n", clique->id);
2868 
2869  if( SCIPvarGetType(clique->vars[0]) >= SCIPvarGetType(clique->vars[1]) )
2870  {
2871  var0 = clique->vars[0];
2872  var1 = clique->vars[1];
2873 
2874  if( !clique->values[0] )
2875  {
2876  scalarx = -1.0;
2877  rhs -= 1.0;
2878  }
2879  else
2880  scalarx = 1.0;
2881 
2882  if( !clique->values[1] )
2883  {
2884  scalary = -1.0;
2885  rhs -= 1.0;
2886  }
2887  else
2888  scalary = 1.0;
2889  }
2890  else
2891  {
2892  var0 = clique->vars[1];
2893  var1 = clique->vars[0];
2894 
2895  if( !clique->values[0] )
2896  {
2897  scalary = -1.0;
2898  rhs -= 1.0;
2899  }
2900  else
2901  scalary = 1.0;
2902 
2903  if( !clique->values[1] )
2904  {
2905  scalarx = -1.0;
2906  rhs -= 1.0;
2907  }
2908  else
2909  scalarx = 1.0;
2910  }
2911 
2914 
2915  /* aggregate the variable */
2916  SCIP_CALL( SCIPvarTryAggregateVars(set, blkmem, stat, transprob, origprob, primal,
2917  tree, lp, cliquetable, branchcand, eventfilter, eventqueue,
2918  var0, var1, scalarx, scalary, rhs, infeasible, &aggregated) );
2919 
2920  assert(aggregated || *infeasible);
2921  }
2922 #endif
2923 
2924  sameclique = (SCIP_CLIQUE*)SCIPhashtableRetrieve(cliquetable->hashtable, (void*)clique);
2925 
2926  /* check if the clique is already contained in the clique table, or if it is redundant (too small) */
2927  if( clique->nvars <= 1 || sameclique != NULL )
2928  {
2929  int j;
2930 
2931  /* infeasible or fixing should be performed already on trivial clique */
2932  assert(clique->nvars > 1 || !clique->equation);
2933 
2934  /* if the clique which is already in the hashtable is an inequality and the current clique is an equation, we
2935  * update the equation status of the old one
2936  */
2937  if( clique->nvars > 1 && clique->equation && !sameclique->equation )
2938  {
2939  assert(sameclique->nvars >= 2);
2940 
2941  /* @note if we might change the order of the clique, e.g. put the equations up front, we should rather remove
2942  * the sameclique from the hashmap while adding the new clique
2943  */
2944  sameclique->equation = TRUE;
2945  }
2946 
2947  /* delete the clique from the variables' clique lists */
2948  for( j = 0; j < clique->nvars; ++j )
2949  {
2950  SCIP_CALL( SCIPvarDelCliqueFromList(clique->vars[j], blkmem, clique->values[j], clique) );
2951  }
2952 
2953  /* free clique and remove it from clique table */
2954  cliqueFree(&clique, blkmem);
2955  cliquetable->ncliques--;
2956  /* insert a clean clique from the end of the array */
2957  if( cliquetable->ndirtycliques < cliquetable->ncliques )
2958  {
2959  assert(SCIPcliqueIsCleanedUp(cliquetable->cliques[cliquetable->ncliques]));
2960  cliquetable->cliques[cliquetable->ndirtycliques] = cliquetable->cliques[cliquetable->ncliques];
2961  cliquetable->cliques[cliquetable->ndirtycliques]->index = cliquetable->ndirtycliques;
2962  }
2963  }
2964  else
2965  {
2966  cliquetable->nentries += clique->nvars;
2967 
2968  SCIP_CALL( SCIPhashtableInsert(cliquetable->hashtable, (void*)clique) );
2969  if( !clique->eventsissued )
2970  {
2971  int j;
2972 
2973  /* issue IMPLADDED event on each variable in the clique */
2974  for( j = 0; j < clique->nvars; ++j )
2975  {
2976  SCIP_EVENT* event;
2977 
2978  SCIP_CALL( SCIPeventCreateImplAdded(&event, blkmem, clique->vars[j]) );
2979  SCIP_CALL( SCIPeventqueueAdd(eventqueue, blkmem, set, NULL, NULL, NULL, NULL, &event) );
2980  }
2981  clique->eventsissued = TRUE;
2982  }
2983  }
2984  }
2985  cliquetable->incleanup = FALSE;
2986 
2987  /* remember the number of fixed variables and cliques in order to avoid unnecessary cleanups */
2988  cliquetable->ncleanupfixedvars = stat->npresolfixedvars;
2989  cliquetable->ncleanupaggrvars = stat->npresolaggrvars;
2990  assert(*infeasible || cliquetable->ndirtycliques == 0);
2991 
2992  assert(*infeasible || checkNEntries(cliquetable));
2993 
2994  SCIPsetDebugMsg(set, "cleaned up clique table has %d cliques left (with %" SCIP_LONGINT_FORMAT " entries)\n", cliquetable->ncliques, cliquetable->nentries);
2995 
2996  /* process events */
2997  SCIP_CALL( SCIPeventqueueProcess(eventqueue, blkmem, set, NULL, lp, branchcand, NULL) );
2998 
2999  return SCIP_OKAY;
3000 }
3001 
3002 /** helper function that returns the graph node index for a variable during connected component detection */
3003 static
3005  SCIP_VAR* binvar /**< binary (or binary integer or implicit binary) variable */
3006  )
3007 {
3008  SCIP_VAR* activevar;
3009  int nodeindex;
3010 
3011  assert(binvar != NULL);
3012  assert(SCIPvarIsBinary(binvar));
3013 
3014  /* get active representative of variable */
3015  if( !SCIPvarIsActive(binvar) )
3016  {
3017  activevar = SCIPvarGetProbvar(binvar);
3018  if( !SCIPvarIsActive(activevar) )
3019  return -1;
3020  }
3021  else
3022  activevar = binvar;
3023 
3024 
3025  assert(SCIPvarIsBinary(activevar));
3026 
3027  /* assign node index (problem index for binaries, subtract number of integer variables for integers) */
3028  nodeindex = SCIPvarGetProbindex(activevar);
3029 
3030  assert(nodeindex >= 0);
3031 
3032  return nodeindex;
3033 }
3034 
3035 /** computes connected components of the clique graph
3036  *
3037  * use depth-first search similarly to the components presolver/constraint handler, representing a clique as a
3038  * path to reduce memory usage, but leaving the connected components the same
3039  *
3040  * an update becomes necessary if a clique gets added with variables from different components
3041  */
3043  SCIP_CLIQUETABLE* cliquetable, /**< clique table data structure */
3044  SCIP_SET* set, /**< global SCIP settings */
3045  SCIP_VAR** vars, /**< array of problem variables, sorted by variable type */
3046  int nbinvars, /**< number of binary variables */
3047  int nintvars, /**< number of integer variables */
3048  int nimplvars /**< number of implicit integer variables */
3049  )
3050 {
3051  SCIP_DIGRAPH* digraph;
3052  int nimplbinvars;
3053  int* components;
3054  int* sizes;
3055  int v;
3056  int c;
3057  int nbinvarstotal;
3058  int ndiscvars;
3059  SCIP_CLIQUE** cliques;
3060 
3061  assert(cliquetable != NULL);
3062  assert(vars != NULL);
3063 
3064  nimplbinvars = 0;
3065  cliquetable->componentupdate = FALSE;
3066  ndiscvars = nbinvars + nintvars + nimplvars;
3067 
3068  /* detect integer and implicit integer variables with bounds {0,1} because they might appear in cliques, as well */
3069  for( v = nbinvars; v < ndiscvars; ++v )
3070  {
3071  if( SCIPvarIsBinary(vars[v]) )
3072  ++nimplbinvars;
3073  }
3074 
3075  /* count binary and implicit binary variables */
3076  nbinvarstotal = nbinvars + nimplbinvars;
3077 
3078  /* if there are no binary variables, return */
3079  if( nbinvarstotal == 0 )
3080  {
3081  SCIPsetDebugMsg(set, "0 binary variables in total --> 0 connected components in the clique graph");
3082  cliquetable->ncliquecomponents = 0;
3083  return SCIP_OKAY;
3084  }
3085 
3086  /* no cliques are present */
3087  if( cliquetable->ncliques == 0 )
3088  {
3089  SCIPsetDebugMsg(set, "0 cliques --> Clique graph has %d isolated nodes", nbinvarstotal);
3090  cliquetable->ncliquecomponents = nbinvarstotal;
3091  return SCIP_OKAY;
3092  }
3093 
3094  SCIP_CALL( SCIPsetAllocBufferArray(set, &components, ndiscvars) );
3095  SCIP_CALL( SCIPsetAllocBufferArray(set, &sizes, ndiscvars) );
3096 
3097  /* collect clique list sizes as an upper bound for the edges for each variable node in the digraph */
3098  for( v = 0; v < nbinvars; ++v )
3099  {
3100  assert(SCIPvarIsActive(vars[v]));
3101  assert(SCIPvarGetProbindex(vars[v]) == v);
3102  sizes[v] = 2 * (SCIPvarGetNCliques(vars[v], TRUE) + SCIPvarGetNCliques(vars[v], FALSE));
3103  }
3104  /* collect sizes also for the implicit binary variables */
3105  for( v = nbinvars; v < nbinvars + nintvars + nimplvars; ++v )
3106  {
3107  if( SCIPvarIsBinary(vars[v]) )
3108  sizes[v] = 2 * (SCIPvarGetNCliques(vars[v], TRUE) + SCIPvarGetNCliques(vars[v], FALSE));
3109  else
3110  sizes[v] = 0;
3111  }
3112 
3113 
3114  /* we need to consider integer and implicit integer variables for which SCIPvarIsBinary() returns TRUE.
3115  * These may be scattered across the ninteger + nimplvars implicit integer variables.
3116  * For simplicity, we add all integer and implicit integer variables as nodes to the digraph, and subtract
3117  * the amount of nonbinary integer and implicit integer variables afterwards.
3118  */
3119  SCIP_CALL( SCIPdigraphCreate(&digraph, ndiscvars) );
3120  SCIP_CALL( SCIPdigraphSetSizes(digraph, sizes) );
3121 
3122  cliques = cliquetable->cliques;
3123 
3124  /* loop over cliques and add them as paths to the digraph */
3125  for( c = 0; c < cliquetable->ncliques; ++c )
3126  {
3127  SCIP_CLIQUE* clique;
3128  SCIP_VAR** cliquevars;
3129  int nclqvars;
3130  int cv;
3131  int lastactiveindex = -1;
3132 
3133  clique = cliques[c];
3134  cliquevars = SCIPcliqueGetVars(clique);
3135  nclqvars = SCIPcliqueGetNVars(clique);
3136  assert(nclqvars > 0);
3137 
3138  /* add a variable and its last active predecessor in this clique as an arc to the digraph */
3139  for( cv = 0; cv < nclqvars; ++cv )
3140  {
3141  int nodeindex = getNodeIndexBinvar(cliquevars[cv]);
3142 
3143  assert(nodeindex < ndiscvars);
3144 
3145  if( nodeindex >= 0 )
3146  {
3147  /* add an arc to the digraph between this node and the previous active variable from this clique */
3148  if( lastactiveindex >= 0 )
3149  {
3150  SCIP_CALL( SCIPdigraphAddArc(digraph, nodeindex, lastactiveindex, NULL) );
3151  }
3152  /* store this node index as active index for the next arc */
3153  lastactiveindex = nodeindex;
3154  }
3155  }
3156  }
3157 
3158  cliquetable->ncliquecomponents = -1;
3159  SCIP_CALL( SCIPdigraphComputeUndirectedComponents(digraph, 1, components, &cliquetable->ncliquecomponents) );
3160 
3161  /* subtract superfluous integer and implicit integer variables added to the auxiliary graph */
3162  cliquetable->ncliquecomponents -= (nintvars + nimplvars - nimplbinvars);
3163  assert(cliquetable->ncliquecomponents >= 0);
3164  assert(cliquetable->ncliquecomponents <= nbinvarstotal);
3165 
3166  SCIPsetDebugMsg(set, "connected components detection: %d comps (%d clqs, %d vars)", cliquetable->ncliquecomponents, cliquetable->ncliques, nbinvarstotal);
3167 
3168  /* save variable component in variable data structure */
3169  for( v = 0; v < ndiscvars; ++v )
3170  SCIPvarSetCliqueComponentIdx(vars[v], components[v]);
3171 
3172  SCIPdigraphFree(&digraph);
3173  SCIPsetFreeBufferArray(set, &sizes);
3174  SCIPsetFreeBufferArray(set, &components);
3175 
3176  return SCIP_OKAY;
3177 }
3178 
3179 /*
3180  * simple functions implemented as defines
3181  */
3182 
3183 /* In debug mode, the following methods are implemented as function calls to ensure
3184  * type validity.
3185  * In optimized mode, the methods are implemented as defines to improve performance.
3186  * However, we want to have them in the library anyways, so we have to undef the defines.
3187  */
3188 
3189 #undef SCIPvboundsGetNVbds
3190 #undef SCIPvboundsGetVars
3191 #undef SCIPvboundsGetCoefs
3192 #undef SCIPvboundsGetConstants
3193 #undef SCIPimplicsGetNImpls
3194 #undef SCIPimplicsGetVars
3195 #undef SCIPimplicsGetTypes
3196 #undef SCIPimplicsGetBounds
3197 #undef SCIPimplicsGetIds
3198 #undef SCIPcliqueGetNVars
3199 #undef SCIPcliqueGetVars
3200 #undef SCIPcliqueGetValues
3201 #undef SCIPcliqueGetId
3202 #undef SCIPcliqueIsCleanedUp
3203 #undef SCIPcliqueIsEquation
3204 #undef SCIPcliquelistGetNCliques
3205 #undef SCIPcliquelistGetCliques
3206 #undef SCIPcliquelistCheck
3207 #undef SCIPcliquetableGetNCliques
3208 #undef SCIPcliquetableGetCliques
3209 #undef SCIPcliquetableGetNEntries
3210 #undef SCIPcliquetableGetNCliqueComponents
3211 #undef SCIPcliquetableNeedsComponentUpdate
3212 
3213 /** gets number of variable bounds contained in given variable bounds data structure */
3215  SCIP_VBOUNDS* vbounds /**< variable bounds data structure */
3216  )
3217 {
3218  return vbounds != NULL ? vbounds->len : 0;
3219 }
3220 
3221 /** gets array of variables contained in given variable bounds data structure */
3223  SCIP_VBOUNDS* vbounds /**< variable bounds data structure */
3224  )
3225 {
3226  return vbounds != NULL ? vbounds->vars : NULL;
3227 }
3228 
3229 /** gets array of coefficients contained in given variable bounds data structure */
3231  SCIP_VBOUNDS* vbounds /**< variable bounds data structure */
3232  )
3233 {
3234  return vbounds != NULL ? vbounds->coefs : NULL;
3235 }
3236 
3237 /** gets array of constants contained in given variable bounds data structure */
3239  SCIP_VBOUNDS* vbounds /**< variable bounds data structure */
3240  )
3241 {
3242  return vbounds != NULL ? vbounds->constants : NULL;
3243 }
3244 
3245 /** gets number of implications for a given binary variable fixing */
3247  SCIP_IMPLICS* implics, /**< implication data */
3248  SCIP_Bool varfixing /**< should the implications on var == FALSE or var == TRUE be returned? */
3249  )
3250 {
3251  return implics != NULL ? implics->nimpls[varfixing] : 0;
3252 }
3253 
3254 /** gets array with implied variables for a given binary variable fixing */
3256  SCIP_IMPLICS* implics, /**< implication data */
3257  SCIP_Bool varfixing /**< should the implications on var == FALSE or var == TRUE be returned? */
3258  )
3259 {
3260  return implics != NULL ? implics->vars[varfixing] : NULL;
3261 }
3262 
3263 /** gets array with implication types for a given binary variable fixing */
3265  SCIP_IMPLICS* implics, /**< implication data */
3266  SCIP_Bool varfixing /**< should the implications on var == FALSE or var == TRUE be returned? */
3267  )
3268 {
3269  return implics != NULL ? implics->types[varfixing] : NULL;
3270 }
3271 
3272 /** gets array with implication bounds for a given binary variable fixing */
3274  SCIP_IMPLICS* implics, /**< implication data */
3275  SCIP_Bool varfixing /**< should the implications on var == FALSE or var == TRUE be returned? */
3276  )
3277 {
3278  return implics != NULL ? implics->bounds[varfixing] : NULL;
3279 }
3280 
3281 /** Gets array with unique implication identifiers for a given binary variable fixing.
3282  * If an implication is a shortcut, i.e., it was added as part of the transitive closure of another implication,
3283  * its id is negative, otherwise it is nonnegative.
3284  */
3286  SCIP_IMPLICS* implics, /**< implication data */
3287  SCIP_Bool varfixing /**< should the implications on var == FALSE or var == TRUE be returned? */
3288  )
3289 {
3290  return implics != NULL ? implics->ids[varfixing] : NULL;
3291 }
3292 
3293 /** gets number of variables in the cliques */
3295  SCIP_CLIQUE* clique /**< clique data structure */
3296  )
3297 {
3298  assert(clique != NULL);
3299 
3300  return clique->nvars;
3301 }
3302 
3303 /** gets array of active problem variables in the cliques */
3305  SCIP_CLIQUE* clique /**< clique data structure */
3306  )
3307 {
3308  assert(clique != NULL);
3309 
3310  return clique->vars;
3311 }
3312 
3313 /** gets array of values of active problem variables in the cliques, i.e. whether the variable is fixed to FALSE or
3314  * to TRUE in the clique
3315  */
3317  SCIP_CLIQUE* clique /**< clique data structure */
3318  )
3319 {
3320  assert(clique != NULL);
3321 
3322  return clique->values;
3323 }
3324 
3325 /** gets unique identifier of the clique */
3327  SCIP_CLIQUE* clique /**< clique data structure */
3328  )
3329 {
3330  assert(clique != NULL);
3331 
3332  return (int) clique->id;
3333 }
3334 
3335 /** gets unique identifier of the clique */
3337  SCIP_CLIQUE* clique /**< clique data structure */
3338  )
3339 {
3340  assert(clique != NULL);
3341 
3342  return (clique->startcleanup == -1);
3343 }
3344 
3345 /** return whether the given clique is an equation */
3347  SCIP_CLIQUE* clique /**< clique data structure */
3348  )
3349 {
3350  assert(clique != NULL);
3351 
3352  return (SCIP_Bool)(clique->equation); /*lint !e571*/
3353 }
3354 
3355 /** returns the number of cliques stored in the clique list */
3357  SCIP_CLIQUELIST* cliquelist, /**< clique list data structure */
3358  SCIP_Bool value /**< value of the variable for which the cliques should be returned */
3359  )
3360 {
3361  return cliquelist != NULL ? cliquelist->ncliques[value] : 0;
3362 }
3363 
3364 /** returns the cliques stored in the clique list, or NULL if the clique list is empty */
3366  SCIP_CLIQUELIST* cliquelist, /**< clique list data structure */
3367  SCIP_Bool value /**< value of the variable for which the cliques should be returned */
3368  )
3369 {
3370  return cliquelist != NULL ? cliquelist->cliques[value] : NULL;
3371 }
3372 
3373 /** checks whether variable is contained in all cliques of the cliquelist */
3375  SCIP_CLIQUELIST* cliquelist, /**< clique list data structure */
3376  SCIP_VAR* var /**< variable, the clique list belongs to */
3377  )
3378 {
3379  /* @todo might need to change ifndef NDEBUG to ifdef SCIP_MORE_DEBUG because it can take at lot of time to check for
3380  * correctness
3381  */
3382 #ifndef NDEBUG
3383  int value;
3384 
3385  assert(SCIPvarGetNCliques(var, FALSE) == SCIPcliquelistGetNCliques(cliquelist, FALSE));
3386  assert(SCIPvarGetCliques(var, FALSE) == SCIPcliquelistGetCliques(cliquelist, FALSE));
3387  assert(SCIPvarGetNCliques(var, TRUE) == SCIPcliquelistGetNCliques(cliquelist, TRUE));
3388  assert(SCIPvarGetCliques(var, TRUE) == SCIPcliquelistGetCliques(cliquelist, TRUE));
3389 
3390  for( value = 0; value < 2; ++value )
3391  {
3392  SCIP_CLIQUE** cliques;
3393  int ncliques;
3394  int i;
3395 
3396  ncliques = SCIPcliquelistGetNCliques(cliquelist, (SCIP_Bool)value);
3397  cliques = SCIPcliquelistGetCliques(cliquelist, (SCIP_Bool)value);
3398  for( i = 0; i < ncliques; ++i )
3399  {
3400  SCIP_CLIQUE* clique;
3401  int pos;
3402 
3403  clique = cliques[i];
3404  assert(clique != NULL);
3405 
3406  pos = SCIPcliqueSearchVar(clique, var, (SCIP_Bool)value);
3407  assert(0 <= pos && pos < clique->nvars);
3408  assert(clique->vars[pos] == var);
3409  assert(clique->values[pos] == (SCIP_Bool)value);
3410  }
3411  }
3412 #endif
3413 }
3414 
3415 /** gets the number of cliques stored in the clique table */
3417  SCIP_CLIQUETABLE* cliquetable /**< clique table data structure */
3418  )
3419 {
3420  assert(cliquetable != NULL);
3421 
3422  return cliquetable->ncliques;
3423 }
3424 
3425 /** gets the array of cliques stored in the clique table */
3427  SCIP_CLIQUETABLE* cliquetable /**< clique table data structure */
3428  )
3429 {
3430  assert(cliquetable != NULL);
3431 
3432  return cliquetable->cliques;
3433 }
3434 
3435 /** gets the number of entries in the whole clique table */
3437  SCIP_CLIQUETABLE* cliquetable /**< clique table data structure */
3438  )
3439 {
3440  assert(cliquetable != NULL);
3441 
3442  return cliquetable->nentries;
3443 }
3444 
3445 /** returns the number of clique components, or -1 if update is necessary first */
3447  SCIP_CLIQUETABLE* cliquetable /**< clique table data structure */
3448  )
3449 {
3450  return cliquetable->componentupdate ? -1 : cliquetable->ncliquecomponents;
3451 }
3452 
3453 /** returns TRUE iff the connected clique components need an update (because new cliques were added) */
3455  SCIP_CLIQUETABLE* cliquetable /**< clique table data structure */
3456  )
3457 {
3458  return cliquetable->componentupdate || cliquetable->ncliquecomponents == -1;
3459 }
SCIP_Bool componentupdate
SCIP_CLIQUE ** cliques
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
void SCIPcliquelistRemoveFromCliques(SCIP_CLIQUELIST *cliquelist, SCIP_CLIQUETABLE *cliquetable, SCIP_VAR *var, SCIP_Bool irrelevantvar)
Definition: implics.c:1659
#define HASHTABLE_CLIQUETABLE_SIZE
Definition: implics.c:1761
#define BMSfreeBlockMemoryArrayNull(mem, ptr, num)
Definition: memory.h:426
internal methods for managing events
SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
Definition: implics.c:3304
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:589
#define BMSfreeMemoryArrayNull(ptr)
Definition: memory.h:107
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2253
void SCIPimplicsGetVarImplics(SCIP_IMPLICS *implics, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_Bool *haslowerimplic, SCIP_Bool *hasupperimplic)
Definition: implics.c:887
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:2363
SCIP_HASHTABLE * hashtable
SCIP_Longint SCIPcliquetableGetNEntries(SCIP_CLIQUETABLE *cliquetable)
Definition: implics.c:3436
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:1127
static void cliquetableCheckComponentUpdate(SCIP_CLIQUETABLE *cliquetable, SCIP_CLIQUE *clique)
Definition: implics.c:2229
#define SCIPsetDuplicateBufferArray(set, ptr, source, num)
Definition: set.h:1836
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:2112
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17169
SCIP_RETCODE SCIPvarGetProbvarBinary(SCIP_VAR **var, SCIP_Bool *negated)
Definition: var.c:11616
SCIP_Real * constants
#define SCIP_HASHSIZE_CLIQUES_SMALL
Definition: def.h:240
SCIP_RETCODE SCIPeventCreateImplAdded(SCIP_EVENT **event, BMS_BLKMEM *blkmem, SCIP_VAR *var)
Definition: event.c:766
SCIP_VAR ** SCIPimplicsGetVars(SCIP_IMPLICS *implics, SCIP_Bool varfixing)
Definition: implics.c:3255
SCIP_RETCODE SCIPdigraphComputeUndirectedComponents(SCIP_DIGRAPH *digraph, int minsize, int *components, int *ncomponents)
Definition: misc.c:6931
int npresolaggrvars
Definition: struct_stat.h:224
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17532
static SCIP_RETCODE cliquetableEnsureSize(SCIP_CLIQUETABLE *cliquetable, SCIP_SET *set, int num)
Definition: implics.c:1827
int npresolfixedvars
Definition: struct_stat.h:223
int SCIPcliquelistGetNCliques(SCIP_CLIQUELIST *cliquelist, SCIP_Bool value)
Definition: implics.c:3356
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:16735
SCIP_VAR ** SCIPvboundsGetVars(SCIP_VBOUNDS *vbounds)
Definition: implics.c:3222
#define SCIPdebugCheckClique(set, vars, values, nvars)
Definition: debug.h:260
SCIP_Bool SCIPcliqueHasVar(SCIP_CLIQUE *clique, SCIP_VAR *var, SCIP_Bool value)
Definition: implics.c:1117
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:2523
#define FALSE
Definition: def.h:64
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:1748
SCIP_Bool SCIPsetIsZero(SCIP_SET *set, SCIP_Real val)
Definition: set.c:5629
SCIP_RETCODE SCIPeventqueueDelay(SCIP_EVENTQUEUE *eventqueue)
Definition: event.c:2348
SCIP_RETCODE SCIPvboundsDel(SCIP_VBOUNDS **vbounds, BMS_BLKMEM *blkmem, SCIP_VAR *vbdvar, SCIP_Bool negativecoef)
Definition: implics.c:281
#define TRUE
Definition: def.h:63
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
SCIP_Bool SCIPcliqueIsEquation(SCIP_CLIQUE *clique)
Definition: implics.c:3346
SCIP_RETCODE SCIPdigraphSetSizes(SCIP_DIGRAPH *digraph, int *sizes)
Definition: misc.c:6569
SCIP_RETCODE SCIPcliquetableCreate(SCIP_CLIQUETABLE **cliquetable, SCIP_SET *set, BMS_BLKMEM *blkmem)
Definition: implics.c:1764
#define SCIPsetAllocBufferArray(set, ptr, num)
Definition: set.h:1834
#define checkNEntries(cliquetable)
Definition: implics.c:2786
static SCIP_RETCODE cliquelistCreate(SCIP_CLIQUELIST **cliquelist, BMS_BLKMEM *blkmem)
Definition: implics.c:1398
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:16862
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:2795
int SCIPsetCalcMemGrowSize(SCIP_SET *set, int num)
Definition: set.c:5091
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:829
SCIP_RETCODE SCIPcliquetableFree(SCIP_CLIQUETABLE **cliquetable, BMS_BLKMEM *blkmem)
Definition: implics.c:1798
#define SCIPdebugMessage
Definition: pub_message.h:77
SCIP_CLIQUE ** SCIPcliquelistGetCliques(SCIP_CLIQUELIST *cliquelist, SCIP_Bool value)
Definition: implics.c:3365
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:1458
#define SCIPsetFreeBufferArray(set, ptr)
Definition: set.h:1841
#define BMSfreeMemory(ptr)
Definition: memory.h:104
SCIP_Real * coefs
SCIP_VAR * SCIPvarGetNegationVar(SCIP_VAR *var)
Definition: var.c:16995
static void implicsSearchVar(SCIP_IMPLICS *implics, SCIP_Bool varfixing, SCIP_VAR *implvar, int *poslower, int *posupper, int *posadd)
Definition: implics.c:505
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:17521
static int getNodeIndexBinvar(SCIP_VAR *binvar)
Definition: implics.c:3004
static void cliquetableSwapCliques(SCIP_CLIQUETABLE *cliquetable, int first, int second)
Definition: implics.c:932
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:2014
static void cliquetableMarkCliqueForCleanup(SCIP_CLIQUETABLE *cliquetable, SCIP_CLIQUE *clique)
Definition: implics.c:958
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
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:980
int * ids[2]
#define SCIP_HASHSIZE_CLIQUES
Definition: def.h:237
void SCIPcliquelistFree(SCIP_CLIQUELIST **cliquelist, BMS_BLKMEM *blkmem)
Definition: implics.c:1417
void SCIPvarSetCliqueComponentIdx(SCIP_VAR *var, int idx)
Definition: var.c:17658
SCIP_RETCODE SCIPdigraphCreate(SCIP_DIGRAPH **digraph, int nnodes)
Definition: misc.c:6442
int SCIPcliqueSearchVar(SCIP_CLIQUE *clique, SCIP_VAR *var, SCIP_Bool value)
Definition: implics.c:1057
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17179
SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
Definition: var.c:11524
int SCIPcliquetableGetNCliques(SCIP_CLIQUETABLE *cliquetable)
Definition: implics.c:3416
#define BMSduplicateBlockMemoryArray(mem, ptr, source, num)
Definition: memory.h:420
SCIP_BOUNDTYPE * SCIPimplicsGetTypes(SCIP_IMPLICS *implics, SCIP_Bool varfixing)
Definition: implics.c:3264
void SCIPcliqueDelVar(SCIP_CLIQUE *clique, SCIP_CLIQUETABLE *cliquetable, SCIP_VAR *var, SCIP_Bool value)
Definition: implics.c:1261
SCIP_Bool SCIPimplicsContainsImpl(SCIP_IMPLICS *implics, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_BOUNDTYPE impltype)
Definition: implics.c:909
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:626
void SCIPsortPtrBool(void **ptrarray, SCIP_Bool *boolarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
static SCIP_DECL_HASHGETKEY(hashgetkeyClique)
Definition: implics.c:1715
#define SCIPcombineThreeInt(a, b, c)
Definition: pub_misc.h:480
#define BMSmoveMemoryArray(ptr, source, num)
Definition: memory.h:97
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:1309
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16555
#define NULL
Definition: lpi_spx1.cpp:137
SCIP_Real * SCIPvboundsGetCoefs(SCIP_VBOUNDS *vbounds)
Definition: implics.c:3230
SCIP_Bool incleanup
internal methods for global SCIP settings
#define SCIP_CALL(x)
Definition: def.h:316
#define SCIPhashTwo(a, b)
Definition: pub_misc.h:472
static void checkImplics(SCIP_IMPLICS *implics)
Definition: implics.c:376
SCIP_Bool SCIPsetIsFeasGE(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:6003
SCIP_RETCODE SCIPhashtableRemove(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2383
SCIP_VAR ** vars
SCIP_Real * SCIPvboundsGetConstants(SCIP_VBOUNDS *vbounds)
Definition: implics.c:3238
SCIP_RETCODE SCIPdigraphAddArc(SCIP_DIGRAPH *digraph, int startnode, int endnode, void *data)
Definition: misc.c:6668
unsigned int equation
SCIP_Bool SCIPcliquelistsHaveCommonClique(SCIP_CLIQUELIST *cliquelist1, SCIP_Bool value1, SCIP_CLIQUELIST *cliquelist2, SCIP_Bool value2)
Definition: implics.c:1581
SCIP_Bool SCIPsetIsFeasLE(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:5959
int SCIPcliquetableGetNCliqueComponents(SCIP_CLIQUETABLE *cliquetable)
Definition: implics.c:3446
void SCIPvboundsShrink(SCIP_VBOUNDS **vbounds, BMS_BLKMEM *blkmem, int newnvbds)
Definition: implics.c:326
#define BMSfreeBlockMemory(mem, ptr)
Definition: memory.h:423
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:4937
datastructures for implications, variable bounds, and cliques
public data structures and miscellaneous methods
SCIP_Bool SCIPcliquetableNeedsComponentUpdate(SCIP_CLIQUETABLE *cliquetable)
Definition: implics.c:3454
#define SCIP_Bool
Definition: def.h:61
int SCIPvarGetCliqueComponentIdx(SCIP_VAR *var)
Definition: var.c:17649
#define BMSfreeBlockMemoryArray(mem, ptr, num)
Definition: memory.h:425
int * SCIPimplicsGetIds(SCIP_IMPLICS *implics, SCIP_Bool varfixing)
Definition: implics.c:3285
#define MAX(x, y)
Definition: tclique_def.h:75
int SCIPimplicsGetNImpls(SCIP_IMPLICS *implics, SCIP_Bool varfixing)
Definition: implics.c:3246
methods for debugging
SCIP_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
Definition: implics.c:3316
#define SCIPsetDebugMsg
Definition: set.h:1870
SCIP_RETCODE SCIPvarAddCliqueToList(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_Bool value, SCIP_CLIQUE *clique)
Definition: var.c:10703
static SCIP_DECL_HASHKEYEQ(hashkeyeqClique)
Definition: implics.c:1722
SCIP_BOUNDTYPE * types[2]
#define cliqueCheck(clique)
Definition: implics.c:1393
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:10489
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2314
SCIP_Bool SCIPsetIsFeasLT(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:5937
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:2260
static SCIP_RETCODE vboundsCreate(SCIP_VBOUNDS **vbounds, BMS_BLKMEM *blkmem)
Definition: implics.c:48
int SCIPvboundsGetNVbds(SCIP_VBOUNDS *vbounds)
Definition: implics.c:3214
static void cliqueFree(SCIP_CLIQUE **clique, BMS_BLKMEM *blkmem)
Definition: implics.c:1014
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2064
static SCIP_RETCODE cliqueEnsureSize(SCIP_CLIQUE *clique, BMS_BLKMEM *blkmem, SCIP_SET *set, int num)
Definition: implics.c:1031
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:1850
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:3374
SCIP_CLIQUE ** cliques[2]
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16674
#define SCIP_Real
Definition: def.h:145
internal methods for problem statistics
SCIP_RETCODE SCIPvarsGetProbvarBinary(SCIP_VAR ***vars, SCIP_Bool **negatedarr, int nvars)
Definition: var.c:11584
SCIP_RETCODE SCIPcliquetableComputeCliqueComponents(SCIP_CLIQUETABLE *cliquetable, SCIP_SET *set, SCIP_VAR **vars, int nbinvars, int nintvars, int nimplvars)
Definition: implics.c:3042
#define MIN(x, y)
Definition: memory.c:75
#define BMSallocMemory(ptr)
Definition: memory.h:78
#define BMSreallocMemoryArray(ptr, num)
Definition: memory.h:86
#define SCIP_Longint
Definition: def.h:130
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:16852
SCIP_Bool SCIPsetIsFeasGT(SCIP_SET *set, SCIP_Real val1, SCIP_Real val2)
Definition: set.c:5981
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:16720
static SCIP_RETCODE cliquelistEnsureSize(SCIP_CLIQUELIST *cliquelist, BMS_BLKMEM *blkmem, SCIP_SET *set, SCIP_Bool value, int num)
Definition: implics.c:1434
SCIP_STAGE SCIPsetGetStage(SCIP_SET *set)
Definition: set.c:2664
SCIP_Bool SCIPvarIsMarkedDeleteGlobalStructures(SCIP_VAR *var)
Definition: var.c:16822
SCIP_Bool SCIPcliqueIsCleanedUp(SCIP_CLIQUE *clique)
Definition: implics.c:3336
int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
Definition: implics.c:3294
#define BMSallocBlockMemory(mem, ptr)
Definition: memory.h:410
common defines and data types used in all packages of SCIP
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:396
void SCIPdigraphFree(SCIP_DIGRAPH **digraph)
Definition: misc.c:6591
SCIP_Real * SCIPimplicsGetBounds(SCIP_IMPLICS *implics, SCIP_Bool varfixing)
Definition: implics.c:3273
#define SCIPcombineTwoInt(a, b)
Definition: pub_misc.h:478
#define SCIP_ALLOC(x)
Definition: def.h:327
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:10665
#define BMSreallocBlockMemoryArray(mem, ptr, oldnum, newnum)
Definition: memory.h:416
SCIP_CLIQUE ** SCIPcliquetableGetCliques(SCIP_CLIQUETABLE *cliquetable)
Definition: implics.c:3426
void SCIPimplicsFree(SCIP_IMPLICS **implics, BMS_BLKMEM *blkmem)
Definition: implics.c:444
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:16842
SCIP_RETCODE SCIPcliquelistDel(SCIP_CLIQUELIST **cliquelist, BMS_BLKMEM *blkmem, SCIP_Bool value, SCIP_CLIQUE *clique)
Definition: implics.c:1503
SCIP_Longint nentries
int nimplications
Definition: struct_stat.h:218
int SCIPcliqueGetId(SCIP_CLIQUE *clique)
Definition: implics.c:3326
SCIP_RETCODE SCIPvarDelCliqueFromList(SCIP_VAR *var, BMS_BLKMEM *blkmem, SCIP_Bool value, SCIP_CLIQUE *clique)
Definition: var.c:10725