Scippy

SCIP

Solving Constraint Integer Programs

cons_and.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 cons_and.c
26 * @ingroup DEFPLUGINS_CONS
27 * @ingroup CONSHDLRS
28 * @brief Constraint handler for AND-constraints, \f$r = x_1 \wedge x_2 \wedge \dots \wedge x_n\f$
29 * @author Tobias Achterberg
30 * @author Stefan Heinz
31 * @author Michael Winkler
32 *
33 * This constraint handler deals with AND-constraints. These are constraint of the form:
34 *
35 * \f[
36 * r = x_1 \wedge x_2 \wedge \dots \wedge x_n
37 * \f]
38 *
39 * where \f$x_i\f$ is a binary variable for all \f$i\f$. Hence, \f$r\f$ is also of binary type. The variable \f$r\f$ is
40 * called resultant and the \f$x\f$'s operators.
41 */
42
43/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
44
46#include "scip/cons_and.h"
47#include "scip/cons_linear.h"
48#include "scip/cons_logicor.h"
50#include "scip/cons_setppc.h"
51#include "scip/expr_product.h"
52#include "scip/expr_var.h"
53#include "scip/debug.h"
54#include "scip/pub_cons.h"
55#include "scip/pub_event.h"
56#include "scip/pub_lp.h"
57#include "scip/pub_message.h"
58#include "scip/pub_misc.h"
59#include "scip/pub_misc_sort.h"
60#include "scip/pub_var.h"
61#include "scip/scip_conflict.h"
62#include "scip/scip_cons.h"
63#include "scip/scip_copy.h"
64#include "scip/scip_cut.h"
65#include "scip/scip_event.h"
66#include "scip/scip_expr.h"
67#include "scip/scip_general.h"
68#include "scip/scip_lp.h"
69#include "scip/scip_mem.h"
70#include "scip/scip_message.h"
71#include "scip/scip_nlp.h"
72#include "scip/scip_numerics.h"
73#include "scip/scip_param.h"
74#include "scip/scip_prob.h"
75#include "scip/scip_probing.h"
76#include "scip/scip_sol.h"
77#include "scip/scip_tree.h"
78#include "scip/scip_var.h"
79#include "scip/symmetry_graph.h"
81#include <string.h>
82
83
84/* constraint handler properties */
85#define CONSHDLR_NAME "and"
86#define CONSHDLR_DESC "constraint handler for AND-constraints: r = and(x1, ..., xn)"
87#define CONSHDLR_SEPAPRIORITY +850100 /**< priority of the constraint handler for separation */
88#define CONSHDLR_ENFOPRIORITY -850100 /**< priority of the constraint handler for constraint enforcing */
89#define CONSHDLR_CHECKPRIORITY -850100 /**< priority of the constraint handler for checking feasibility */
90#define CONSHDLR_SEPAFREQ 1 /**< frequency for separating cuts; zero means to separate only in the root node */
91#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
92#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
93 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
94#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
95#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
96#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
97#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
98
99#define CONSHDLR_PRESOLTIMING (SCIP_PRESOLTIMING_FAST | SCIP_PRESOLTIMING_EXHAUSTIVE)
100#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
101
102#define EVENTHDLR_NAME "and"
103#define EVENTHDLR_DESC "bound change event handler for AND-constraints"
104
105#define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
106#define DEFAULT_LINEARIZE FALSE /**< should constraint get linearized and removed? */
107#define DEFAULT_ENFORCECUTS TRUE /**< should cuts be separated during LP enforcing? */
108#define DEFAULT_AGGRLINEARIZATION FALSE /**< should an aggregated linearization be used? */
109#define DEFAULT_UPGRRESULTANT FALSE /**< should implied integrality of resultant variables be detected? */
110#define DEFAULT_DUALPRESOLVING TRUE /**< should dual presolving be performed? */
111
112#define HASHSIZE_ANDCONS 500 /**< minimal size of hash table in and constraint tables */
113#define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
114#define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */
115#define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise comparison round */
116
117/* @todo maybe use event SCIP_EVENTTYPE_VARUNLOCKED to decide for another dual-presolving run on a constraint */
118
119/*
120 * Data structures
121 */
122
123/** constraint data for AND-constraints */
124struct SCIP_ConsData
125{
126 SCIP_VAR** vars; /**< variables in the AND-constraint */
127 SCIP_VAR* resvar; /**< resultant variable */
128 SCIP_ROW** rows; /**< rows for linear relaxation of AND-constraint */
129 SCIP_ROW* aggrrow; /**< aggregated row for linear relaxation of AND-constraint */
130 SCIP_NLROW* nlrow; /**< row for representation in nonlinear relaxation */
131 int nvars; /**< number of variables in AND-constraint */
132 int varssize; /**< size of vars array */
133 int nrows; /**< number of rows for linear relaxation of AND-constraint */
134 int watchedvar1; /**< position of first watched operator variable */
135 int watchedvar2; /**< position of second watched operator variable */
136 int filterpos1; /**< event filter position of first watched operator variable */
137 int filterpos2; /**< event filter position of second watched operator variable */
138 unsigned int propagated:1; /**< is constraint already preprocessed/propagated? */
139 unsigned int nofixedzero:1; /**< is none of the operator variables fixed to FALSE? */
140 unsigned int impladded:1; /**< were the implications of the constraint already added? */
141 unsigned int opimpladded:1; /**< was the implication for 2 operands with fixed resultant added? */
142 unsigned int sorted:1; /**< are the constraint's variables sorted? */
143 unsigned int changed:1; /**< was constraint changed since last pair preprocessing round? */
144 unsigned int merged:1; /**< are the constraint's equal variables already merged? */
145};
146
147/** constraint handler data */
148struct SCIP_ConshdlrData
149{
150 SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events on watched variables */
151 SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
152 SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance */
153 SCIP_Bool linearize; /**< should constraint get linearized and removed? */
154 SCIP_Bool enforcecuts; /**< should cuts be separated during LP enforcing? */
155 SCIP_Bool aggrlinearization; /**< should an aggregated linearization be used? */
156 SCIP_Bool upgrresultant; /**< should implied integrality of resultant variables be detected? */
157 SCIP_Bool dualpresolving; /**< should dual presolving be performed? */
158};
159
160
161/*
162 * Propagation rules
163 */
164
166{
167 PROPRULE_INVALID = 0, /**< propagation was applied without a specific propagation rule */
168 PROPRULE_1 = 1, /**< v_i = FALSE => r = FALSE */
169 PROPRULE_2 = 2, /**< r = TRUE => v_i = TRUE for all i */
170 PROPRULE_3 = 3, /**< v_i = TRUE for all i => r = TRUE */
171 PROPRULE_4 = 4 /**< r = FALSE, v_i = TRUE for all i except j => v_j = FALSE */
173typedef enum Proprule PROPRULE;
174
175
176/*
177 * Local methods
178 */
179
180/** installs rounding locks for the given variable in the given AND-constraint */
181static
183 SCIP* scip, /**< SCIP data structure */
184 SCIP_CONS* cons, /**< constraint data */
185 SCIP_VAR* var /**< variable of constraint entry */
186 )
187{
188 /* rounding in both directions may violate the constraint */
189 SCIP_CALL( SCIPlockVarCons(scip, var, cons, TRUE, TRUE) );
190
191 return SCIP_OKAY;
192}
193
194/** removes rounding locks for the given variable in the given AND-constraint */
195static
197 SCIP* scip, /**< SCIP data structure */
198 SCIP_CONS* cons, /**< constraint data */
199 SCIP_VAR* var /**< variable of constraint entry */
200 )
201{
202 /* rounding in both directions may violate the constraint */
203 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, TRUE) );
204
205 return SCIP_OKAY;
206}
207
208/** creates constraint handler data */
209static
211 SCIP* scip, /**< SCIP data structure */
212 SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
213 SCIP_EVENTHDLR* eventhdlr /**< event handler */
214 )
215{
216 assert(scip != NULL);
217 assert(conshdlrdata != NULL);
218 assert(eventhdlr != NULL);
219
220 SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
221
222 /* set event handler for catching bound change events on variables */
223 (*conshdlrdata)->eventhdlr = eventhdlr;
224
225 return SCIP_OKAY;
226}
227
228/** frees constraint handler data */
229static
231 SCIP* scip, /**< SCIP data structure */
232 SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
233 )
234{
235 assert(conshdlrdata != NULL);
236 assert(*conshdlrdata != NULL);
237
238 SCIPfreeBlockMemory(scip, conshdlrdata);
239}
240
241/** catches events for the watched variable at given position */
242static
244 SCIP* scip, /**< SCIP data structure */
245 SCIP_CONSDATA* consdata, /**< AND-constraint data */
246 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
247 int pos, /**< array position of variable to catch bound change events for */
248 int* filterpos /**< pointer to store position of event filter entry */
249 )
250{
251 assert(consdata != NULL);
252 assert(consdata->vars != NULL);
253 assert(eventhdlr != NULL);
254 assert(0 <= pos && pos < consdata->nvars);
255 assert(filterpos != NULL);
256
257 /* catch tightening events for lower bound and relaxed events for upper bounds on watched variable */
259 eventhdlr, (SCIP_EVENTDATA*)consdata, filterpos) );
260
261 return SCIP_OKAY;
262}
263
264
265/** drops events for the watched variable at given position */
266static
268 SCIP* scip, /**< SCIP data structure */
269 SCIP_CONSDATA* consdata, /**< AND-constraint data */
270 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
271 int pos, /**< array position of watched variable to drop bound change events for */
272 int filterpos /**< position of event filter entry */
273 )
274{
275 assert(consdata != NULL);
276 assert(consdata->vars != NULL);
277 assert(eventhdlr != NULL);
278 assert(0 <= pos && pos < consdata->nvars);
279 assert(filterpos >= 0);
280
281 /* drop tightening events for lower bound and relaxed events for upper bounds on watched variable */
283 eventhdlr, (SCIP_EVENTDATA*)consdata, filterpos) );
284
285 return SCIP_OKAY;
286}
287
288/** catches needed events on all variables of constraint, except the special ones for watched variables */
289static
291 SCIP* scip, /**< SCIP data structure */
292 SCIP_CONSDATA* consdata, /**< AND-constraint data */
293 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
294 )
295{
296 int i;
297
298 assert(consdata != NULL);
299
300 /* catch bound change events for both bounds on resultant variable */
302 eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
303
304 /* catch tightening events for upper bound and relaxed events for lower bounds on operator variables */
305 for( i = 0; i < consdata->nvars; ++i )
306 {
308 eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
309 }
310
311 return SCIP_OKAY;
312}
313
314/** drops events on all variables of constraint, except the special ones for watched variables */
315static
317 SCIP* scip, /**< SCIP data structure */
318 SCIP_CONSDATA* consdata, /**< AND-constraint data */
319 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
320 )
321{
322 int i;
323
324 assert(consdata != NULL);
325
326 /* drop bound change events for both bounds on resultant variable */
328 eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
329
330 /* drop tightening events for upper bound and relaxed events for lower bounds on operator variables */
331 for( i = 0; i < consdata->nvars; ++i )
332 {
334 eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
335 }
336
337 return SCIP_OKAY;
338}
339
340/** stores the given variable numbers as watched variables, and updates the event processing */
341static
343 SCIP* scip, /**< SCIP data structure */
344 SCIP_CONSDATA* consdata, /**< AND-constraint data */
345 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
346 int watchedvar1, /**< new first watched variable */
347 int watchedvar2 /**< new second watched variable */
348 )
349{
350 assert(consdata != NULL);
351 assert(watchedvar1 == -1 || watchedvar1 != watchedvar2);
352 assert(watchedvar1 != -1 || watchedvar2 == -1);
353 assert(watchedvar1 == -1 || (0 <= watchedvar1 && watchedvar1 < consdata->nvars));
354 assert(watchedvar2 == -1 || (0 <= watchedvar2 && watchedvar2 < consdata->nvars));
355
356 /* if one watched variable is equal to the old other watched variable, just switch positions */
357 if( watchedvar1 == consdata->watchedvar2 || watchedvar2 == consdata->watchedvar1 )
358 {
359 int tmp;
360
361 tmp = consdata->watchedvar1;
362 consdata->watchedvar1 = consdata->watchedvar2;
363 consdata->watchedvar2 = tmp;
364 tmp = consdata->filterpos1;
365 consdata->filterpos1 = consdata->filterpos2;
366 consdata->filterpos2 = tmp;
367 }
368 assert(watchedvar1 == -1 || watchedvar1 != consdata->watchedvar2);
369 assert(watchedvar2 == -1 || watchedvar2 != consdata->watchedvar1);
370
371 /* drop events on old watched variables */
372 if( consdata->watchedvar1 != -1 && consdata->watchedvar1 != watchedvar1 )
373 {
374 assert(consdata->filterpos1 != -1);
375 SCIP_CALL( consdataDropWatchedEvents(scip, consdata, eventhdlr, consdata->watchedvar1, consdata->filterpos1) );
376 }
377 if( consdata->watchedvar2 != -1 && consdata->watchedvar2 != watchedvar2 )
378 {
379 assert(consdata->filterpos2 != -1);
380 SCIP_CALL( consdataDropWatchedEvents(scip, consdata, eventhdlr, consdata->watchedvar2, consdata->filterpos2) );
381 }
382
383 /* catch events on new watched variables */
384 if( watchedvar1 != -1 && watchedvar1 != consdata->watchedvar1 )
385 {
386 SCIP_CALL( consdataCatchWatchedEvents(scip, consdata, eventhdlr, watchedvar1, &consdata->filterpos1) );
387 }
388 if( watchedvar2 != -1 && watchedvar2 != consdata->watchedvar2 )
389 {
390 SCIP_CALL( consdataCatchWatchedEvents(scip, consdata, eventhdlr, watchedvar2, &consdata->filterpos2) );
391 }
392
393 /* set the new watched variables */
394 consdata->watchedvar1 = watchedvar1;
395 consdata->watchedvar2 = watchedvar2;
396
397 return SCIP_OKAY;
398}
399
400/** ensures, that the vars array can store at least num entries */
401static
403 SCIP* scip, /**< SCIP data structure */
404 SCIP_CONSDATA* consdata, /**< linear constraint data */
405 int num /**< minimum number of entries to store */
406 )
407{
408 assert(consdata != NULL);
409 assert(consdata->nvars <= consdata->varssize);
410
411 if( num > consdata->varssize )
412 {
413 int newsize;
414
415 newsize = SCIPcalcMemGrowSize(scip, num);
416 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
417 consdata->varssize = newsize;
418 }
419 assert(num <= consdata->varssize);
420
421 return SCIP_OKAY;
422}
423
424/** creates constraint data for AND-constraint */
425static
427 SCIP* scip, /**< SCIP data structure */
428 SCIP_CONSDATA** consdata, /**< pointer to store the constraint data */
429 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
430 int nvars, /**< number of variables in the AND-constraint */
431 SCIP_VAR** vars, /**< variables in AND-constraint */
432 SCIP_VAR* resvar /**< resultant variable */
433 )
434{
435 int v;
436
437 assert(consdata != NULL);
438 assert(nvars == 0 || vars != NULL);
439 assert(resvar != NULL);
440
441 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
442 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
443 (*consdata)->resvar = resvar;
444 (*consdata)->rows = NULL;
445 (*consdata)->aggrrow = NULL;
446 (*consdata)->nlrow = NULL;
447 (*consdata)->nvars = nvars;
448 (*consdata)->varssize = nvars;
449 (*consdata)->nrows = 0;
450 (*consdata)->watchedvar1 = -1;
451 (*consdata)->watchedvar2 = -1;
452 (*consdata)->filterpos1 = -1;
453 (*consdata)->filterpos2 = -1;
454 (*consdata)->propagated = FALSE;
455 (*consdata)->nofixedzero = FALSE;
456 (*consdata)->impladded = FALSE;
457 (*consdata)->opimpladded = FALSE;
458 (*consdata)->sorted = FALSE;
459 (*consdata)->changed = TRUE;
460 (*consdata)->merged = FALSE;
461
462 /* get transformed variables, if we are in the transformed problem */
464 {
465 SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
466 SCIP_CALL( SCIPgetTransformedVar(scip, (*consdata)->resvar, &(*consdata)->resvar) );
467
468 /* catch needed events on variables */
469 SCIP_CALL( consdataCatchEvents(scip, *consdata, eventhdlr) );
470 }
471
472 assert(SCIPvarIsBinary((*consdata)->resvar));
473
474 /* note: currently, this constraint handler does not handle multiaggregations (e.g. during propagation), hence we forbid
475 * multiaggregation from the beginning for the involved variables
476 */
478 {
479 for( v = 0; v < (*consdata)->nvars; ++v )
480 {
481 assert((*consdata)->vars[v] != NULL);
482 SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->vars[v]) );
483 }
484 SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->resvar) );
485 }
486
487 /* capture vars */
488 SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->resvar) );
489 for( v = 0; v < (*consdata)->nvars; v++ )
490 {
491 assert((*consdata)->vars[v] != NULL);
492 assert(SCIPvarIsBinary((*consdata)->vars[v]));
493 SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[v]) );
494 }
495
496 return SCIP_OKAY;
497}
498
499/** releases LP rows of constraint data and frees rows array */
500static
502 SCIP* scip, /**< SCIP data structure */
503 SCIP_CONSDATA* consdata /**< constraint data */
504 )
505{
506 int r;
507
508 assert(consdata != NULL);
509
510 if( consdata->rows != NULL )
511 {
512 for( r = 0; r < consdata->nrows; ++r )
513 {
514 SCIP_CALL( SCIPreleaseRow(scip, &consdata->rows[r]) );
515 }
516 SCIPfreeBlockMemoryArray(scip, &consdata->rows, consdata->nrows);
517
518 consdata->nrows = 0;
519 }
520
521 if( consdata->aggrrow != NULL )
522 {
523 SCIP_CALL( SCIPreleaseRow(scip, &consdata->aggrrow) );
524 consdata->aggrrow = NULL;
525 }
526
527 return SCIP_OKAY;
528}
529
530/** frees constraint data for AND-constraint */
531static
533 SCIP* scip, /**< SCIP data structure */
534 SCIP_CONSDATA** consdata, /**< pointer to the constraint data */
535 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
536 )
537{
538 int v;
539
540 assert(consdata != NULL);
541 assert(*consdata != NULL);
542
544 {
545 /* drop events for watched variables */
546 SCIP_CALL( consdataSwitchWatchedvars(scip, *consdata, eventhdlr, -1, -1) );
547
548 /* drop all other events on variables */
549 SCIP_CALL( consdataDropEvents(scip, *consdata, eventhdlr) );
550 }
551 else
552 {
553 assert((*consdata)->watchedvar1 == -1);
554 assert((*consdata)->watchedvar2 == -1);
555 }
556
557 /* release and free the rows */
558 SCIP_CALL( consdataFreeRows(scip, *consdata) );
559
560 /* release the nlrow */
561 if( (*consdata)->nlrow != NULL )
562 {
563 SCIP_CALL( SCIPreleaseNlRow(scip, &(*consdata)->nlrow) );
564 }
565
566 /* release vars */
567 for( v = 0; v < (*consdata)->nvars; v++ )
568 {
569 assert((*consdata)->vars[v] != NULL);
570 SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->vars[v])) );
571 }
572 SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->resvar)) );
573
574 SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize);
575 SCIPfreeBlockMemory(scip, consdata);
576
577 return SCIP_OKAY;
578}
579
580/** prints AND-constraint to file stream */
581static
583 SCIP* scip, /**< SCIP data structure */
584 SCIP_CONSDATA* consdata, /**< AND-constraint data */
585 FILE* file /**< output file (or NULL for standard output) */
586 )
587{
588 assert(consdata != NULL);
589
590 /* print resultant */
591 SCIP_CALL( SCIPwriteVarName(scip, file, consdata->resvar, TRUE) );
592
593 /* start the variable list */
594 SCIPinfoMessage(scip, file, " == and(");
595
596 /* print variable list */
597 SCIP_CALL( SCIPwriteVarsList(scip, file, consdata->vars, consdata->nvars, TRUE, ',') );
598
599 /* close the variable list */
600 SCIPinfoMessage(scip, file, ")");
601
602 return SCIP_OKAY;
603}
604
605/** adds coefficient to AND-constraint */
606static
608 SCIP* scip, /**< SCIP data structure */
609 SCIP_CONS* cons, /**< linear constraint */
610 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
611 SCIP_VAR* var /**< variable to add to the constraint */
612 )
613{
614 SCIP_CONSDATA* consdata;
615 SCIP_Bool transformed;
616
617 assert(var != NULL);
618
619 consdata = SCIPconsGetData(cons);
620 assert(consdata != NULL);
621 assert(consdata->rows == NULL);
622
623 /* are we in the transformed problem? */
624 transformed = SCIPconsIsTransformed(cons);
625
626 /* always use transformed variables in transformed constraints */
627 if( transformed )
628 {
629 SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
630 }
631 assert(var != NULL);
632 assert(transformed == SCIPvarIsTransformed(var));
633
634 SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1) );
635 consdata->vars[consdata->nvars] = var;
636 consdata->nvars++;
637 consdata->sorted = (consdata->nvars == 1);
638 consdata->changed = TRUE;
639 consdata->merged = FALSE;
640
641 /* capture variable */
643
644 /* if we are in transformed problem, catch the variable's events */
645 if( transformed )
646 {
647 /* catch bound change events of variable */
649 eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
650 }
651
652 /* install the rounding locks for the new variable */
653 SCIP_CALL( lockRounding(scip, cons, var) );
654
655 /**@todo update LP rows */
656 if( consdata->rows != NULL )
657 {
658 SCIPerrorMessage("cannot add coefficients to AND-constraint after LP relaxation was created\n");
659 return SCIP_INVALIDCALL;
660 }
661
662 return SCIP_OKAY;
663}
664
665/** deletes coefficient at given position from AND-constraint data */
666static
668 SCIP* scip, /**< SCIP data structure */
669 SCIP_CONS* cons, /**< AND-constraint */
670 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
671 int pos /**< position of coefficient to delete */
672 )
673{
674 SCIP_CONSDATA* consdata;
675
676 assert(eventhdlr != NULL);
677
678 consdata = SCIPconsGetData(cons);
679 assert(consdata != NULL);
680 assert(0 <= pos && pos < consdata->nvars);
681 assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(consdata->vars[pos]));
682
683 /* remove the rounding locks of the variable */
684 SCIP_CALL( unlockRounding(scip, cons, consdata->vars[pos]) );
685
686 if( SCIPconsIsTransformed(cons) )
687 {
688 /* drop bound change events of variable */
690 eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
691 }
692
693 if( SCIPconsIsTransformed(cons) )
694 {
695 /* if the position is watched, stop watching the position */
696 if( consdata->watchedvar1 == pos )
697 {
698 SCIP_CALL( consdataSwitchWatchedvars(scip, consdata, eventhdlr, consdata->watchedvar2, -1) );
699 }
700 if( consdata->watchedvar2 == pos )
701 {
702 SCIP_CALL( consdataSwitchWatchedvars(scip, consdata, eventhdlr, consdata->watchedvar1, -1) );
703 }
704 }
705 assert(pos != consdata->watchedvar1);
706 assert(pos != consdata->watchedvar2);
707
708 /* release variable */
709 SCIP_CALL( SCIPreleaseVar(scip, &(consdata->vars[pos])) );
710
711 /* move the last variable to the free slot */
712 consdata->vars[pos] = consdata->vars[consdata->nvars-1];
713 consdata->nvars--;
714
715 /* if the last variable (that moved) was watched, update the watched position */
716 if( consdata->watchedvar1 == consdata->nvars )
717 consdata->watchedvar1 = pos;
718 if( consdata->watchedvar2 == consdata->nvars )
719 consdata->watchedvar2 = pos;
720
721 consdata->propagated = FALSE;
722 consdata->sorted = FALSE;
723 consdata->changed = TRUE;
724
725 return SCIP_OKAY;
726}
727
728/** sorts AND-constraint's variables by non-decreasing variable index */
729static
731 SCIP_CONSDATA* consdata /**< constraint data */
732 )
733{
734 assert(consdata != NULL);
735
736 if( !consdata->sorted )
737 {
738 if( consdata->nvars <= 1 )
739 consdata->sorted = TRUE;
740 else
741 {
742 SCIP_VAR* var1 = NULL;
743 SCIP_VAR* var2 = NULL;
744
745 /* remember watch variables */
746 if( consdata->watchedvar1 != -1 )
747 {
748 var1 = consdata->vars[consdata->watchedvar1];
749 assert(var1 != NULL);
750 consdata->watchedvar1 = -1;
751 if( consdata->watchedvar2 != -1 )
752 {
753 var2 = consdata->vars[consdata->watchedvar2];
754 assert(var2 != NULL);
755 consdata->watchedvar2 = -1;
756 }
757 }
758 assert(consdata->watchedvar1 == -1);
759 assert(consdata->watchedvar2 == -1);
760 assert(var1 != NULL || var2 == NULL);
761
762 /* sort variables after index */
763 SCIPsortPtr((void**)consdata->vars, SCIPvarComp, consdata->nvars);
764 consdata->sorted = TRUE;
765
766 /* correct watched variables */
767 if( var1 != NULL )
768 {
769 int pos;
770#ifndef NDEBUG
771 SCIP_Bool found;
772
773 found = SCIPsortedvecFindPtr((void**)consdata->vars, SCIPvarComp, (void*)var1, consdata->nvars, &pos);
774 assert(found);
775#else
776 (void) SCIPsortedvecFindPtr((void**)consdata->vars, SCIPvarComp, (void*)var1, consdata->nvars, &pos);
777#endif
778 assert(pos >= 0 && pos < consdata->nvars);
779 consdata->watchedvar1 = pos;
780
781 if( var2 != NULL )
782 {
783#ifndef NDEBUG
784 found = SCIPsortedvecFindPtr((void**)consdata->vars, SCIPvarComp, (void*)var2, consdata->nvars, &pos);
785 assert(found);
786#else
787 (void) SCIPsortedvecFindPtr((void**)consdata->vars, SCIPvarComp, (void*)var2, consdata->nvars, &pos);
788#endif
789 assert(pos >= 0 && pos < consdata->nvars);
790 consdata->watchedvar2 = pos;
791 }
792 }
793 }
794 }
795
796#ifdef SCIP_DEBUG
797 /* check sorting */
798 {
799 int v;
800
801 for( v = 0; v < consdata->nvars; ++v )
802 {
803 assert(v == consdata->nvars-1 || SCIPvarCompare(consdata->vars[v], consdata->vars[v+1]) <= 0);
804 }
805 }
806#endif
807}
808
809/** deletes all one-fixed variables */
810static
812 SCIP* scip, /**< SCIP data structure */
813 SCIP_CONS* cons, /**< AND-constraint */
814 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
815 int* nchgcoefs /**< pointer to add up the number of changed coefficients */
816 )
817{
818 SCIP_CONSDATA* consdata;
819 SCIP_VAR* var;
820 int v;
821
822 assert(scip != NULL);
823 assert(cons != NULL);
824 assert(eventhdlr != NULL);
825 assert(nchgcoefs != NULL);
826
827 consdata = SCIPconsGetData(cons);
828 assert(consdata != NULL);
829 assert(consdata->nvars == 0 || consdata->vars != NULL);
830
831 v = 0;
832 while( v < consdata->nvars )
833 {
834 var = consdata->vars[v];
835 assert(SCIPvarIsBinary(var));
836
837 if( SCIPvarGetLbGlobal(var) > 0.5 )
838 {
839 assert(SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(var), 1.0));
840 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
841 (*nchgcoefs)++;
842 }
843 else
844 {
845 SCIP_VAR* repvar;
846 SCIP_Bool negated;
847
848 /* get binary representative of variable */
849 SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
850
851 /* check, if the variable should be replaced with the representative */
852 if( repvar != var )
853 {
854 /* delete old (aggregated) variable */
855 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
856
857 /* add representative instead */
858 SCIP_CALL( addCoef(scip, cons, eventhdlr, repvar) );
859 }
860 else
861 ++v;
862 }
863 }
864
865#ifdef SCIP_DISABLED_CODE /* does not work with pseudoboolean constraint handler, need to be fixed */
866 /* check, if the resultant should be replaced with the active representative */
867 if( !SCIPvarIsActive(consdata->resvar) )
868 {
869 SCIP_VAR* repvar;
870 SCIP_Bool negated;
871
872 /* get binary representative of variable */
873 SCIP_CALL( SCIPgetBinvarRepresentative(scip, consdata->resvar, &repvar, &negated) );
874 assert(SCIPvarIsBinary(repvar));
875
876 /* check, if the variable should be replaced with the representative */
877 if( repvar != consdata->resvar )
878 {
879 if( SCIPconsIsTransformed(cons) )
880 {
881 /* drop bound change events of old resultant */
883 eventhdlr, (SCIP_EVENTDATA*)consdata, -1) );
884
885 /* catch bound change events of new resultant */
887 eventhdlr, (SCIP_EVENTDATA*)consdata, NULL) );
888 }
889
890 /* release old resultant */
891 SCIP_CALL( SCIPreleaseVar(scip, &(consdata->resvar)) );
892
893 /* capture new resultant */
894 SCIP_CALL( SCIPcaptureVar(scip, repvar) );
895
896 consdata->resvar = repvar;
897 consdata->changed = TRUE;
898 }
899 }
900#endif
901
902 SCIPdebugMsg(scip, "after fixings: ");
903 SCIPdebug( SCIP_CALL( consdataPrint(scip, consdata, NULL)) );
904 SCIPdebugMsgPrint(scip, "\n");
905
906 return SCIP_OKAY;
907}
908
909/** creates a linearization of the AND-constraint */
910static
912 SCIP* scip, /**< SCIP data structure */
913 SCIP_CONS* cons /**< constraint to check */
914 )
915{
916 SCIP_CONSDATA* consdata;
917 char rowname[SCIP_MAXSTRLEN];
918 int nvars;
919 int i;
920
921 consdata = SCIPconsGetData(cons);
922 assert(consdata != NULL);
923 assert(consdata->rows == NULL);
924
925 nvars = consdata->nvars;
926
927 /* get memory for rows */
928 consdata->nrows = nvars + 1;
929 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->rows, consdata->nrows) );
930
931 /* creates LP rows corresponding to AND-constraint:
932 * - one additional row: resvar - v1 - ... - vn >= 1-n
933 * - for each operator variable vi: resvar - vi <= 0
934 */
935
936 /* create additional row */
937 (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s_add", SCIPconsGetName(cons));
938 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->rows[0], cons, rowname, -consdata->nvars + 1.0, SCIPinfinity(scip),
940 SCIP_CALL( SCIPaddVarToRow(scip, consdata->rows[0], consdata->resvar, 1.0) );
941 SCIP_CALL( SCIPaddVarsToRowSameCoef(scip, consdata->rows[0], nvars, consdata->vars, -1.0) );
942
943 /* create operator rows */
944 for( i = 0; i < nvars; ++i )
945 {
946 (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s_%d", SCIPconsGetName(cons), i);
947 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->rows[i+1], cons, rowname, -SCIPinfinity(scip), 0.0,
949 SCIP_CALL( SCIPaddVarToRow(scip, consdata->rows[i+1], consdata->resvar, 1.0) );
950 SCIP_CALL( SCIPaddVarToRow(scip, consdata->rows[i+1], consdata->vars[i], -1.0) );
951 }
952
953 return SCIP_OKAY;
954}
955
956/** adds linear relaxation of AND-constraint to the LP */
957static
959 SCIP* scip, /**< SCIP data structure */
960 SCIP_CONS* cons, /**< constraint to check */
961 SCIP_Bool* infeasible /**< pointer to store whether an infeasibility was detected */
962 )
963{
964 SCIP_CONSDATA* consdata;
965
966 /* in the root LP we only add the weaker relaxation which consists of two rows:
967 * - one additional row: resvar - v1 - ... - vn >= 1-n
968 * - aggregated row: n*resvar - v1 - ... - vn <= 0.0
969 *
970 * during separation we separate the stronger relaxation which consists of n+1 row:
971 * - one additional row: resvar - v1 - ... - vn >= 1-n
972 * - for each operator variable vi: resvar - vi <= 0.0
973 */
974
975 consdata = SCIPconsGetData(cons);
976 assert(consdata != NULL);
977
978 /* create the aggregated row */
979 if( consdata->aggrrow == NULL )
980 {
981 char rowname[SCIP_MAXSTRLEN];
982
983 (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s_operators", SCIPconsGetName(cons));
984 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->aggrrow, cons, rowname, -SCIPinfinity(scip), 0.0,
986 SCIP_CALL( SCIPaddVarToRow(scip, consdata->aggrrow, consdata->resvar, (SCIP_Real) consdata->nvars) );
987 SCIP_CALL( SCIPaddVarsToRowSameCoef(scip, consdata->aggrrow, consdata->nvars, consdata->vars, -1.0) );
988 }
989
990 /* insert aggregated LP row as cut */
991 if( !SCIProwIsInLP(consdata->aggrrow) )
992 {
993 SCIP_CALL( SCIPaddRow(scip, consdata->aggrrow, FALSE, infeasible) );
994 }
995
996 if( !(*infeasible) )
997 {
998 if( consdata->rows == NULL )
999 {
1000 /* create the n+1 row relaxation */
1002 }
1003
1004 assert(consdata->rows != NULL);
1005
1006 /* add additional row */
1007 if( !SCIProwIsInLP(consdata->rows[0]) )
1008 {
1009 SCIP_CALL( SCIPaddRow(scip, consdata->rows[0], FALSE, infeasible) );
1010 }
1011 }
1012
1013 return SCIP_OKAY;
1014}
1015
1016/** adds constraint as row to the NLP, if not added yet */
1017static
1019 SCIP* scip, /**< SCIP data structure */
1020 SCIP_CONS* cons /**< and constraint */
1021 )
1022{
1023 SCIP_CONSDATA* consdata;
1024
1025 assert(SCIPisNLPConstructed(scip));
1026
1027 /* skip deactivated, redundant, or local constraints (the NLP does not allow for local rows at the moment) */
1028 if( !SCIPconsIsActive(cons) || !SCIPconsIsChecked(cons) || SCIPconsIsLocal(cons) )
1029 return SCIP_OKAY;
1030
1031 consdata = SCIPconsGetData(cons);
1032 assert(consdata != NULL);
1033 assert(consdata->resvar != NULL);
1034
1035 if( consdata->nlrow == NULL )
1036 {
1037 SCIP_EXPR* expr;
1038 SCIP_EXPR** varexprs;
1039 SCIP_Real minusone = -1.0;
1040 int i;
1041
1042 SCIP_CALL( SCIPallocBufferArray(scip, &varexprs, consdata->nvars) );
1043 for( i = 0; i < consdata->nvars; ++i )
1044 {
1045 SCIP_CALL( SCIPcreateExprVar(scip, &varexprs[i], consdata->vars[i], NULL, NULL) );
1046 }
1047 SCIP_CALL( SCIPcreateExprProduct(scip, &expr, consdata->nvars, varexprs, 1.0, NULL, NULL) );
1048
1049 SCIP_CALL( SCIPcreateNlRow(scip, &consdata->nlrow, SCIPconsGetName(cons),
1050 0.0, 1, &consdata->resvar, &minusone, expr, 0.0, 0.0, SCIP_EXPRCURV_UNKNOWN) );
1051 assert(consdata->nlrow != NULL);
1052
1053 SCIP_CALL( SCIPreleaseExpr(scip, &expr) );
1054 for( i = 0; i < consdata->nvars; ++i )
1055 {
1056 SCIP_CALL( SCIPreleaseExpr(scip, &varexprs[i]) );
1057 }
1058 SCIPfreeBufferArray(scip, &varexprs);
1059 }
1060
1061 if( !SCIPnlrowIsInNLP(consdata->nlrow) )
1062 {
1063 SCIP_CALL( SCIPaddNlRow(scip, consdata->nlrow) );
1064 }
1065
1066 return SCIP_OKAY;
1067}
1068
1069/** checks AND-constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
1070static
1072 SCIP* scip, /**< SCIP data structure */
1073 SCIP_CONS* cons, /**< constraint to check */
1074 SCIP_SOL* sol, /**< solution to check, NULL for current solution */
1075 SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */
1076 SCIP_Bool printreason, /**< Should the reason for the violation be printed? */
1077 SCIP_Bool* violated /**< pointer to store whether the constraint is violated */
1078 )
1079{
1080 SCIP_CONSDATA* consdata;
1081 SCIP_Bool mustcheck;
1082 int r;
1083
1084 assert(violated != NULL);
1085
1086 consdata = SCIPconsGetData(cons);
1087 assert(consdata != NULL);
1088
1089 *violated = FALSE;
1090
1091 /* check whether we can skip this feasibility check, because all rows are in the LP and do not have to be checked */
1092 mustcheck = checklprows;
1093 mustcheck = mustcheck || (consdata->rows == NULL);
1094 if( !mustcheck )
1095 {
1096 assert(consdata->rows != NULL);
1097
1098 for( r = 0; r < consdata->nrows; ++r )
1099 {
1100 mustcheck = !SCIProwIsInLP(consdata->rows[r]);
1101 if( mustcheck )
1102 break;
1103 }
1104 }
1105
1106 /* check feasibility of constraint if necessary */
1107 if( mustcheck )
1108 {
1109 SCIP_Real minsolval = 1.0;
1110 SCIP_Real sumsolval = 0.0;
1111 SCIP_Real solval;
1112 SCIP_Real viol;
1113 int minsolind = 0;
1114 int i;
1115
1116 /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
1117 * enforcement
1118 */
1119 if( sol == NULL )
1120 {
1121 SCIP_CALL( SCIPincConsAge(scip, cons) );
1122 }
1123
1124 /* evaluate operator variables */
1125 for( i = 0; i < consdata->nvars; ++i )
1126 {
1127 solval = SCIPgetSolVal(scip, sol, consdata->vars[i]);
1128
1129 if( minsolval > solval )
1130 {
1131 minsolind = i;
1132 minsolval = solval;
1133 }
1134
1135 sumsolval += solval;
1136 }
1137
1138 /* the resultant must be at most as large as every operator
1139 * and at least as large as one minus the sum of negated operators
1140 */
1141 solval = SCIPgetSolVal(scip, sol, consdata->resvar);
1142 viol = MAX3(0.0, solval - minsolval, sumsolval - (consdata->nvars - 1.0 + solval));
1143
1144 if( SCIPisFeasPositive(scip, viol) )
1145 {
1146 *violated = TRUE;
1147
1148 /* only reset constraint age if we are in enforcement */
1149 if( sol == NULL )
1150 {
1152 }
1153
1154 if( printreason )
1155 {
1156 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
1157 SCIPinfoMessage(scip, NULL, ";\n");
1158 SCIPinfoMessage(scip, NULL, "violation:");
1159
1160 if( SCIPisFeasPositive(scip, solval - minsolval) )
1161 {
1162 SCIPinfoMessage(scip, NULL, " operand <%s> = FALSE and resultant <%s> = TRUE\n",
1163 SCIPvarGetName(consdata->vars[minsolind]), SCIPvarGetName(consdata->resvar));
1164 }
1165 else
1166 {
1167 SCIPinfoMessage(scip, NULL, " all operands are TRUE and resultant <%s> = FALSE\n",
1168 SCIPvarGetName(consdata->resvar));
1169 }
1170 }
1171 }
1172
1173 /* update constraint violation in solution */
1174 if( sol != NULL )
1175 SCIPupdateSolConsViolation(scip, sol, viol, viol);
1176 }
1177
1178 return SCIP_OKAY;
1179}
1180
1181/** separates given primal solution */
1182static
1184 SCIP* scip, /**< SCIP data structure */
1185 SCIP_CONS* cons, /**< constraint to check */
1186 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
1187 SCIP_Bool* separated, /**< pointer to store whether a cut was found */
1188 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
1189 )
1190{
1191 SCIP_CONSDATA* consdata;
1192 SCIP_Real feasibility;
1193 int r;
1194
1195 assert(separated != NULL);
1196 assert(cutoff != NULL);
1197
1198 *separated = FALSE;
1199 *cutoff = FALSE;
1200
1201 consdata = SCIPconsGetData(cons);
1202 assert(consdata != NULL);
1203
1204 /* create all necessary rows for the linear relaxation */
1205 if( consdata->rows == NULL )
1206 {
1208 }
1209 assert(consdata->rows != NULL);
1210
1211 /* test all rows for feasibility and add infeasible rows */
1212 for( r = 0; r < consdata->nrows; ++r )
1213 {
1214 if( !SCIProwIsInLP(consdata->rows[r]) )
1215 {
1216 feasibility = SCIPgetRowSolFeasibility(scip, consdata->rows[r], sol);
1217 if( SCIPisFeasNegative(scip, feasibility) )
1218 {
1219 SCIP_CALL( SCIPaddRow(scip, consdata->rows[r], FALSE, cutoff) );
1220 if ( *cutoff )
1221 return SCIP_OKAY;
1222 *separated = TRUE;
1223 }
1224 }
1225 }
1226
1227 return SCIP_OKAY;
1228}
1229
1230/** analyzes conflicting TRUE assignment to resultant of given constraint, and adds conflict constraint to problem */
1231static
1233 SCIP* scip, /**< SCIP data structure */
1234 SCIP_CONS* cons, /**< AND-constraint that detected the conflict */
1235 int falsepos /**< position of operand that is fixed to FALSE */
1236 )
1237{
1238 SCIP_CONSDATA* consdata;
1239
1240 /* conflict analysis can only be applied in solving stage and if it turned on */
1242 return SCIP_OKAY;
1243
1244 consdata = SCIPconsGetData(cons);
1245 assert(consdata != NULL);
1246 assert(SCIPvarGetLbLocal(consdata->resvar) > 0.5);
1247 assert(0 <= falsepos && falsepos < consdata->nvars);
1248 assert(SCIPvarGetUbLocal(consdata->vars[falsepos]) < 0.5);
1249
1250 /* initialize conflict analysis, and add resultant and single operand variable to conflict candidate queue */
1252
1253 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->resvar) );
1254 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[falsepos]) );
1255
1256 /* analyze the conflict */
1258
1259 return SCIP_OKAY;
1260}
1261
1262/** analyzes conflicting FALSE assignment to resultant of given constraint, and adds conflict constraint to problem */
1263static
1265 SCIP* scip, /**< SCIP data structure */
1266 SCIP_CONS* cons /**< or constraint that detected the conflict */
1267 )
1268{
1269 SCIP_CONSDATA* consdata;
1270 int v;
1271
1272 assert(!SCIPconsIsModifiable(cons));
1273
1274 /* conflict analysis can only be applied in solving stage and if it is applicable */
1276 return SCIP_OKAY;
1277
1278 consdata = SCIPconsGetData(cons);
1279 assert(consdata != NULL);
1280 assert(SCIPvarGetUbLocal(consdata->resvar) < 0.5);
1281
1282 /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */
1284
1285 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->resvar) );
1286 for( v = 0; v < consdata->nvars; ++v )
1287 {
1288 assert(SCIPvarGetLbLocal(consdata->vars[v]) > 0.5);
1289 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->vars[v]) );
1290 }
1291
1292 /* analyze the conflict */
1294
1295 return SCIP_OKAY;
1296}
1297
1298/** tries to fix the given resultant to zero */
1299static
1301 SCIP* scip, /**< SCIP data structure */
1302 SCIP_CONS* cons, /**< AND-constraint to be processed */
1303 SCIP_VAR* resvar, /**< resultant variable to fix to zero */
1304 int pos, /**< position of operand that is fixed to FALSE */
1305 SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
1306 int* nfixedvars /**< pointer to add up the number of found domain reductions */
1307 )
1308{
1309 SCIP_Bool infeasible;
1310 SCIP_Bool tightened;
1311
1312 SCIPdebugMsg(scip, "constraint <%s>: operator %d fixed to 0.0 -> fix resultant <%s> to 0.0\n",
1313 SCIPconsGetName(cons), pos, SCIPvarGetName(resvar));
1314
1315 SCIP_CALL( SCIPinferBinvarCons(scip, resvar, FALSE, cons, (int)PROPRULE_1, &infeasible, &tightened) );
1316
1317 if( infeasible )
1318 {
1319 /* use conflict analysis to get a conflict constraint out of the conflicting assignment */
1320 SCIP_CALL( analyzeConflictOne(scip, cons, pos) );
1322 (*cutoff) = TRUE;
1323 }
1324 else
1325 {
1327 if( tightened )
1328 {
1330 (*nfixedvars)++;
1331 }
1332 }
1333
1334 return SCIP_OKAY;
1335}
1336
1337/** fix all operands to one */
1338static
1340 SCIP* scip, /**< SCIP data structure */
1341 SCIP_CONS* cons, /**< AND-constraint to be processed */
1342 SCIP_VAR** vars, /**< array of operands */
1343 int nvars, /**< number of operands */
1344 SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
1345 int* nfixedvars /**< pointer to add up the number of found domain reductions */
1346 )
1347{
1348 SCIP_Bool infeasible;
1349 SCIP_Bool tightened;
1350 int v;
1351
1352 for( v = 0; v < nvars && !(*cutoff); ++v )
1353 {
1354 SCIPdebugMsg(scip, "constraint <%s>: resultant fixed to 1.0 -> fix operator var <%s> to 1.0\n",
1355 SCIPconsGetName(cons), SCIPvarGetName(vars[v]));
1356
1357 SCIP_CALL( SCIPinferBinvarCons(scip, vars[v], TRUE, cons, (int)PROPRULE_2, &infeasible, &tightened) );
1358
1359 if( infeasible )
1360 {
1361 /* use conflict analysis to get a conflict constraint out of the conflicting assignment */
1362 SCIP_CALL( analyzeConflictOne(scip, cons, v) );
1364 (*cutoff) = TRUE;
1365 }
1366 else if( tightened )
1367 {
1369 (*nfixedvars)++;
1370 }
1371 }
1372
1373 if( !(*cutoff) )
1374 {
1376 }
1377
1378 return SCIP_OKAY;
1379}
1380
1381/** linearize AND-constraint due to a globally to zero fixed resultant; that is, creates, adds, and releases a logicor
1382 * constraint and remove the AND-constraint globally.
1383 *
1384 * Since the resultant is fixed to zero the AND-constraint collapses to linear constraint of the form:
1385 *
1386 * - \f$\sum_{i=0}^{n-1} v_i \leq n-1\f$
1387 *
1388 * This can be transformed into a logicor constraint of the form
1389 *
1390 * - \f$\sum_{i=0}^{n-1} ~v_i \geq 1\f$
1391 */
1392static
1394 SCIP* scip, /**< SCIP data structure */
1395 SCIP_CONS* cons, /**< AND-constraint to linearize */
1396 SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
1397 int* nfixedvars, /**< pointer to add up the number of found domain reductions */
1398 int* nupgdconss /**< pointer to add up the number of upgraded constraints */
1399 )
1400{
1401 SCIP_CONSDATA* consdata;
1402 SCIP_VAR** vars;
1403 SCIP_CONS* lincons;
1404 SCIP_Bool conscreated;
1405 int nvars;
1406
1407 consdata = SCIPconsGetData(cons);
1408 assert(consdata != NULL);
1409
1410 assert(!(*cutoff));
1411 assert(SCIPvarGetUbGlobal(consdata->resvar) < 0.5);
1412
1413 nvars = consdata->nvars;
1414 conscreated = FALSE;
1415
1416 /* allocate memory for variables for updated constraint */
1417 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
1418
1419 /* if we only have two variables, we prefer a set packing constraint instead of a logicor constraint */
1420 if( nvars == 2 && !SCIPconsIsModifiable(cons) )
1421 {
1422 SCIP_Bool* negated;
1423 SCIP_Bool infeasible;
1424 SCIP_Bool tightened;
1425
1426 /* get active representation */
1427 SCIP_CALL( SCIPallocBufferArray(scip, &negated, nvars) );
1428 SCIP_CALL( SCIPgetBinvarRepresentatives(scip, nvars, consdata->vars, vars, negated) );
1429 SCIPfreeBufferArray(scip, &negated);
1430
1431 /* if one of the two operators is globally fixed to one it follows that the other has to be zero */
1432 if( SCIPvarGetLbGlobal(vars[0]) > 0.5 )
1433 {
1434 SCIP_CALL( SCIPfixVar(scip, vars[1], 0.0, &infeasible, &tightened) );
1435
1436 if( infeasible )
1437 *cutoff = TRUE;
1438 else if( tightened )
1439 ++(*nfixedvars);
1440 }
1441 else if( SCIPvarGetLbGlobal(vars[1]) > 0.5 )
1442 {
1443 SCIP_CALL( SCIPfixVar(scip, vars[0], 0.0, &infeasible, &tightened) );
1444
1445 if( infeasible )
1446 *cutoff = TRUE;
1447 else if( tightened )
1448 ++(*nfixedvars);
1449 }
1450 else if( SCIPvarGetUbGlobal(vars[0]) > 0.5 && SCIPvarGetUbGlobal(vars[1]) > 0.5 )
1451 {
1452 /* create, add, and release the setppc constraint */
1453 SCIP_CALL( SCIPcreateConsSetpack(scip, &lincons, SCIPconsGetName(cons), nvars, vars,
1457 SCIPconsIsStickingAtNode(cons)) );
1458
1459 conscreated = TRUE;
1460 }
1461 }
1462 else
1463 {
1464 int v;
1465
1466 /* collect negated variables */
1467 for( v = 0; v < nvars; ++v )
1468 {
1469 SCIP_CALL( SCIPgetNegatedVar(scip, consdata->vars[v], &vars[v]) );
1470 }
1471
1472 /* create, add, and release the logicor constraint */
1473 SCIP_CALL( SCIPcreateConsLogicor(scip, &lincons, SCIPconsGetName(cons), nvars, vars,
1477 SCIPconsIsStickingAtNode(cons)) );
1478
1479 conscreated = TRUE;
1480 }
1481
1482 if( conscreated )
1483 {
1484 /* add and release new constraint */
1485 SCIPdebugPrintCons(scip, lincons, NULL); /*lint !e644*/
1486 SCIP_CALL( SCIPaddConsUpgrade(scip, cons, &lincons) );
1487 ++(*nupgdconss);
1488 }
1489
1490 /* remove the AND-constraint globally */
1491 SCIP_CALL( SCIPdelCons(scip, cons) );
1492
1493 /* delete temporary memory */
1494 SCIPfreeBufferArray(scip, &vars);
1495
1496 return SCIP_OKAY;
1497}
1498
1499/** the resultant is fixed to zero; in case all except one operator are fixed to TRUE the last operator has to fixed to FALSE */
1500/** @note consdata->watchedvars might not be the same to the watchedvar parameters, because the update was not yet done */
1501static
1503 SCIP* scip, /**< SCIP data structure */
1504 SCIP_CONS* cons, /**< AND-constraint to be processed */
1505 int watchedvar1, /**< maybe last unfixed variable position */
1506 int watchedvar2, /**< second watched position */
1507 SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
1508 int* nfixedvars /**< pointer to add up the number of found domain reductions */
1509 )
1510{
1511 SCIP_CONSDATA* consdata;
1512
1513 consdata = SCIPconsGetData(cons);
1514 assert(consdata != NULL);
1515 assert(SCIPvarGetUbLocal(consdata->resvar) < 0.5);
1516
1517 if( watchedvar2 == -1 )
1518 {
1519 SCIP_Bool infeasible;
1520 SCIP_Bool tightened;
1521
1522 assert(watchedvar1 != -1);
1523
1524#ifndef NDEBUG
1525 /* check that all variables regardless of wathcedvar1 are fixed to 1 */
1526 {
1527 int v;
1528
1529 for( v = consdata->nvars - 1; v >= 0; --v )
1530 if( v != watchedvar1 )
1531 assert(SCIPvarGetLbLocal(consdata->vars[v]) > 0.5);
1532 }
1533#endif
1534
1535 SCIPdebugMsg(scip, "constraint <%s>: resultant <%s> fixed to 0.0, only one unfixed operand -> fix operand <%s> to 0.0\n",
1536 SCIPconsGetName(cons), SCIPvarGetName(consdata->resvar), SCIPvarGetName(consdata->vars[watchedvar1]));
1537
1538 SCIP_CALL( SCIPinferBinvarCons(scip, consdata->vars[watchedvar1], FALSE, cons, (int)PROPRULE_4, &infeasible, &tightened) );
1539
1540 if( infeasible )
1541 {
1542 /* use conflict analysis to get a conflict constraint out of the conflicting assignment */
1545 *cutoff = TRUE;
1546 }
1547 else
1548 {
1550 if( tightened )
1551 {
1553 (*nfixedvars)++;
1554 }
1555 }
1556 }
1557
1558 return SCIP_OKAY;
1559}
1560
1561/** replaces multiple occurrences of variables */
1562static
1564 SCIP* scip, /**< SCIP data structure */
1565 SCIP_CONS* cons, /**< AND-constraint */
1566 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
1567 unsigned char** entries, /**< array to store whether two positions in constraints represent the same variable */
1568 int* nentries, /**< pointer for array size, if array will be to small it's corrected */
1569 int* nfixedvars, /**< pointer to store number of fixed variables */
1570 int* nchgcoefs, /**< pointer to store number of changed coefficients */
1571 int* ndelconss /**< pointer to store number of deleted constraints */
1572 )
1573{
1574 SCIP_CONSDATA* consdata;
1575 SCIP_VAR** vars;
1576 SCIP_VAR* var;
1577 SCIP_VAR* probvar;
1578 int probidx;
1579 int nvars;
1580 int v;
1581#ifndef NDEBUG
1582 int nbinvars;
1583 int nintvars;
1584 int nimplvars;
1585#endif
1586
1587 assert(scip != NULL);
1588 assert(cons != NULL);
1589 assert(eventhdlr != NULL);
1590 assert(*entries != NULL);
1591 assert(nentries != NULL);
1592 assert(nfixedvars != NULL);
1593 assert(nchgcoefs != NULL);
1594 assert(ndelconss != NULL);
1595
1596 consdata = SCIPconsGetData(cons);
1597 assert(consdata != NULL);
1598
1599 if( consdata->merged )
1600 return SCIP_OKAY;
1601
1602 /* nothing to merge */
1603 if( consdata->nvars <= 1 )
1604 {
1605 consdata->merged = TRUE;
1606 return SCIP_OKAY;
1607 }
1608
1609 vars = consdata->vars;
1610 nvars = consdata->nvars;
1611
1612 assert(vars != NULL);
1613 assert(nvars >= 2);
1614
1615#ifndef NDEBUG
1616 nbinvars = SCIPgetNBinVars(scip);
1617 nintvars = SCIPgetNIntVars(scip);
1618 nimplvars = SCIPgetNImplVars(scip);
1619 assert(*nentries >= nbinvars + nintvars + nimplvars);
1620#endif
1621
1622 /* initialize entries array */
1623 for( v = nvars - 1; v >= 0; --v )
1624 {
1625 var = vars[v];
1626 assert(var != NULL);
1628
1629 probvar = (SCIPvarIsActive(var) ? var : SCIPvarGetNegatedVar(var));
1630 assert(probvar != NULL);
1631
1632 probidx = SCIPvarGetProbindex(probvar);
1633 assert(0 <= probidx);
1634
1635 /* check variable type, either pure binary or an integer/implicit integer variable with 0/1 bounds */
1636 assert((probidx < nbinvars && SCIPvarGetType(probvar) == SCIP_VARTYPE_BINARY && !SCIPvarIsImpliedIntegral(probvar))
1637 || (SCIPvarIsBinary(probvar) &&
1638 ((probidx >= nbinvars && probidx < nbinvars + nintvars && SCIPvarGetType(probvar) == SCIP_VARTYPE_INTEGER
1639 && !SCIPvarIsImpliedIntegral(probvar)) ||
1640 (probidx >= nbinvars + nintvars && probidx < nbinvars + nintvars + nimplvars &&
1641 SCIPvarIsImpliedIntegral(probvar)))));
1642
1643 /* var is not active yet */
1644 (*entries)[probidx] = 0;
1645 }
1646
1647 /* search for multiple variables; scan from back to front because deletion doesn't affect the order of the front
1648 * variables
1649 * @note don't reorder variables because we would loose the watched variables and filter position inforamtion
1650 */
1651 for( v = nvars - 1; v >= 0; --v )
1652 {
1653 var = vars[v];
1654 assert(var != NULL);
1656
1657 probvar = (SCIPvarIsActive(var) ? var : SCIPvarGetNegatedVar(var));
1658 assert(probvar != NULL);
1659
1660 probidx = SCIPvarGetProbindex(probvar);
1661 assert(0 <= probidx && probidx < *nentries);
1662
1663 /* if var occurs first time in constraint init entries array */
1664 if( (*entries)[probidx] == 0 )
1665 {
1666 (*entries)[probidx] = (SCIPvarIsActive(var) ? 1 : 2);
1667 }
1668 /* if var occurs second time in constraint, first time it was not negated */
1669 else if( ((*entries)[probidx] == 1 && SCIPvarIsActive(var)) || ((*entries)[probidx] == 2 && !SCIPvarIsActive(var)) )
1670 {
1671 /* delete the multiple variable */
1672 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
1673 ++(*nchgcoefs);
1674 }
1675 else
1676 {
1677 SCIP_Bool infeasible;
1678 SCIP_Bool fixed;
1679
1680 assert(((*entries)[probidx] == 1 && !SCIPvarIsActive(var)) || ((*entries)[probidx] == 2 && SCIPvarIsActive(var)));
1681
1682 SCIPdebugMsg(scip, "AND-constraint <%s> is redundant: variable <%s> and its negation are present -> fix resultant <%s> = 0\n",
1683 SCIPconsGetName(cons), SCIPvarGetName(var), SCIPvarGetName(consdata->resvar));
1684
1685 /* negation of the variable is already present in the constraint: fix resultant to zero */
1686#ifndef NDEBUG
1687 {
1688 int i;
1689 for( i = consdata->nvars - 1; i > v && var != SCIPvarGetNegatedVar(vars[i]); --i )
1690 {}
1691 assert(i > v);
1692 }
1693#endif
1694
1695 SCIP_CALL( SCIPfixVar(scip, consdata->resvar, 0.0, &infeasible, &fixed) );
1696 assert(!infeasible);
1697 if( fixed )
1698 ++(*nfixedvars);
1699
1700 SCIP_CALL( SCIPdelCons(scip, cons) );
1701 break;
1702 }
1703 }
1704
1705 consdata->merged = TRUE;
1706
1707 return SCIP_OKAY;
1708}
1709
1710/** propagates constraint with the following rules:
1711 * (1) v_i = FALSE => r = FALSE
1712 * (2) r = TRUE => v_i = TRUE for all i
1713 * (3) v_i = TRUE for all i => r = TRUE
1714 * (4) r = FALSE, v_i = TRUE for all i except j => v_j = FALSE
1715 *
1716 * additional if the resultant is fixed to zero during presolving or in the root node (globally), then the
1717 * AND-constraint is collapsed to a linear (logicor) constraint of the form
1718 * -> sum_{i=0}^{n-1} ~v_i >= 1
1719 */
1720static
1722 SCIP* scip, /**< SCIP data structure */
1723 SCIP_CONS* cons, /**< AND-constraint to be processed */
1724 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
1725 SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
1726 int* nfixedvars, /**< pointer to add up the number of found domain reductions */
1727 int* nupgdconss /**< pointer to add up the number of upgraded constraints */
1728 )
1729{
1730 SCIP_CONSDATA* consdata;
1731 SCIP_VAR* resvar;
1732 SCIP_VAR** vars;
1733 int nvars;
1734 int watchedvar1;
1735 int watchedvar2;
1736 int i;
1737 SCIP_Bool infeasible;
1738 SCIP_Bool tightened;
1739
1740 assert(cutoff != NULL);
1741 assert(nfixedvars != NULL);
1742
1743 consdata = SCIPconsGetData(cons);
1744 assert(consdata != NULL);
1745
1746 resvar = consdata->resvar;
1747 vars = consdata->vars;
1748 nvars = consdata->nvars;
1749
1750 /* don't process the constraint, if none of the operator variables was fixed to FALSE, and if the watched variables
1751 * and the resultant weren't fixed to any value since last propagation call
1752 */
1753 if( consdata->propagated )
1754 {
1755 assert(consdata->nofixedzero);
1756 assert(SCIPisFeasEQ(scip, SCIPvarGetLbLocal(resvar), 0.0));
1757 return SCIP_OKAY;
1758 }
1759
1760 /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
1762 {
1763 SCIP_CALL( SCIPincConsAge(scip, cons) );
1764 }
1765
1766 /* if one of the operator variables was fixed to FALSE, the resultant can be fixed to FALSE (rule (1)) */
1767 if( !consdata->nofixedzero )
1768 {
1769 for( i = 0; i < nvars && SCIPvarGetUbLocal(vars[i]) > 0.5; ++i ) /* search for operator fixed to zero */
1770 {}
1771 if( i < nvars )
1772 {
1773 /* fix resultant to zero */
1774 SCIP_CALL( consdataFixResultantZero(scip, cons, resvar, i, cutoff, nfixedvars) );
1775 }
1776 else
1777 consdata->nofixedzero = TRUE;
1778 }
1779
1780 /* check if resultant variables is globally fixed to zero */
1781 if( !SCIPinProbing(scip) && SCIPconsGetNUpgradeLocks(cons) == 0 && SCIPvarGetUbGlobal(resvar) < 0.5 )
1782 {
1783 SCIP_CALL( consdataLinearize(scip, cons, cutoff, nfixedvars, nupgdconss) );
1784
1785 if( *cutoff && SCIPgetDepth(scip) > 0 )
1786 {
1787 /* we are done with solving since a global bound change was infeasible */
1789 }
1790
1791 return SCIP_OKAY;
1792 }
1793
1794 /* if the resultant and at least one operand are locally fixed to zero, the constraint is locally redundant */
1795 if( SCIPvarGetUbLocal(resvar) < 0.5 && !consdata->nofixedzero )
1796 {
1798 return SCIP_OKAY;
1799 }
1800
1801 /* if resultant is fixed to TRUE, all operator variables can be fixed to TRUE (rule (2)) */
1802 if( SCIPvarGetLbLocal(resvar) > 0.5 )
1803 {
1804 /* fix operands to one */
1805 SCIP_CALL( consdataFixOperandsOne(scip, cons, vars, nvars, cutoff, nfixedvars) );
1806
1807 return SCIP_OKAY;
1808 }
1809
1810 /* rules (3) and (4) can only be applied, if we know all operator variables */
1811 if( SCIPconsIsModifiable(cons) )
1812 return SCIP_OKAY;
1813
1814 /* rules (3) and (4) cannot be applied, if we have at least two unfixed variables left;
1815 * that means, we only have to watch (i.e. capture events) of two variables, and switch to other variables
1816 * if these ones get fixed
1817 */
1818 watchedvar1 = consdata->watchedvar1;
1819 watchedvar2 = consdata->watchedvar2;
1820
1821 /* check, if watched variables are still unfixed */
1822 if( watchedvar1 != -1 )
1823 {
1824 assert(SCIPvarGetUbLocal(vars[watchedvar1]) > 0.5); /* otherwise, rule (1) could be applied */
1825 if( SCIPvarGetLbLocal(vars[watchedvar1]) > 0.5 )
1826 watchedvar1 = -1;
1827 }
1828 if( watchedvar2 != -1 )
1829 {
1830 assert(SCIPvarGetUbLocal(vars[watchedvar2]) > 0.5); /* otherwise, rule (1) could be applied */
1831 if( SCIPvarGetLbLocal(vars[watchedvar2]) > 0.5 )
1832 watchedvar2 = -1;
1833 }
1834
1835 /* if only one watched variable is still unfixed, make it the first one */
1836 if( watchedvar1 == -1 )
1837 {
1838 watchedvar1 = watchedvar2;
1839 watchedvar2 = -1;
1840 }
1841 assert(watchedvar1 != -1 || watchedvar2 == -1);
1842
1843 /* if the watched variables are invalid (fixed), find new ones if existing */
1844 if( watchedvar2 == -1 )
1845 {
1846 for( i = 0; i < nvars; ++i )
1847 {
1848 assert(SCIPvarGetUbLocal(vars[i]) > 0.5); /* otherwise, rule (1) could be applied */
1849 if( SCIPvarGetLbLocal(vars[i]) < 0.5 )
1850 {
1851 if( watchedvar1 == -1 )
1852 {
1853 assert(watchedvar2 == -1);
1854 watchedvar1 = i;
1855 }
1856 else if( watchedvar1 != i )
1857 {
1858 watchedvar2 = i;
1859 break;
1860 }
1861 }
1862 }
1863 }
1864 assert(watchedvar1 != -1 || watchedvar2 == -1);
1865
1866 /* if all variables are fixed to TRUE, the resultant can also be fixed to TRUE (rule (3)) */
1867 if( watchedvar1 == -1 )
1868 {
1869 assert(watchedvar2 == -1);
1870
1871 SCIPdebugMsg(scip, "constraint <%s>: all operator vars fixed to 1.0 -> fix resultant <%s> to 1.0\n",
1872 SCIPconsGetName(cons), SCIPvarGetName(resvar));
1873 SCIP_CALL( SCIPinferBinvarCons(scip, resvar, TRUE, cons, (int)PROPRULE_3, &infeasible, &tightened) );
1874
1875 if( infeasible )
1876 {
1877 /* use conflict analysis to get a conflict constraint out of the conflicting assignment */
1880 *cutoff = TRUE;
1881 }
1882 else
1883 {
1885 if( tightened )
1886 {
1888 (*nfixedvars)++;
1889 }
1890 }
1891
1892 return SCIP_OKAY;
1893 }
1894
1895 /* if resultant is fixed to FALSE, and only one operator variable is not fixed to TRUE, this operator variable
1896 * can be fixed to FALSE (rule (4))
1897 */
1898 if( watchedvar2 == -1 && SCIPvarGetUbLocal(resvar) < 0.5 )
1899 {
1900 assert(watchedvar1 != -1);
1901
1902 SCIP_CALL( analyzeZeroResultant(scip, cons, watchedvar1, watchedvar2, cutoff, nfixedvars) );
1903
1904 return SCIP_OKAY;
1905 }
1906
1907 /* switch to the new watched variables */
1908 SCIP_CALL( consdataSwitchWatchedvars(scip, consdata, eventhdlr, watchedvar1, watchedvar2) );
1909
1910 /* mark the constraint propagated if we have an unfixed resultant or are not in probing, it is necessary that a fixed
1911 * resulting in probing mode does not lead to a propagated constraint, because the constraint upgrade needs to be performed
1912 */
1913 consdata->propagated = (!SCIPinProbing(scip) || (SCIPvarGetLbLocal(consdata->resvar) < 0.5 && SCIPvarGetUbLocal(consdata->resvar) > 0.5));
1914
1915 return SCIP_OKAY;
1916}
1917
1918/** resolves a conflict on the given variable by supplying the variables needed for applying the corresponding
1919 * propagation rule (see propagateCons()):
1920 * (1) v_i = FALSE => r = FALSE
1921 * (2) r = TRUE => v_i = TRUE for all i
1922 * (3) v_i = TRUE for all i => r = TRUE
1923 * (4) r = FALSE, v_i = TRUE for all i except j => v_j = FALSE
1924 */
1925static
1927 SCIP* scip, /**< SCIP data structure */
1928 SCIP_CONS* cons, /**< constraint that inferred the bound change */
1929 SCIP_VAR* infervar, /**< variable that was deduced */
1930 PROPRULE proprule, /**< propagation rule that deduced the value */
1931 SCIP_BDCHGIDX* bdchgidx, /**< bound change index (time stamp of bound change), or NULL for current time */
1932 SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
1933 )
1934{
1935 SCIP_CONSDATA* consdata;
1936 SCIP_VAR** vars;
1937 int nvars;
1938 int i;
1939
1940 assert(result != NULL);
1941
1942 consdata = SCIPconsGetData(cons);
1943 assert(consdata != NULL);
1944 vars = consdata->vars;
1945 nvars = consdata->nvars;
1946
1947 switch( proprule )
1948 {
1949 case PROPRULE_1:
1950 /* the resultant was inferred to FALSE, because one operand variable was FALSE */
1951 assert(SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE) < 0.5);
1952 assert(infervar == consdata->resvar);
1953 for( i = 0; i < nvars; ++i )
1954 {
1955 if( SCIPgetVarUbAtIndex(scip, vars[i], bdchgidx, FALSE) < 0.5 )
1956 {
1958 break;
1959 }
1960 }
1961 assert(i < nvars);
1962 *result = SCIP_SUCCESS;
1963 break;
1964
1965 case PROPRULE_2:
1966 /* the operand variable was inferred to TRUE, because the resultant was TRUE */
1967 assert(SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE) > 0.5);
1968 assert(SCIPgetVarLbAtIndex(scip, consdata->resvar, bdchgidx, FALSE) > 0.5);
1969 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->resvar) );
1970 *result = SCIP_SUCCESS;
1971 break;
1972
1973 case PROPRULE_3:
1974 /* the resultant was inferred to TRUE, because all operand variables were TRUE */
1975 assert(SCIPgetVarLbAtIndex(scip, infervar, bdchgidx, TRUE) > 0.5);
1976 assert(infervar == consdata->resvar);
1977 for( i = 0; i < nvars; ++i )
1978 {
1979 assert(SCIPgetVarLbAtIndex(scip, vars[i], bdchgidx, FALSE) > 0.5);
1981 }
1982 *result = SCIP_SUCCESS;
1983 break;
1984
1985 case PROPRULE_4:
1986 /* the operand variable was inferred to FALSE, because the resultant was FALSE and all other operands were TRUE */
1987 assert(SCIPgetVarUbAtIndex(scip, infervar, bdchgidx, TRUE) < 0.5);
1988 assert(SCIPgetVarUbAtIndex(scip, consdata->resvar, bdchgidx, FALSE) < 0.5);
1989 SCIP_CALL( SCIPaddConflictBinvar(scip, consdata->resvar) );
1990 for( i = 0; i < nvars; ++i )
1991 {
1992 if( vars[i] != infervar )
1993 {
1994 assert(SCIPgetVarLbAtIndex(scip, vars[i], bdchgidx, FALSE) > 0.5);
1996 }
1997 }
1998 *result = SCIP_SUCCESS;
1999 break;
2000
2001 case PROPRULE_INVALID:
2002 default:
2003 SCIPerrorMessage("invalid inference information %d in AND-constraint <%s>\n", proprule, SCIPconsGetName(cons));
2004 return SCIP_INVALIDDATA;
2005 }
2006
2007 return SCIP_OKAY;
2008}
2009
2010/** perform dual presolving on AND-constraints */
2011static
2013 SCIP* scip, /**< SCIP data structure */
2014 SCIP_CONS** conss, /**< AND-constraints to perform dual presolving on */
2015 int nconss, /**< number of AND-constraints */
2016 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
2017 unsigned char** entries, /**< array to store whether two positions in constraints represent the same variable */
2018 int* nentries, /**< pointer for array size, if array will be to small it's corrected */
2019 SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
2020 int* nfixedvars, /**< pointer to add up the number of found domain reductions */
2021 int* naggrvars, /**< pointer to add up the number of aggregated variables */
2022 int* nchgcoefs, /**< pointer to add up the number of changed coefficients */
2023 int* ndelconss, /**< pointer to add up the number of deleted constraints */
2024 int* nupgdconss, /**< pointer to add up the number of upgraded constraints */
2025 int* naddconss /**< pointer to add up the number of added constraints */
2026 )
2027{
2028 SCIP_CONS* cons;
2029 SCIP_CONSDATA* consdata;
2030 SCIP_VAR** impoperands;
2031 SCIP_VAR** vars;
2032 SCIP_VAR* resvar;
2033 SCIP_VAR* var;
2034 int nimpoperands;
2035 int nvars;
2036 int size;
2037 int v;
2038 int c;
2039 SCIP_Bool infeasible;
2040 SCIP_Bool fixed;
2041
2042 assert(scip != NULL);
2043 assert(conss != NULL || nconss == 0);
2044 assert(eventhdlr != NULL);
2045 assert(*entries != NULL);
2046 assert(nentries != NULL);
2047 assert(cutoff != NULL);
2048 assert(nfixedvars != NULL);
2049 assert(naggrvars != NULL);
2050 assert(nchgcoefs != NULL);
2051 assert(ndelconss != NULL);
2052 assert(nupgdconss != NULL);
2053 assert(naddconss != NULL);
2054
2055 if( nconss == 0 )
2056 return SCIP_OKAY;
2057
2058 assert(conss != NULL);
2059
2060 size = 2 * (SCIPgetNBinVars(scip) + SCIPgetNImplVars(scip));
2061
2062 SCIP_CALL( SCIPallocBufferArray(scip, &impoperands, size) );
2063
2064 for( c = nconss - 1; c >= 0 && !(*cutoff); --c )
2065 {
2066 cons = conss[c];
2067 assert(cons != NULL);
2068
2069 if( !SCIPconsIsActive(cons) || !SCIPconsIsChecked(cons) || SCIPconsIsModifiable(cons) )
2070 continue;
2071
2072 /* propagate constraint */
2073 SCIP_CALL( propagateCons(scip, cons, eventhdlr, cutoff, nfixedvars, nupgdconss) );
2074
2075 if( !SCIPconsIsActive(cons) )
2076 continue;
2077
2078 if( *cutoff )
2079 break;
2080
2081 SCIP_CALL( applyFixings(scip, cons, eventhdlr, nchgcoefs) );
2082
2083 /* merge multiple occurances of variables or variables with their negated variables */
2084 SCIP_CALL( mergeMultiples(scip, cons, eventhdlr, entries, nentries, nfixedvars, nchgcoefs, ndelconss) );
2085
2086 if( !SCIPconsIsActive(cons) )
2087 continue;
2088
2089 consdata = SCIPconsGetData(cons);
2090 assert(consdata != NULL);
2091
2092 vars = consdata->vars;
2093 nvars = consdata->nvars;
2094 assert(vars != NULL || nvars == 0);
2095
2096 if( nvars == 0 )
2097 continue;
2098
2099 assert(vars != NULL);
2100
2101 resvar = consdata->resvar;
2102 assert(SCIPvarGetLbGlobal(resvar) < 0.5);
2103
2104 /* dual presolving does not apply to a fixed resultant */
2105 if( SCIPvarGetUbGlobal(resvar) < 0.5 )
2106 continue;
2107
2108 assert(SCIPvarGetNLocksUpType(resvar, SCIP_LOCKTYPE_MODEL) >= 1
2110
2113 {
2114 SCIP_Real resobj;
2115 SCIP_Real obj;
2116 SCIP_Real posobjsum = 0;
2117 SCIP_Real maxobj = -SCIPinfinity(scip);
2118 int maxpos = -1;
2119 int oldnfixedvars = *nfixedvars;
2120 int oldnaggrvars = *naggrvars;
2121
2122 nimpoperands = 0;
2123
2124 /* collect important operands */
2125 for( v = nvars - 1; v >= 0; --v )
2126 {
2127 var = vars[v];
2128 assert(var != NULL);
2131
2134 {
2135 impoperands[nimpoperands] = var;
2136 ++nimpoperands;
2137
2138 /* get aggregated objective value of active variable */
2139 SCIP_CALL( SCIPvarGetAggregatedObj(var, &obj) );
2140
2141 /* add up all positive objective values of operands which have exactly one lock in both directions */
2142 if( obj > 0 )
2143 posobjsum += obj;
2144
2145 /* memorize maximal objective value of operands and its position */
2146 if( obj > maxobj )
2147 {
2148 maxpos = nimpoperands - 1;
2149 maxobj = obj;
2150 }
2151 }
2152 }
2153 assert(nimpoperands >= 0 && nimpoperands <= nvars);
2154
2155 /* no dual fixable variables found */
2156 if( nimpoperands == 0 )
2157 continue;
2158
2159 /* get aggregated objective value of active variable */
2160 SCIP_CALL( SCIPvarGetAggregatedObj(resvar, &resobj) );
2161
2162 /* resultant contributes to the objective with a negative value */
2163 if( SCIPisLE(scip, resobj, 0.0) )
2164 {
2165 SCIP_Bool poscontissmall = SCIPisLE(scip, posobjsum, REALABS(resobj));
2166
2167 /* if all variables are only locked by this constraint and the resultants contribution more then compensates
2168 * the positive contribution, we can fix all variables to 1
2169 */
2170 if( nimpoperands == nvars && poscontissmall )
2171 {
2172 SCIPdebugMsg(scip, "dual-fixing all variables in constraint <%s> to 1\n", SCIPconsGetName(cons));
2173
2174 SCIP_CALL( SCIPfixVar(scip, resvar, 1.0, &infeasible, &fixed) );
2175
2176 *cutoff = *cutoff || infeasible;
2177 if( fixed )
2178 ++(*nfixedvars);
2179
2180 for( v = nvars - 1; v >= 0 && !(*cutoff); --v )
2181 {
2182 SCIP_CALL( SCIPfixVar(scip, vars[v], 1.0, &infeasible, &fixed) );
2183
2184 *cutoff = *cutoff || infeasible;
2185 if( fixed )
2186 ++(*nfixedvars);
2187 }
2188
2189 SCIPdebugMsg(scip, "deleting constraint <%s> because all variables are fixed to one\n", SCIPconsGetName(cons));
2190
2191 SCIP_CALL( SCIPdelCons(scip, cons) );
2192 ++(*ndelconss);
2193 }
2194 else
2195 {
2196 SCIP_Bool aggregationperformed = FALSE;
2197 SCIP_Bool zerofix = FALSE;
2198
2199 assert(nimpoperands > 0);
2200
2201 SCIPdebugMsg(scip, "dual-fixing all variables in constraint <%s> with positive contribution (when together exceeding the negative contribution of the resultant) to 0 and with negative contribution to 1\n", SCIPconsGetName(cons));
2202
2203 for( v = nimpoperands - 1; v >= 0 && !(*cutoff); --v )
2204 {
2205 /* get aggregated objective value of active variable */
2206 SCIP_CALL( SCIPvarGetAggregatedObj(impoperands[v], &obj) );
2207
2208 if( SCIPisLE(scip, obj, 0.0) )
2209 {
2210 SCIP_CALL( SCIPfixVar(scip, impoperands[v], 1.0, &infeasible, &fixed) );
2211
2212 *cutoff = *cutoff || infeasible;
2213 if( fixed )
2214 ++(*nfixedvars);
2215 }
2216 else if( !poscontissmall )
2217 {
2218 SCIP_CALL( SCIPfixVar(scip, impoperands[v], 0.0, &infeasible, &fixed) );
2219 assert(!infeasible);
2220 assert(fixed);
2221
2222 ++(*nfixedvars);
2223 zerofix = TRUE;
2224 }
2225 else
2226 {
2227 SCIP_Bool redundant;
2228 SCIP_Bool aggregated;
2229
2230 /* aggregate resultant to operand */
2231 SCIP_CALL( SCIPaggregateVars(scip, resvar, impoperands[v], 1.0, -1.0, 0.0,
2232 &infeasible, &redundant, &aggregated) );
2233 assert(!infeasible);
2234
2235 if( aggregated )
2236 {
2237 /* note that we cannot remove the aggregated operand because we do not know the position */
2238 ++(*naggrvars);
2239
2240 aggregationperformed = TRUE;
2241
2242 SCIPdebugMsg(scip, "dual aggregating operand <%s> with 1 up- and downlock to the resultant <%s> in constraint <%s>\n", SCIPvarGetName(impoperands[v]), SCIPvarGetName(resvar), SCIPconsGetName(cons));
2243 }
2244 }
2245 }
2246 assert(*nfixedvars - oldnfixedvars + *naggrvars - oldnaggrvars <= nimpoperands);
2247
2248 /* did we aggregate the resultant, then we can decide the value to fix it on the (aggregated) objective
2249 * value since it was a independant variable
2250 */
2251 if( aggregationperformed || zerofix )
2252 {
2253 SCIP_Real fixval;
2254
2255 if( zerofix )
2256 fixval = 0.0;
2257 else
2258 {
2259 /* get aggregated objective value of active variable, that might be changed */
2260 SCIP_CALL( SCIPvarGetAggregatedObj(resvar, &obj) );
2261 assert(!SCIPisPositive(scip, obj));
2262
2263 fixval = (SCIPisNegative(scip, obj) ? 1.0 : 0.0);
2264 }
2265
2266 if( fixval < 0.5 || *nfixedvars - oldnfixedvars + *naggrvars - oldnaggrvars == nvars )
2267 {
2268 SCIPdebugMsg(scip, "constraint <%s> we can fix the resultant <%s> to %g, because the AND-constraint will alwys be fulfilled\n", SCIPconsGetName(cons), SCIPvarGetName(resvar), fixval);
2269
2270 SCIP_CALL( SCIPfixVar(scip, resvar, fixval, &infeasible, &fixed) );
2271 assert(!infeasible);
2272 assert(fixed);
2273
2274 ++(*nfixedvars);
2275
2276 SCIPdebugMsg(scip, "deleting constraint <%s> because \n", SCIPconsGetName(cons));
2277
2278 SCIP_CALL( SCIPdelCons(scip, cons) );
2279 ++(*ndelconss);
2280 }
2281 }
2282 }
2283 }
2284 /* resultant contributes to the objective with a positive value */
2285 else
2286 {
2287 SCIP_Bool zerofix = FALSE;
2288#ifndef NDEBUG
2289 SCIP_Real tmpobj;
2290
2291 assert(nimpoperands > 0);
2292 assert(maxpos >= 0 && maxpos <= consdata->nvars);
2293 assert(!SCIPisInfinity(scip, -maxobj));
2294 SCIP_CALL( SCIPvarGetAggregatedObj(impoperands[maxpos], &tmpobj) );
2295 assert(SCIPisEQ(scip, tmpobj, maxobj));
2296#endif
2297
2298 /* if the smallest possible contribution is negative, but does not compensate the positive contribution of
2299 * the resultant we need to fix this variable to 0
2300 */
2301 if( nimpoperands == nvars && SCIPisLE(scip, maxobj, 0.0) )
2302 {
2303 SCIP_Real fixval = (SCIPisLE(scip, REALABS(maxobj), resobj) ? 0.0 : 1.0);
2304
2305 SCIPdebugMsg(scip, "dual-fixing variable <%s> in constraint <%s> to %g, because the contribution is%s " \
2306 "enough to nullify/exceed the contribution of the resultant \n",
2307 SCIPvarGetName(impoperands[maxpos]), SCIPconsGetName(cons), fixval, (fixval < 0.5) ? " not" : "");
2308
2309 SCIP_CALL( SCIPfixVar(scip, impoperands[maxpos], fixval, &infeasible, &fixed) );
2310 zerofix = (fixval < 0.5);
2311
2312 *cutoff = *cutoff || infeasible;
2313 if( fixed )
2314 ++(*nfixedvars);
2315 }
2316
2317 SCIPdebugMsg(scip, "dual-fixing all variables, except the variable with the highest contribution to " \
2318 "the objective, in constraint <%s> with positive contribution to 0 and with negative contribution to 1\n",
2319 SCIPconsGetName(cons));
2320
2321 for( v = nimpoperands - 1; v >= 0 && !(*cutoff); --v )
2322 {
2323 /* get aggregated objective value of active variable */
2324 SCIP_CALL( SCIPvarGetAggregatedObj(impoperands[v], &obj) );
2325
2326 if( SCIPisLE(scip, obj, 0.0) )
2327 {
2328 if( v == maxpos )
2329 continue;
2330
2331 SCIP_CALL( SCIPfixVar(scip, impoperands[v], 1.0, &infeasible, &fixed) );
2332 }
2333 else
2334 {
2335 SCIP_CALL( SCIPfixVar(scip, impoperands[v], 0.0, &infeasible, &fixed) );
2336 zerofix = TRUE;
2337 }
2338
2339 *cutoff = *cutoff || infeasible;
2340 if( fixed )
2341 ++(*nfixedvars);
2342 }
2343 assert(*nfixedvars - oldnfixedvars <= nimpoperands);
2344 /* iff we have fixed all variables, all variables needed to be stored in the impoperands array */
2345 assert((*nfixedvars - oldnfixedvars == nvars) == (nimpoperands == nvars));
2346
2347 if( *nfixedvars - oldnfixedvars == nvars )
2348 {
2349 SCIPdebugMsg(scip, "all operands are fixed in constraint <%s> => fix resultant <%s> to %g\n", SCIPconsGetName(cons), SCIPvarGetName(resvar), (zerofix ? 0.0 : 1.0));
2350
2351 SCIP_CALL( SCIPfixVar(scip, resvar, zerofix ? 0.0 : 1.0, &infeasible, &fixed) );
2352
2353 *cutoff = *cutoff || infeasible;
2354 if( fixed )
2355 ++(*nfixedvars);
2356
2357 SCIPdebugMsg(scip, "deleting constraint <%s> because all variables are fixed\n", SCIPconsGetName(cons));
2358
2359 SCIP_CALL( SCIPdelCons(scip, cons) );
2360 ++(*ndelconss);
2361 }
2362 }
2363 }
2364 /* resultant is lock by another constraint (handler), check for operands with only one down- and uplock */
2365 else
2366 {
2367 SCIP_Real maxobj = -SCIPinfinity(scip);
2368 SCIP_Real resobj;
2369 SCIP_Real obj;
2370 SCIP_Bool redundant;
2371 SCIP_Bool aggregated;
2372 SCIP_Bool resobjispos;
2373 SCIP_Bool linearize = FALSE;
2374 SCIP_Bool zerofix = FALSE;
2375#ifndef NDEBUG
2376 int oldnchgcoefs = *nchgcoefs;
2377 int oldnfixedvars = *nfixedvars;
2378#endif
2379
2380 /* get aggregated objective value of active variable */
2381 SCIP_CALL( SCIPvarGetAggregatedObj(resvar, &resobj) );
2382
2383 resobjispos = SCIPisGT(scip, resobj, 0.0);
2384
2385 /* we can only aggregate when the objective contribution of the resultant is less or equal to 0 */
2386 if( !resobjispos )
2387 {
2388 SCIP_Bool goodvarsfound = FALSE;
2389
2390 for( v = nvars - 1; v >= 0; --v )
2391 {
2392 var = vars[v];
2393 assert(var != NULL);
2396
2397 /* get aggregated objective value of active variable */
2398 SCIP_CALL( SCIPvarGetAggregatedObj(var, &obj) );
2399
2400 /* all operands which are only locked by this constraint, the objective contribution is greater or equal
2401 * to 0 can be aggregated to the resultant
2402 */
2405 {
2406 if( !SCIPisNegative(scip, obj) )
2407 {
2408 /* aggregate resultant to operand */
2409 SCIP_CALL( SCIPaggregateVars(scip, resvar, var, 1.0, -1.0, 0.0, &infeasible, &redundant,
2410 &aggregated) );
2411
2412 if( aggregated && SCIPconsGetNUpgradeLocks(cons) == 0 )
2413 {
2414 ++(*naggrvars);
2415
2416 linearize = TRUE;
2417
2418 /* delete redundant entry from constraint */
2419 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
2420 ++(*nchgcoefs);
2421
2423 "dual aggregating operand <%s> with 1 up- and downlock to the resultant <%s> in constraint <%s>\n",
2424 SCIPvarGetName(var), SCIPvarGetName(resvar), SCIPconsGetName(cons));
2425 }
2426
2427 *cutoff = *cutoff || infeasible;
2428 }
2429 else
2430 goodvarsfound = TRUE;
2431 }
2432 }
2433 assert(*nchgcoefs - oldnchgcoefs <= nvars);
2434
2435 /* if we aggregated an operands with the resultant we can also fix "good" independant operands to 1, since
2436 * the correctness of "resultant = 0 => at least one operand = 0" in enforced by that aggregation
2437 * without an aggregation we cannot fix these variables since it might lead to infeasibility, e.g.
2438 *
2439 * obj(x3) = -1
2440 * r = x1 * x2 * x3
2441 * r = 0
2442 * x1 = 1
2443 * x2 = 1
2444 */
2445 if( !*cutoff && goodvarsfound && linearize )
2446 {
2447 /* fix good variables to 1 */
2448 for( v = consdata->nvars - 1; v >= 0; --v )
2449 {
2450 var = vars[v];
2451 assert(var != NULL);
2452
2455 {
2456#ifndef NDEBUG
2457 /* aggregated objective value of active variable need to be negative */
2458 SCIP_CALL( SCIPvarGetAggregatedObj(var, &obj) );
2459 assert(SCIPisNegative(scip, obj));
2460#endif
2462 "dual-fixing variable <%s> in constraint <%s> to 1, because the contribution is negative\n",
2463 SCIPvarGetName(var), SCIPconsGetName(cons));
2464
2465 SCIP_CALL( SCIPfixVar(scip, var, 1.0, &infeasible, &fixed) );
2466
2467 assert(!infeasible);
2468 if( fixed )
2469 ++(*nfixedvars);
2470 }
2471 }
2472 assert(*nfixedvars - oldnfixedvars <= consdata->nvars);
2473 }
2474 assert(*nchgcoefs - oldnchgcoefs + *nfixedvars - oldnfixedvars <= nvars);
2475 }
2476 /* if the downlocks of the resultant are only from this constraint and the objective contribution is positive,
2477 * we can try to fix operands
2478 */
2479 else if( SCIPvarGetNLocksDownType(resvar, SCIP_LOCKTYPE_MODEL) == 1 )
2480 {
2481 SCIP_Bool locksareone = TRUE;
2482 int maxpos = -1;
2483
2484 for( v = nvars - 1; v >= 0; --v )
2485 {
2486 var = vars[v];
2487 assert(var != NULL);
2490
2491 /* check if all resultants are only locked by this constraint */
2492 locksareone = locksareone && (SCIPvarGetNLocksUpType(var, SCIP_LOCKTYPE_MODEL) == 1
2494
2495 /* get aggregated objective value of active variable */
2496 SCIP_CALL( SCIPvarGetAggregatedObj(var, &obj) );
2497
2498 /* memorize maximal objective value of operands and its position */
2499 if( obj > maxobj )
2500 {
2501 maxpos = v;
2502 maxobj = obj;
2503 }
2504
2505 /* all operands which are only locked by this constraint, the objective contribution is greater or equal
2506 * to 0, and the absolute value of the contribution of the resultant exceeds can be eliminated and
2507 * aggregated to the resultant
2508 */
2510 && SCIPvarGetNLocksDownType(var, SCIP_LOCKTYPE_MODEL) == 1 && SCIPisGE(scip, obj, 0.0) )
2511 {
2512 SCIPdebugMsg(scip, "dualfix operand <%s> in constraint <%s> to 0\n", SCIPvarGetName(var), SCIPconsGetName(cons));
2513
2514 SCIP_CALL( SCIPfixVar(scip, var, 0.0, &infeasible, &fixed) );
2515
2516 *cutoff = *cutoff || infeasible;
2517 if( fixed )
2518 ++(*nfixedvars);
2519
2520 zerofix = TRUE;
2521 }
2522 }
2523 assert(*nchgcoefs - oldnchgcoefs <= nvars);
2524
2525 /* if constraint is still active and all operands are only lock by this constraint, we check if we can fix
2526 * the worst (in objective contribution) operand to zero
2527 */
2528 if( !zerofix && locksareone && SCIPisGE(scip, resobj, REALABS(maxobj)) )
2529 {
2530 assert(!zerofix);
2531 /* objective contribution needs to be negative, otherwise, the variable should already be fixed to 0 */
2532 assert(SCIPisLT(scip, maxobj, 0.0));
2533
2534 SCIPdebugMsg(scip, "dualfix operand <%s> with worst contribution in constraint <%s> to 0\n", SCIPvarGetName(vars[maxpos]), SCIPconsGetName(cons));
2535
2536 SCIP_CALL( SCIPfixVar(scip, vars[maxpos], 0.0, &infeasible, &fixed) );
2537
2538 *cutoff = *cutoff || infeasible;
2539 if( fixed )
2540 ++(*nfixedvars);
2541
2542 zerofix = TRUE;
2543 }
2544
2545 /* fix the resultant if one operand was fixed to zero and delete the constraint */
2546 if( zerofix )
2547 {
2548 SCIPdebugMsg(scip, "fix resultant <%s> in constraint <%s> to 0\n", SCIPvarGetName(resvar), SCIPconsGetName(cons));
2549
2550 SCIP_CALL( SCIPfixVar(scip, resvar, 0.0, &infeasible, &fixed) );
2551
2552 *cutoff = *cutoff || infeasible;
2553 if( fixed )
2554 ++(*nfixedvars);
2555
2556 SCIPdebugMsg(scip, "deleting constraint <%s> because at least one operand and the resultant is fixed to zero\n", SCIPconsGetName(cons));
2557
2558 SCIP_CALL( SCIPdelCons(scip, cons) );
2559 ++(*ndelconss);
2560 }
2561 }
2562
2563 /* we have to linearize the constraint, otherwise we might get wrong propagations, since due to aggregations a
2564 * resultant fixed to zero is already fulfilling the constraint, and we must not ensure that some remaining
2565 * operand needs to be 0
2566 */
2567 if( linearize )
2568 {
2569 SCIP_CONS* newcons;
2570 char consname[SCIP_MAXSTRLEN];
2571 SCIP_VAR* consvars[2];
2572 SCIP_Real vals[2];
2573
2574 assert(SCIPconsIsActive(cons));
2575 assert(SCIPconsGetNUpgradeLocks(cons) == 0);
2576
2577 consvars[0] = consdata->resvar;
2578 vals[0] = 1.0;
2579 vals[1] = -1.0;
2580
2581 /* create operator linear constraints */
2582 for( v = consdata->nvars - 1; v >= 0; --v )
2583 {
2584 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_%d", SCIPconsGetName(cons), v);
2585 consvars[1] = consdata->vars[v];
2586
2587 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, consname, 2, consvars, vals, -SCIPinfinity(scip), 0.0,
2591 SCIPconsIsStickingAtNode(cons)) );
2592
2593 /* add constraint */
2594 SCIP_CALL( SCIPaddCons(scip, newcons) );
2595 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
2596 }
2597 (*naddconss) += consdata->nvars;
2598
2599 SCIPdebugMsg(scip, "deleting constraint <%s> because it was linearized\n", SCIPconsGetName(cons));
2600
2601 SCIP_CALL( SCIPdelCons(scip, cons) );
2602 ++(*ndelconss);
2603 }
2604 /* if only one operand is leftover, aggregate it to the resultant */
2605 else if( consdata->nvars == 1 )
2606 {
2607 SCIPdebugMsg(scip, "aggregating last operand <%s> to the resultant <%s> in constraint <%s>\n", SCIPvarGetName(consdata->vars[0]), SCIPvarGetName(resvar), SCIPconsGetName(cons));
2608
2609 /* aggregate resultant to operand */
2610 SCIP_CALL( SCIPaggregateVars(scip, resvar, consdata->vars[0], 1.0, -1.0, 0.0,
2611 &infeasible, &redundant, &aggregated) );
2612
2613 if( aggregated )
2614 ++(*naggrvars);
2615
2616 *cutoff = *cutoff || infeasible;
2617
2618 SCIPdebugMsg(scip, "deleting constraint <%s> because all variables are removed\n", SCIPconsGetName(cons));
2619
2620 SCIP_CALL( SCIPdelCons(scip, cons) );
2621 ++(*ndelconss);
2622 }
2623
2624 /* if no operand is leftover delete the constraint */
2625 if( SCIPconsIsActive(cons) && consdata->nvars == 0 )
2626 {
2627 SCIPdebugMsg(scip, "deleting constraint <%s> because all variables are removed\n", SCIPconsGetName(cons));
2628
2629 SCIP_CALL( SCIPdelCons(scip, cons) );
2630 ++(*ndelconss);
2631 }
2632 }
2633 }
2634
2635 SCIPfreeBufferArray(scip, &impoperands);
2636
2637 return SCIP_OKAY;
2638}
2639
2640/** 1. check if at least two operands or one operand and the resultant are in one clique, if so, we can fix the
2641 * resultant to zero and in the former case we can also delete this constraint but we need to extract the clique
2642 * information as constraint
2643 *
2644 * x == AND(y, z) and clique(y,z) => x = 0, delete constraint and create y + z <= 1
2645 * x == AND(y, z) and clique(x,y) => x = 0
2646 *
2647 * special handled cases are:
2648 * - if the resultant is a negation of an operand, in that case we fix the resultant to 0
2649 * - if the resultant is equal to an operand, we will linearize this constraint by adding all necessary
2650 * set-packing constraints like resultant + ~operand <= 1 and delete the old constraint
2651 *
2652 * x == AND(~x, y) => x = 0
2653 * x == AND(x, y) => add x + ~y <= 1 and delete the constraint
2654 *
2655 * 2. check if one operand is in a clique with the negation of all other operands, this means we can aggregate this
2656 * operand to the resultant
2657 *
2658 * r == AND(x,y,z) and clique(x,~y) and clique(x,~z) => r == x
2659 *
2660 * 3. check if the resultant and the negations of all operands are in a clique
2661 *
2662 * r == AND(x,y) and clique(r, ~x,~y) => upgrade the constraint to a set-partitioning constraint r + ~x + ~y = 1
2663 *
2664 * @note We removed also fixed variables and propagate them, and if only one operand is remaining due to removal, we
2665 * will aggregate the resultant with this operand
2666 */
2667static
2669 SCIP* scip, /**< SCIP data structure */
2670 SCIP_CONS* cons, /**< constraint to process */
2671 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
2672 SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
2673 int* nfixedvars, /**< pointer to add up the number of found domain reductions */
2674 int* naggrvars, /**< pointer to add up the number of aggregated variables */
2675 int* nchgcoefs, /**< pointer to add up the number of changed coefficients */
2676 int* ndelconss, /**< pointer to add up the number of deleted constraints */
2677 int* naddconss /**< pointer to add up the number of added constraints */
2678 )
2679{
2680 SCIP_CONSDATA* consdata;
2681 SCIP_VAR** vars;
2682 SCIP_VAR* var1;
2683 SCIP_VAR* var2;
2684 int nvars;
2685 int vstart;
2686 int vend;
2687 int v;
2688 int v2;
2689 SCIP_Bool negated;
2690 SCIP_Bool value1;
2691 SCIP_Bool value2;
2692 SCIP_Bool infeasible;
2693 SCIP_Bool fixed;
2694 SCIP_Bool allnegoperandsexist;
2695
2696 assert(scip != NULL);
2697 assert(cons != NULL);
2698 assert(eventhdlr != NULL);
2699 assert(cutoff != NULL);
2700 assert(nfixedvars != NULL);
2701 assert(naggrvars != NULL);
2702 assert(nchgcoefs != NULL);
2703 assert(ndelconss != NULL);
2704 assert(naddconss != NULL);
2705
2706 consdata = SCIPconsGetData(cons);
2707 assert(consdata != NULL);
2708
2709 if( !SCIPconsIsActive(cons) || SCIPconsIsModifiable(cons) )
2710 return SCIP_OKAY;
2711
2712 vars = consdata->vars;
2713 nvars = consdata->nvars;
2714 assert(vars != NULL || nvars == 0);
2715
2716 /* remove fixed variables to be able to ask for cliques
2717 *
2718 * if an operand is fixed to 0 fix the resultant to 0 and delete the constraint
2719 * if an operand is fixed to 1 remove it from the constraint
2720 */
2721 for( v = nvars - 1; v >= 0; --v )
2722 {
2723 assert(vars != NULL);
2724
2725 if( SCIPvarGetLbGlobal(vars[v]) > 0.5 )
2726 {
2727 SCIPdebugMsg(scip, "In constraint <%s> the operand <%s> is fixed to 1 so remove it from the constraint\n",
2728 SCIPconsGetName(cons), SCIPvarGetName(vars[v]));
2729
2730 /* because we loop from back to front we can delete the entry in the consdata structure */
2731 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
2732 ++(*nchgcoefs);
2733
2734 assert(consdata->vars == vars);
2735
2736 continue;
2737 }
2738 else if( SCIPvarGetUbGlobal(vars[v]) < 0.5 )
2739 {
2740 SCIPdebugMsg(scip, "constraint <%s> redundant: because operand <%s> is fixed to zero so we can fix the resultant <%s> to 0\n",
2741 SCIPconsGetName(cons), SCIPvarGetName(vars[v]), SCIPvarGetName(consdata->resvar));
2742
2743 SCIP_CALL( SCIPfixVar(scip, consdata->resvar, 0.0, &infeasible, &fixed) );
2744 *cutoff = *cutoff || infeasible;
2745 if( fixed )
2746 ++(*nfixedvars);
2747
2748 SCIP_CALL( SCIPdelCons(scip, cons) );
2749 ++(*ndelconss);
2750
2751 return SCIP_OKAY;
2752 }
2753 }
2754
2755 /* if we deleted some operands constraint might be redundant */
2756 if( consdata->nvars < nvars )
2757 {
2758 assert(vars == consdata->vars);
2759
2760 /* all operands fixed to one were removed, so if no operand is left this means we can fix the resultant to 1
2761 * too
2762 */
2763 if( consdata->nvars == 0 )
2764 {
2765 SCIPdebugMsg(scip, "All operand in constraint <%s> were deleted, so the resultant needs to be fixed to 1\n",
2766 SCIPconsGetName(cons));
2767
2768 SCIP_CALL( SCIPfixVar(scip, consdata->resvar, 1.0, &infeasible, &fixed) );
2769 *cutoff = *cutoff || infeasible;
2770 if( fixed )
2771 ++(*nfixedvars);
2772
2773 SCIP_CALL( SCIPdelCons(scip, cons) );
2774 ++(*ndelconss);
2775
2776 return SCIP_OKAY;
2777 }
2778 /* if only one not fixed operand is left, we can aggregate it to the resultant */
2779 else if( consdata->nvars == 1 )
2780 {
2781 SCIP_Bool redundant;
2782 SCIP_Bool aggregated;
2783
2784 /* aggregate resultant to last operand */
2785 SCIP_CALL( SCIPaggregateVars(scip, consdata->resvar, consdata->vars[0], 1.0, -1.0, 0.0,
2786 &infeasible, &redundant, &aggregated) );
2787
2788 if( aggregated )
2789 ++(*naggrvars);
2790
2791 SCIP_CALL( SCIPdelCons(scip, cons) );
2792 ++(*ndelconss);
2793
2794 *cutoff = *cutoff || infeasible;
2795
2796 return SCIP_OKAY;
2797 }
2798
2799 nvars = consdata->nvars;
2800 }
2801
2802 /* @todo when cliques are improved, we only need to collect all clique-ids for all variables and check for doubled
2803 * entries
2804 */
2805 /* case 1 first part */
2806 /* check if two operands are in a clique */
2807 if( SCIPconsGetNUpgradeLocks(cons) == 0 )
2808 {
2809 for( v = nvars - 1; v > 0; --v )
2810 {
2811 assert(vars != NULL);
2812
2813 var1 = vars[v];
2814 assert(var1 != NULL);
2815 negated = FALSE;
2816
2817 SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &negated) );
2818 assert(var1 != NULL);
2819
2820 if( negated )
2821 value1 = FALSE;
2822 else
2823 value1 = TRUE;
2824
2825 assert(SCIPvarGetStatus(var1) != SCIP_VARSTATUS_FIXED);
2826
2827 for( v2 = v - 1; v2 >= 0; --v2 )
2828 {
2829 var2 = vars[v2];
2830 assert(var2 != NULL);
2831
2832 negated = FALSE;
2833 SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &negated) );
2834 assert(var2 != NULL);
2835
2836 if( negated )
2837 value2 = FALSE;
2838 else
2839 value2 = TRUE;
2840
2841 assert(SCIPvarGetStatus(var2) != SCIP_VARSTATUS_FIXED);
2842
2843 /* if both variables are negated of each other or the same, this will be handled in applyFixings();
2844 * @note if both variables are the same, then SCIPvarsHaveCommonClique() will return TRUE, so we better
2845 * continue
2846 */
2847 if( var1 == var2 )
2848 continue;
2849
2850 if( SCIPvarsHaveCommonClique(var1, value1, var2, value2, TRUE) )
2851 {
2852 SCIP_CONS* cliquecons;
2853 SCIP_VAR* consvars[2];
2854 char name[SCIP_MAXSTRLEN];
2855
2856 SCIPdebugMsg(scip, "constraint <%s> redundant: because variable <%s> and variable <%s> are in a clique, the resultant <%s> can be fixed to 0\n",
2857 SCIPconsGetName(cons), SCIPvarGetName(var1), SCIPvarGetName(var2), SCIPvarGetName(consdata->resvar));
2858
2859 SCIP_CALL( SCIPfixVar(scip, consdata->resvar, 0.0, &infeasible, &fixed) );
2860 *cutoff = *cutoff || infeasible;
2861 if( fixed )
2862 ++(*nfixedvars);
2863
2864 /* create clique constraint which lead to the last fixing */
2865 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%d", SCIPconsGetName(cons), v2);
2866
2867 if( value1 )
2868 consvars[0] = var1;
2869 else
2870 {
2871 SCIP_CALL( SCIPgetNegatedVar(scip, var1, &(consvars[0])) );
2872 }
2873
2874 if( value2 )
2875 consvars[1] = var2;
2876 else
2877 {
2878 SCIP_CALL( SCIPgetNegatedVar(scip, var2, &(consvars[1])) );
2879 }
2880
2881 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, 2, consvars,
2885 SCIPconsIsStickingAtNode(cons)) );
2886 SCIPdebugMsg(scip, " -> adding clique constraint: ");
2887 SCIPdebugPrintCons(scip, cliquecons, NULL);
2888 SCIP_CALL( SCIPaddConsUpgrade(scip, cons, &cliquecons) );
2889 ++(*naddconss);
2890
2891 SCIP_CALL( SCIPdelCons(scip, cons) );
2892 ++(*ndelconss);
2893
2894 return SCIP_OKAY;
2895 }
2896 }
2897 }
2898 }
2899
2900 var1 = consdata->resvar;
2901 assert(var1 != NULL);
2902
2903 negated = FALSE;
2904 SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &negated) );
2905 assert(var1 != NULL);
2906
2907 /* it may appear that we have a fixed resultant */
2909 {
2910 /* resultant is fixed to 1, so fix all operands to 1 */
2911 if( SCIPvarGetLbGlobal(consdata->resvar) > 0.5 )
2912 {
2913 SCIPdebugMsg(scip, "In constraint <%s> the resultant <%s> is fixed to 1 so fix all operands to 1\n",
2914 SCIPconsGetName(cons), SCIPvarGetName(consdata->resvar));
2915
2916 /* fix all operands to 1 */
2917 for( v = nvars - 1; v >= 0 && !(*cutoff); --v )
2918 {
2919 assert(vars != NULL);
2920
2921 SCIPdebugMsg(scip, "Fixing operand <%s> to 1.\n", SCIPvarGetName(vars[v]));
2922
2923 SCIP_CALL( SCIPfixVar(scip, vars[v], 1.0, &infeasible, &fixed) );
2924 *cutoff = *cutoff || infeasible;
2925
2926 if( fixed )
2927 ++(*nfixedvars);
2928 }
2929
2930 SCIP_CALL( SCIPdelCons(scip, cons) );
2931 ++(*ndelconss);
2932 }
2933 /* the upgrade to a linear constraint because of the to 0 fixed resultant we do in propagateCons() */
2934 else
2935 assert(SCIPvarGetUbGlobal(consdata->resvar) < 0.5);
2936
2937 return SCIP_OKAY;
2938 }
2939
2940 if( negated )
2941 value1 = FALSE;
2942 else
2943 value1 = TRUE;
2944
2945 /* case 1 second part */
2946 /* check if one operands is in a clique with the resultant */
2947 for( v = nvars - 1; v >= 0; --v )
2948 {
2949 assert(vars != NULL);
2950
2951 var2 = vars[v];
2952 assert(var2 != NULL);
2953
2954 negated = FALSE;
2955 SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &negated) );
2956 assert(var2 != NULL);
2957
2958 if( negated )
2959 value2 = FALSE;
2960 else
2961 value2 = TRUE;
2962
2963 /* if both variables are negated of each other or the same, this will be handled in applyFixings();
2964 * @note if both variables are the same, then SCIPvarsHaveCommonClique() will return TRUE, so we better continue
2965 */
2966 if( var1 == var2 )
2967 {
2968 /* x1 == AND(~x1, x2 ...) => x1 = 0 */
2969 if( value1 != value2 )
2970 {
2971 SCIPdebugMsg(scip, "In constraint <%s> the resultant <%s> can be fixed to 0 because the negation of it is an operand.\n",
2972 SCIPconsGetName(cons), SCIPvarGetName(consdata->resvar));
2973
2974 SCIP_CALL( SCIPfixVar(scip, consdata->resvar, 0.0, &infeasible, &fixed) );
2975 *cutoff = *cutoff || infeasible;
2976
2977 if( fixed )
2978 ++(*nfixedvars);
2979
2980 return SCIP_OKAY;
2981 }
2982 /* x1 == AND(x1, x2 ...) => delete constraint and create all set-packing constraints x1 + ~x2 <= 1, x1 + ~... <= 1 */
2983 else if( SCIPconsGetNUpgradeLocks(cons) == 0 )
2984 {
2985 SCIP_CONS* cliquecons;
2986 SCIP_VAR* consvars[2];
2987 char name[SCIP_MAXSTRLEN];
2988
2989 assert(value1 == value2);
2990
2991 consvars[0] = consdata->resvar;
2992
2993 for( v2 = nvars - 1; v2 >= 0; --v2 )
2994 {
2995 var2 = vars[v2];
2996 negated = FALSE;
2997 SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &negated) );
2998
2999 /* if the active representations of the resultant and an operand are different then we need to extract
3000 * this as a clique constraint
3001 *
3002 * if the active representations of the resultant and an operand are equal then the clique constraint
3003 * would look like x1 + ~x1 <= 1, which is redundant
3004 *
3005 * if the active representations of the resultant and an operand are negated of each other then the
3006 * clique constraint would look like x1 + x1 <= 1, which will lead to a fixation of the resultant later
3007 * on
3008 */
3009 if( var1 == var2 )
3010 {
3011 if( value1 == negated )
3012 {
3013 SCIPdebugMsg(scip, "In constraint <%s> the resultant <%s> can be fixed to 0 because the negation of it is an operand.\n",
3014 SCIPconsGetName(cons), SCIPvarGetName(consdata->resvar));
3015
3016 SCIP_CALL( SCIPfixVar(scip, consdata->resvar, 0.0, &infeasible, &fixed) );
3017 *cutoff = *cutoff || infeasible;
3018
3019 if( fixed )
3020 ++(*nfixedvars);
3021
3022 break;
3023 }
3024 }
3025 else
3026 {
3027 SCIP_CALL( SCIPgetNegatedVar(scip, vars[v2], &consvars[1]) );
3028 assert(consvars[1] != NULL);
3029
3030 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clq_%d", SCIPconsGetName(cons), v2);
3031
3032 SCIP_CALL( SCIPcreateConsSetpack(scip, &cliquecons, name, 2, consvars,
3036 SCIPconsIsStickingAtNode(cons)) );
3037 SCIPdebugMsg(scip, " -> adding clique constraint: ");
3038 SCIPdebugPrintCons(scip, cliquecons, NULL);
3039 SCIP_CALL( SCIPaddCons(scip, cliquecons) );
3040 SCIP_CALL( SCIPreleaseCons(scip, &cliquecons) );
3041 ++(*naddconss);
3042 }
3043 }
3044
3045 /* delete old constraint */
3046 SCIP_CALL( SCIPdelCons(scip, cons) );
3047 ++(*ndelconss);
3048
3049 return SCIP_OKAY;
3050 }
3051 /* due to SCIPvarsHaveCommonClique() returns on two same variables that they are in a clique, we need to
3052 * handle it explicitly
3053 */
3054 else
3055 continue;
3056 }
3057
3058 /* fix resultant in operand clique */
3059 if( SCIPvarsHaveCommonClique(var1, value1, var2, value2, TRUE) )
3060 {
3061 SCIPdebugMsg(scip, "in constraint <%s> the resultant <%s> can be fixed to 0 because it is in a clique with operand <%s>\n",
3062 SCIPconsGetName(cons), SCIPvarGetName(var1), SCIPvarGetName(var2));
3063
3064 SCIP_CALL( SCIPfixVar(scip, consdata->resvar, 0.0, &infeasible, &fixed) );
3065 *cutoff = *cutoff || infeasible;
3066 if( fixed )
3067 ++(*nfixedvars);
3068
3069 return SCIP_OKAY;
3070 }
3071 }
3072
3073 if( !SCIPconsIsActive(cons) )
3074 return SCIP_OKAY;
3075
3076 v2 = -1;
3077 /* check which operands have a negated variable */
3078 for( v = nvars - 1; v >= 0; --v )
3079 {
3080 assert(vars != NULL);
3081
3082 var1 = vars[v];
3083 assert(var1 != NULL);
3084
3085 negated = FALSE;
3086 SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &negated) );
3087 assert(var1 != NULL);
3088
3089 if( SCIPvarGetNegatedVar(var1) == NULL )
3090 {
3091 if( v2 >= 0 )
3092 break;
3093 v2 = v;
3094 }
3095 }
3096
3097 allnegoperandsexist = FALSE;
3098
3099 /* all operands have a negated variable, so we will check for all possible negated ciques */
3100 if( v2 == -1 )
3101 {
3102 allnegoperandsexist = TRUE;
3103 vstart = nvars - 1;
3104 vend = 0;
3105 }
3106 /* exactly one operands has no negated variable, so only this variable can be in a clique with all other negations */
3107 else if( v2 >= 0 && v == -1 )
3108 {
3109 vstart = v2;
3110 vend = v2;
3111 }
3112 /* at least two operands have no negated variable, so there is no possible clique with negated variables */
3113 else
3114 {
3115 vstart = -1;
3116 vend = 0;
3117 }
3118
3119 /* case 2 */
3120 /* check for negated cliques in the operands */
3121 for( v = vstart; v >= vend; --v )
3122 {
3123 assert(vars != NULL);
3124
3125 var1 = vars[v];
3126 assert(var1 != NULL);
3127
3128 negated = FALSE;
3129 SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &negated) );
3130 assert(var1 != NULL);
3131
3132 if( negated )
3133 value1 = FALSE;
3134 else
3135 value1 = TRUE;
3136
3137 for( v2 = nvars - 1; v2 >= 0; --v2 )
3138 {
3139 if( v2 == v )
3140 continue;
3141
3142 var2 = vars[v2];
3143 assert(var2 != NULL);
3144
3145 negated = FALSE;
3146 SCIP_CALL( SCIPvarGetProbvarBinary(&var2, &negated) );
3147 assert(var2 != NULL);
3148
3149 if( negated )
3150 value2 = FALSE;
3151 else
3152 value2 = TRUE;
3153
3154 assert(SCIPvarGetNegatedVar(var2) != NULL);
3155
3156 /* invert flag, because we want to check var 1 against all negations of the other variables */
3157 value2 = !value2;
3158
3159 /* due to SCIPvarsHaveCommonClique() returns on two same variables that they are in a clique, we need to handle
3160 * it explicitly
3161 */
3162 if( var1 == var2 && value1 == value2 )
3163 {
3164 SCIPdebugMsg(scip, "in constraint <%s> the resultant <%s> can be fixed to 0 because two operands are negated of each other\n",
3165 SCIPconsGetName(cons), SCIPvarGetName(consdata->resvar));
3166
3167 SCIP_CALL( SCIPfixVar(scip, consdata->resvar, 0.0, &infeasible, &fixed) );
3168 *cutoff = *cutoff || infeasible;
3169 if( fixed )
3170 ++(*nfixedvars);
3171
3172 return SCIP_OKAY;
3173 }
3174
3175 /* due to SCIPvarsHaveCommonClique() returns on two negated variables that they are not in a clique, we need to
3176 * handle it explicitly
3177 */
3178 if( var1 == var2 && value1 != value2 )
3179 continue;
3180
3181 if( !SCIPvarsHaveCommonClique(var1, value1, var2, value2, TRUE) )
3182 break;
3183 }
3184
3185 if( v2 == -1 )
3186 {
3187 SCIP_Bool redundant;
3188 SCIP_Bool aggregated;
3189
3190 SCIPdebugMsg(scip, "In constraint <%s> the operand <%s> is in a negated clique with all other operands, so we can aggregated this operand to the resultant <%s>.\n",
3191 SCIPconsGetName(cons), SCIPvarGetName(vars[v]), SCIPvarGetName(consdata->resvar));
3192
3193 SCIP_CALL( SCIPaggregateVars(scip, consdata->resvar, vars[v], 1.0, -1.0, 0.0,
3194 &infeasible, &redundant, &aggregated) );
3195 *cutoff = *cutoff || infeasible;
3196
3197 if( aggregated )
3198 ++(*naggrvars);
3199
3200 return SCIP_OKAY;
3201 }
3202 }
3203
3204 /* case 3 */
3205 /* check if the resultant and the negations of the operands are in a clique, then we can upgrade this constraint to a
3206 * set-partitioning constraint
3207 */
3208 if( allnegoperandsexist && SCIPconsIsActive(cons) && SCIPconsGetNUpgradeLocks(cons) == 0 )
3209 {
3210 SCIP_VAR** newvars;
3211 SCIP_Bool* negations;
3212 SCIP_Bool upgrade;
3213
3214 SCIP_CALL( SCIPallocBufferArray(scip, &newvars, nvars + 1) );
3215 SCIP_CALL( SCIPallocBufferArray(scip, &negations, nvars + 1) );
3216 BMSclearMemoryArray(negations, nvars + 1);
3217
3218 var1 = consdata->resvar;
3219 SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &negations[nvars]) );
3220 assert(var1 != NULL);
3221 assert(SCIPvarGetStatus(var1) != SCIP_VARSTATUS_FIXED);
3222
3223 newvars[nvars] = var1;
3224
3225 /* get active variables */
3226 for( v = nvars - 1; v >= 0; --v )
3227 {
3228 assert(vars != NULL);
3229
3230 var1 = vars[v];
3231 SCIP_CALL( SCIPvarGetProbvarBinary(&var1, &negations[v]) );
3232 assert(var1 != NULL);
3233 assert(SCIPvarGetStatus(var1) != SCIP_VARSTATUS_FIXED);
3234
3235 newvars[v] = var1;
3236
3237 /* there should be no variable left that is equal or negated to the resultant */
3238 assert(newvars[v] != newvars[nvars]);
3239 }
3240
3241 upgrade = TRUE;
3242
3243 /* the resultant is in a clique with the negations of all operands, due to this AND-constraint */
3244 /* only check if the negations of all operands are in a clique */
3245 for( v = nvars - 1; v >= 0 && upgrade; --v )
3246 {
3247 for( v2 = v - 1; v2 >= 0; --v2 )
3248 {
3249 /* the resultant need to be in a clique with the negations of all operands */
3250 if( !SCIPvarsHaveCommonClique(newvars[v], negations[v], newvars[v2], negations[v2], TRUE) )
3251 {
3252 upgrade = FALSE;
3253 break;
3254 }
3255 }
3256 }
3257
3258 /* all variables are in a clique, so upgrade thi AND-constraint */
3259 if( upgrade )
3260 {
3261 SCIP_CONS* cliquecons;
3262 char name[SCIP_MAXSTRLEN];
3263
3264 /* get new constraint variables */
3265 if( negations[nvars] )
3266 {
3267 /* negation does not need to be existing, so SCIPvarGetNegatedVar() cannot be called
3268 * (e.g. resultant = ~x = 1 - x and x = y = newvars[nvars] and negations[nvars] = TRUE,
3269 * then y does not need to have a negated variable, yet)
3270 */
3271 SCIP_CALL( SCIPgetNegatedVar(scip, newvars[nvars], &(newvars[nvars])) );
3272 }
3273 assert(newvars[nvars] != NULL);
3274
3275 for( v = nvars - 1; v >= 0; --v )
3276 {
3277 if( !negations[v] )
3278 {
3279 /* negation does not need to be existing, so SCIPvarGetNegatedVar() cannot be called
3280 * (e.g. vars[v] = ~x = 1 - x and x = y = newvars[v] and negations[v] = TRUE,
3281 * then y does not need to have a negated variable, yet)
3282 */
3283 SCIP_CALL( SCIPgetNegatedVar(scip, newvars[v], &(newvars[v])) );
3284 }
3285 assert(newvars[v] != NULL);
3286 }
3287
3288 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_clqeq", SCIPconsGetName(cons));
3289
3290 SCIP_CALL( SCIPcreateConsSetpart(scip, &cliquecons, name, nvars + 1, newvars,
3294 SCIPconsIsStickingAtNode(cons)) );
3295 SCIPdebugMsg(scip, " -> upgrading AND-constraint <%s> with use of clique information to a set-partitioning constraint: \n", SCIPconsGetName(cons));
3296 SCIPdebugPrintCons(scip, cliquecons, NULL);
3297 SCIP_CALL( SCIPaddConsUpgrade(scip, cons, &cliquecons) );
3298 ++(*naddconss);
3299
3300 /* delete old constraint */
3301 SCIP_CALL( SCIPdelCons(scip, cons) );
3302 ++(*ndelconss);
3303 }
3304
3305 SCIPfreeBufferArray(scip, &negations);
3306 SCIPfreeBufferArray(scip, &newvars);
3307 }
3308
3309 return SCIP_OKAY;
3310}
3311
3312/** gets the key of the given element */
3313static
3314SCIP_DECL_HASHGETKEY(hashGetKeyAndcons)
3315{ /*lint --e{715}*/
3316 /* the key is the element itself */
3317 return elem;
3318}
3319
3320/** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables */
3321static
3322SCIP_DECL_HASHKEYEQ(hashKeyEqAndcons)
3323{
3324 SCIP_CONSDATA* consdata1;
3325 SCIP_CONSDATA* consdata2;
3326 SCIP_Bool coefsequal;
3327 int i;
3328#ifndef NDEBUG
3329 SCIP* scip;
3330
3331 scip = (SCIP*)userptr;
3332 assert(scip != NULL);
3333#endif
3334
3335 consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
3336 consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
3337
3338 /* checks trivial case */
3339 if( consdata1->nvars != consdata2->nvars )
3340 return FALSE;
3341
3342 /* sorts the constraints */
3343 consdataSort(consdata1);
3344 consdataSort(consdata2);
3345 assert(consdata1->sorted);
3346 assert(consdata2->sorted);
3347
3348 coefsequal = TRUE;
3349
3350 for( i = 0; i < consdata1->nvars ; ++i )
3351 {
3352 /* tests if variables are equal */
3353 if( consdata1->vars[i] != consdata2->vars[i] )
3354 {
3355 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
3356 SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
3357 coefsequal = FALSE;
3358 break;
3359 }
3360 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 0);
3361 }
3362
3363 return coefsequal;
3364}
3365
3366/** returns the hash value of the key */
3367static
3368SCIP_DECL_HASHKEYVAL(hashKeyValAndcons)
3369{ /*lint --e{715}*/
3370 SCIP_CONSDATA* consdata;
3371 int minidx;
3372 int mididx;
3373 int maxidx;
3374
3375 consdata = SCIPconsGetData((SCIP_CONS*)key);
3376 assert(consdata != NULL);
3377 assert(consdata->sorted);
3378 assert(consdata->nvars > 0);
3379
3380 minidx = SCIPvarGetIndex(consdata->vars[0]);
3381 mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
3382 maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
3383 assert(minidx >= 0 && minidx <= maxidx);
3384
3385 return SCIPhashFour(consdata->nvars, minidx, mididx, maxidx);
3386}
3387
3388/** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
3389 * accordingly; in contrast to removeRedundantConstraints(), it uses a hash table
3390 */
3391static
3393 SCIP* scip, /**< SCIP data structure */
3394 BMS_BLKMEM* blkmem, /**< block memory */
3395 SCIP_CONS** conss, /**< constraint set */
3396 int nconss, /**< number of constraints in constraint set */
3397 int* firstchange, /**< pointer to store first changed constraint */
3398 SCIP_Bool* cutoff, /**< pointer to store TRUE, if a cutoff was found */
3399 int* naggrvars, /**< pointer to count number of aggregated variables */
3400 int* ndelconss /**< pointer to count number of deleted constraints */
3401 )
3402{
3403 SCIP_HASHTABLE* hashtable;
3404 int hashtablesize;
3405 int c;
3406
3407 assert(conss != NULL);
3408 assert(ndelconss != NULL);
3409
3410 /* create a hash table for the constraint set */
3411 hashtablesize = nconss;
3412 hashtablesize = MAX(hashtablesize, HASHSIZE_ANDCONS);
3413 SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
3414 hashGetKeyAndcons, hashKeyEqAndcons, hashKeyValAndcons, (void*) scip) );
3415
3416 *cutoff = FALSE;
3417
3418 /* check all constraints in the given set for redundancy */
3419 for( c = 0; c < nconss; ++c )
3420 {
3421 SCIP_CONS* cons0;
3422 SCIP_CONS* cons1;
3423 SCIP_CONSDATA* consdata0;
3424
3425 cons0 = conss[c];
3426
3427 if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
3428 continue;
3429
3430 consdata0 = SCIPconsGetData(cons0);
3431
3432 /* sort the constraint */
3433 consdataSort(consdata0);
3434 assert(consdata0->sorted);
3435
3436 /* get constraint from current hash table with same variables as cons0 */
3437 cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
3438
3439 if( cons1 != NULL )
3440 {
3441 SCIP_CONSDATA* consdata1;
3442 SCIP_Bool redundant;
3443
3444 assert(SCIPconsIsActive(cons1));
3445 assert(!SCIPconsIsModifiable(cons1));
3446
3447 consdata1 = SCIPconsGetData(cons1);
3448
3449 assert(consdata1 != NULL);
3450 assert(consdata0->nvars >= 1 && consdata0->nvars == consdata1->nvars);
3451
3452 assert(consdata0->sorted && consdata1->sorted);
3453 assert(consdata0->vars[0] == consdata1->vars[0]);
3454
3455 redundant = FALSE;
3456
3457 if( consdata0->resvar != consdata1->resvar )
3458 {
3459 SCIP_Bool aggregated;
3460
3461 assert(SCIPvarCompare(consdata0->resvar, consdata1->resvar) != 0);
3462
3463 /* aggregate resultants */
3464 SCIP_CALL( SCIPaggregateVars(scip, consdata0->resvar, consdata1->resvar, 1.0, -1.0, 0.0,
3465 cutoff, &redundant, &aggregated) );
3466 assert(redundant || SCIPdoNotAggr(scip));
3467
3468 if( aggregated )
3469 ++(*naggrvars);
3470 if( *cutoff )
3471 goto TERMINATE;
3472 }
3473 else
3474 redundant = TRUE;
3475
3476 /* delete consdel */
3477 if( redundant )
3478 {
3479 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
3480 /* coverity[swapped_arguments] */
3481 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
3482
3483 /* delete constraint */
3484 SCIP_CALL( SCIPdelCons(scip, cons0) );
3485 (*ndelconss)++;
3486 }
3487
3488 /* update the first changed constraint to begin the next aggregation round with */
3489 if( consdata0->changed && SCIPconsGetPos(cons1) < *firstchange )
3490 *firstchange = SCIPconsGetPos(cons1);
3491
3492 assert(SCIPconsIsActive(cons1));
3493 }
3494 else
3495 {
3496 /* no such constraint in current hash table: insert cons0 into hash table */
3497 SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
3498 }
3499 }
3500 TERMINATE:
3501 /* free hash table */
3502 SCIPhashtableFree(&hashtable);
3503
3504 return SCIP_OKAY;
3505}
3506
3507/** helper function to enforce constraints */
3508static
3510 SCIP* scip, /**< SCIP data structure */
3511 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
3512 SCIP_CONS** conss, /**< constraints to process */
3513 int nconss, /**< number of constraints */
3514 SCIP_SOL* sol, /**< solution to enforce (NULL for the LP solution) */
3515 SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
3516 )
3517{
3518 SCIP_CONSHDLRDATA* conshdlrdata;
3519 SCIP_Bool separated;
3520 SCIP_Bool violated;
3521 SCIP_Bool cutoff;
3522 int i;
3523
3524 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3525 assert(conshdlrdata != NULL);
3526
3527 *result = SCIP_FEASIBLE;
3528
3529 /* method is called only for integral solutions, because the enforcing priority is negative */
3530 for( i = 0; i < nconss; i++ )
3531 {
3532 SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
3533 if( !violated )
3534 continue;
3535
3536 if( !conshdlrdata->enforcecuts )
3537 {
3538 *result = SCIP_INFEASIBLE;
3539 return SCIP_OKAY;
3540 }
3541
3542 SCIP_CALL( separateCons(scip, conss[i], sol, &separated, &cutoff) );
3543 if( cutoff )
3544 {
3545 *result = SCIP_CUTOFF;
3546 return SCIP_OKAY;
3547 }
3548 else if( separated )
3549 {
3550 *result = SCIP_SEPARATED;
3551 }
3552 else if( *result == SCIP_FEASIBLE ) /* do not change result separated to infeasible */
3553 {
3554 *result = SCIP_INFEASIBLE;
3555 }
3556 }
3557
3558 return SCIP_OKAY;
3559}
3560
3561
3562/** compares constraint with all prior constraints for possible redundancy or aggregation,
3563 * and removes or changes constraint accordingly
3564 */
3565static
3567 SCIP* scip, /**< SCIP data structure */
3568 SCIP_CONS** conss, /**< constraint set */
3569 int firstchange, /**< first constraint that changed since last pair preprocessing round */
3570 int chkind, /**< index of constraint to check against all prior indices upto startind */
3571 SCIP_Bool* cutoff, /**< pointer to store TRUE, if a cutoff was found */
3572 int* naggrvars, /**< pointer to count number of aggregated variables */
3573 int* nbdchgs, /**< pointer to count the number of performed bound changes, or NULL */
3574 int* ndelconss /**< pointer to count number of deleted constraints */
3575 )
3576{
3577 SCIP_CONS* cons0;
3578 SCIP_CONSDATA* consdata0;
3579 SCIP_Bool cons0changed;
3580 int c;
3581
3582 assert(conss != NULL);
3583 assert(firstchange <= chkind);
3584 assert(cutoff != NULL);
3585 assert(naggrvars != NULL);
3586 assert(nbdchgs != NULL);
3587 assert(ndelconss != NULL);
3588
3589 /* get the constraint to be checked against all prior constraints */
3590 cons0 = conss[chkind];
3591 assert(SCIPconsIsActive(cons0));
3592 assert(!SCIPconsIsModifiable(cons0));
3593
3594 consdata0 = SCIPconsGetData(cons0);
3595
3596 /* sort the constraint */
3597 consdataSort(consdata0);
3598
3599 assert(consdata0->nvars >= 1);
3600 assert(consdata0->sorted);
3601
3602 /* check constraint against all prior constraints */
3603 cons0changed = consdata0->changed;
3604
3605 if( SCIPconsIsActive(cons0) )
3606 {
3607 for( c = (cons0changed ? 0 : firstchange); c < chkind && !(*cutoff); ++c )
3608 {
3609 SCIP_CONS* cons1;
3610 SCIP_CONSDATA* consdata1;
3611 SCIP_Bool cons0superset;
3612 SCIP_Bool cons1superset;
3613 int v0;
3614 int v1;
3615
3616 if( c % 1000 == 0 && SCIPisStopped(scip) )
3617 break;
3618
3619 cons1 = conss[c];
3620
3621 /* ignore inactive and modifiable constraints */
3622 if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
3623 continue;
3624
3625 consdata1 = SCIPconsGetData(cons1);
3626 assert(consdata1 != NULL);
3627
3628#ifdef SCIP_DISABLED_CODE
3629 SCIPdebugMsg(scip, "preprocess AND-constraint pair <%s>[chg:%d] and <%s>[chg:%d]\n",
3630 SCIPconsGetName(cons0), cons0changed, SCIPconsGetName(cons1), consdata1->changed);
3631#endif
3632
3633 /* if both constraints were not changed since last round, we can ignore the pair */
3634 if( !cons0changed && !consdata1->changed )
3635 continue;
3636
3637 assert(consdata1->nvars >= 1);
3638
3639 /* sort the constraint */
3640 consdataSort(consdata1);
3641 assert(consdata1->sorted);
3642
3643 /* check consdata0 against consdata1:
3644 * - if they consist of the same operands, the resultants can be aggregated
3645 * - if one operand list is a subset of the other, add implication r0 = 1 -> r1 = 1, or r1 = 1 -> r0 = 1
3646 */
3647 v0 = 0;
3648 v1 = 0;
3649 cons0superset = TRUE;
3650 cons1superset = TRUE;
3651 while( (v0 < consdata0->nvars || v1 < consdata1->nvars) && (cons0superset || cons1superset) )
3652 {
3653 int varcmp;
3654
3655 /* test, if variable appears in only one or in both constraints */
3656 if( v0 < consdata0->nvars && v1 < consdata1->nvars )
3657 varcmp = SCIPvarCompare(consdata0->vars[v0], consdata1->vars[v1]);
3658 else if( v0 < consdata0->nvars )
3659 varcmp = -1;
3660 else
3661 varcmp = +1;
3662
3663 switch( varcmp )
3664 {
3665 case -1:
3666 /* variable doesn't appear in consdata1 */
3667 cons1superset = FALSE;
3668 v0++;
3669 break;
3670
3671 case +1:
3672 /* variable doesn't appear in consdata0 */
3673 cons0superset = FALSE;
3674 v1++;
3675 break;
3676
3677 case 0:
3678 /* variable appears in both constraints */
3679 v0++;
3680 v1++;
3681 break;
3682
3683 default:
3684 SCIPerrorMessage("invalid comparison result\n");
3685 SCIPABORT();
3686 return SCIP_INVALIDDATA; /*lint !e527*/
3687 }
3688 }
3689
3690 /* check for equivalence and domination */
3691 if( cons0superset && cons1superset )
3692 {
3693 SCIP_Bool infeasible;
3694 SCIP_Bool redundant;
3695 SCIP_Bool aggregated;
3696
3697 /* constraints are equivalent */
3698 SCIPdebugMsg(scip, "equivalent AND-constraints <%s> and <%s>: aggregate resultants <%s> == <%s>\n",
3699 SCIPconsGetName(cons0), SCIPconsGetName(cons1), SCIPvarGetName(consdata0->resvar),
3700 SCIPvarGetName(consdata1->resvar));
3701
3702 /* aggregate resultants */
3703 SCIP_CALL( SCIPaggregateVars(scip, consdata0->resvar, consdata1->resvar, 1.0, -1.0, 0.0,
3704 &infeasible, &redundant, &aggregated) );
3705 assert(redundant || SCIPdoNotAggr(scip));
3706
3707 if( aggregated )
3708 {
3709 assert(redundant);
3710 (*naggrvars)++;
3711 }
3712
3713 if( redundant )
3714 {
3715 /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
3716 SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
3717
3718 /* delete constraint */
3719 SCIP_CALL( SCIPdelCons(scip, cons1) );
3720 (*ndelconss)++;
3721 }
3722
3723 *cutoff = *cutoff || infeasible;
3724 }
3725 else if( cons0superset )
3726 {
3727 SCIP_Bool infeasible;
3728 int nboundchgs;
3729
3730 /* the conjunction of cons0 is a superset of the conjunction of cons1 */
3731 SCIPdebugMsg(scip, "AND-constraint <%s> is superset of <%s>: add implication <%s> = 1 -> <%s> = 1\n",
3732 SCIPconsGetName(cons0), SCIPconsGetName(cons1), SCIPvarGetName(consdata0->resvar),
3733 SCIPvarGetName(consdata1->resvar));
3734
3735 /* add implication */
3736 SCIP_CALL( SCIPaddVarImplication(scip, consdata0->resvar, TRUE, consdata1->resvar, SCIP_BOUNDTYPE_LOWER, 1.0,
3737 &infeasible, &nboundchgs) );
3738 *cutoff = *cutoff || infeasible;
3739 (*nbdchgs) += nboundchgs;
3740 }
3741 else if( cons1superset )
3742 {
3743 SCIP_Bool infeasible;
3744 int nboundchgs;
3745
3746 /* the conjunction of cons1 is a superset of the conjunction of cons0 */
3747 SCIPdebugMsg(scip, "AND-constraint <%s> is superset of <%s>: add implication <%s> = 1 -> <%s> = 1\n",
3748 SCIPconsGetName(cons1), SCIPconsGetName(cons0), SCIPvarGetName(consdata1->resvar),
3749 SCIPvarGetName(consdata0->resvar));
3750
3751 /* add implication */
3752 SCIP_CALL( SCIPaddVarImplication(scip, consdata1->resvar, TRUE, consdata0->resvar, SCIP_BOUNDTYPE_LOWER, 1.0,
3753 &infeasible, &nboundchgs) );
3754 *cutoff = *cutoff || infeasible;
3755 (*nbdchgs) += nboundchgs;
3756 }
3757 }
3758 }
3759 consdata0->changed = FALSE;
3760
3761 return SCIP_OKAY;
3762}
3763
3764/** adds symmetry information of constraint to a symmetry detection graph */
3765static
3767 SCIP* scip, /**< SCIP pointer */
3768 SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */
3769 SCIP_CONS* cons, /**< constraint */
3770 SYM_GRAPH* graph, /**< symmetry detection graph */
3771 SCIP_Bool* success /**< pointer to store whether symmetry information could be added */
3772 )
3773{
3774 SCIP_CONSDATA* consdata;
3775 SCIP_VAR** andvars;
3776 SCIP_VAR** vars;
3777 SCIP_Real* vals;
3778 SCIP_Real constant;
3779 int consnodeidx;
3780 int andnodeidx;
3781 int nlocvars;
3782 int i;
3783
3784 assert(scip != NULL);
3785 assert(cons != NULL);
3786 assert(graph != NULL);
3787 assert(success != NULL);
3788
3789 consdata = SCIPconsGetData(cons);
3790 assert(consdata != NULL);
3791
3792 /* create arrays to store active representation of variables */
3793 nlocvars = 1;
3794 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nlocvars) );
3795 SCIP_CALL( SCIPallocBufferArray(scip, &vals, nlocvars) );
3796
3797 /* add constraint node */
3798 SCIP_CALL( SCIPaddSymgraphConsnode(scip, graph, cons, 0.0, 0.0, &consnodeidx) );
3799
3800 /* add resultant to symmetry detection graph */
3801 assert(consdata->resvar != NULL);
3802 vars[0] = consdata->resvar;
3803 vals[0] = 1.0;
3804 constant = 0.0;
3805 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &vars, &vals, &nlocvars, &constant, SCIPisTransformed(scip)) );
3806 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, consnodeidx, vars, vals, nlocvars, constant) );
3807
3808 /* add node modeling the AND-part and connect it with constraint node */
3809 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int)SYM_CONSOPTYPE_AND, &andnodeidx) );
3810 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, consnodeidx, andnodeidx, FALSE, 0.0) );
3811
3812 /* add variables */
3813 andvars = consdata->vars;
3814 for( i = 0; i < consdata->nvars; ++i )
3815 {
3816 assert(andvars[i] != NULL);
3817 vars[0] = andvars[i];
3818 vals[0] = 1.0;
3819 constant = 0.0;
3820 nlocvars = 1;
3821 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &vars, &vals, &nlocvars, &constant, SCIPisTransformed(scip)) );
3822 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, andnodeidx, vars, vals, nlocvars, constant) );
3823 }
3824
3825 SCIPfreeBufferArray(scip, &vals);
3826 SCIPfreeBufferArray(scip, &vars);
3827
3828 *success = TRUE;
3829
3830 return SCIP_OKAY;
3831}
3832
3833/*
3834 * Callback methods of constraint handler
3835 */
3836
3837/** copy method for constraint handler plugins (called when SCIP copies plugins) */
3838static
3840{ /*lint --e{715}*/
3841 assert(scip != NULL);
3842 assert(conshdlr != NULL);
3843 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
3844
3845 /* call inclusion method of constraint handler */
3847
3848 *valid = TRUE;
3849
3850 return SCIP_OKAY;
3851}
3852
3853/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
3854static
3856{ /*lint --e{715}*/
3857 SCIP_CONSHDLRDATA* conshdlrdata;
3858
3859 /* free constraint handler data */
3860 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3861 assert(conshdlrdata != NULL);
3862
3863 conshdlrdataFree(scip, &conshdlrdata);
3864
3865 SCIPconshdlrSetData(conshdlr, NULL);
3866
3867 return SCIP_OKAY;
3868}
3869
3870
3871/** presolving initialization method of constraint handler (called when presolving is about to begin) */
3872static
3874{ /*lint --e{715}*/
3875 SCIP_CONSHDLRDATA* conshdlrdata;
3876
3877 assert( scip != NULL );
3878 assert( conshdlr != NULL );
3879 assert( nconss == 0 || conss != NULL );
3880
3881 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3882 assert(conshdlrdata != NULL);
3883
3884 if( conshdlrdata->linearize )
3885 {
3886 /* linearize all AND-constraints and remove the AND-constraints */
3887 SCIP_CONS* newcons;
3888 SCIP_CONS* cons;
3889 SCIP_CONSDATA* consdata;
3890 char consname[SCIP_MAXSTRLEN];
3891
3892 SCIP_VAR** vars;
3893 SCIP_Real* vals;
3894
3895 int nvars;
3896 int c, v;
3897
3898 /* allocate buffer array */
3899 SCIP_CALL( SCIPallocBufferArray(scip, &vars, 2) );
3900 SCIP_CALL( SCIPallocBufferArray(scip, &vals, 2) );
3901
3902 for( c = 0; c < nconss; ++c )
3903 {
3904 cons = conss[c];
3905 assert( cons != NULL );
3906
3907 /* only added constraints can be upgraded */
3908 if( !SCIPconsIsAdded(cons) || SCIPconsGetNUpgradeLocks(cons) >= 1 )
3909 continue;
3910
3911 consdata = SCIPconsGetData(cons);
3912 assert( consdata != NULL );
3913 assert( consdata->resvar != NULL );
3914
3915 nvars = consdata->nvars;
3916
3917 if( !conshdlrdata->aggrlinearization )
3918 {
3919 vars[0] = consdata->resvar;
3920 vals[0] = 1.0;
3921 vals[1] = -1.0;
3922
3923 /* create operator linear constraints */
3924 for( v = 0; v < nvars; ++v )
3925 {
3926 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_%d", SCIPconsGetName(cons), v);
3927 vars[1] = consdata->vars[v];
3928
3929 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, consname, 2, vars, vals, -SCIPinfinity(scip), 0.0,
3933 SCIPconsIsStickingAtNode(cons)) );
3934
3935 /* add constraint */
3936 SCIP_CALL( SCIPaddCons(scip, newcons) );
3937 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3938 }
3939 }
3940
3941 /* reallocate buffer array */
3942 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, nvars + 1) );
3943 SCIP_CALL( SCIPreallocBufferArray(scip, &vals, nvars + 1) );
3944
3945 for( v = 0; v < nvars; ++v )
3946 {
3947 vars[v] = consdata->vars[v];
3948 vals[v] = -1.0;
3949 }
3950
3951 vars[nvars] = consdata->resvar;
3952
3953 if( conshdlrdata->aggrlinearization )
3954 {
3955 /* create additional linear constraint */
3956 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_operators", SCIPconsGetName(cons));
3957
3958 vals[nvars] = (SCIP_Real) nvars;
3959
3960 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, consname, nvars + 1, vars, vals, -SCIPinfinity(scip), 0.0,
3964 SCIPconsIsStickingAtNode(cons)) );
3965
3966 /* add constraint */
3967 SCIP_CALL( SCIPaddCons(scip, newcons) );
3968 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3969 }
3970
3971 /* create additional linear constraint */
3972 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_add", SCIPconsGetName(cons));
3973
3974 vals[nvars] = 1.0;
3975
3976 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, consname, nvars + 1, vars, vals, -nvars + 1.0, SCIPinfinity(scip),
3980 SCIPconsIsStickingAtNode(cons)) );
3981
3982 /* add constraint */
3983 SCIP_CALL( SCIPaddCons(scip, newcons) );
3984 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3985
3986 /* delete constraint */
3987 SCIP_CALL( SCIPdelCons(scip, cons) );
3988 }
3989
3990 /* free buffer array */
3991 SCIPfreeBufferArray(scip, &vars);
3992 SCIPfreeBufferArray(scip, &vals);
3993 }
3994
3995 return SCIP_OKAY;
3996}
3997
3998
3999#ifdef GMLGATEPRINTING
4000
4001/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
4002static
4003SCIP_DECL_CONSEXITPRE(consExitpreAnd)
4004{ /*lint --e{715}*/
4005 SCIP_HASHMAP* hashmap;
4006 FILE* gmlfile;
4007 char fname[SCIP_MAXSTRLEN];
4008 SCIP_CONS* cons;
4009 SCIP_CONSDATA* consdata;
4010 SCIP_VAR** activeconsvars;
4011 SCIP_VAR* activevar;
4012 int* varnodeids;
4013 SCIP_VAR** vars;
4014 int nvars;
4015 int nbinvars;
4016 int nintvars;
4017 int nimplvars;
4018 int ncontvars;
4019 int v;
4020 int c;
4021 int resid;
4022 int varid;
4023 int id = 1;
4024
4025 /* no AND-constraints available */
4026 if( nconss == 0 )
4027 return SCIP_OKAY;
4028
4029 nvars = SCIPgetNVars(scip);
4030
4031 /* no variables left anymore */
4032 if( nvars == 0 )
4033 return SCIP_OKAY;
4034
4035 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
4036 SCIP_CALL( SCIPallocBufferArray(scip, &varnodeids, nvars) );
4037 SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, &nbinvars, &nintvars, &nimplvars, &ncontvars) );
4038
4039 /* open gml file */
4040 (void) SCIPsnprintf(fname, SCIP_MAXSTRLEN, "and-gates%p.gml", scip);
4041 gmlfile = fopen(fname, "w");
4042
4043 if( gmlfile == NULL )
4044 {
4045 SCIPerrorMessage("cannot open graph file <%s>\n", fname);
4046 SCIPABORT();
4047 return SCIP_WRITEERROR; /*lint !e527*/
4048 }
4049
4050 /* create the variable mapping hash map */
4051 SCIP_CALL_FINALLY( SCIPhashmapCreate(&hashmap, SCIPblkmem(scip), nvars), fclose(gmlfile) );
4052
4053 /* write starting of gml file */
4054 SCIPgmlWriteOpening(gmlfile, TRUE);
4055
4056 /* walk over all AND-constraints */
4057 for( c = nconss - 1; c >= 0; --c )
4058 {
4059 cons = conss[c];
4060
4061 /* only handle active constraints */
4062 if( !SCIPconsIsActive(cons) )
4063 continue;
4064
4065 consdata = SCIPconsGetData(cons);
4066 assert(consdata != NULL);
4067
4068 /* only handle constraints which have operands */
4069 if( consdata->nvars == 0 )
4070 continue;
4071
4072 assert(consdata->vars != NULL);
4073 assert(consdata->resvar != NULL);
4074
4075 /* get active variable of resultant */
4076 activevar = SCIPvarGetProbvar(consdata->resvar);
4077
4078 /* check if we already found this variables */
4079 resid = SCIPhashmapGetImageInt(hashmap, activevar);
4080 assert(resid >= 0);
4081
4082 if( resid == 0 )
4083 {
4084 resid = id;
4085 ++id;
4086 SCIP_CALL( SCIPhashmapInsertInt(hashmap, (void*)activevar, resid) );
4087
4088 /* write new gml node for new resultant */
4089 SCIPgmlWriteNode(gmlfile, resid, SCIPvarGetName(activevar), NULL, NULL, NULL);
4090 }
4091
4092 /* copy operands to get problem variables for */
4093 SCIP_CALL( SCIPduplicateBufferArray(scip, &activeconsvars, consdata->vars, consdata->nvars) );
4094
4095 /* get problem variables of operands */
4096 SCIPvarsGetProbvar(activeconsvars, consdata->nvars);
4097
4098 for( v = consdata->nvars - 1; v >= 0; --v )
4099 {
4100 /* check if we already found this variables */
4101 varid = SCIPhashmapGetImageInt(hashmap, activeconsvars[v]);
4102 if( varid == 0 )
4103 {
4104 varid = id;
4105 ++id;
4106 SCIP_CALL( SCIPhashmapInsertInt(hashmap, (void*)activeconsvars[v], varid) );
4107
4108 /* write new gml node for new operand */
4109 SCIPgmlWriteNode(gmlfile, varid, SCIPvarGetName(activeconsvars[v]), NULL, NULL, NULL);
4110 }
4111 /* write gml arc between resultant and operand */
4112 SCIPgmlWriteArc(gmlfile, resid, varid, NULL, NULL);
4113 }
4114
4115 /* free temporary memory for active constraint variables */
4116 SCIPfreeBufferArray(scip, &activeconsvars);
4117 }
4118
4119 /* write all remaining variables as nodes */
4120#ifdef SCIP_DISABLED_CODE
4121 for( v = nvars - 1; v >= 0; --v )
4122 {
4123 activevar = SCIPvarGetProbvar(vars[v]);
4124
4125 varid = SCIPhashmapGetImageInt(hashmap, activevar);
4126 assert(varid >= 0);
4127
4128 if( varid == 0 )
4129 {
4130 varid = id;
4131 ++id;
4132 SCIP_CALL( SCIPhashmapInsertInt(hashmap, (void*)activeconsvars[v], varid) );
4133
4134 /* write new gml node for new operand */
4135 SCIPgmlWriteNode(gmlfile, varid, SCIPvarGetName(activevar), NULL, NULL, NULL);
4136 }
4137 }
4138#endif
4139
4140 /* free the variable mapping hash map */
4141 SCIPhashmapFree(&hashmap);
4142
4143 SCIPgmlWriteClosing(gmlfile);
4144
4145 fclose(gmlfile);
4146
4147 SCIPfreeBufferArray(scip, &varnodeids);
4148 SCIPfreeBufferArray(scip, &vars);
4149
4150 return SCIP_OKAY;
4151}
4152#endif
4153
4154/** solving process initialization method of constraint handler */
4155static
4157{ /*lint --e{715}*/
4158 /* add nlrow representation to NLP, if NLP had been constructed */
4160 {
4161 int c;
4162 for( c = 0; c < nconss; ++c )
4163 {
4164 SCIP_CALL( addNlrow(scip, conss[c]) );
4165 }
4166 }
4167
4168 return SCIP_OKAY;
4169}
4170
4171/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
4172static
4174{ /*lint --e{715}*/
4175 SCIP_CONSDATA* consdata;
4176 int c;
4177
4178 /* release and free the rows and nlrow of all constraints */
4179 for( c = 0; c < nconss; ++c )
4180 {
4181 consdata = SCIPconsGetData(conss[c]);
4182 assert(consdata != NULL);
4183
4184 SCIP_CALL( consdataFreeRows(scip, consdata) );
4185
4186 if( consdata->nlrow != NULL )
4187 {
4188 SCIP_CALL( SCIPreleaseNlRow(scip, &consdata->nlrow) );
4189 }
4190 }
4191
4192 return SCIP_OKAY;
4193}
4194
4195
4196/** frees specific constraint data */
4197static
4199{ /*lint --e{715}*/
4200 SCIP_CONSHDLRDATA* conshdlrdata;
4201
4202 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4203 assert(conshdlrdata != NULL);
4204
4205 SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
4206
4207 return SCIP_OKAY;
4208}
4209
4210
4211/** transforms constraint data into data belonging to the transformed problem */
4212static
4214{ /*lint --e{715}*/
4215 SCIP_CONSHDLRDATA* conshdlrdata;
4216 SCIP_CONSDATA* sourcedata;
4217 SCIP_CONSDATA* targetdata;
4218
4219 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4220 assert(conshdlrdata != NULL);
4221
4222 sourcedata = SCIPconsGetData(sourcecons);
4223 assert(sourcedata != NULL);
4224
4225 /* create target constraint data */
4226 SCIP_CALL( consdataCreate(scip, &targetdata, conshdlrdata->eventhdlr,
4227 sourcedata->nvars, sourcedata->vars, sourcedata->resvar) );
4228
4229 /* create target constraint */
4230 SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
4231 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
4232 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
4233 SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons),
4234 SCIPconsIsStickingAtNode(sourcecons)) );
4235
4236 return SCIP_OKAY;
4237}
4238
4239
4240/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
4241static
4243{ /*lint --e{715}*/
4244 int i;
4245
4246 *infeasible = FALSE;
4247
4248 for( i = 0; i < nconss && !(*infeasible); i++ )
4249 {
4250 assert(SCIPconsIsInitial(conss[i]));
4251 SCIP_CALL( addRelaxation(scip, conss[i], infeasible) );
4252 }
4253
4254 return SCIP_OKAY;
4255}
4256
4257
4258/** separation method of constraint handler for LP solutions */
4259static
4261{ /*lint --e{715}*/
4262 SCIP_Bool separated;
4263 SCIP_Bool cutoff;
4264 int c;
4265
4266 *result = SCIP_DIDNOTFIND;
4267
4268 /* separate all useful constraints */
4269 for( c = 0; c < nusefulconss; ++c )
4270 {
4271 SCIP_CALL( separateCons(scip, conss[c], NULL, &separated, &cutoff) );
4272 if ( cutoff )
4273 *result = SCIP_CUTOFF;
4274 else if ( separated )
4275 *result = SCIP_SEPARATED;
4276 }
4277
4278 /* combine constraints to get more cuts */
4279 /**@todo combine constraints to get further cuts */
4280
4281 return SCIP_OKAY;
4282}
4283
4284
4285/** separation method of constraint handler for arbitrary primal solutions */
4286static
4288{ /*lint --e{715}*/
4289 SCIP_Bool separated;
4290 SCIP_Bool cutoff;
4291 int c;
4292
4293 *result = SCIP_DIDNOTFIND;
4294
4295 /* separate all useful constraints */
4296 for( c = 0; c < nusefulconss; ++c )
4297 {
4298 SCIP_CALL( separateCons(scip, conss[c], sol, &separated, &cutoff) );
4299 if ( cutoff )
4300 *result = SCIP_CUTOFF;
4301 else if ( separated )
4302 *result = SCIP_SEPARATED;
4303 }
4304
4305 /* combine constraints to get more cuts */
4306 /**@todo combine constraints to get further cuts */
4307
4308 return SCIP_OKAY;
4309}
4310
4311
4312/** constraint enforcing method of constraint handler for LP solutions */
4313static
4315{ /*lint --e{715}*/
4316 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, NULL, result) );
4317
4318 return SCIP_OKAY;
4319}
4320
4321/** constraint enforcing method of constraint handler for relaxation solutions */
4322static
4324{ /*lint --e{715}*/
4325 SCIP_CALL( enforceConstraint(scip, conshdlr, conss, nconss, sol, result) );
4326
4327 return SCIP_OKAY;
4328}
4329
4330/** constraint enforcing method of constraint handler for pseudo solutions */
4331static
4333{ /*lint --e{715}*/
4334 SCIP_Bool violated;
4335 int i;
4336
4337 /* method is called only for integral solutions, because the enforcing priority is negative */
4338 for( i = 0; i < nconss; i++ )
4339 {
4340 SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
4341 if( violated )
4342 {
4343 *result = SCIP_INFEASIBLE;
4344 return SCIP_OKAY;
4345 }
4346 }
4347 *result = SCIP_FEASIBLE;
4348
4349 return SCIP_OKAY;
4350}
4351
4352/** feasibility check method of constraint handler and */
4353static
4355{ /*lint --e{715}*/
4356 SCIP_Bool violated;
4357 int i;
4358
4359 *result = SCIP_FEASIBLE;
4360
4361 for( i = 0; i < nconss && ( *result == SCIP_FEASIBLE || completely ); ++i )
4362 {
4363 SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
4364 if( violated )
4365 *result = SCIP_INFEASIBLE;
4366 }
4367
4368 return SCIP_OKAY;
4369}
4370
4371/** domain propagation method of constraint handler */
4372static
4374{ /*lint --e{715}*/
4375 SCIP_CONSHDLRDATA* conshdlrdata;
4376 SCIP_Bool cutoff;
4377 int nfixedvars;
4378 int nupgdconss;
4379 int c;
4380
4381 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4382 assert(conshdlrdata != NULL);
4383
4384 cutoff = FALSE;
4385 nfixedvars = 0;
4386 nupgdconss = 0;
4387
4388 /* propagate all useful constraints */
4389 for( c = 0; c < nusefulconss && !cutoff; ++c )
4390 {
4391 SCIP_CALL( propagateCons(scip, conss[c], conshdlrdata->eventhdlr, &cutoff, &nfixedvars, &nupgdconss) );
4392 }
4393
4394 /* return the correct result */
4395 if( cutoff )
4396 *result = SCIP_CUTOFF;
4397 else if( nfixedvars > 0 || nupgdconss > 0 )
4398 *result = SCIP_REDUCEDDOM;
4399 else
4400 *result = SCIP_DIDNOTFIND;
4401
4402 return SCIP_OKAY;
4403}
4404
4405
4406/** presolving method of constraint handler */
4407static
4409{ /*lint --e{715}*/
4410 SCIP_CONSHDLRDATA* conshdlrdata;
4411 SCIP_CONS* cons;
4412 SCIP_CONSDATA* consdata;
4413 unsigned char* entries;
4414 SCIP_Bool cutoff;
4415 int oldnfixedvars;
4416 int oldnaggrvars;
4417 int oldnchgbds;
4418 int oldndelconss;
4419 int oldnupgdconss;
4420 int firstchange;
4421 int nentries;
4422 int c;
4423
4424 assert(result != NULL);
4425
4426 oldnfixedvars = *nfixedvars;
4427 oldnaggrvars = *naggrvars;
4428 oldnchgbds = *nchgbds;
4429 oldndelconss = *ndelconss;
4430 oldnupgdconss = *nupgdconss;
4431
4432 nentries = SCIPgetNVars(scip) - SCIPgetNContVars(scip);
4433 SCIP_CALL( SCIPallocBufferArray(scip, &entries, nentries) );
4434
4435 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4436 assert(conshdlrdata != NULL);
4437
4438 /* process constraints */
4439 cutoff = FALSE;
4440 firstchange = INT_MAX;
4441 for( c = 0; c < nconss && !cutoff && (c % 1000 != 0 || !SCIPisStopped(scip)); ++c )
4442 {
4443 cons = conss[c];
4444 assert(cons != NULL);
4445 consdata = SCIPconsGetData(cons);
4446 assert(consdata != NULL);
4447
4448 /* force presolving the constraint in the initial round */
4449 if( nrounds == 0 )
4450 consdata->propagated = FALSE;
4451
4452 /* remember the first changed constraint to begin the next aggregation round with */
4453 if( firstchange == INT_MAX && consdata->changed )
4454 firstchange = c;
4455
4456 /* propagate constraint */
4457 SCIP_CALL( propagateCons(scip, cons, conshdlrdata->eventhdlr, &cutoff, nfixedvars, nupgdconss) );
4458
4459 /* remove all variables that are fixed to one; merge multiple entries of the same variable;
4460 * fix resultant to zero if a pair of negated variables is contained in the operand variables
4461 */
4462 if( !cutoff && !SCIPconsIsDeleted(cons) )
4463 {
4464 SCIP_CALL( applyFixings(scip, cons, conshdlrdata->eventhdlr, nchgcoefs) );
4465
4466 /* merge multiple occurances of variables or variables with their negated variables */
4467 SCIP_CALL( mergeMultiples(scip, cons, conshdlrdata->eventhdlr, &entries, &nentries, nfixedvars, nchgcoefs, ndelconss) );
4468 }
4469
4470 if( !cutoff && !SCIPconsIsDeleted(cons) && !SCIPconsIsModifiable(cons) )
4471 {
4472 assert(consdata->nvars >= 1); /* otherwise, propagateCons() has deleted the constraint */
4473
4474 /* if only one variable is left, the resultant has to be equal to this single variable */
4475 if( consdata->nvars == 1 )
4476 {
4477 SCIP_Bool redundant;
4478 SCIP_Bool aggregated;
4479
4480 SCIPdebugMsg(scip, "AND-constraint <%s> has only one variable not fixed to 1.0\n", SCIPconsGetName(cons));
4481
4482 assert(consdata->vars != NULL);
4483 assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(consdata->vars[0]), 0.0));
4484 assert(SCIPisFeasEQ(scip, SCIPvarGetUbGlobal(consdata->vars[0]), 1.0));
4485
4486 /* aggregate variables: resultant - operand == 0 */
4487 SCIP_CALL( SCIPaggregateVars(scip, consdata->resvar, consdata->vars[0], 1.0, -1.0, 0.0,
4488 &cutoff, &redundant, &aggregated) );
4489 assert(redundant || SCIPdoNotAggr(scip));
4490
4491 if( aggregated )
4492 {
4493 assert(redundant);
4494 (*naggrvars)++;
4495 }
4496
4497 if( redundant )
4498 {
4499 /* delete constraint */
4500 SCIP_CALL( SCIPdelCons(scip, cons) );
4501 (*ndelconss)++;
4502 }
4503 }
4504 else if( !consdata->impladded )
4505 {
4506 int i;
4507
4508 /* add implications: resultant == 1 -> all operands == 1 */
4509 for( i = 0; i < consdata->nvars && !cutoff; ++i )
4510 {
4511 int nimplbdchgs;
4512
4513 SCIP_CALL( SCIPaddVarImplication(scip, consdata->resvar, TRUE, consdata->vars[i],
4514 SCIP_BOUNDTYPE_LOWER, 1.0, &cutoff, &nimplbdchgs) );
4515 (*nchgbds) += nimplbdchgs;
4516 }
4517 consdata->impladded = TRUE;
4518 }
4519
4520 /* if in r = x and y, the resultant is fixed to zero, add implication x = 1 -> y = 0 */
4521 if( !cutoff && SCIPconsIsActive(cons) && consdata->nvars == 2 && !consdata->opimpladded
4522 && SCIPvarGetUbGlobal(consdata->resvar) < 0.5 )
4523 {
4524 int nimplbdchgs;
4525
4526 SCIP_CALL( SCIPaddVarImplication(scip, consdata->vars[0], TRUE, consdata->vars[1],
4527 SCIP_BOUNDTYPE_UPPER, 0.0, &cutoff, &nimplbdchgs) );
4528 (*nchgbds) += nimplbdchgs;
4529 consdata->opimpladded = TRUE;
4530 }
4531 }
4532 }
4533
4534 /* perform dual presolving on AND-constraints */
4535 if( conshdlrdata->dualpresolving && !cutoff && !SCIPisStopped(scip) && SCIPallowStrongDualReds(scip))
4536 {
4537 SCIP_CALL( dualPresolve(scip, conss, nconss, conshdlrdata->eventhdlr, &entries, &nentries, &cutoff, nfixedvars, naggrvars, nchgcoefs, ndelconss, nupgdconss, naddconss) );
4538 }
4539
4540 /* check for cliques inside the AND constraint */
4541 if( (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
4542 {
4543 for( c = 0; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
4544 {
4545 cons = conss[c];
4546 assert(cons != NULL);
4547
4548 if( !SCIPconsIsActive(cons) )
4549 continue;
4550
4551 /* cliquePresolve() may aggregate variables which need to be removed from other constraints, we also need
4552 * to make sure that we remove fixed variables by calling propagateCons() to make sure that applyFixing()
4553 * and mergeMultiples() work
4554 */
4555 SCIP_CALL( propagateCons(scip, cons, conshdlrdata->eventhdlr, &cutoff, nfixedvars, nupgdconss) );
4556
4557 if( !cutoff && !SCIPconsIsDeleted(cons) )
4558 {
4559 /* remove all variables that are fixed to one; merge multiple entries of the same variable;
4560 * fix resultant to zero if a pair of negated variables is contained in the operand variables
4561 */
4562 SCIP_CALL( applyFixings(scip, cons, conshdlrdata->eventhdlr, nchgcoefs) );
4563 SCIP_CALL( mergeMultiples(scip, cons, conshdlrdata->eventhdlr, &entries, &nentries, nfixedvars, nchgcoefs, ndelconss) );
4564
4565 /* check if at least two operands are in one clique */
4566 SCIP_CALL( cliquePresolve(scip, cons, conshdlrdata->eventhdlr, &cutoff, nfixedvars, naggrvars, nchgcoefs, ndelconss, naddconss) );
4567 }
4568 }
4569 }
4570
4571 /* process pairs of constraints: check them for equal operands in order to aggregate resultants;
4572 * only apply this expensive procedure, if the single constraint preprocessing did not find any reductions
4573 * (otherwise, we delay the presolving to be called again next time)
4574 */
4575 if( !cutoff && conshdlrdata->presolusehashing && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
4576 {
4577 if( *nfixedvars == oldnfixedvars && *naggrvars == oldnaggrvars )
4578 {
4579 if( firstchange < nconss )
4580 {
4581 /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
4582 SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &firstchange, &cutoff, naggrvars, ndelconss) );
4583 oldnaggrvars = *naggrvars;
4584 }
4585 }
4586 }
4587
4588 if( !cutoff && conshdlrdata->presolpairwise && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 )
4589 {
4590 if( *nfixedvars == oldnfixedvars && *naggrvars == oldnaggrvars )
4591 {
4592 SCIP_Longint npaircomparisons;
4593 npaircomparisons = 0;
4594 oldndelconss = *ndelconss;
4595
4596 for( c = firstchange; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
4597 {
4598 if( SCIPconsIsActive(conss[c]) && !SCIPconsIsModifiable(conss[c]) )
4599 {
4600 npaircomparisons += ((SCIPconsGetData(conss[c])->changed) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange));
4601
4602 SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c, &cutoff, naggrvars, nchgbds,
4603 ndelconss) );
4604
4605 if( npaircomparisons > NMINCOMPARISONS )
4606 {
4607 if( ((*ndelconss - oldndelconss) + (*naggrvars - oldnaggrvars) + (*nchgbds - oldnchgbds)/2.0) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
4608 break;
4609 oldndelconss = *ndelconss;
4610 oldnaggrvars = *naggrvars;
4611 oldnchgbds = *nchgbds;
4612
4613 npaircomparisons = 0;
4614 }
4615 }
4616 }
4617 }
4618 }
4619
4620 SCIPfreeBufferArray(scip, &entries);
4621
4622 /* return the correct result code */
4623 if( cutoff )
4624 *result = SCIP_CUTOFF;
4625 else if( *nfixedvars > oldnfixedvars || *naggrvars > oldnaggrvars || *nchgbds > oldnchgbds
4626 || *ndelconss > oldndelconss || *nupgdconss > oldnupgdconss )
4627 *result = SCIP_SUCCESS;
4628 else
4629 *result = SCIP_DIDNOTFIND;
4630
4631 return SCIP_OKAY;
4632}
4633
4634
4635/** propagation conflict resolving method of constraint handler */
4636static
4638{ /*lint --e{715}*/
4639 SCIP_CALL( resolvePropagation(scip, cons, infervar, (PROPRULE)inferinfo, bdchgidx, result) );
4640
4641 return SCIP_OKAY;
4642}
4643
4644
4645/** variable rounding lock method of constraint handler */
4646static
4648{ /*lint --e{715}*/
4649 SCIP_CONSDATA* consdata;
4650 int i;
4651
4652 consdata = SCIPconsGetData(cons);
4653 assert(consdata != NULL);
4654
4655 /* resultant variable */
4656 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->resvar, locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
4657
4658 /* operand variables */
4659 for( i = 0; i < consdata->nvars; ++i )
4660 {
4661 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
4662 }
4663
4664 return SCIP_OKAY;
4665}
4666
4667/** constraint activation notification method of constraint handler */
4668static
4670{ /*lint --e{715}*/
4672 {
4673 SCIP_CALL( addNlrow(scip, cons) );
4674 }
4675
4676 return SCIP_OKAY;
4677}
4678
4679/** constraint deactivation notification method of constraint handler */
4680static
4682{ /*lint --e{715}*/
4683 SCIP_CONSDATA* consdata;
4684
4685 assert(cons != NULL);
4686
4687 consdata = SCIPconsGetData(cons);
4688 assert(consdata != NULL);
4689
4690 /* remove row from NLP, if still in solving
4691 * if we are in exitsolve, the whole NLP will be freed anyway
4692 */
4693 if( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && consdata->nlrow != NULL )
4694 {
4695 SCIP_CALL( SCIPdelNlRow(scip, consdata->nlrow) );
4696 }
4697
4698 return SCIP_OKAY;
4699}
4700
4701/** constraint display method of constraint handler */
4702static
4704{ /*lint --e{715}*/
4705 assert( scip != NULL );
4706 assert( conshdlr != NULL );
4707 assert( cons != NULL );
4708
4710
4711 return SCIP_OKAY;
4712}
4713
4714/** constraint copying method of constraint handler */
4715static
4717{ /*lint --e{715}*/
4718 SCIP_VAR** sourcevars;
4719 SCIP_VAR** vars;
4720 SCIP_VAR* sourceresvar;
4721 SCIP_VAR* resvar;
4722 const char* consname;
4723 int nvars;
4724 int v;
4725
4726 assert(valid != NULL);
4727 (*valid) = TRUE;
4728
4729 sourceresvar = SCIPgetResultantAnd(sourcescip, sourcecons);
4730
4731 /* map resultant to active variable of the target SCIP */
4732 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourceresvar, &resvar, varmap, consmap, global, valid) );
4733 assert(!(*valid) || resvar != NULL);
4734
4735 /* we do not copy, if a variable is missing */
4736 if( !(*valid) )
4737 return SCIP_OKAY;
4738
4739 /* map operand variables to active variables of the target SCIP */
4740 sourcevars = SCIPgetVarsAnd(sourcescip, sourcecons);
4741 nvars = SCIPgetNVarsAnd(sourcescip, sourcecons);
4742
4743 if( nvars == -1 )
4744 return SCIP_INVALIDCALL;
4745
4746 /* allocate buffer array */
4747 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
4748
4749 for( v = 0; v < nvars; ++v )
4750 {
4751 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &vars[v], varmap, consmap, global, valid) );
4752 assert(!(*valid) || vars[v] != NULL);
4753
4754 /* we do not copy, if a variable is missing */
4755 if( !(*valid) )
4756 goto TERMINATE;
4757 }
4758
4759 if( name != NULL )
4760 consname = name;
4761 else
4762 consname = SCIPconsGetName(sourcecons);
4763
4764 /* creates and captures a AND-constraint */
4765 SCIP_CALL( SCIPcreateConsAnd(scip, cons, consname, resvar, nvars, vars,
4766 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
4767
4768 TERMINATE:
4769 /* free buffer array */
4770 SCIPfreeBufferArray(scip, &vars);
4771
4772 return SCIP_OKAY;
4773}
4774
4775/** constraint parsing method of constraint handler */
4776static
4778{ /*lint --e{715}*/
4779 SCIP_VAR** vars;
4780 SCIP_VAR* resvar;
4781 char* endptr;
4782 int requiredsize;
4783 int varssize;
4784 int nvars;
4785
4786 SCIPdebugMsg(scip, "parse <%s> as AND-constraint\n", str);
4787
4788 *success = FALSE;
4789
4790 /* parse variable name of resultant */
4791 SCIP_CALL( SCIPparseVarName(scip, str, &resvar, &endptr) );
4792
4793 if( resvar == NULL )
4794 {
4795 SCIPerrorMessage("resultant variable does not exist\n");
4796 }
4797 else
4798 {
4799 char* strcopy = NULL;
4800 char* startptr;
4801
4802 str = endptr;
4803
4804 /* cutoff "== and(" form the constraint string */
4805 startptr = strchr((char*)str, '(');
4806
4807 if( startptr == NULL )
4808 {
4809 SCIPerrorMessage("missing starting character '(' parsing AND-constraint\n");
4810 return SCIP_OKAY;
4811 }
4812
4813 /* skip '(' */
4814 ++startptr;
4815
4816 /* find end character ')' */
4817 endptr = strrchr(startptr, ')');
4818
4819 if( endptr == NULL )
4820 {
4821 SCIPerrorMessage("missing ending character ')' parsing AND-constraint\n");
4822 return SCIP_OKAY;
4823 }
4824 assert(endptr >= startptr);
4825
4826 if( endptr > startptr )
4827 {
4828 /* copy string for parsing; note that SCIPskipSpace() in SCIPparseVarsList() requires that strcopy ends with '\0' */
4829 SCIP_CALL( SCIPduplicateBufferArray(scip, &strcopy, startptr, (int)(endptr-startptr+1)) );
4830 strcopy[endptr-startptr] = '\0';
4831 varssize = 100;
4832 nvars = 0;
4833
4834 /* allocate buffer array for variables */
4835 SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
4836
4837 /* parse string */
4838 SCIP_CALL( SCIPparseVarsList(scip, strcopy, vars, &nvars, varssize, &requiredsize, &endptr, ',', success) );
4839
4840 if( *success )
4841 {
4842 /* check if the size of the variable array was great enough */
4843 if( varssize < requiredsize )
4844 {
4845 /* reallocate memory */
4846 varssize = requiredsize;
4847 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
4848
4849 /* parse string again with the correct size of the variable array */
4850 SCIP_CALL( SCIPparseVarsList(scip, strcopy, vars, &nvars, varssize, &requiredsize, &endptr, ',', success) );
4851 }
4852
4853 assert(*success);
4854 assert(varssize >= requiredsize);
4855
4856 /* create AND-constraint */
4857 SCIP_CALL( SCIPcreateConsAnd(scip, cons, name, resvar, nvars, vars,
4858 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
4859 }
4860
4861 /* free variable buffer */
4862 SCIPfreeBufferArray(scip, &vars);
4863 SCIPfreeBufferArray(scip, &strcopy);
4864 }
4865 else
4866 {
4867 if( !modifiable )
4868 {
4869 SCIPerrorMessage("cannot create empty AND-constraint\n");
4870 return SCIP_OKAY;
4871 }
4872
4873 /* create empty AND-constraint */
4874 SCIP_CALL( SCIPcreateConsAnd(scip, cons, name, resvar, 0, NULL,
4875 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
4876
4877 *success = TRUE;
4878 }
4879 }
4880
4881 return SCIP_OKAY;
4882}
4883
4884/** constraint method of constraint handler which returns the variables (if possible) */
4885static
4887{ /*lint --e{715}*/
4888 SCIP_CONSDATA* consdata;
4889
4890 consdata = SCIPconsGetData(cons);
4891 assert(consdata != NULL);
4892
4893 if( varssize < consdata->nvars + 1 )
4894 (*success) = FALSE;
4895 else
4896 {
4897 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
4898 vars[consdata->nvars] = consdata->resvar;
4899 (*success) = TRUE;
4900 }
4901
4902 return SCIP_OKAY;
4903}
4904
4905/** constraint method of constraint handler which returns the number of variable (if possible) */
4906static
4908{ /*lint --e{715}*/
4909 SCIP_CONSDATA* consdata;
4910
4911 assert(cons != NULL);
4912
4913 consdata = SCIPconsGetData(cons);
4914 assert(consdata != NULL);
4915
4916 (*nvars) = consdata->nvars + 1;
4917 (*success) = TRUE;
4918
4919 return SCIP_OKAY;
4920}
4921
4922/** constraint handler method which returns the permutation symmetry detection graph of a constraint */
4923static
4924SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphAnd)
4925{ /*lint --e{715}*/
4926 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
4927
4928 return SCIP_OKAY;
4929}
4930
4931/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */
4932static
4933SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphAnd)
4934{ /*lint --e{715}*/
4935 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
4936
4937 return SCIP_OKAY;
4938}
4939
4940/*
4941 * Callback methods of event handler
4942 */
4943
4944static
4946{ /*lint --e{715}*/
4947 SCIP_CONSDATA* consdata;
4948
4949 assert(eventhdlr != NULL);
4950 assert(eventdata != NULL);
4951 assert(event != NULL);
4952
4953 consdata = (SCIP_CONSDATA*)eventdata;
4954 assert(consdata != NULL);
4955
4956 /* check, if the variable was fixed to zero */
4958 consdata->nofixedzero = FALSE;
4959
4960 consdata->propagated = FALSE;
4961
4962 return SCIP_OKAY;
4963}
4964
4965
4966/*
4967 * constraint specific interface methods
4968 */
4969
4970/** creates the handler for AND-constraints and includes it in SCIP */
4972 SCIP* scip /**< SCIP data structure */
4973 )
4974{
4975 SCIP_CONSHDLRDATA* conshdlrdata;
4976 SCIP_CONSHDLR* conshdlr;
4977 SCIP_EVENTHDLR* eventhdlr;
4978
4979 /* create event handler for events on variables */
4981 eventExecAnd, NULL) );
4982
4983 /* create constraint handler data */
4984 SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
4985
4986 /* include constraint handler */
4989 consEnfolpAnd, consEnfopsAnd, consCheckAnd, consLockAnd,
4990 conshdlrdata) );
4991
4992 assert(conshdlr != NULL);
4993
4994 /* set non-fundamental callbacks via specific setter functions */
4995 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyAnd, consCopyAnd) );
4996 SCIP_CALL( SCIPsetConshdlrActive(scip, conshdlr, consActiveAnd) );
4997 SCIP_CALL( SCIPsetConshdlrDeactive(scip, conshdlr, consDeactiveAnd) );
4998 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteAnd) );
4999#ifdef GMLGATEPRINTING
5000 SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreAnd) );
5001#endif
5002 SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolAnd) );
5003 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolAnd) );
5004 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeAnd) );
5005 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsAnd) );
5006 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsAnd) );
5007 SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreAnd) );
5008 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpAnd) );
5009 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseAnd) );
5011 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintAnd) );
5014 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropAnd) );
5015 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpAnd, consSepasolAnd, CONSHDLR_SEPAFREQ,
5017 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransAnd) );
5018 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxAnd) );
5019 SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphAnd) );
5020 SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphAnd) );
5021
5022 /* add AND-constraint handler parameters */
5024 "constraints/" CONSHDLR_NAME "/presolpairwise",
5025 "should pairwise constraint comparison be performed in presolving?",
5026 &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
5028 "constraints/and/presolusehashing",
5029 "should hash table be used for detecting redundant constraints in advance",
5030 &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
5032 "constraints/" CONSHDLR_NAME "/linearize",
5033 "should the AND-constraint get linearized and removed (in presolving)?",
5034 &conshdlrdata->linearize, TRUE, DEFAULT_LINEARIZE, NULL, NULL) );
5036 "constraints/" CONSHDLR_NAME "/enforcecuts",
5037 "should cuts be separated during LP enforcing?",
5038 &conshdlrdata->enforcecuts, TRUE, DEFAULT_ENFORCECUTS, NULL, NULL) );
5040 "constraints/" CONSHDLR_NAME "/aggrlinearization",
5041 "should an aggregated linearization be used?",
5042 &conshdlrdata->aggrlinearization, TRUE, DEFAULT_AGGRLINEARIZATION, NULL, NULL) );
5044 "constraints/" CONSHDLR_NAME "/upgraderesultant",
5045 "should implied integrality of resultant variables be detected?",
5046 &conshdlrdata->upgrresultant, TRUE, DEFAULT_UPGRRESULTANT, NULL, NULL) );
5048 "constraints/" CONSHDLR_NAME "/dualpresolving",
5049 "should dual presolving be performed?",
5050 &conshdlrdata->dualpresolving, TRUE, DEFAULT_DUALPRESOLVING, NULL, NULL) );
5051
5052 return SCIP_OKAY;
5053}
5054
5055/** creates and captures a AND-constraint
5056 *
5057 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
5058 */
5060 SCIP* scip, /**< SCIP data structure */
5061 SCIP_CONS** cons, /**< pointer to hold the created constraint */
5062 const char* name, /**< name of constraint */
5063 SCIP_VAR* resvar, /**< resultant variable of the operation */
5064 int nvars, /**< number of operator variables in the constraint */
5065 SCIP_VAR** vars, /**< array with operator variables of constraint */
5066 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
5067 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
5068 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
5069 * Usually set to TRUE. */
5070 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
5071 * TRUE for model constraints, FALSE for additional, redundant constraints. */
5072 SCIP_Bool check, /**< should the constraint be checked for feasibility?
5073 * TRUE for model constraints, FALSE for additional, redundant constraints. */
5074 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
5075 * Usually set to TRUE. */
5076 SCIP_Bool local, /**< is constraint only valid locally?
5077 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
5078 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
5079 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
5080 * adds coefficients to this constraint. */
5081 SCIP_Bool dynamic, /**< is constraint subject to aging?
5082 * Usually set to FALSE. Set to TRUE for own cuts which
5083 * are separated as constraints. */
5084 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
5085 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
5086 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
5087 * if it may be moved to a more global node?
5088 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
5089 )
5090{
5091 SCIP_CONSHDLR* conshdlr;
5092 SCIP_CONSHDLRDATA* conshdlrdata;
5093 SCIP_CONSDATA* consdata;
5094 SCIP_Bool infeasible;
5095 int i;
5096
5097 /* find the AND-constraint handler */
5098 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
5099 if( conshdlr == NULL )
5100 {
5101 SCIPerrorMessage("AND-constraint handler not found\n");
5102 return SCIP_PLUGINNOTFOUND;
5103 }
5104
5105 /* check whether resultant variable is binary */
5106 if( !SCIPvarIsBinary(resvar) )
5107 {
5108 SCIPerrorMessage("resultant <%s> is not binary\n", SCIPvarGetName(resvar));
5109 return SCIP_INVALIDDATA;
5110 }
5111
5112 /* check whether all variables are binary */
5113 assert(vars != NULL || nvars == 0);
5114 for( i = 0; i < nvars; ++i )
5115 {
5116 if( !SCIPvarIsBinary(vars[i]) )
5117 {
5118 SCIPerrorMessage("operand <%s> is not binary\n", SCIPvarGetName(vars[i]));
5119 return SCIP_INVALIDDATA;
5120 }
5121 }
5122
5123 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5124 assert(conshdlrdata != NULL);
5125
5126 /* upgrade binary resultant variable to an implicit binary variable */
5127 /* @todo add implicit upgrade in presolving, improve decision making for upgrade by creating an implication graph */
5128 if( conshdlrdata->upgrresultant && !SCIPvarIsImpliedIntegral(resvar) )
5129 {
5130 SCIP_VAR* activeresvar;
5131 SCIP_VAR* activevar;
5132 int v;
5133
5134 if( SCIPisTransformed(scip) )
5135 activeresvar = SCIPvarGetProbvar(resvar);
5136 else
5137 activeresvar = resvar;
5138
5139 if( SCIPvarGetType(activeresvar) == SCIP_VARTYPE_BINARY && !SCIPvarIsImpliedIntegral(activeresvar) )
5140 {
5141 /* check if we can upgrade the variable type of the resultant */
5142 for( v = nvars - 1; v >= 0; --v )
5143 {
5144 if( SCIPisTransformed(scip) )
5145 activevar = SCIPvarGetProbvar(vars[v]);
5146 else
5147 activevar = vars[v];
5148
5149 if( activevar == activeresvar || SCIPvarIsImpliedIntegral(activevar) )
5150 break;
5151 }
5152
5153 /* upgrade the type of the resultant */
5154 if( v < 0 )
5155 {
5156 SCIP_CALL( SCIPchgVarImplType(scip, resvar, SCIP_IMPLINTTYPE_STRONG, &infeasible) );
5157 assert(!infeasible);
5158 }
5159 }
5160 }
5161
5162 /* create constraint data */
5163 SCIP_CALL( consdataCreate(scip, &consdata, conshdlrdata->eventhdlr, nvars, vars, resvar) );
5164
5165 /* create constraint */
5166 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
5167 local, modifiable, dynamic, removable, stickingatnode) );
5168
5169 return SCIP_OKAY;
5170}
5171
5172/** creates and captures an AND-constraint
5173 * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
5174 * method SCIPcreateConsAnd(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
5175 *
5176 * @see SCIPcreateConsAnd() for information about the basic constraint flag configuration
5177 *
5178 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
5179 */
5181 SCIP* scip, /**< SCIP data structure */
5182 SCIP_CONS** cons, /**< pointer to hold the created constraint */
5183 const char* name, /**< name of constraint */
5184 SCIP_VAR* resvar, /**< resultant variable of the operation */
5185 int nvars, /**< number of operator variables in the constraint */
5186 SCIP_VAR** vars /**< array with operator variables of constraint */
5187 )
5188{
5189 assert(scip != NULL);
5190
5191 SCIP_CALL( SCIPcreateConsAnd(scip, cons, name, resvar, nvars, vars,
5193
5194 return SCIP_OKAY;
5195}
5196
5197
5198/** gets number of variables in AND-constraint */
5200 SCIP* scip, /**< SCIP data structure */
5201 SCIP_CONS* cons /**< constraint data */
5202 )
5203{
5204 SCIP_CONSDATA* consdata;
5205
5206 assert(scip != NULL);
5207 assert(cons != NULL);
5208
5209 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
5210 {
5211 SCIPerrorMessage("constraint is not an AND-constraint\n");
5212 SCIPABORT();
5213 return -1; /*lint !e527*/
5214 }
5215
5216 consdata = SCIPconsGetData(cons);
5217 assert(consdata != NULL);
5218
5219 return consdata->nvars;
5220}
5221
5222/** gets array of variables in AND-constraint */
5224 SCIP* scip, /**< SCIP data structure */
5225 SCIP_CONS* cons /**< constraint data */
5226 )
5227{ /*lint --e{715}*/
5228 SCIP_CONSDATA* consdata;
5229
5230 assert(scip != NULL);
5231 assert(cons != NULL);
5232
5233 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
5234 {
5235 SCIPerrorMessage("constraint is not an AND-constraint\n");
5236 SCIPABORT();
5237 return NULL; /*lint !e527*/
5238 }
5239
5240 consdata = SCIPconsGetData(cons);
5241 assert(consdata != NULL);
5242
5243 return consdata->vars;
5244}
5245
5246
5247/** gets the resultant variable in AND-constraint */ /*lint -e715*/
5249 SCIP* scip, /**< SCIP data structure */
5250 SCIP_CONS* cons /**< constraint data */
5251 )
5252{
5253 SCIP_CONSDATA* consdata;
5254
5255 assert(cons != NULL);
5256
5257 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
5258 {
5259 SCIPerrorMessage("constraint is not an AND-constraint\n");
5260 SCIPABORT();
5261 return NULL; /*lint !e527*/
5262 }
5263
5264 consdata = SCIPconsGetData(cons);
5265 assert(consdata != NULL);
5266
5267 return consdata->resvar;
5268}
5269
5270/** return if the variables of the AND-constraint are sorted with respect to their indices */
5272 SCIP* scip, /**< SCIP data structure */
5273 SCIP_CONS* cons /**< constraint data */
5274 )
5275{
5276 SCIP_CONSDATA* consdata;
5277
5278 assert(scip != NULL);
5279 assert(cons != NULL);
5280
5281 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
5282 {
5283 SCIPerrorMessage("constraint is not an AND-constraint\n");
5284 SCIPABORT();
5285 return FALSE; /*lint !e527*/
5286 }
5287
5288 consdata = SCIPconsGetData(cons);
5289 assert(consdata != NULL);
5290
5291 return consdata->sorted;
5292}
5293
5294/** sort the variables of the AND-constraint with respect to their indices */
5296 SCIP* scip, /**< SCIP data structure */
5297 SCIP_CONS* cons /**< constraint data */
5298 )
5299{
5300 SCIP_CONSDATA* consdata;
5301
5302 assert(scip != NULL);
5303 assert(cons != NULL);
5304
5305 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
5306 {
5307 SCIPerrorMessage("constraint is not an AND-constraint\n");
5308 SCIPABORT();
5309 return SCIP_INVALIDDATA; /*lint !e527*/
5310 }
5311
5312 consdata = SCIPconsGetData(cons);
5313 assert(consdata != NULL);
5314
5315 consdataSort(consdata);
5316 assert(consdata->sorted);
5317
5318 return SCIP_OKAY;
5319}
SCIP_Real * r
Definition: circlepacking.c:59
static SCIP_RETCODE addRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *infeasible)
Definition: cons_and.c:958
enum Proprule PROPRULE
Definition: cons_and.c:173
static SCIP_DECL_CONSACTIVE(consActiveAnd)
Definition: cons_and.c:4669
static SCIP_RETCODE consdataFreeRows(SCIP *scip, SCIP_CONSDATA *consdata)
Definition: cons_and.c:501
static SCIP_RETCODE consdataPrint(SCIP *scip, SCIP_CONSDATA *consdata, FILE *file)
Definition: cons_and.c:582
static SCIP_RETCODE consdataCatchWatchedEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr, int pos, int *filterpos)
Definition: cons_and.c:243
static SCIP_RETCODE consdataDropEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
Definition: cons_and.c:316
#define DEFAULT_DUALPRESOLVING
Definition: cons_and.c:110
static SCIP_RETCODE dualPresolve(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_EVENTHDLR *eventhdlr, unsigned char **entries, int *nentries, SCIP_Bool *cutoff, int *nfixedvars, int *naggrvars, int *nchgcoefs, int *ndelconss, int *nupgdconss, int *naddconss)
Definition: cons_and.c:2012
static SCIP_RETCODE consdataSwitchWatchedvars(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr, int watchedvar1, int watchedvar2)
Definition: cons_and.c:342
#define CONSHDLR_NEEDSCONS
Definition: cons_and.c:97
#define CONSHDLR_SEPAFREQ
Definition: cons_and.c:90
static SCIP_DECL_CONSDELETE(consDeleteAnd)
Definition: cons_and.c:4198
static SCIP_DECL_HASHKEYEQ(hashKeyEqAndcons)
Definition: cons_and.c:3322
static SCIP_DECL_EVENTEXEC(eventExecAnd)
Definition: cons_and.c:4945
static SCIP_RETCODE delCoefPos(SCIP *scip, SCIP_CONS *cons, SCIP_EVENTHDLR *eventhdlr, int pos)
Definition: cons_and.c:667
#define CONSHDLR_CHECKPRIORITY
Definition: cons_and.c:89
static SCIP_DECL_CONSFREE(consFreeAnd)
Definition: cons_and.c:3855
#define CONSHDLR_DESC
Definition: cons_and.c:86
static SCIP_RETCODE consdataFixOperandsOne(SCIP *scip, SCIP_CONS *cons, SCIP_VAR **vars, int nvars, SCIP_Bool *cutoff, int *nfixedvars)
Definition: cons_and.c:1339
static SCIP_RETCODE separateCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool *separated, SCIP_Bool *cutoff)
Definition: cons_and.c:1183
static SCIP_RETCODE addCoef(SCIP *scip, SCIP_CONS *cons, SCIP_EVENTHDLR *eventhdlr, SCIP_VAR *var)
Definition: cons_and.c:607
static SCIP_DECL_CONSCOPY(consCopyAnd)
Definition: cons_and.c:4716
static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons)
Definition: cons_and.c:911
#define CONSHDLR_PROP_TIMING
Definition: cons_and.c:100
#define HASHSIZE_ANDCONS
Definition: cons_and.c:112
static void conshdlrdataFree(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata)
Definition: cons_and.c:230
static SCIP_RETCODE unlockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition: cons_and.c:196
static SCIP_DECL_CONSENFOPS(consEnfopsAnd)
Definition: cons_and.c:4332
static SCIP_RETCODE analyzeZeroResultant(SCIP *scip, SCIP_CONS *cons, int watchedvar1, int watchedvar2, SCIP_Bool *cutoff, int *nfixedvars)
Definition: cons_and.c:1502
static SCIP_DECL_CONSINITPRE(consInitpreAnd)
Definition: cons_and.c:3873
static SCIP_DECL_HASHGETKEY(hashGetKeyAndcons)
Definition: cons_and.c:3314
#define DEFAULT_UPGRRESULTANT
Definition: cons_and.c:109
#define CONSHDLR_MAXPREROUNDS
Definition: cons_and.c:94
static SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphAnd)
Definition: cons_and.c:4933
static SCIP_RETCODE consdataFixResultantZero(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *resvar, int pos, SCIP_Bool *cutoff, int *nfixedvars)
Definition: cons_and.c:1300
static SCIP_DECL_CONSENFORELAX(consEnforelaxAnd)
Definition: cons_and.c:4323
#define DEFAULT_PRESOLPAIRWISE
Definition: cons_and.c:105
#define CONSHDLR_SEPAPRIORITY
Definition: cons_and.c:87
static SCIP_RETCODE analyzeConflictOne(SCIP *scip, SCIP_CONS *cons, int falsepos)
Definition: cons_and.c:1232
static SCIP_RETCODE detectRedundantConstraints(SCIP *scip, BMS_BLKMEM *blkmem, SCIP_CONS **conss, int nconss, int *firstchange, SCIP_Bool *cutoff, int *naggrvars, int *ndelconss)
Definition: cons_and.c:3392
static SCIP_DECL_CONSRESPROP(consRespropAnd)
Definition: cons_and.c:4637
static SCIP_DECL_CONSSEPASOL(consSepasolAnd)
Definition: cons_and.c:4287
#define DEFAULT_LINEARIZE
Definition: cons_and.c:106
static SCIP_RETCODE cliquePresolve(SCIP *scip, SCIP_CONS *cons, SCIP_EVENTHDLR *eventhdlr, SCIP_Bool *cutoff, int *nfixedvars, int *naggrvars, int *nchgcoefs, int *ndelconss, int *naddconss)
Definition: cons_and.c:2668
static SCIP_RETCODE preprocessConstraintPairs(SCIP *scip, SCIP_CONS **conss, int firstchange, int chkind, SCIP_Bool *cutoff, int *naggrvars, int *nbdchgs, int *ndelconss)
Definition: cons_and.c:3566
static SCIP_DECL_CONSTRANS(consTransAnd)
Definition: cons_and.c:4213
static SCIP_RETCODE consdataLinearize(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *cutoff, int *nfixedvars, int *nupgdconss)
Definition: cons_and.c:1393
static SCIP_DECL_CONSLOCK(consLockAnd)
Definition: cons_and.c:4647
static SCIP_DECL_CONSINITLP(consInitlpAnd)
Definition: cons_and.c:4242
static SCIP_RETCODE addSymmetryInformation(SCIP *scip, SYM_SYMTYPE symtype, SCIP_CONS *cons, SYM_GRAPH *graph, SCIP_Bool *success)
Definition: cons_and.c:3766
static SCIP_DECL_CONSSEPALP(consSepalpAnd)
Definition: cons_and.c:4260
static SCIP_RETCODE lockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition: cons_and.c:182
static SCIP_DECL_CONSEXITSOL(consExitsolAnd)
Definition: cons_and.c:4173
static SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphAnd)
Definition: cons_and.c:4924
static SCIP_RETCODE consdataEnsureVarsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
Definition: cons_and.c:402
Proprule
Definition: cons_and.c:166
@ PROPRULE_2
Definition: cons_and.c:169
@ PROPRULE_1
Definition: cons_and.c:168
@ PROPRULE_3
Definition: cons_and.c:170
@ PROPRULE_INVALID
Definition: cons_and.c:167
@ PROPRULE_4
Definition: cons_and.c:171
static SCIP_RETCODE checkCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool checklprows, SCIP_Bool printreason, SCIP_Bool *violated)
Definition: cons_and.c:1071
#define DEFAULT_PRESOLUSEHASHING
Definition: cons_and.c:113
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_EVENTHDLR *eventhdlr)
Definition: cons_and.c:532
static SCIP_DECL_CONSPARSE(consParseAnd)
Definition: cons_and.c:4777
static SCIP_RETCODE consdataDropWatchedEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr, int pos, int filterpos)
Definition: cons_and.c:267
#define MINGAINPERNMINCOMPARISONS
Definition: cons_and.c:115
static SCIP_RETCODE analyzeConflictZero(SCIP *scip, SCIP_CONS *cons)
Definition: cons_and.c:1264
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyAnd)
Definition: cons_and.c:3839
static SCIP_DECL_CONSINITSOL(consInitsolAnd)
Definition: cons_and.c:4156
#define CONSHDLR_PROPFREQ
Definition: cons_and.c:91
static SCIP_DECL_CONSDEACTIVE(consDeactiveAnd)
Definition: cons_and.c:4681
#define NMINCOMPARISONS
Definition: cons_and.c:114
#define DEFAULT_ENFORCECUTS
Definition: cons_and.c:107
#define CONSHDLR_PRESOLTIMING
Definition: cons_and.c:99
static SCIP_DECL_CONSGETNVARS(consGetNVarsAnd)
Definition: cons_and.c:4907
static void consdataSort(SCIP_CONSDATA *consdata)
Definition: cons_and.c:730
static SCIP_DECL_CONSPROP(consPropAnd)
Definition: cons_and.c:4373
static SCIP_RETCODE addNlrow(SCIP *scip, SCIP_CONS *cons)
Definition: cons_and.c:1018
static SCIP_DECL_CONSPRINT(consPrintAnd)
Definition: cons_and.c:4703
#define CONSHDLR_EAGERFREQ
Definition: cons_and.c:92
#define EVENTHDLR_DESC
Definition: cons_and.c:103
static SCIP_RETCODE conshdlrdataCreate(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata, SCIP_EVENTHDLR *eventhdlr)
Definition: cons_and.c:210
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_EVENTHDLR *eventhdlr, int nvars, SCIP_VAR **vars, SCIP_VAR *resvar)
Definition: cons_and.c:426
static SCIP_DECL_HASHKEYVAL(hashKeyValAndcons)
Definition: cons_and.c:3368
static SCIP_DECL_CONSENFOLP(consEnfolpAnd)
Definition: cons_and.c:4314
static SCIP_DECL_CONSPRESOL(consPresolAnd)
Definition: cons_and.c:4408
#define CONSHDLR_ENFOPRIORITY
Definition: cons_and.c:88
static SCIP_DECL_CONSCHECK(consCheckAnd)
Definition: cons_and.c:4354
static SCIP_RETCODE applyFixings(SCIP *scip, SCIP_CONS *cons, SCIP_EVENTHDLR *eventhdlr, int *nchgcoefs)
Definition: cons_and.c:811
static SCIP_RETCODE resolvePropagation(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *infervar, PROPRULE proprule, SCIP_BDCHGIDX *bdchgidx, SCIP_RESULT *result)
Definition: cons_and.c:1926
#define CONSHDLR_DELAYSEPA
Definition: cons_and.c:95
static SCIP_RETCODE mergeMultiples(SCIP *scip, SCIP_CONS *cons, SCIP_EVENTHDLR *eventhdlr, unsigned char **entries, int *nentries, int *nfixedvars, int *nchgcoefs, int *ndelconss)
Definition: cons_and.c:1563
static SCIP_RETCODE enforceConstraint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_RESULT *result)
Definition: cons_and.c:3509
#define CONSHDLR_NAME
Definition: cons_and.c:85
#define EVENTHDLR_NAME
Definition: cons_and.c:102
#define DEFAULT_AGGRLINEARIZATION
Definition: cons_and.c:108
static SCIP_RETCODE propagateCons(SCIP *scip, SCIP_CONS *cons, SCIP_EVENTHDLR *eventhdlr, SCIP_Bool *cutoff, int *nfixedvars, int *nupgdconss)
Definition: cons_and.c:1721
#define CONSHDLR_DELAYPROP
Definition: cons_and.c:96
static SCIP_RETCODE consdataCatchEvents(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr)
Definition: cons_and.c:290
static SCIP_DECL_CONSGETVARS(consGetVarsAnd)
Definition: cons_and.c:4886
Constraint handler for AND constraints, .
Constraint handler for linear constraints in their most general form, .
Constraint handler for logicor constraints (equivalent to set covering, but algorithms are suited fo...
constraint handler for pseudoboolean constraints
Constraint handler for the set partitioning / packing / covering constraints .
methods for debugging
#define NULL
Definition: def.h:248
#define SCIP_MAXSTRLEN
Definition: def.h:269
#define SCIP_Longint
Definition: def.h:141
#define SCIP_Bool
Definition: def.h:91
#define MAX3(x, y, z)
Definition: def.h:228
#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 SCIPABORT()
Definition: def.h:327
#define REALABS(x)
Definition: def.h:182
#define SCIP_CALL(x)
Definition: def.h:355
#define SCIP_CALL_FINALLY(x, y)
Definition: def.h:397
product expression handler
variable expression handler
SCIP_RETCODE SCIPcreateConsAnd(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *resvar, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: cons_and.c:5059
SCIP_VAR * SCIPgetResultantAnd(SCIP *scip, SCIP_CONS *cons)
Definition: cons_and.c:5248
int SCIPgetNVarsAnd(SCIP *scip, SCIP_CONS *cons)
Definition: cons_and.c:5199
SCIP_RETCODE SCIPcreateConsSetpack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: cons_setppc.c:9460
SCIP_RETCODE SCIPsortAndCons(SCIP *scip, SCIP_CONS *cons)
Definition: cons_and.c:5295
SCIP_Bool SCIPisAndConsSorted(SCIP *scip, SCIP_CONS *cons)
Definition: cons_and.c:5271
SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPcreateConsSetpart(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: cons_setppc.c:9402
SCIP_VAR ** SCIPgetVarsAnd(SCIP *scip, SCIP_CONS *cons)
Definition: cons_and.c:5223
SCIP_RETCODE SCIPcreateConsLogicor(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPcreateConsBasicAnd(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *resvar, int nvars, SCIP_VAR **vars)
Definition: cons_and.c:5180
SCIP_RETCODE SCIPincludeConshdlrAnd(SCIP *scip)
Definition: cons_and.c:4971
SCIP_RETCODE SCIPgetVarCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR *sourcevar, SCIP_VAR **targetvar, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *success)
Definition: scip_copy.c:713
SCIP_RETCODE SCIPcreateExprVar(SCIP *scip, SCIP_EXPR **expr, SCIP_VAR *var, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: expr_var.c:398
SCIP_RETCODE SCIPcreateExprProduct(SCIP *scip, SCIP_EXPR **expr, int nchildren, SCIP_EXPR **children, SCIP_Real coefficient, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
void SCIPgmlWriteNode(FILE *file, unsigned int id, const char *label, const char *nodetype, const char *fillcolor, const char *bordercolor)
Definition: misc.c:501
void SCIPgmlWriteClosing(FILE *file)
Definition: misc.c:703
void SCIPgmlWriteOpening(FILE *file, SCIP_Bool directed)
Definition: misc.c:687
void SCIPgmlWriteArc(FILE *file, unsigned int source, unsigned int target, const char *label, const char *color)
Definition: misc.c:643
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip_general.c:647
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:759
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:444
int SCIPgetNIntVars(SCIP *scip)
Definition: scip_prob.c:2340
SCIP_RETCODE SCIPaddConsUpgrade(SCIP *scip, SCIP_CONS *oldcons, SCIP_CONS **newcons)
Definition: scip_prob.c:3368
int SCIPgetNImplVars(SCIP *scip)
Definition: scip_prob.c:2387
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2569
SCIP_RETCODE SCIPgetVarsData(SCIP *scip, SCIP_VAR ***vars, int *nvars, int *nbinvars, int *nintvars, int *nimplvars, int *ncontvars)
Definition: scip_prob.c:2115
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:2246
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3274
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3420
int SCIPgetNBinVars(SCIP *scip)
Definition: scip_prob.c:2293
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_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3179
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 SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2535
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:4067
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:208
#define SCIPdebugMsgPrint
Definition: scip_message.h:79
#define SCIPdebugMsg
Definition: scip_message.h:78
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:57
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
SCIP_RETCODE SCIPaddConflictBinvar(SCIP *scip, SCIP_VAR *var)
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip_cons.c:808
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4346
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:540
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:831
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITPRE((*consinitpre)))
Definition: scip_cons.c:492
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition: scip_cons.c:235
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip_cons.c:281
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip_cons.c:181
SCIP_RETCODE SCIPsetConshdlrDeactive(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDEACTIVE((*consdeactive)))
Definition: scip_cons.c:693
SCIP_RETCODE SCIPsetConshdlrGetPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETPERMSYMGRAPH((*consgetpermsymgraph)))
Definition: scip_cons.c:900
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:578
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:372
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip_cons.c:323
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4316
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip_cons.c:516
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:347
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:940
SCIP_RETCODE SCIPsetConshdlrGetSignedPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH((*consgetsignedpermsymgraph)))
Definition: scip_cons.c:924
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip_cons.c:468
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip_cons.c:624
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
Definition: scip_cons.c:444
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4336
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:601
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip_cons.c:647
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:854
SCIP_RETCODE SCIPsetConshdlrActive(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSACTIVE((*consactive)))
Definition: scip_cons.c:670
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip_cons.c:785
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8419
int SCIPconsGetPos(SCIP_CONS *cons)
Definition: cons.c:8399
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8648
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8409
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8558
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2536
int SCIPconsGetNUpgradeLocks(SCIP_CONS *cons)
Definition: cons.c:8841
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8588
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8518
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8698
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8578
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8450
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip_cons.c:997
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8608
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8628
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8389
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1812
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8638
SCIP_Bool SCIPconsIsAdded(SCIP_CONS *cons)
Definition: cons.c:8818
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition: scip_cons.c:1524
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8668
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1173
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8568
SCIP_RETCODE SCIPincConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1784
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8658
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:225
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip_event.c:111
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:1194
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:367
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:413
SCIP_RETCODE SCIPreleaseExpr(SCIP *scip, SCIP_EXPR **expr)
Definition: scip_expr.c:1443
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:57
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:139
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:128
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip_mem.h:132
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:99
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:105
SCIP_RETCODE SCIPdelNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition: scip_nlp.c:424
SCIP_RETCODE SCIPaddNlRow(SCIP *scip, SCIP_NLROW *nlrow)
Definition: scip_nlp.c:396
SCIP_Bool SCIPisNLPConstructed(SCIP *scip)
Definition: scip_nlp.c:110
SCIP_RETCODE SCIPreleaseNlRow(SCIP *scip, SCIP_NLROW **nlrow)
Definition: scip_nlp.c:1058
SCIP_Bool SCIPnlrowIsInNLP(SCIP_NLROW *nlrow)
Definition: nlp.c:1953
SCIP_RETCODE SCIPcreateNlRow(SCIP *scip, SCIP_NLROW **nlrow, const char *name, SCIP_Real constant, int nlinvars, SCIP_VAR **linvars, SCIP_Real *lincoefs, SCIP_EXPR *expr, SCIP_Real lhs, SCIP_Real rhs, SCIP_EXPRCURV curvature)
Definition: scip_nlp.c:954
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:98
SCIP_RETCODE SCIPaddVarsToRowSameCoef(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real val)
Definition: scip_lp.c:1718
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONS *cons, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1398
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1646
SCIP_Real SCIPgetRowSolFeasibility(SCIP *scip, SCIP_ROW *row, SCIP_SOL *sol)
Definition: scip_lp.c:2131
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1508
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:17917
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip_sol.c:453
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1765
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip_tree.c:146
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:672
SCIP_RETCODE SCIPcutoffNode(SCIP *scip, SCIP_NODE *node)
Definition: scip_tree.c:436
SCIP_NODE * SCIPgetRootNode(SCIP *scip)
Definition: scip_tree.c:110
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:5210
void SCIPvarsGetProbvar(SCIP_VAR **vars, int nvars)
Definition: var.c:17530
SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
Definition: var.c:23868
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:23642
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:23478
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition: scip_var.c:2119
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:23386
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:4386
SCIP_Bool SCIPdoNotAggr(SCIP *scip)
Definition: scip_var.c:10909
SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
Definition: var.c:23498
SCIP_RETCODE SCIPvarGetAggregatedObj(SCIP_VAR *var, SCIP_Real *aggrobj)
Definition: var.c:23944
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:24268
SCIP_RETCODE SCIPgetBinvarRepresentatives(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **repvars, SCIP_Bool *negated)
Definition: scip_var.c:2283
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:23430
SCIP_RETCODE SCIPparseVarsList(SCIP *scip, const char *str, SCIP_VAR **vars, int *nvars, int varssize, int *requiredsize, char **endptr, char delimiter, SCIP_Bool *success)
Definition: scip_var.c:805
SCIP_RETCODE SCIPaggregateVars(SCIP *scip, SCIP_VAR *varx, SCIP_VAR *vary, SCIP_Real scalarx, SCIP_Real scalary, SCIP_Real rhs, SCIP_Bool *infeasible, SCIP_Bool *redundant, SCIP_Bool *aggregated)
Definition: scip_var.c:10550
SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
Definition: var.c:17550
SCIP_RETCODE SCIPchgVarImplType(SCIP *scip, SCIP_VAR *var, SCIP_IMPLINTTYPE impltype, SCIP_Bool *infeasible)
Definition: scip_var.c:10218
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip_var.c:728
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
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:5118
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:5296
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:2872
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:23662
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:23267
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1887
SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
Definition: scip_var.c:2166
SCIP_RETCODE SCIPaddVarImplication(SCIP *scip, SCIP_VAR *var, SCIP_Bool varfixing, SCIP_VAR *implvar, SCIP_BOUNDTYPE impltype, SCIP_Real implbound, SCIP_Bool *infeasible, int *nbdchgs)
Definition: scip_var.c:8740
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:24234
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition: var.c:23443
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:24120
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:11057
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip_var.c:10318
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:2736
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:17274
SCIP_RETCODE SCIPvarGetProbvarBinary(SCIP_VAR **var, SCIP_Bool *negated)
Definition: var.c:17642
SCIP_RETCODE SCIPinferBinvarCons(SCIP *scip, SCIP_VAR *var, SCIP_Bool fixedval, SCIP_CONS *infercons, int inferinfo, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:7412
SCIP_RETCODE SCIPwriteVarName(SCIP *scip, FILE *file, SCIP_VAR *var, SCIP_Bool type)
Definition: scip_var.c:361
SCIP_RETCODE SCIPgetBinvarRepresentative(SCIP *scip, SCIP_VAR *var, SCIP_VAR **repvar, SCIP_Bool *negated)
Definition: scip_var.c:2236
SCIP_RETCODE SCIPwriteVarsList(SCIP *scip, FILE *file, SCIP_VAR **vars, int nvars, SCIP_Bool type, char delimiter)
Definition: scip_var.c:423
SCIP_Bool SCIPvarsHaveCommonClique(SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition: var.c:16807
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:4328
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip_var.c:2078
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1853
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition: scip_var.c:10984
SCIP_Bool SCIPsortedvecFindPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), void *val, int len, int *pos)
void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10827
SCIP_RETCODE SCIPaddSymgraphEdge(SCIP *scip, SYM_GRAPH *graph, int first, int second, SCIP_Bool hasval, SCIP_Real val)
SCIP_RETCODE SCIPaddSymgraphOpnode(SCIP *scip, SYM_GRAPH *graph, int op, int *nodeidx)
SCIP_RETCODE SCIPgetSymActiveVariables(SCIP *scip, SYM_SYMTYPE symtype, SCIP_VAR ***vars, SCIP_Real **scalars, int *nvars, SCIP_Real *constant, SCIP_Bool transformed)
SCIP_RETCODE SCIPaddSymgraphConsnode(SCIP *scip, SYM_GRAPH *graph, SCIP_CONS *cons, SCIP_Real lhs, SCIP_Real rhs, int *nodeidx)
SCIP_RETCODE SCIPaddSymgraphVarAggregation(SCIP *scip, SYM_GRAPH *graph, int rootidx, SCIP_VAR **vars, SCIP_Real *vals, int nvars, SCIP_Real constant)
memory allocation routines
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:134
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:130
struct BMS_BlkMem BMS_BLKMEM
Definition: memory.h:437
public methods for managing constraints
public methods for managing events
public methods for LP management
public methods for message output
#define SCIPerrorMessage
Definition: pub_message.h:64
#define SCIPdebug(x)
Definition: pub_message.h:93
#define SCIPdebugPrintCons(x, y, z)
Definition: pub_message.h:102
public data structures and miscellaneous methods
methods for sorting joint arrays of various types
public methods for problem variables
public methods for conflict handler plugins and conflict analysis
public methods for constraint handler plugins and constraints
public methods for problem copies
public methods for cuts and aggregation rows
public methods for event handler plugins and event handlers
public functions to work with algebraic expressions
general public methods
public methods for the LP relaxation, rows and columns
public methods for memory management
public methods for message handling
public methods for nonlinear relaxation
public methods for numerical tolerances
public methods for SCIP parameter handling
public methods for global and local (sub)problems
public methods for the probing mode
public methods for solutions
public methods for the branch-and-bound tree
public methods for SCIP variables
static SCIP_RETCODE separate(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_RESULT *result)
Main separation function.
Definition: sepa_flower.c:1221
structs for symmetry computations
methods for dealing with symmetry detection graphs
@ SCIP_CONFTYPE_PROPAGATION
Definition: type_conflict.h:62
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:64
#define SCIP_DECL_CONSEXITPRE(x)
Definition: type_cons.h:180
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:65
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition: type_event.h:127
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:179
#define SCIP_EVENTTYPE_UBTIGHTENED
Definition: type_event.h:79
#define SCIP_EVENTTYPE_LBRELAXED
Definition: type_event.h:78
#define SCIP_EVENTTYPE_LBTIGHTENED
Definition: type_event.h:77
#define SCIP_EVENTTYPE_UBRELAXED
Definition: type_event.h:80
@ SCIP_EXPRCURV_UNKNOWN
Definition: type_expr.h:62
@ SCIP_BOUNDTYPE_UPPER
Definition: type_lp.h:58
@ SCIP_BOUNDTYPE_LOWER
Definition: type_lp.h:57
@ SCIP_CUTOFF
Definition: type_result.h:48
@ SCIP_FEASIBLE
Definition: type_result.h:45
@ SCIP_REDUCEDDOM
Definition: type_result.h:51
@ SCIP_DIDNOTFIND
Definition: type_result.h:44
@ SCIP_SEPARATED
Definition: type_result.h:49
@ SCIP_SUCCESS
Definition: type_result.h:58
@ SCIP_INFEASIBLE
Definition: type_result.h:46
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:61
@ SCIP_INVALIDDATA
Definition: type_retcode.h:52
@ SCIP_PLUGINNOTFOUND
Definition: type_retcode.h:54
@ SCIP_WRITEERROR
Definition: type_retcode.h:46
@ SCIP_OKAY
Definition: type_retcode.h:42
@ SCIP_INVALIDCALL
Definition: type_retcode.h:51
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_STAGE_EXITPRESOLVE
Definition: type_set.h:50
@ SCIP_STAGE_SOLVING
Definition: type_set.h:53
enum SYM_Symtype SYM_SYMTYPE
Definition: type_symmetry.h:64
@ SYM_CONSOPTYPE_AND
Definition: type_symmetry.h:92
@ SYM_SYMTYPE_SIGNPERM
Definition: type_symmetry.h:62
@ SYM_SYMTYPE_PERM
Definition: type_symmetry.h:61
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:54
@ SCIP_IMPLINTTYPE_STRONG
Definition: type_var.h:106
@ SCIP_VARTYPE_INTEGER
Definition: type_var.h:65
@ SCIP_VARTYPE_BINARY
Definition: type_var.h:64
@ SCIP_VARSTATUS_FIXED
Definition: type_var.h:54
@ SCIP_LOCKTYPE_MODEL
Definition: type_var.h:141