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