SCIP Doxygen Documentation
Loading...
Searching...
No Matches
cons_xor.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-2026 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_xor.c
26 * @ingroup DEFPLUGINS_CONS
27 * @brief Constraint handler for "xor" constraints, \f$rhs = x_1 \oplus x_2 \oplus \dots \oplus x_n\f$
28 * @author Tobias Achterberg
29 * @author Stefan Heinz
30 * @author Marc Pfetsch
31 * @author Michael Winkler
32 *
33 * This constraint handler deals with "xor" constraint. These are constraint of the form:
34 *
35 * \f[
36 * rhs = x_1 \oplus x_2 \oplus \dots \oplus x_n
37 * \f]
38 *
39 * where \f$x_i\f$ is a binary variable for all \f$i\f$ and \f$rhs\f$ is bool. The variables \f$x\f$'s are called
40 * operators. This constraint is satisfied if \f$rhs\f$ is TRUE and an odd number of the operators are TRUE or if the
41 * \f$rhs\f$ is FALSE and a even number of operators are TRUE. Hence, if the sum of \f$rhs\f$ and operators is even.
42 *
43 * @todo reduce code duplication
44 * - unified treatment of constraint with 0/1/2 binary variables
45 * - static functions for certain operations that respect deleteintvar flag properly (e.g., deletion of constraints)
46 * @todo add offset for activity which might allow to handle intvar in a more unified way
47 * (right now, we do not remove fixed variables from the constraint, because we must ensure that the intvar gets
48 * the correct value in the end)
49 * @todo check if preprocessConstraintPairs can also be executed for non-artificial intvars (after the previous changes)
50 */
51
52/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
53
55#include "scip/cons_linear.h"
56#include "scip/cons_setppc.h"
57#include "scip/cons_xor.h"
58#include "scip/debug.h"
59#include "scip/heur_trysol.h"
60#include "scip/pub_cons.h"
61#include "scip/pub_event.h"
62#include "scip/pub_lp.h"
63#include "scip/pub_message.h"
64#include "scip/pub_misc.h"
65#include "scip/pub_misc_sort.h"
66#include "scip/pub_var.h"
67#include "scip/scip_conflict.h"
68#include "scip/scip_cons.h"
69#include "scip/scip_copy.h"
70#include "scip/scip_cut.h"
71#include "scip/scip_event.h"
72#include "scip/scip_general.h"
73#include "scip/scip_heur.h"
74#include "scip/scip_lp.h"
75#include "scip/scip_mem.h"
76#include "scip/scip_message.h"
77#include "scip/scip_numerics.h"
78#include "scip/scip_param.h"
79#include "scip/scip_prob.h"
80#include "scip/scip_probing.h"
81#include "scip/scip_sol.h"
82#include "scip/scip_tree.h"
83#include "scip/scip_var.h"
84#include "scip/symmetry_graph.h"
86#include <string.h>
87
88/* constraint handler properties */
89#define CONSHDLR_NAME "xor"
90#define CONSHDLR_DESC "constraint handler for xor constraints: r = xor(x1, ..., xn)"
91#define CONSHDLR_SEPAPRIORITY +850200 /**< priority of the constraint handler for separation */
92#define CONSHDLR_ENFOPRIORITY -850200 /**< priority of the constraint handler for constraint enforcing */
93#define CONSHDLR_CHECKPRIORITY -850200 /**< priority of the constraint handler for checking feasibility */
94#define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
95#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
96#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
97 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
98#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
99#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
100#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
101#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
102
103#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
104#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_ALWAYS
105
106#define EVENTHDLR_NAME "xor"
107#define EVENTHDLR_DESC "event handler for xor constraints"
108
109#define LINCONSUPGD_PRIORITY +600000 /**< priority of the constraint handler for upgrading of linear constraints */
110
111#define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
112#define DEFAULT_ADDEXTENDEDFORM FALSE /**< should the extended formulation be added in presolving? */
113#define DEFAULT_ADDFLOWEXTENDED FALSE /**< should the extended flow formulation be added (nonsymmetric formulation otherwise)? */
114#define DEFAULT_SEPARATEPARITY FALSE /**< should parity inequalities be separated? */
115#define DEFAULT_GAUSSPROPFREQ 5 /**< frequency for applying the Gauss propagator */
116#define HASHSIZE_XORCONS 500 /**< minimal size of hash table in logicor constraint tables */
117#define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
118#define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */
119#define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise comparison round */
120#define MAXXORCONSSSYSTEM 1000 /**< maximal number of active constraints for which checking the system over GF2 is performed */
121#define MAXXORVARSSYSTEM 1000 /**< maximal number of variables in xor constraints for which checking the system over GF2 is performed */
122
123#define NROWS 5
124
125
126/*
127 * Data structures
128 */
129
130/** type used for matrix entries in function checkGauss() */
131typedef unsigned short Type;
132
133/** constraint data for xor constraints */
134struct SCIP_ConsData
135{
136 SCIP_VAR** vars; /**< variables in the xor operation */
137 SCIP_VAR* intvar; /**< internal variable for LP relaxation */
138 SCIP_VAR** extvars; /**< variables in extended (flow|asymmetric) formulation (order for flow formulation: nn, ns, sn, ss) */
139 SCIP_ROW* rows[NROWS]; /**< rows for linear relaxation of xor constraint */
140 int nvars; /**< number of variables in xor operation */
141 int nextvars; /**< number of variables in extended flow formulation */
142 int varssize; /**< size of vars array */
143 int extvarssize; /**< size of extvars array */
144 int watchedvar1; /**< position of first watched operator variable */
145 int watchedvar2; /**< position of second watched operator variable */
146 int filterpos1; /**< event filter position of first watched operator variable */
147 int filterpos2; /**< event filter position of second watched operator variable */
148 SCIP_Bool rhs; /**< right hand side of the constraint */
149 unsigned int deleteintvar:1; /**< should artificial variable be deleted */
150 unsigned int propagated:1; /**< is constraint already preprocessed/propagated? */
151 unsigned int sorted:1; /**< are the constraint's variables sorted? */
152 unsigned int changed:1; /**< was constraint changed since last pair preprocessing round? */
153};
154
155/** constraint handler data */
156struct SCIP_ConshdlrData
157{
158 SCIP_EVENTHDLR* eventhdlr; /**< event handler for events on watched variables */
159 SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
160 SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance? */
161 SCIP_Bool addextendedform; /**< should the extended formulation be added in presolving? */
162 SCIP_Bool addflowextended; /**< should the extended flow formulation be added (nonsymmetric formulation otherwise)? */
163 SCIP_Bool separateparity; /**< should parity inequalities be separated? */
164 int gausspropfreq; /**< frequency for applying the Gauss propagator */
165};
166
167
168/*
169 * Propagation rules
170 */
171
173{
174 PROPRULE_0, /**< all variables are fixed => fix integral variable */
175 PROPRULE_1, /**< all except one variable fixed => fix remaining variable */
176 PROPRULE_INTLB, /**< lower bound propagation of integral variable */
177 PROPRULE_INTUB, /**< upper bound propagation of integral variable */
178 PROPRULE_INVALID /**< propagation was applied without a specific propagation rule */
179};
180typedef enum Proprule PROPRULE;
181
182
183/*
184 * Local methods
185 */
186
187/** installs rounding locks for the given variable in the given xor constraint */
188static
190 SCIP* scip, /**< SCIP data structure */
191 SCIP_CONS* cons, /**< xor constraint */
192 SCIP_VAR* var /**< variable of constraint entry */
193 )
194{
196
197 /* rounding in both directions may violate the constraint */
199
200 return SCIP_OKAY;
201}
202
203/** removes rounding locks for the given variable in the given xor constraint */
204static
206 SCIP* scip, /**< SCIP data structure */
207 SCIP_CONS* cons, /**< xor constraint */
208 SCIP_VAR* var /**< variable of constraint entry */
209 )
210{
212
213 /* rounding in both directions may violate the constraint */
215
216 return SCIP_OKAY;
217}
218
219/** creates constraint handler data */
220static
222 SCIP* scip, /**< SCIP data structure */
223 SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
224 SCIP_EVENTHDLR* eventhdlr /**< event handler */
225 )
226{
227 assert(scip != NULL);
228 assert(conshdlrdata != NULL);
229 assert(eventhdlr != NULL);
230
231 SCIP_CALL( SCIPallocBlockMemory(scip, conshdlrdata) );
232
233 /* set event handler for catching events on watched variables */
234 (*conshdlrdata)->eventhdlr = eventhdlr;
235
236 return SCIP_OKAY;
237}
238
239/** frees constraint handler data */
240static
242 SCIP* scip, /**< SCIP data structure */
243 SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
244 )
245{
246 assert(conshdlrdata != NULL);
247 assert(*conshdlrdata != NULL);
248
249 SCIPfreeBlockMemory(scip, conshdlrdata);
250}
251
252/** stores the given variable numbers as watched variables, and updates the event processing */
253static
255 SCIP* scip, /**< SCIP data structure */
256 SCIP_CONSDATA* consdata, /**< xor constraint data */
257 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
258 int watchedvar1, /**< new first watched variable */
259 int watchedvar2 /**< new second watched variable */
260 )
261{
262 assert(consdata != NULL);
263 assert(watchedvar1 == -1 || watchedvar1 != watchedvar2);
264 assert(watchedvar1 != -1 || watchedvar2 == -1);
265 assert(watchedvar1 == -1 || (0 <= watchedvar1 && watchedvar1 < consdata->nvars));
266 assert(watchedvar2 == -1 || (0 <= watchedvar2 && watchedvar2 < consdata->nvars));
267
268 /* if one watched variable is equal to the old other watched variable, just switch positions */
269 if( watchedvar1 == consdata->watchedvar2 || watchedvar2 == consdata->watchedvar1 )
270 {
271 int tmp;
272
273 tmp = consdata->watchedvar1;
274 consdata->watchedvar1 = consdata->watchedvar2;
275 consdata->watchedvar2 = tmp;
276 tmp = consdata->filterpos1;
277 consdata->filterpos1 = consdata->filterpos2;
278 consdata->filterpos2 = tmp;
279 }
280 assert(watchedvar1 == -1 || watchedvar1 != consdata->watchedvar2);
281 assert(watchedvar2 == -1 || watchedvar2 != consdata->watchedvar1);
282
283 /* drop events on old watched variables */
284 if( consdata->watchedvar1 != -1 && consdata->watchedvar1 != watchedvar1 )
285 {
286 assert(consdata->filterpos1 != -1);
287 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[consdata->watchedvar1], SCIP_EVENTTYPE_BOUNDCHANGED, eventhdlr,
288 (SCIP_EVENTDATA*)consdata, consdata->filterpos1) );
289 }
290 if( consdata->watchedvar2 != -1 && consdata->watchedvar2 != watchedvar2 )
291 {
292 assert(consdata->filterpos2 != -1);
293 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[consdata->watchedvar2], SCIP_EVENTTYPE_BOUNDCHANGED, eventhdlr,
294 (SCIP_EVENTDATA*)consdata, consdata->filterpos2) );
295 }
296
297 /* catch events on new watched variables */
298 if( watchedvar1 != -1 && watchedvar1 != consdata->watchedvar1 )
299 {
300 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[watchedvar1], SCIP_EVENTTYPE_BOUNDCHANGED, eventhdlr,
301 (SCIP_EVENTDATA*)consdata, &consdata->filterpos1) );
302 }
303 if( watchedvar2 != -1 && watchedvar2 != consdata->watchedvar2 )
304 {
305 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[watchedvar2], SCIP_EVENTTYPE_BOUNDCHANGED, eventhdlr,
306 (SCIP_EVENTDATA*)consdata, &consdata->filterpos2) );
307 }
308
309 /* set the new watched variables */
310 consdata->watchedvar1 = watchedvar1;
311 consdata->watchedvar2 = watchedvar2;
312
313 return SCIP_OKAY;
314}
315
316/** ensures, that the vars array can store at least num entries */
317static
319 SCIP* scip, /**< SCIP data structure */
320 SCIP_CONSDATA* consdata, /**< linear constraint data */
321 int num /**< minimum number of entries to store */
322 )
323{
324 assert(consdata != NULL);
325 assert(consdata->nvars <= consdata->varssize);
326
327 if( num > consdata->varssize )
328 {
329 int newsize;
330
331 newsize = SCIPcalcMemGrowSize(scip, num);
332 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
333 consdata->varssize = newsize;
334 }
335 assert(num <= consdata->varssize);
336
337 return SCIP_OKAY;
338}
339
340/** creates constraint data for xor constraint */
341static
343 SCIP* scip, /**< SCIP data structure */
344 SCIP_CONSDATA** consdata, /**< pointer to store the constraint data */
345 SCIP_Bool rhs, /**< right hand side of the constraint */
346 int nvars, /**< number of variables in the xor operation */
347 SCIP_VAR** vars, /**< variables in xor operation */
348 SCIP_VAR* intvar /**< artificial integer variable for linear relaxation */
349 )
350{
351 int r;
352
353 assert(consdata != NULL);
354 assert(nvars == 0 || vars != NULL);
355
356 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
357 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
358
359 (*consdata)->rhs = rhs;
360 (*consdata)->intvar = intvar;
361 for( r = 0; r < NROWS; ++r )
362 (*consdata)->rows[r] = NULL;
363 (*consdata)->nvars = nvars;
364 (*consdata)->varssize = nvars;
365 (*consdata)->watchedvar1 = -1;
366 (*consdata)->watchedvar2 = -1;
367 (*consdata)->filterpos1 = -1;
368 (*consdata)->filterpos2 = -1;
369 (*consdata)->deleteintvar = (intvar == NULL);
370 (*consdata)->propagated = FALSE;
371 (*consdata)->sorted = FALSE;
372 (*consdata)->changed = TRUE;
373 (*consdata)->extvars = NULL;
374 (*consdata)->nextvars = 0;
375 (*consdata)->extvarssize = 0;
376
377 /* get transformed variables, if we are in the transformed problem */
379 {
380 SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
381
382 if( (*consdata)->intvar != NULL )
383 {
384 SCIP_CALL( SCIPgetTransformedVar(scip, (*consdata)->intvar, &((*consdata)->intvar)) );
385 }
386
388 {
389 SCIP_CONSHDLRDATA* conshdlrdata;
390 SCIP_CONSHDLR* conshdlr;
391 int v;
392
394 assert(conshdlr != NULL);
395 conshdlrdata = SCIPconshdlrGetData(conshdlr);
396 assert(conshdlrdata != NULL);
397
398 for( v = (*consdata)->nvars - 1; v >= 0; --v )
399 {
400 SCIP_CALL( SCIPcatchVarEvent(scip, (*consdata)->vars[v], SCIP_EVENTTYPE_VARFIXED, conshdlrdata->eventhdlr,
401 (SCIP_EVENTDATA*)(*consdata), NULL) );
402 }
403 }
404 }
405
406 if( (*consdata)->intvar != NULL )
407 {
408 /* capture artificial variable */
409 SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->intvar) );
410 }
411
412 return SCIP_OKAY;
413}
414
415/** releases LP row of constraint data */
416static
418 SCIP* scip, /**< SCIP data structure */
419 SCIP_CONSDATA* consdata /**< constraint data */
420 )
421{
422 int r;
423
424 assert(consdata != NULL);
425
426 for( r = 0; r < NROWS; ++r )
427 {
428 if( consdata->rows[r] != NULL )
429 {
430 SCIP_CALL( SCIPreleaseRow(scip, &consdata->rows[r]) );
431 }
432 }
433
434 return SCIP_OKAY;
435}
436
437/** frees constraint data for xor constraint */
438static
440 SCIP* scip, /**< SCIP data structure */
441 SCIP_CONSDATA** consdata, /**< pointer to the constraint data */
442 SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
443 )
444{
445 assert(consdata != NULL);
446 assert(*consdata != NULL);
447
449 {
450 int j;
451
452 /* drop events for watched variables */
453 SCIP_CALL( consdataSwitchWatchedvars(scip, *consdata, eventhdlr, -1, -1) );
454
455 /* release flow variables */
456 if( (*consdata)->nextvars > 0 )
457 {
458 assert((*consdata)->extvars != NULL);
459 for( j = 0; j < (*consdata)->extvarssize; ++j )
460 {
461 if( (*consdata)->extvars[j] != NULL )
462 {
463 SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->extvars[j])) );
464 }
465 }
466
467 SCIPfreeBlockMemoryArray(scip, &((*consdata)->extvars), (*consdata)->extvarssize);
468 (*consdata)->nextvars = 0;
469 (*consdata)->extvarssize = 0;
470 }
471 }
472 else
473 {
474 assert((*consdata)->watchedvar1 == -1);
475 assert((*consdata)->watchedvar2 == -1);
476 }
477
478 /* release LP row */
479 SCIP_CALL( consdataFreeRows(scip, *consdata) );
480
481 /* release internal variable */
482 if( (*consdata)->intvar != NULL )
483 {
484 /* if the constraint is deleted and the integral variable is present, it should be fixed */
485 assert(SCIPisEQ(scip, SCIPvarGetLbGlobal((*consdata)->intvar), SCIPvarGetLbGlobal((*consdata)->intvar)));
486
487 /* We do not delete the integral variable, but leave the handling to SCIP, because it might happen that the
488 integral variable is stored in some basis information somewhere. */
489 SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->intvar) );
490 }
491
492 SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize);
493 SCIPfreeBlockMemory(scip, consdata);
494
495 return SCIP_OKAY;
496}
497
498/** prints xor constraint to file stream */
499static
501 SCIP* scip, /**< SCIP data structure */
502 SCIP_CONSDATA* consdata, /**< xor constraint data */
503 FILE* file, /**< output file (or NULL for standard output) */
504 SCIP_Bool endline /**< should an endline be set? */
505 )
506{
507 assert(consdata != NULL);
508
509 /* start variable list */
510 SCIPinfoMessage(scip, file, "xor(");
511
512 /* print variable list */
513 SCIP_CALL( SCIPwriteVarsList(scip, file, consdata->vars, consdata->nvars, TRUE, ',') );
514
515 /* close variable list and write right hand side */
516 SCIPinfoMessage(scip, file, ") = %u", consdata->rhs);
517
518 /* write integer variable if it exists */
519 if( consdata->intvar != NULL )
520 {
521 SCIPinfoMessage(scip, file, " (intvar = ");
522 SCIP_CALL( SCIPwriteVarName(scip, file, consdata->intvar, TRUE) );
523 SCIPinfoMessage(scip, file, ")");
524 }
525
526 if( endline )
527 SCIPinfoMessage(scip, file, "\n");
528
529 return SCIP_OKAY;
530}
531
532/** sets intvar of an xor constraint */
533static
535 SCIP* scip, /**< SCIP data structure */
536 SCIP_CONS* cons, /**< xor constraint */
537 SCIP_VAR* var /**< variable to add to the constraint */
538 )
539{
540 SCIP_CONSDATA* consdata;
541 SCIP_Bool transformed;
542
543 assert(var != NULL);
544
545 consdata = SCIPconsGetData(cons);
546 assert(consdata != NULL);
547 assert(consdata->rows[0] == NULL);
548
549 /* are we in the transformed problem? */
550 transformed = SCIPconsIsTransformed(cons);
551
552 /* always use transformed variables in transformed constraints */
553 if( transformed )
554 {
556 }
557 assert(var != NULL);
558 assert(transformed == SCIPvarIsTransformed(var));
559
560 /* remove the rounding locks for the old variable and release it */
561 if( consdata->intvar != NULL )
562 {
563 SCIP_CALL( unlockRounding(scip, cons, consdata->intvar) );
564 SCIP_CALL( SCIPreleaseVar(scip, &(consdata->intvar)) );
565 }
566
567 consdata->intvar = var;
568 consdata->changed = TRUE;
569
570 /* install the rounding locks for the new variable and capture it */
571 SCIP_CALL( lockRounding(scip, cons, consdata->intvar) );
572 SCIP_CALL( SCIPcaptureVar(scip, consdata->intvar) );
573
574 /**@todo update LP rows */
575 if( consdata->rows[0] != NULL )
576 {
577 SCIPerrorMessage("cannot change intvar of xor constraint after LP relaxation was created\n");
578 return SCIP_INVALIDCALL;
579 }
580
581 return SCIP_OKAY;
582}
583
584/** adds coefficient to xor constraint */
585static
587 SCIP* scip, /**< SCIP data structure */
588 SCIP_CONS* cons, /**< xor constraint */
589 SCIP_VAR* var /**< variable to add to the constraint */
590 )
591{
592 SCIP_CONSDATA* consdata;
593 SCIP_Bool transformed;
594
595 assert(var != NULL);
596
597 consdata = SCIPconsGetData(cons);
598 assert(consdata != NULL);
599 assert(consdata->rows[0] == NULL);
600
601 /* are we in the transformed problem? */
602 transformed = SCIPconsIsTransformed(cons);
603
604 /* always use transformed variables in transformed constraints */
605 if( transformed )
606 {
608 }
609 assert(var != NULL);
610 assert(transformed == SCIPvarIsTransformed(var));
611
612 SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1) );
613 consdata->vars[consdata->nvars] = var;
614 consdata->nvars++;
615 consdata->sorted = (consdata->nvars == 1);
616 consdata->changed = TRUE;
617
618 /* install the rounding locks for the new variable */
619 SCIP_CALL( lockRounding(scip, cons, var) );
620
621 /* we only catch this event in presolving stages
622 * we need to catch this event also during exiting presolving because we call applyFixings to clean up the constraint
623 * and this can lead to an insertion of a replacement of variables for which we will try to drop the VARFIXED event.
624 */
627 {
628 SCIP_CONSHDLRDATA* conshdlrdata;
629 SCIP_CONSHDLR* conshdlr;
630
632 assert(conshdlr != NULL);
633 conshdlrdata = SCIPconshdlrGetData(conshdlr);
634 assert(conshdlrdata != NULL);
635
636 SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_VARFIXED, conshdlrdata->eventhdlr,
637 (SCIP_EVENTDATA*)consdata, NULL) );
638 }
639
640 /**@todo update LP rows */
641 if( consdata->rows[0] != NULL )
642 {
643 SCIPerrorMessage("cannot add coefficients to xor constraint after LP relaxation was created\n");
644 return SCIP_INVALIDCALL;
645 }
646
647 return SCIP_OKAY;
648}
649
650/** deletes coefficient at given position from xor constraint data */
651static
653 SCIP* scip, /**< SCIP data structure */
654 SCIP_CONS* cons, /**< xor constraint */
655 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
656 int pos /**< position of coefficient to delete */
657 )
658{
659 SCIP_CONSDATA* consdata;
660
661 assert(eventhdlr != NULL);
662
663 consdata = SCIPconsGetData(cons);
664 assert(consdata != NULL);
665 assert(0 <= pos && pos < consdata->nvars);
666 assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(consdata->vars[pos]));
667
668 /* remove the rounding locks of the deleted variable */
669 SCIP_CALL( unlockRounding(scip, cons, consdata->vars[pos]) );
670
671 /* we only catch this event in presolving stage, so we need to only drop it there */
674 {
675 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos], SCIP_EVENTTYPE_VARFIXED, eventhdlr,
676 (SCIP_EVENTDATA*)consdata, -1) );
677 }
678
679 if( SCIPconsIsTransformed(cons) )
680 {
681 /* if the position is watched, stop watching the position */
682 if( consdata->watchedvar1 == pos )
683 {
684 SCIP_CALL( consdataSwitchWatchedvars(scip, consdata, eventhdlr, consdata->watchedvar2, -1) );
685 }
686 if( consdata->watchedvar2 == pos )
687 {
688 SCIP_CALL( consdataSwitchWatchedvars(scip, consdata, eventhdlr, consdata->watchedvar1, -1) );
689 }
690 }
691 assert(pos != consdata->watchedvar1);
692 assert(pos != consdata->watchedvar2);
693
694 /* move the last variable to the free slot */
695 consdata->vars[pos] = consdata->vars[consdata->nvars-1];
696 consdata->nvars--;
697
698 /* if the last variable (that moved) was watched, update the watched position */
699 if( consdata->watchedvar1 == consdata->nvars )
700 consdata->watchedvar1 = pos;
701 if( consdata->watchedvar2 == consdata->nvars )
702 consdata->watchedvar2 = pos;
703
704 consdata->propagated = FALSE;
705 consdata->sorted = FALSE;
706 consdata->changed = TRUE;
707
708 return SCIP_OKAY;
709}
710
711/** sorts and constraint's variables by non-decreasing variable index */
712static
714 SCIP_CONSDATA* consdata /**< constraint data */
715 )
716{
717 assert(consdata != NULL);
718
719 if( !consdata->sorted )
720 {
721 if( consdata->nvars <= 1 )
722 consdata->sorted = TRUE;
723 else
724 {
725 SCIP_VAR* var1 = NULL;
726 SCIP_VAR* var2 = NULL;
727
728 /* remember watch variables */
729 if( consdata->watchedvar1 != -1 )
730 {
731 var1 = consdata->vars[consdata->watchedvar1];
732 assert(var1 != NULL);
733 consdata->watchedvar1 = -1;
734 if( consdata->watchedvar2 != -1 )
735 {
736 var2 = consdata->vars[consdata->watchedvar2];
737 assert(var2 != NULL);
738 consdata->watchedvar2 = -1;
739 }
740 }
741 assert(consdata->watchedvar1 == -1);
742 assert(consdata->watchedvar2 == -1);
743 assert(var1 != NULL || var2 == NULL);
744
745 /* sort variables after index */
746 SCIPsortPtr((void**)consdata->vars, SCIPvarCompActiveAndNegated, consdata->nvars);
747 consdata->sorted = TRUE;
748
749 /* correct watched variables */
750 if( var1 != NULL )
751 {
752 int v;
753
754 /* since negated variables exist, we need to loop over all variables to find the old variable and cannot use
755 * SCIPsortedvecFindPtr()
756 */
757 for( v = consdata->nvars - 1; v >= 0; --v )
758 {
759 if( consdata->vars[v] == var1 )
760 {
761 consdata->watchedvar1 = v;
762 if( var2 == NULL || consdata->watchedvar2 != -1 )
763 break;
764 }
765 else if( consdata->vars[v] == var2 )
766 {
767 assert(consdata->vars[v] != NULL);
768 consdata->watchedvar2 = v;
769 if( consdata->watchedvar1 != -1 )
770 break;
771 }
772 }
773 assert(consdata->watchedvar1 != -1);
774 assert(consdata->watchedvar2 != -1 || var2 == NULL);
775 assert(consdata->watchedvar1 < consdata->nvars);
776 assert(consdata->watchedvar2 < consdata->nvars);
777 }
778 }
779 }
780
781#ifdef SCIP_DEBUG
782 /* check sorting */
783 {
784 int v;
785
786 for( v = 0; v < consdata->nvars; ++v )
787 {
788 assert(v == consdata->nvars-1 || SCIPvarCompareActiveAndNegated(consdata->vars[v], consdata->vars[v+1]) <= 0);
789 }
790 }
791#endif
792}
793
794
795/** gets the key of the given element */
796static
797SCIP_DECL_HASHGETKEY(hashGetKeyXorcons)
798{ /*lint --e{715}*/
799 /* the key is the element itself */
800 return elem;
801}
802
803/** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables */
804static
805SCIP_DECL_HASHKEYEQ(hashKeyEqXorcons)
806{
807 SCIP_CONSDATA* consdata1;
808 SCIP_CONSDATA* consdata2;
809 int i;
810#ifndef NDEBUG
811 SCIP* scip;
812
813 scip = (SCIP*)userptr;
814 assert(scip != NULL);
815#endif
816
817 consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
818 consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
819
820 /* checks trivial case */
821 if( consdata1->nvars != consdata2->nvars )
822 return FALSE;
823
824 /* sorts the constraints */
825 consdataSort(consdata1);
826 consdataSort(consdata2);
827 assert(consdata1->sorted);
828 assert(consdata2->sorted);
829
830 for( i = 0; i < consdata1->nvars ; ++i )
831 {
832 /* tests if variables are equal */
833 if( consdata1->vars[i] != consdata2->vars[i] )
834 {
835 assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
836 SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
837 return FALSE;
838 }
839 assert(SCIPvarCompareActiveAndNegated(consdata1->vars[i], consdata2->vars[i]) == 0);
840 }
841
842 return TRUE;
843}
844
845/** returns the hash value of the key */
846static
847SCIP_DECL_HASHKEYVAL(hashKeyValXorcons)
848{ /*lint --e{715}*/
849 SCIP_CONSDATA* consdata;
850 int minidx;
851 int mididx;
852 int maxidx;
853
854 consdata = SCIPconsGetData((SCIP_CONS*)key);
855 assert(consdata != NULL);
856 assert(consdata->sorted);
857 assert(consdata->nvars > 0);
858
859 /* only active, fixed or negated variables are allowed */
860 assert(consdata->vars[0] != NULL);
861 assert(consdata->vars[consdata->nvars / 2] != NULL);
862 assert(consdata->vars[consdata->nvars - 1] != NULL);
863 assert(SCIPvarIsActive(consdata->vars[0]) || SCIPvarGetStatus(consdata->vars[0]) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(consdata->vars[0]) == SCIP_VARSTATUS_FIXED);
864 assert(SCIPvarIsActive(consdata->vars[consdata->nvars / 2]) || SCIPvarGetStatus(consdata->vars[consdata->nvars / 2]) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(consdata->vars[consdata->nvars / 2]) == SCIP_VARSTATUS_FIXED);
865 assert(SCIPvarIsActive(consdata->vars[consdata->nvars - 1]) || SCIPvarGetStatus(consdata->vars[consdata->nvars - 1]) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(consdata->vars[consdata->nvars - 1]) == SCIP_VARSTATUS_FIXED);
866
867 minidx = SCIPvarGetIndex(consdata->vars[0]);
868 mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
869 maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
870 /* note that for all indices it does not hold that they are sorted, because variables are sorted with
871 * SCIPvarCompareActiveAndNegated (see var.c)
872 */
873
874 return SCIPhashFour(consdata->nvars, minidx, mididx, maxidx);
875}
876
877/** deletes all fixed variables and all pairs of equal variables */
878static
880 SCIP* scip, /**< SCIP data structure */
881 SCIP_CONS* cons, /**< xor constraint */
882 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
883 int* nchgcoefs, /**< pointer to add up the number of changed coefficients */
884 int* naggrvars, /**< pointer to add up the number of aggregated variables */
885 int* naddconss, /**< pointer to add up the number of added constraints */
886 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
887 )
888{
889 SCIP_VAR** intoffsetvars = NULL;
890 SCIP_Real* intoffsetvals = NULL;
891 SCIP_CONSDATA* consdata;
892 int intoffsetnvars = 0;
893 int intoffsetconst = 0;
894 int v;
895
896 assert(nchgcoefs != NULL);
897 consdata = SCIPconsGetData(cons);
898 assert(consdata != NULL);
899 assert(consdata->nvars == 0 || consdata->vars != NULL);
900
901 SCIPdebugMsg(scip, "before fixings: ");
902 SCIPdebug( SCIP_CALL( consdataPrint(scip, consdata, NULL, TRUE) ) );
903
904 for( v = consdata->nvars - 1; v >= 0; --v )
905 {
906 SCIP_VAR* var;
907
908 var = consdata->vars[v];
910
911 if( SCIPvarGetUbGlobal(var) < 0.5 )
912 {
914 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
915 ++(*nchgcoefs);
916 }
917 else if( SCIPvarGetLbGlobal(var) > 0.5 )
918 {
920 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
921 ++(*nchgcoefs);
922 consdata->rhs = !consdata->rhs;
923 if( consdata->rhs )
924 ++intoffsetconst;
925 }
926 else
927 {
928 SCIP_VAR* repvar;
929 SCIP_Bool negated;
930
931 /* get binary representative of variable */
932 SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
933
934 /* check if the variable should be replaced with the representative */
935 if( repvar != var )
936 {
937 /* delete old (aggregated) variable */
938 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
939
940 /* add representative instead */
941 SCIP_CALL( addCoef(scip, cons, repvar) );
942 }
943 }
944 }
945
946 /* sort the variables in the constraint */
947 consdataSort(consdata);
948 assert(consdata->sorted);
949
950 SCIPdebugMsg(scip, "after sort : ");
951 SCIPdebug( SCIP_CALL( consdataPrint(scip, consdata, NULL, TRUE) ) );
952
953 if( consdata->intvar != NULL )
954 {
955 SCIP_CALL( SCIPallocBufferArray(scip, &intoffsetvars, consdata->nvars / 2 + 2) );
956 SCIP_CALL( SCIPallocBufferArray(scip, &intoffsetvals, consdata->nvars / 2 + 2) );
957 intoffsetvars[1] = consdata->intvar;
958 intoffsetvals[1] = -1.0;
959 intoffsetnvars = 2;
960 }
961
962 /* delete pairs of equal or negated variables; scan backwards to not affect the order of the front variables */
963 v = consdata->nvars - 2;
964 while( v >= 0 )
965 {
966 if( consdata->vars[v] == consdata->vars[v + 1] ) /*lint !e679*/
967 {
968 /* delete both variables */
969 SCIPdebugMsg(scip, "xor constraint <%s>: deleting pair of equal variables <%s>\n",
970 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[v]));
971
972 /* collect variable to subtract from intvar after pair removal */
973 if( consdata->intvar != NULL )
974 {
975 assert(intoffsetvars != NULL);
976 assert(intoffsetvals != NULL);
977 assert(intoffsetnvars >= 2);
978 assert(intoffsetconst >= 0);
979
980 if( consdata->intvar == consdata->vars[v] )
981 intoffsetvals[1] += 1.0;
982 else if( intoffsetvars[intoffsetnvars - 1] == consdata->vars[v] )
983 intoffsetvals[intoffsetnvars - 1] += 1.0;
984 else
985 {
986 intoffsetvars[intoffsetnvars] = consdata->vars[v];
987 intoffsetvals[intoffsetnvars] = 1.0;
988 ++intoffsetnvars;
989 }
990 }
991
992 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v + 1) );
993 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
994 *nchgcoefs += 2;
995 --v;
996 }
997 else if( consdata->vars[v] == SCIPvarGetNegatedVar(consdata->vars[v + 1]) ) /*lint !e679*/
998 {
999 /* delete both variables and negate the rhs */
1000 SCIPdebugMsg(scip, "xor constraint <%s>: deleting pair of negated variables <%s> and <%s>\n",
1001 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[v]), SCIPvarGetName(consdata->vars[v+1])); /*lint !e679*/
1002
1003 /* flip rhs and track constant offset to subtract from intvar after pair removal */
1004 consdata->rhs = !consdata->rhs;
1005 if( consdata->rhs )
1006 ++intoffsetconst;
1007
1008 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v + 1) );
1009 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
1010 *nchgcoefs += 2;
1011 --v;
1012 }
1013 else
1014 assert(SCIPvarGetProbvar(consdata->vars[v]) != SCIPvarGetProbvar(consdata->vars[v + 1])); /*lint !e679*/
1015 --v;
1016 }
1017
1018 /* a xor constraint is represented by sum(x) - 2 * intvar = rhs, so variable duplicate
1019 * offsets need to be eliminated from the integer variable y, replacing it by z with
1020 * y = z + intoffsetsum and z in [max(lb_y - intoffsetmax, 0), ub_y - intoffsetmin]
1021 */
1022 if( consdata->intvar != NULL )
1023 {
1024 assert(intoffsetvars != NULL);
1025 assert(intoffsetvals != NULL);
1026 assert(intoffsetnvars >= 2);
1027 assert(intoffsetconst >= 0);
1028
1029 if( intoffsetconst >= 1 || intoffsetvals[1] != -1.0 || intoffsetnvars > 2 ) /*lint !e777*/
1030 {
1031 SCIP_Real lb = -(double)intoffsetconst;
1032 SCIP_Real ub = lb;
1033 SCIP_Bool aggregated;
1034 SCIP_Bool infeasible = FALSE;
1035 SCIP_Bool redundant = FALSE;
1036 char varname[SCIP_MAXSTRLEN];
1037
1038 (void)SCIPsnprintf(varname, SCIP_MAXSTRLEN, "agg_%s", SCIPvarGetName(consdata->intvar));
1039
1040 if( intoffsetvals[1] < 0.0 )
1041 {
1042 lb -= intoffsetvals[1] * SCIPvarGetLbGlobal(consdata->intvar);
1043 ub -= intoffsetvals[1] * SCIPvarGetUbGlobal(consdata->intvar);
1044 }
1045 else
1046 {
1047 lb -= intoffsetvals[1] * SCIPvarGetUbGlobal(consdata->intvar);
1048 ub -= intoffsetvals[1] * SCIPvarGetLbGlobal(consdata->intvar);
1049 }
1050
1051 for( v = 2; v < intoffsetnvars; ++v )
1052 {
1053 lb -= intoffsetvals[v] * SCIPvarGetUbGlobal(intoffsetvars[v]);
1054 ub -= intoffsetvals[v] * SCIPvarGetLbGlobal(intoffsetvars[v]);
1055 }
1056
1057 if( lb < 0.0 )
1058 {
1059 lb = 0.0;
1060
1061 if( ub < 0.0 )
1062 ub = 0.0;
1063 }
1064
1065 SCIP_CALL( SCIPcreateVarImpl(scip, intoffsetvars, varname, lb, ub, 0.0,
1066 SCIPvarGetType(consdata->intvar), SCIPvarGetImplType(consdata->intvar),
1067 SCIPvarIsInitial(consdata->intvar), SCIPvarIsRemovable(consdata->intvar),
1068 NULL, NULL, NULL, NULL, NULL) );
1069 intoffsetvals[0] = 1.0;
1070 SCIP_CALL( SCIPaddVar(scip, intoffsetvars[0]) );
1071
1072 if( intoffsetnvars == 2 )
1073 {
1074 if( intoffsetvals[1] == 0.0 ) /*lint !e777*/
1075 redundant = TRUE;
1076 else
1077 {
1078 SCIP_CALL( SCIPaggregateVars(scip, intoffsetvars[1], intoffsetvars[0], -intoffsetvals[1], -intoffsetvals[0],
1079 (double)intoffsetconst, &infeasible, &redundant, &aggregated) );
1080
1081 if( aggregated )
1082 ++(*naggrvars);
1083 }
1084 assert(infeasible || redundant || SCIPdoNotAggr(scip));
1085 }
1086
1087 if( infeasible )
1088 *cutoff = TRUE;
1089 else if( redundant )
1090 {
1091 SCIP_CALL( setIntvar(scip, cons, intoffsetvars[0]) );
1092 }
1093 else
1094 {
1095 SCIP_CONS* newcons;
1096 char consname[SCIP_MAXSTRLEN];
1097
1098 (void)SCIPsnprintf(consname, SCIP_MAXSTRLEN, "agg_%s", SCIPconsGetName(cons));
1099
1100 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, consname, intoffsetnvars, intoffsetvars, intoffsetvals,
1101 -(double)intoffsetconst, -(double)intoffsetconst,
1103 TRUE, TRUE, TRUE, /*SCIPconsIsEnforced(cons), SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons),*/
1106 SCIP_CALL( SCIPaddCons(scip, newcons) );
1107 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1108 ++(*naddconss);
1109
1110 SCIP_CALL( setIntvar(scip, cons, intoffsetvars[0]) );
1111 }
1112
1113 SCIP_CALL( SCIPreleaseVar(scip, intoffsetvars) );
1114 }
1115
1116 SCIPfreeBufferArray(scip, &intoffsetvals);
1117 SCIPfreeBufferArray(scip, &intoffsetvars);
1118 }
1119
1120 SCIPdebugMsg(scip, "after fixings : ");
1121 SCIPdebug( SCIP_CALL( consdataPrint(scip, consdata, NULL, TRUE) ) );
1122
1123 return SCIP_OKAY;
1124}
1125
1126/** adds extended flow formulation
1127 *
1128 * The extended flow formulation is built as follows: Let \f$x_1, \dots, x_k\f$ be the variables contained in the given
1129 * XOR constraint. We construct a two layered flow network. The upper layer is called the north layer and the lower is
1130 * called the south layer. For each \f$x_i,\; i = 2, \ldots, k-1\f$, we add arcs that stay in the north and south layer
1131 * (denoted by 'nn' and 'ss', respectively), as well as arcs that change the layers (denoted by 'ns' and 'sn'). For
1132 * \f$x_1\f$, we only add two arcs from the source to the two layers. The source is located on the north layer. For
1133 * \f$x_k\f$, we add two arcs connecting the two layers to the sink. Depending on the rhs of the constraint the sink is
1134 * located on the north or south layer. A change in the layers corresponds to a parity change, i.e., the corresponding
1135 * variable \f$x_i\f$ is 1 (and 0 otherwise).
1136 */
1137static
1139 SCIP* scip, /**< SCIP data structure */
1140 SCIP_CONS* cons, /**< constraint to check */
1141 int* naggrvars, /**< pointer to add up the number of aggregated variables */
1142 int* naddedconss /**< number of added constraints */
1143 )
1144{
1145 char name[SCIP_MAXSTRLEN];
1146 SCIP_CONSDATA* consdata;
1147 SCIP_VAR* varprevnn = NULL;
1148 SCIP_VAR* varprevns = NULL;
1149 SCIP_VAR* varprevsn = NULL;
1150 SCIP_VAR* varprevss = NULL;
1151 SCIP_VAR* vars[4];
1152 SCIP_Real vals[4];
1153 int i;
1154
1155 assert(scip != NULL);
1156 assert(cons != NULL);
1157 assert(naddedconss != NULL);
1158 *naddedconss = 0;
1159
1160 /* exit if contraints is modifiable */
1161 if( SCIPconsIsModifiable(cons) )
1162 return SCIP_OKAY;
1163
1164 consdata = SCIPconsGetData(cons);
1165 assert(consdata != NULL);
1166
1167 /* exit if extended formulation has been added already */
1168 if( consdata->extvars != NULL )
1169 return SCIP_OKAY;
1170
1171 /* xor constraints with at most 3 variables are handled directly through rows for the convex hull */
1172 if( consdata->nvars <= 3 )
1173 return SCIP_OKAY;
1174
1175 SCIPdebugMsg(scip, "Add extended formulation for xor constraint <%s> ...\n", SCIPconsGetName(cons));
1176 assert(consdata->extvars == NULL);
1177 assert(consdata->nextvars == 0);
1178 assert(consdata->extvarssize == 0);
1179
1180 /* get storage for auxiliary variables */
1181 consdata->extvarssize = 4 * (consdata->nvars);
1182 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(consdata->extvars), consdata->extvarssize) );
1183
1184 /* pass through components */
1185 for( i = 0; i < consdata->nvars; ++i )
1186 {
1187 /* variables: n - north, s - south */
1188 SCIP_VAR* varnn = NULL;
1189 SCIP_VAR* varns = NULL;
1190 SCIP_VAR* varsn = NULL;
1191 SCIP_VAR* varss = NULL;
1192 SCIP_CONS* newcons;
1193 SCIP_Real rhs = 0.0;
1194 SCIP_Bool infeasible = FALSE;
1195 SCIP_Bool redundant = FALSE;
1196 SCIP_Bool aggregated = FALSE;
1197 int cnt = 0;
1198
1199 /* create variables */
1200 if( i == 0 )
1201 {
1202 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_nn", SCIPconsGetName(cons), i);
1203 SCIP_CALL( SCIPcreateVarImpl(scip, &varnn, name, 0.0, 1.0, 0.0,
1205 NULL, NULL, NULL, NULL, NULL) );
1206 SCIP_CALL( SCIPaddVar(scip, varnn) );
1207
1208 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_ns", SCIPconsGetName(cons), i);
1209 SCIP_CALL( SCIPcreateVarImpl(scip, &varns, name, 0.0, 1.0, 0.0,
1211 NULL, NULL, NULL, NULL, NULL) );
1212 SCIP_CALL( SCIPaddVar(scip, varns) );
1213
1214 /* need to lock variables, because we aggregate them */
1215 SCIP_CALL( SCIPlockVarCons(scip, varnn, cons, TRUE, TRUE) );
1216 SCIP_CALL( SCIPlockVarCons(scip, varns, cons, TRUE, TRUE) );
1217
1218 /* aggregate ns variable with original variable */
1219 SCIP_CALL( SCIPaggregateVars(scip, varns, consdata->vars[0], 1.0, -1.0, 0.0, &infeasible, &redundant, &aggregated) );
1220 assert(!infeasible);
1221 assert(redundant);
1222 assert(aggregated);
1223 ++(*naggrvars);
1224 }
1225 else
1226 {
1227 if( i == consdata->nvars-1 )
1228 {
1229 if( consdata->rhs )
1230 {
1231 /* if the rhs is 1 (true) the flow goes to the bottom level */
1232 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_ns", SCIPconsGetName(cons), i);
1233 SCIP_CALL( SCIPcreateVarImpl(scip, &varns, name, 0.0, 1.0, 0.0,
1235 NULL, NULL, NULL, NULL, NULL) );
1236 SCIP_CALL( SCIPaddVar(scip, varns) );
1237
1238 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_ss", SCIPconsGetName(cons), i);
1239 SCIP_CALL( SCIPcreateVarImpl(scip, &varss, name, 0.0, 1.0, 0.0,
1241 NULL, NULL, NULL, NULL, NULL) );
1242 SCIP_CALL( SCIPaddVar(scip, varss) );
1243
1244 /* need to lock variables, because we aggregate them */
1245 SCIP_CALL( SCIPlockVarCons(scip, varns, cons, TRUE, TRUE) );
1246 SCIP_CALL( SCIPlockVarCons(scip, varss, cons, TRUE, TRUE) );
1247
1248 /* aggregate ns variable with original variable */
1249 SCIP_CALL( SCIPaggregateVars(scip, varns, consdata->vars[i], 1.0, -1.0, 0.0, &infeasible, &redundant, &aggregated) );
1250 assert(!infeasible);
1251 assert(redundant);
1252 assert(aggregated);
1253 ++(*naggrvars);
1254 }
1255 else
1256 {
1257 /* if the rhs is 0 (false) the flow stays on the top level */
1258 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_nn", SCIPconsGetName(cons), i);
1259 SCIP_CALL( SCIPcreateVarImpl(scip, &varnn, name, 0.0, 1.0, 0.0,
1261 NULL, NULL, NULL, NULL, NULL) );
1262 SCIP_CALL( SCIPaddVar(scip, varnn) );
1263
1264 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_sn", SCIPconsGetName(cons), i);
1265 SCIP_CALL( SCIPcreateVarImpl(scip, &varsn, name, 0.0, 1.0, 0.0,
1267 NULL, NULL, NULL, NULL, NULL) );
1268 SCIP_CALL( SCIPaddVar(scip, varsn) );
1269
1270 /* need to lock variables, because we aggregate them */
1271 SCIP_CALL( SCIPlockVarCons(scip, varnn, cons, TRUE, TRUE) );
1272 SCIP_CALL( SCIPlockVarCons(scip, varsn, cons, TRUE, TRUE) );
1273
1274 /* aggregate sn variable with original variable */
1275 SCIP_CALL( SCIPaggregateVars(scip, varsn, consdata->vars[i], 1.0, -1.0, 0.0, &infeasible, &redundant, &aggregated) );
1276 assert(!infeasible);
1277 assert(redundant);
1278 assert(aggregated);
1279 ++(*naggrvars);
1280 }
1281 }
1282 else
1283 {
1284 /* add the four flow variables */
1285 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_nn", SCIPconsGetName(cons), i);
1286 SCIP_CALL( SCIPcreateVarImpl(scip, &varnn, name, 0.0, 1.0, 0.0,
1288 NULL, NULL, NULL, NULL, NULL) );
1289 SCIP_CALL( SCIPaddVar(scip, varnn) );
1290
1291 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_ns", SCIPconsGetName(cons), i);
1292 SCIP_CALL( SCIPcreateVarImpl(scip, &varns, name, 0.0, 1.0, 0.0,
1294 NULL, NULL, NULL, NULL, NULL) );
1295 SCIP_CALL( SCIPaddVar(scip, varns) );
1296
1297 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_sn", SCIPconsGetName(cons), i);
1298 SCIP_CALL( SCIPcreateVarImpl(scip, &varsn, name, 0.0, 1.0, 0.0,
1300 NULL, NULL, NULL, NULL, NULL) );
1301 SCIP_CALL( SCIPaddVar(scip, varsn) );
1302
1303 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_ss", SCIPconsGetName(cons), i);
1304 SCIP_CALL( SCIPcreateVarImpl(scip, &varss, name, 0.0, 1.0, 0.0,
1306 NULL, NULL, NULL, NULL, NULL) );
1307 SCIP_CALL( SCIPaddVar(scip, varss) );
1308
1309 SCIP_CALL( SCIPlockVarCons(scip, varnn, cons, TRUE, TRUE) );
1310 SCIP_CALL( SCIPlockVarCons(scip, varns, cons, TRUE, TRUE) );
1311 SCIP_CALL( SCIPlockVarCons(scip, varsn, cons, TRUE, TRUE) );
1312 SCIP_CALL( SCIPlockVarCons(scip, varss, cons, TRUE, TRUE) );
1313
1314 /* add coupling constraint */
1315 cnt = 0;
1316 if( varns != NULL )
1317 {
1318 vars[cnt] = varns;
1319 vals[cnt++] = 1.0;
1320 }
1321 if( varsn != NULL )
1322 {
1323 vars[cnt] = varsn;
1324 vals[cnt++] = 1.0;
1325 }
1326 assert(SCIPvarIsTransformed(consdata->vars[i]));
1327 vars[cnt] = consdata->vars[i];
1328 vals[cnt++] = -1.0;
1329
1330 assert(cnt >= 2);
1331 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_couple", SCIPconsGetName(cons));
1332 /* not initial, separate, do not enforce, do not check, propagate, not local, not modifiable, dynamic, removable, not sticking */
1333 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, cnt, vars, vals, 0.0, 0.0,
1335 SCIP_CALL( SCIPaddCons(scip, newcons) );
1336 SCIPdebugPrintCons(scip, newcons, NULL);
1337 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1338 ++(*naddedconss);
1339 }
1340
1341 /* add south flow conservation constraint */
1342
1343 /* incoming variables */
1344 cnt = 0;
1345 if( varprevss != NULL )
1346 {
1347 vars[cnt] = varprevss;
1348 vals[cnt++] = 1.0;
1349 }
1350 if( varprevns != NULL )
1351 {
1352 vars[cnt] = varprevns;
1353 vals[cnt++] = 1.0;
1354 }
1355
1356 /* outgoing variables */
1357 if( varss != NULL )
1358 {
1359 vars[cnt] = varss;
1360 vals[cnt++] = -1.0;
1361 }
1362 if( varsn != NULL )
1363 {
1364 vars[cnt] = varsn;
1365 vals[cnt++] = -1.0;
1366 }
1367
1368 assert(cnt >= 2);
1369 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_south", SCIPconsGetName(cons));
1370 /* not initial, separate, do not enforce, do not check, propagate, not local, not modifiable, dynamic, removable, not sticking */
1371 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, cnt, vars, vals, 0.0, 0.0,
1373 SCIP_CALL( SCIPaddCons(scip, newcons) );
1374 SCIPdebugPrintCons(scip, newcons, NULL);
1375 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1376 ++(*naddedconss);
1377 }
1378
1379 /* add north flow conservation constraint */
1380
1381 /* incoming variables */
1382 cnt = 0;
1383 if( varprevnn != NULL )
1384 {
1385 vars[cnt] = varprevnn;
1386 vals[cnt++] = 1.0;
1387 }
1388 if( varprevsn != NULL )
1389 {
1390 vars[cnt] = varprevsn;
1391 vals[cnt++] = 1.0;
1392 }
1393
1394 /* outgoing variables */
1395 if( varnn != NULL )
1396 {
1397 vars[cnt] = varnn;
1398 vals[cnt++] = -1.0;
1399 }
1400 if( varns != NULL )
1401 {
1402 vars[cnt] = varns;
1403 vals[cnt++] = -1.0;
1404 }
1405
1406 assert(cnt >= 2);
1407 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_north", SCIPconsGetName(cons));
1408 if( i == 0 )
1409 rhs = -1.0;
1410 else
1411 rhs = 0.0;
1412
1413 /* not initial, separate, do not enforce, do not check, propagate, not local, not modifiable, dynamic, removable, not sticking */
1414 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, cnt, vars, vals, rhs, rhs,
1416 SCIP_CALL( SCIPaddCons(scip, newcons) );
1417 SCIPdebugPrintCons(scip, newcons, NULL);
1418 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1419 ++(*naddedconss);
1420
1421 /* store variables */
1422 consdata->extvars[4*i] = varnn; /*lint !e679*/
1423 consdata->extvars[4*i + 1] = varns; /*lint !e679*/
1424 consdata->extvars[4*i + 2] = varsn; /*lint !e679*/
1425 consdata->extvars[4*i + 3] = varss; /*lint !e679*/
1426
1427 if( varnn != NULL )
1428 ++(consdata->nextvars);
1429 if( varns != NULL )
1430 ++(consdata->nextvars);
1431 if( varsn != NULL )
1432 ++(consdata->nextvars);
1433 if( varss != NULL )
1434 ++(consdata->nextvars);
1435
1436 /* store previous variables */
1437 varprevnn = varnn;
1438 varprevns = varns;
1439 varprevsn = varsn;
1440 varprevss = varss;
1441 }
1442
1443 return SCIP_OKAY;
1444}
1445
1446/** adds extended asymmetric formulation
1447 *
1448 * The extended asymmetric formulation is constructed as follows: Let \f$x_1, \dots, x_k\f$ be the variables contained
1449 * in the given XOR constraint. We introduce variables \f$p_1, \ldots, p_k\f$ with the following constraints: \f$p_1 =
1450 * x_1\f$, \f$p_k = 1\f$, and for \f$i = 2, \ldots, k-1\f$:
1451 * \f[
1452 * \begin{array}{ll}
1453 * p_i & \leq p_{i-1} + x_i\\
1454 * p_i & \leq 2 - (p_{i-1} + x_i)\\
1455 * p_i & \geq p_{i-1} - x_i\\
1456 * p_i & \geq x_i - p_{i-1}.
1457 * \end{array}
1458 * \f]
1459 * This formulation is described in
1460 *
1461 * Robert D. Carr and Goran Konjevod@n
1462 * Polyhedral combinatorics@n
1463 * In Harvey Greenberg, editor, Tutorials on emerging methodologies and applications in Operations Research,@n
1464 * Chapter 2, pages (2-1)-(2-48). Springer, 2004.
1465 */
1466static
1468 SCIP* scip, /**< SCIP data structure */
1469 SCIP_CONS* cons, /**< constraint to check */
1470 int* naggrvars, /**< pointer to add up the number of aggregated variables */
1471 int* naddedconss /**< number of added constraints */
1472 )
1473{
1474 char name[SCIP_MAXSTRLEN];
1475 SCIP_CONSDATA* consdata;
1476 SCIP_VAR* vars[3];
1477 SCIP_Real vals[3];
1478 SCIP_VAR* prevvar = NULL;
1479 int i;
1480
1481 assert(scip != NULL);
1482 assert(cons != NULL);
1483 assert(naddedconss != NULL);
1484 *naddedconss = 0;
1485
1486 /* exit if contraints is modifiable */
1487 if( SCIPconsIsModifiable(cons) )
1488 return SCIP_OKAY;
1489
1490 consdata = SCIPconsGetData(cons);
1491 assert(consdata != NULL);
1492
1493 /* exit if extended formulation has been added already */
1494 if( consdata->extvars != NULL )
1495 return SCIP_OKAY;
1496
1497 /* xor constraints with at most 3 variables are handled directly through rows for the convex hull */
1498 if( consdata->nvars <= 3 )
1499 return SCIP_OKAY;
1500
1501 SCIPdebugMsg(scip, "Add extended formulation for xor constraint <%s> ...\n", SCIPconsGetName(cons));
1502 assert(consdata->extvars == NULL);
1503 assert(consdata->nextvars == 0);
1504
1505 /* get storage for auxiliary variables */
1506 consdata->extvarssize = consdata->nvars;
1507 consdata->nextvars = consdata->nvars;
1508 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(consdata->extvars), consdata->extvarssize ) );
1509
1510 /* pass through components */
1511 for( i = 0; i < consdata->nvars; ++i )
1512 {
1513 SCIP_Bool infeasible = FALSE;
1514 SCIP_Bool redundant = FALSE;
1515 SCIP_Bool aggregated = FALSE;
1516 SCIP_CONS* newcons;
1517 SCIP_VAR* artvar = NULL;
1518 SCIP_Real lb = 0.0;
1519 SCIP_Real ub = 1.0;
1520
1521 /* determine fixing for last variables */
1522 if( i == consdata->nvars-1 )
1523 {
1524 if( consdata->rhs )
1525 {
1526 lb = 1.0;
1527 ub = 1.0;
1528 }
1529 else
1530 {
1531 lb = 0.0;
1532 ub = 0.0;
1533 }
1534 }
1535
1536 /* create variable */
1537 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "p_%s_%d", SCIPconsGetName(cons), i);
1538 SCIP_CALL( SCIPcreateVarImpl(scip, &artvar, name, lb, ub, 0.0,
1540 NULL, NULL, NULL, NULL, NULL) );
1541 SCIP_CALL( SCIPaddVar(scip, artvar) );
1542 SCIP_CALL( SCIPlockVarCons(scip, artvar, cons, TRUE, TRUE) );
1543
1544 /* create constraints */
1545 if( i == 0 )
1546 {
1547 /* aggregate artificial variable with original variable */
1548 SCIP_CALL( SCIPaggregateVars(scip, artvar, consdata->vars[0], 1.0, -1.0, 0.0, &infeasible, &redundant, &aggregated) );
1549 assert(!infeasible);
1550 assert(redundant);
1551 assert(aggregated);
1552 ++(*naggrvars);
1553 }
1554 else
1555 {
1556 assert(SCIPvarIsTransformed(consdata->vars[i]));
1557
1558 /* add first constraint */
1559 vars[0] = artvar;
1560 vals[0] = 1.0;
1561 vars[1] = prevvar;
1562 vals[1] = -1.0;
1563 vars[2] = consdata->vars[i];
1564 vals[2] = -1.0;
1565
1566 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_1", SCIPconsGetName(cons), i);
1567 /* not initial, separate, do not enforce, do not check, propagate, not local, not modifiable, dynamic, removable, not sticking */
1568 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, 3, vars, vals, -SCIPinfinity(scip), 0.0,
1570 SCIP_CALL( SCIPaddCons(scip, newcons) );
1571 SCIPdebugPrintCons(scip, newcons, NULL);
1572 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1573 ++(*naddedconss);
1574
1575 /* add second constraint */
1576 vars[0] = artvar;
1577 vals[0] = 1.0;
1578 vars[1] = prevvar;
1579 vals[1] = 1.0;
1580 vars[2] = consdata->vars[i];
1581 vals[2] = 1.0;
1582
1583 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_2", SCIPconsGetName(cons), i);
1584 /* not initial, separate, do not enforce, do not check, propagate, not local, not modifiable, dynamic, removable, not sticking */
1585 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, 3, vars, vals, -SCIPinfinity(scip), 2.0,
1587 SCIP_CALL( SCIPaddCons(scip, newcons) );
1588 SCIPdebugPrintCons(scip, newcons, NULL);
1589 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1590 ++(*naddedconss);
1591
1592 /* add third constraint */
1593 vars[0] = artvar;
1594 vals[0] = -1.0;
1595 vars[1] = prevvar;
1596 vals[1] = 1.0;
1597 vars[2] = consdata->vars[i];
1598 vals[2] = -1.0;
1599
1600 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_3", SCIPconsGetName(cons), i);
1601 /* not initial, separate, do not enforce, do not check, propagate, not local, not modifiable, dynamic, removable, not sticking */
1602 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, 3, vars, vals, -SCIPinfinity(scip), 0.0,
1604 SCIP_CALL( SCIPaddCons(scip, newcons) );
1605 SCIPdebugPrintCons(scip, newcons, NULL);
1606 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1607 ++(*naddedconss);
1608
1609 /* add fourth constraint */
1610 vars[0] = artvar;
1611 vals[0] = -1.0;
1612 vars[1] = prevvar;
1613 vals[1] = -1.0;
1614 vars[2] = consdata->vars[i];
1615 vals[2] = 1.0;
1616
1617 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_4", SCIPconsGetName(cons), i);
1618 /* not initial, separate, do not enforce, do not check, propagate, not local, not modifiable, dynamic, removable, not sticking */
1619 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, 3, vars, vals, -SCIPinfinity(scip), 0.0,
1621 SCIP_CALL( SCIPaddCons(scip, newcons) );
1622 SCIPdebugPrintCons(scip, newcons, NULL);
1623 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1624 ++(*naddedconss);
1625 }
1626
1627 /* store variable */
1628 consdata->extvars[i] = artvar;
1629 prevvar = artvar;
1630 }
1631
1632 return SCIP_OKAY;
1633}
1634
1635/** creates LP row corresponding to xor constraint:
1636 * x1 + ... + xn - 2q == rhs
1637 * with internal integer variable q;
1638 * in the special case of 3 variables and c = 0, the following linear system is created:
1639 * + x - y - z <= 0
1640 * - x + y - z <= 0
1641 * - x - y + z <= 0
1642 * + x + y + z <= 2
1643 * in the special case of 3 variables and c = 1, the following linear system is created:
1644 * - x + y + z <= 1
1645 * + x - y + z <= 1
1646 * + x + y - z <= 1
1647 * - x - y - z <= -1
1648 */
1649static
1651 SCIP* scip, /**< SCIP data structure */
1652 SCIP_CONS* cons /**< constraint to check */
1653 )
1654{
1655 SCIP_CONSDATA* consdata;
1656 char varname[SCIP_MAXSTRLEN];
1657
1658 consdata = SCIPconsGetData(cons);
1659 assert(consdata != NULL);
1660 assert(consdata->rows[0] == NULL);
1661
1662 if( SCIPconsIsModifiable(cons) || consdata->nvars != 3 )
1663 {
1664 SCIP_Real rhsval;
1665
1666 /* create internal variable, if not yet existing */
1667 if( consdata->intvar == NULL )
1668 {
1669 int ub;
1670
1671 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "XOR_artificial_%s_int", SCIPconsGetName(cons));
1672 ub = consdata->nvars/2;
1673 SCIP_CALL( SCIPcreateVar(scip, &consdata->intvar, varname, 0.0, (SCIP_Real)ub, 0.0,
1674 consdata->nvars >= 4 ? SCIP_VARTYPE_INTEGER : SCIP_VARTYPE_BINARY,
1676 SCIP_CALL( SCIPaddVar(scip, consdata->intvar) );
1677
1678#ifdef WITH_DEBUG_SOLUTION
1679 if( SCIPdebugIsMainscip(scip) )
1680 {
1681 SCIP_Real solval;
1682 int count = 0;
1683 int v;
1684
1685 for( v = consdata->nvars - 1; v >= 0; --v )
1686 {
1687 SCIP_CALL( SCIPdebugGetSolVal(scip, consdata->vars[v], &solval) );
1688 count += (solval > 0.5 ? 1 : 0);
1689 }
1690 assert((count - consdata->rhs) % 2 == 0);
1691 solval = (SCIP_Real) ((count - consdata->rhs) / 2);
1692
1693 /* store debug sol value of artificial integer variable */
1694 SCIP_CALL( SCIPdebugAddSolVal(scip, consdata->intvar, solval) );
1695 }
1696#endif
1697
1698 /* install the rounding locks for the internal variable */
1699 SCIP_CALL( lockRounding(scip, cons, consdata->intvar) );
1700 }
1701
1702 /* create LP row */
1703 rhsval = (consdata->rhs ? 1.0 : 0.0);
1704 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->rows[0], cons, SCIPconsGetName(cons), rhsval, rhsval,
1706 SCIP_CALL( SCIPaddVarToRow(scip, consdata->rows[0], consdata->intvar, -2.0) );
1707 SCIP_CALL( SCIPaddVarsToRowSameCoef(scip, consdata->rows[0], consdata->nvars, consdata->vars, 1.0) );
1708 }
1709 else if( !consdata->rhs )
1710 {
1711 char rowname[SCIP_MAXSTRLEN];
1712 int r;
1713
1714 /* create the <= 0 rows with one positive sign */
1715 for( r = 0; r < 3; ++r )
1716 {
1717 int v;
1718
1719 (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s_%d", SCIPconsGetName(cons), r);
1720 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->rows[r], cons, rowname, -SCIPinfinity(scip), 0.0,
1722 for( v = 0; v < 3; ++v )
1723 {
1724 SCIP_CALL( SCIPaddVarToRow(scip, consdata->rows[r], consdata->vars[v], v == r ? +1.0 : -1.0) );
1725 }
1726 }
1727
1728 /* create the <= 2 row with all positive signs */
1729 (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s_3", SCIPconsGetName(cons));
1730 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->rows[3], cons, rowname, -SCIPinfinity(scip), 2.0,
1732 SCIP_CALL( SCIPaddVarsToRowSameCoef(scip, consdata->rows[3], consdata->nvars, consdata->vars, 1.0) );
1733
1734 /* create extra LP row if integer variable exists */
1735 if( consdata->intvar != NULL )
1736 {
1737 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->rows[4], cons, SCIPconsGetName(cons), 0.0, 0.0,
1739 SCIP_CALL( SCIPaddVarToRow(scip, consdata->rows[4], consdata->intvar, -2.0) );
1740 SCIP_CALL( SCIPaddVarsToRowSameCoef(scip, consdata->rows[4], consdata->nvars, consdata->vars, 1.0) );
1741 }
1742 }
1743 else
1744 {
1745 char rowname[SCIP_MAXSTRLEN];
1746 int r;
1747
1748 /* create the <= 1 rows with one negative sign */
1749 for( r = 0; r < 3; ++r )
1750 {
1751 int v;
1752
1753 (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s_%d", SCIPconsGetName(cons), r);
1754 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->rows[r], cons, rowname, -SCIPinfinity(scip), 1.0,
1756 for( v = 0; v < 3; ++v )
1757 {
1758 SCIP_CALL( SCIPaddVarToRow(scip, consdata->rows[r], consdata->vars[v], v == r ? -1.0 : +1.0) );
1759 }
1760 }
1761
1762 /* create the <= -1 row with all negative signs */
1763 (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s_3", SCIPconsGetName(cons));
1764 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->rows[3], cons, rowname, -SCIPinfinity(scip), -1.0,
1766 SCIP_CALL( SCIPaddVarsToRowSameCoef(scip, consdata->rows[3], consdata->nvars, consdata->vars, -1.0) );
1767
1768 /* create extra LP row if integer variable exists */
1769 if( consdata->intvar != NULL )
1770 {
1771 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->rows[4], cons, SCIPconsGetName(cons), 1.0, 1.0,
1773 SCIP_CALL( SCIPaddVarToRow(scip, consdata->rows[4], consdata->intvar, -2.0) );
1774 SCIP_CALL( SCIPaddVarsToRowSameCoef(scip, consdata->rows[4], consdata->nvars, consdata->vars, 1.0) );
1775 }
1776 }
1777
1778 return SCIP_OKAY;
1779}
1780
1781/** adds linear relaxation of or constraint to the LP */
1782static
1784 SCIP* scip, /**< SCIP data structure */
1785 SCIP_CONS* cons, /**< constraint to check */
1786 SCIP_Bool* infeasible /**< pointer to store whether infeasibility was detected */
1787 )
1788{
1789 SCIP_CONSDATA* consdata;
1790 int r;
1791
1792 consdata = SCIPconsGetData(cons);
1793 assert(consdata != NULL);
1794 assert(infeasible != NULL);
1795 assert(!(*infeasible));
1796
1797 if( consdata->rows[0] == NULL )
1798 {
1800 }
1801 assert(consdata->rows[0] != NULL);
1802 for( r = 0; r < NROWS && !(*infeasible); ++r )
1803 {
1804 if( consdata->rows[r] != NULL && !SCIProwIsInLP(consdata->rows[r]) )
1805 {
1806 SCIP_CALL( SCIPaddRow(scip, consdata->rows[r], FALSE, infeasible) );
1807 }
1808 }
1809
1810 return SCIP_OKAY;
1811}
1812
1813/** returns whether all rows of the LP relaxation are in the current LP */
1814static
1816 SCIP_CONSDATA* consdata /**< constraint data */
1817 )
1818{
1819 assert(consdata != NULL);
1820
1821 if( consdata->rows[0] == NULL ) /* LP relaxation does not exist */
1822 return FALSE;
1823 else
1824 {
1825 int r;
1826 for( r = 0; r < NROWS; ++r )
1827 {
1828 if( consdata->rows[r] != NULL && !SCIProwIsInLP(consdata->rows[r]) )
1829 return FALSE;
1830 }
1831 return TRUE;
1832 }
1833}
1834
1835/** checks xor constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
1836static
1838 SCIP* scip, /**< SCIP data structure */
1839 SCIP_CONS* cons, /**< constraint to check */
1840 SCIP_SOL* sol, /**< solution to check, NULL for current solution */
1841 SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */
1842 SCIP_Bool printreason, /**< Should the reason for the violation be printed? */
1843 SCIP_Bool* violated /**< pointer to store whether the constraint is violated */
1844 )
1845{
1846 SCIP_CONSDATA* consdata;
1847
1848 assert(violated != NULL);
1849
1850 consdata = SCIPconsGetData(cons);
1851 assert(consdata != NULL);
1852
1853 *violated = FALSE;
1854
1855 /* check feasibility of constraint if necessary */
1856 if( checklprows || !allRowsInLP(consdata) )
1857 {
1858 SCIP_Real maxcenval = 0.0;
1859 SCIP_Real sumcenval = 0.0;
1860 SCIP_Real sumsolval = 0.0;
1861 SCIP_Real cenval;
1862 SCIP_Real solval;
1863 SCIP_Real viol;
1864 SCIP_Bool odd = consdata->rhs;
1865 int ones = 0;
1866 int i;
1867
1868 /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
1869 * enforcement
1870 */
1871 if( sol == NULL )
1872 {
1873 SCIP_CALL( SCIPincConsAge(scip, cons) );
1874 }
1875
1876 /* evaluate operator variables */
1877 for( i = 0; i < consdata->nvars; ++i )
1878 {
1879 solval = SCIPgetSolVal(scip, sol, consdata->vars[i]);
1880
1881 if( solval > 0.5 )
1882 {
1883 odd = !odd;
1884 ++ones;
1885 cenval = 1.0 - solval;
1886 }
1887 else
1888 cenval = solval;
1889
1890 if( maxcenval < cenval )
1891 maxcenval = cenval;
1892
1893 sumcenval += cenval;
1894 sumsolval += solval;
1895 }
1896
1897 /* the center value sum is the additive distance to the nearest integral solution infeasible if odd
1898 * and otherwise the additive distance to the next nearest integral solution infeasible must be at least one
1899 * see separateCons() for further intuition
1900 */
1901 viol = MAX(0.0, (odd ? 1.0 : 2.0 * maxcenval) - sumcenval);
1902
1903 /* additionally check linear feasibility of an existing integer variable */
1904 if( consdata->intvar != NULL )
1905 {
1906 solval = REALABS(sumsolval - 2 * SCIPgetSolVal(scip, sol, consdata->intvar) - (SCIP_Real)consdata->rhs);
1907
1908 if( viol < solval )
1909 viol = solval;
1910 }
1911
1912 if( SCIPisFeasPositive(scip, viol) )
1913 {
1914 *violated = TRUE;
1915
1916 /* only reset constraint age if we are in enforcement */
1917 if( sol == NULL )
1918 {
1920 }
1921
1922 if( printreason )
1923 {
1924 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
1925 SCIPinfoMessage(scip, NULL, ";\n");
1926 SCIPinfoMessage(scip, NULL, "violation: %d operands are set to TRUE ", ones);
1927
1928 if( consdata->intvar == NULL )
1929 SCIPinfoMessage(scip, NULL, "and all sum up to %g\n", sumsolval);
1930 else
1931 SCIPinfoMessage(scip, NULL, "but integer variable is %g\n", SCIPgetSolVal(scip, sol, consdata->intvar));
1932 }
1933 }
1934
1935 /* update constraint violation in solution */
1936 if( sol != NULL )
1937 SCIPupdateSolConsViolation(scip, sol, viol, viol);
1938 }
1939
1940 return SCIP_OKAY;
1941}
1942
1943/** separates current LP solution
1944 *
1945 * Consider a XOR-constraint
1946 * \f[
1947 * x_1 \oplus x_2 \oplus \dots \oplus x_n = b
1948 * \f]
1949 * with \f$b \in \{0,1\}\f$ and a solution \f$x^*\f$ to be cut off. Small XOR constraints are handled by adding the
1950 * inequalities of the convex hull.
1951 *
1952 * The separation of larger XOR constraints has been described by @n
1953 * Xiaojie Zhang and Paul H. Siegel@n
1954 * "Adaptive Cut Generation Algorithm for Improved Linear Programming Decoding of Binary Linear Codes"@n
1955 * IEEE Transactions on Information Theory, vol. 58, no. 10, 2012
1956 *
1957 * We separate the inequalities
1958 * \f[
1959 * \sum_{j \in S} (1 - x_j) + \sum_{j \notin S} x_j \geq 1
1960 * \f]
1961 * with \f$|S| \equiv (b+1) \mbox{ mod } 2\f$ as follows. That these inequalities are valid can be seen as follows: Let
1962 * \f$x\f$ be a feasible solution and suppose that the inequality is violated for some \f$S\f$. Then \f$x_j = 1\f$ for
1963 * all \f$j \in S\f$ and \f$x_j = 0\f$ for all \f$j \notin S\f$. Thus we should have
1964 * \f[
1965 * \oplus_{j \in S} x_j = |S| \mbox{ mod } 2 = b+1 \mbox{ mod } 2,
1966 * \f]
1967 * which is not equal to \f$b\f$ as required by the XOR-constraint.
1968 *
1969 * Let \f$L= \{j \;:\; x^*_j > \frac{1}{2}\}\f$. Suppose that \f$|L|\f$ has @em not the same parity as \f$b\f$ rhs. Then
1970 * \f[
1971 * \sum_{j \in L} (1 - x_j) + \sum_{j \notin L} x_j \geq 1
1972 * \f]
1973 * is the only inequality that can be violated. We rewrite the inequality as
1974 * \f[
1975 * \sum_{j \in L} x_j - \sum_{j \notin L} x_j \leq |L| - 1.
1976 * \f]
1977 * These inequalities are added.
1978 *
1979 * Otherwise let \f$k = \mbox{argmin}\{x^*_j \;:\; j \in L\}\f$ and check the inequality for \f$L \setminus \{k\}\f$
1980 * and similarly for \f$k = \mbox{argmax}\{x^*_j \;:\; j \in L\}\f$.
1981 */
1982static
1984 SCIP* scip, /**< SCIP data structure */
1985 SCIP_CONS* cons, /**< constraint to check */
1986 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
1987 SCIP_Bool separateparity, /**< should parity inequalities be separated? */
1988 SCIP_Bool* separated, /**< pointer to store whether a cut was found */
1989 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
1990 )
1991{
1992 SCIP_CONSDATA* consdata;
1993 SCIP_Real feasibility;
1994 int r;
1995
1996 assert(separated != NULL);
1997 assert(cutoff != NULL);
1998 *cutoff = FALSE;
1999
2000 consdata = SCIPconsGetData(cons);
2001 assert(consdata != NULL);
2002
2003 *separated = FALSE;
2004
2005 /* create row for the linear relaxation */
2006 if( consdata->rows[0] == NULL )
2007 {
2009 }
2010 assert(consdata->rows[0] != NULL);
2011
2012 /* test rows for feasibility and add it, if it is infeasible */
2013 for( r = 0; r < NROWS; ++r )
2014 {
2015 if( consdata->rows[r] != NULL && !SCIProwIsInLP(consdata->rows[r]) )
2016 {
2017 feasibility = SCIPgetRowSolFeasibility(scip, consdata->rows[r], sol);
2018 if( SCIPisFeasNegative(scip, feasibility) )
2019 {
2020 SCIP_CALL( SCIPaddRow(scip, consdata->rows[r], FALSE, cutoff) );
2021 if( *cutoff )
2022 return SCIP_OKAY;
2023 *separated = TRUE;
2024 }
2025 }
2026 }
2027
2028 /* separate parity inequalities if required */
2029 if( separateparity && consdata->nvars > 3 )
2030 {
2031 char name[SCIP_MAXSTRLEN];
2032 SCIP_Real maxval = -1.0;
2033 SCIP_Real minval = 2.0;
2034 SCIP_Real sum = 0.0;
2035 int maxidx = -1;
2036 int minidx = -1;
2037 int ngen = 0;
2038 int cnt = 0;
2039 int j;
2040
2041 SCIPdebugMsg(scip, "separating parity inequalities ...\n");
2042
2043 /* compute value */
2044 for( j = 0; j < consdata->nvars; ++j )
2045 {
2046 SCIP_Real val;
2047
2048 val = SCIPgetSolVal(scip, sol, consdata->vars[j]);
2049 if( val > 0.5 )
2050 {
2051 if( val < minval )
2052 {
2053 minval = val;
2054 minidx = j;
2055 }
2056 ++cnt;
2057 sum += (1.0 - val);
2058 }
2059 else
2060 {
2061 if( val > maxval )
2062 {
2063 maxval = val;
2064 maxidx = j;
2065 }
2066 sum += val;
2067 }
2068 }
2069
2070 /* if size of set does not have the same parity as rhs (e.g., size is odd if rhs is 0) */
2071 if( (cnt - (int) consdata->rhs) % 2 == 1 )
2072 {
2073 if( SCIPisEfficacious(scip, 1.0 - sum) )
2074 {
2075 SCIP_ROW* row;
2076
2077 SCIPdebugMsg(scip, "found violated parity cut (efficiacy: %f)\n", 1.0 - sum);
2078
2079 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "parity#%s", SCIPconsGetName(cons));
2080 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real) (cnt - 1), FALSE, FALSE, TRUE) );
2082
2083 /* fill in row */
2084 for( j = 0; j < consdata->nvars; ++j )
2085 {
2086 if( SCIPgetSolVal(scip, sol, consdata->vars[j]) > 0.5 )
2087 {
2088 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], 1.0) );
2089 }
2090 else
2091 {
2092 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], -1.0) );
2093 }
2094 }
2099 SCIP_CALL( SCIPreleaseRow(scip, &row) );
2100 ++ngen;
2101 }
2102 }
2103 else
2104 {
2105 /* If the parity is equal: check removing the element with smallest value from the set and adding the
2106 * element with largest value to the set. If we remove the element with smallest value, we have to subtract (1
2107 * - minval) and add minval to correct the sum. */
2108 if( SCIPisEfficacious(scip, 1.0 - (sum - 1.0 + 2.0 * minval)) )
2109 {
2110 SCIP_ROW* row;
2111
2112 SCIPdebugMsg(scip, "found violated parity cut (efficiacy: %f, minval: %f)\n", 1.0 - (sum - 1.0 + 2.0 * minval), minval);
2113
2114 /* the rhs of the inequality is the corrected set size minus 1 */
2115 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "parity#%s", SCIPconsGetName(cons));
2116 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real) (cnt - 2), FALSE, FALSE, TRUE) );
2118
2119 /* fill in row */
2120 for( j = 0; j < consdata->nvars; ++j )
2121 {
2122 if( SCIPgetSolVal(scip, sol, consdata->vars[j]) > 0.5 )
2123 {
2124 /* if the index corresponds to the smallest element, we reverse the sign */
2125 if( j == minidx )
2126 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], -1.0) );
2127 else
2128 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], 1.0) );
2129 }
2130 else
2131 {
2132 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], -1.0) );
2133 }
2134 }
2139 SCIP_CALL( SCIPreleaseRow(scip, &row) );
2140 ++ngen;
2141 }
2142
2143 /* If we add the element with largest value, we have to add (1 - maxval) and subtract maxval to get the correct sum. */
2144 if( SCIPisEfficacious(scip, 1.0 - (sum + 1.0 - 2.0 * maxval)) )
2145 {
2146 SCIP_ROW* row;
2147
2148 SCIPdebugMsg(scip, "found violated parity cut (efficiacy: %f, maxval: %f)\n", 1.0 - (sum + 1.0 - 2.0 * maxval), maxval);
2149
2150 /* the rhs of the inequality is the size of the corrected set */
2151 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "parity#%s", SCIPconsGetName(cons));
2152 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real) cnt, FALSE, FALSE, TRUE) );
2154
2155 /* fill in row */
2156 for( j = 0; j < consdata->nvars; ++j )
2157 {
2158 if( SCIPgetSolVal(scip, sol, consdata->vars[j]) > 0.5 )
2159 {
2160 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], 1.0) );
2161 }
2162 else
2163 {
2164 /* if the index corresponds to the largest element, we reverse the sign */
2165 if( j == maxidx )
2166 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], 1.0) );
2167 else
2168 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], -1.0) );
2169 }
2170 }
2175 SCIP_CALL( SCIPreleaseRow(scip, &row) );
2176 ++ngen;
2177 }
2178 }
2179
2180 SCIPdebugMsg(scip, "separated parity inequalites: %d\n", ngen);
2181 if( ngen > 0 )
2182 *separated = TRUE;
2183 }
2184
2185 return SCIP_OKAY;
2186}
2187
2188/** Transform linear system \f$A x = b\f$ into row echelon form via the Gauss algorithm with row pivoting over GF2
2189 * @returns the rank of @p A
2190 *
2191 * Here, \f$A \in R^{m \times n},\; b \in R^m\f$. On exit, the vector @p p contains a permutation of the row indices
2192 * used for pivoting and the function returns the rank @p r of @p A. For each row \f$i = 1, \ldots, r\f$, the entry @p
2193 * s[i] contains the column index of the first nonzero in row @p i.
2194 */
2195static
2197 SCIP* scip, /**< SCIP data structure */
2198 int m, /**< number of rows */
2199 int n, /**< number of columns */
2200 int* p, /**< row permutation */
2201 int* s, /**< steps indicators of the row echelon form */
2202 Type** A, /**< matrix */
2203 Type* b /**< rhs */
2204 )
2205{
2206 int pi;
2207 int i;
2208 int j;
2209 int k;
2210
2211 assert(A != NULL);
2212 assert(b != NULL);
2213 assert(p != NULL);
2214 assert(s != NULL);
2215
2216 /* init permutation and step indicators */
2217 for( i = 0; i < m; ++i )
2218 {
2219 p[i] = i;
2220 s[i] = i;
2221 }
2222
2223 /* loop through possible steps in echelon form (stop at min {n, m}) */
2224 for( i = 0; i < m && i < n; ++i )
2225 {
2226 assert(s[i] == i);
2227
2228 /* init starting column */
2229 if( i == 0 )
2230 j = 0;
2231 else
2232 j = s[i-1] + 1;
2233
2234 /* find pivot row (i.e., first nonzero entry), if all entries in current row are 0 we search the next column */
2235 do
2236 {
2237 /* search in current column j */
2238 k = i;
2239 while( k < m && A[p[k]][j] == 0 )
2240 ++k;
2241
2242 /* found pivot */
2243 if( k < m )
2244 break;
2245
2246 /* otherwise search next column */
2247 ++j;
2248 }
2249 while( j < n );
2250
2251 /* if not pivot entry was found (checked all columns), the rank of A is equal to the current index i; in this case
2252 * all entries in and below row i are 0 */
2253 if( j >= n )
2254 return i;
2255
2256 /* at this place: we have found a pivot entry (p[k], j) */
2257 assert(k < m);
2258
2259 /* store step index */
2260 s[i] = j;
2261 assert(A[p[k]][j] != 0);
2262
2263 /* swap row indices */
2264 if( k != i )
2265 {
2266 int h = p[i];
2267 p[i] = p[k];
2268 p[k] = h;
2269 }
2270 pi = p[i];
2271 assert(A[pi][s[i]] != 0);
2272
2273 /* do elimination */
2274 for( k = i+1; k < m; ++k )
2275 {
2276 int pk = p[k];
2277 /* if entry in leading column is nonzero (otherwise we already have a 0) */
2278 if( A[pk][s[i]] != 0 )
2279 {
2280 for( j = s[i]; j < n; ++j )
2281 A[pk][j] = A[pk][j] ^ A[pi][j]; /*lint !e732*/
2282 b[pk] = b[pk] ^ b[pi]; /*lint !e732*/
2283 }
2284 }
2285
2286 /* check stopped (only every 100 rows in order to save time */
2287 if( i % 100 == 99 )
2288 {
2289 if( SCIPisStopped(scip) )
2290 return -1;
2291 }
2292 }
2293
2294 /* at this point we have treated all rows in which a step can occur; the rank is the minimum of the number of rows or
2295 * columns min {n,m}. */
2296 if( n <= m )
2297 return n;
2298 return m;
2299}
2300
2301/** Construct solution from matrix in row echelon form over GF2
2302 *
2303 * Compute solution of \f$A x = b\f$, which is already in row echelon form (@see computeRowEchelonGF2()) */
2304static
2306 int m, /**< number of rows */
2307 int n, /**< number of columns */
2308 int r, /**< rank of matrix */
2309 int* p, /**< row permutation */
2310 int* s, /**< steps indicators of the row echelon form */
2311 Type** A, /**< matrix */
2312 Type* b, /**< rhs */
2313 Type* x /**< solution vector on exit */
2314 )
2315{
2316 int i;
2317 int k;
2318
2319 assert(A != NULL);
2320 assert(b != NULL);
2321 assert(s != NULL);
2322 assert(p != NULL);
2323 assert(x != NULL);
2324 assert(r <= m && r <= n);
2325
2326 /* init solution vector to 0 */
2327 for( k = 0; k < n; ++k )
2328 x[k] = 0;
2329
2330 /* loop backwards through solution vector */
2331 for( i = r-1; i >= 0; --i )
2332 {
2333 Type val;
2334
2335 assert(i <= s[i] && s[i] <= n);
2336
2337 /* init val with rhs and then add the contributions of the components of x already computed */
2338 val = b[p[i]];
2339 for( k = i+1; k < r; ++k )
2340 {
2341 assert(i <= s[k] && s[k] <= n);
2342 if( A[p[i]][s[k]] != 0 )
2343 val = val ^ x[s[k]]; /*lint !e732*/
2344 }
2345
2346 /* store solution */
2347 x[s[i]] = val;
2348 }
2349}
2350
2351/** solve equation system over GF 2 by Gauss algorithm and create solution out of it or return cutoff
2352 *
2353 * Collect all information in xor constraints into a linear system over GF2. Then solve the system by computing a row
2354 * echelon form. If the system is infeasible, the current node is infeasible. Otherwise, we can compute a solution for
2355 * the xor constraints given. We check whether this gives a solution for the whole problem.
2356 *
2357 * We sort the columns with respect to the product of the objective coefficients and 1 minus the current LP solution
2358 * value. The idea is that columns that are likely to provide the steps in the row echelon form should appear towards
2359 * the front of the matrix. The smaller the product, the more it makes sense to set the variable to 1 (because the
2360 * solution value is already close to 1 and the objective function is small).
2361 *
2362 * Note that this function is called from propagation where usually no solution is available. However, the solution is
2363 * only used for sorting the columns. Thus, the procedure stays correct even with nonsense solutions.
2364 */
2365static
2367 SCIP* scip, /**< SCIP data structure */
2368 SCIP_CONS** conss, /**< xor constraints */
2369 int nconss, /**< number of xor constraints */
2370 SCIP_SOL* currentsol, /**< current solution (maybe NULL) */
2371 SCIP_RESULT* result /**< result of propagation (possibly cutoff, no change if primal solution has been tried) */
2372 )
2373{
2374 SCIP_CONSDATA* consdata;
2375 SCIP_HASHMAP* varhash;
2376 SCIP_Bool* xoractive;
2377 SCIP_Real* xorvals;
2378 SCIP_VAR** xorvars;
2379 SCIP_Bool noaggr = TRUE;
2380 Type** A;
2381 Type* b;
2382 int* s;
2383 int* p;
2384 int* xoridx;
2385 int* xorbackidx;
2386 int nconssactive = 0;
2387 int nconssmat = 0;
2388 int nvarsmat = 0;
2389 int nvars;
2390 int rank;
2391 int i;
2392 int j;
2393
2394 assert(scip != NULL);
2395 assert(conss != NULL);
2396 assert(result != NULL);
2397
2398 if( *result == SCIP_CUTOFF )
2399 return SCIP_OKAY;
2400
2401 SCIPdebugMsg(scip, "Checking feasibility via the linear equation system over GF2 using Gauss.\n");
2402
2404
2405 /* set up hash map from variable to column index */
2407 SCIP_CALL( SCIPallocBufferArray(scip, &xoractive, nconss) );
2411
2412 /* collect variables */
2413 for( i = 0; i < nconss; ++i )
2414 {
2415 int cnt = 0;
2416
2417 xoractive[i] = FALSE;
2418
2419 assert(conss[i] != NULL);
2420 consdata = SCIPconsGetData(conss[i]);
2421 assert(consdata != NULL);
2422
2423 /* count nonfixed variables in constraint */
2424 for( j = 0; j < consdata->nvars; ++j )
2425 {
2426 SCIP_VAR* var;
2427
2428 var = consdata->vars[j];
2429 assert(var != NULL);
2431
2432 /* replace negated variables */
2433 if( SCIPvarIsNegated(var) )
2435 assert(var != NULL);
2436
2437 /* get the active variable */
2440 /* consider nonfixed variables */
2441 if( var != NULL && SCIPcomputeVarLbLocal(scip, var) < 0.5 && SCIPcomputeVarUbLocal(scip, var) > 0.5 )
2442 {
2443 /* consider active variables and collect only new ones */
2444 if( SCIPvarIsActive(var) && !SCIPhashmapExists(varhash, var) )
2445 {
2446 /* add variable in map */
2447 SCIP_CALL( SCIPhashmapInsertInt(varhash, var, nvarsmat) );
2448 assert(nvarsmat == SCIPhashmapGetImageInt(varhash, var));
2449 xorvals[nvarsmat] = SCIPvarGetObj(var) * (1.0 - SCIPgetSolVal(scip, currentsol, var));
2450 xorvars[nvarsmat++] = var;
2451 }
2452 ++cnt;
2453 }
2454 }
2455
2456 if( cnt > 0 )
2457 {
2458 xoractive[i] = TRUE;
2459 ++nconssactive;
2460 }
2461#ifdef SCIP_DISABLED_CODE
2462 /* The following can save time, if there are constraints with all variables fixed that are infeasible; this
2463 * should, however, be detected somewhere else, e.g., in propagateCons(). */
2464 else
2465 {
2466 /* all variables are fixed - check whether constraint is feasible (could be that the constraint is not propagated) */
2467 assert(cnt == 0);
2468 for( j = 0; j < consdata->nvars; ++j )
2469 {
2470 /* count variables fixed to 1 */
2471 if( SCIPcomputeVarLbLocal(scip, consdata->vars[j]) > 0.5 )
2472 ++cnt;
2473 else
2474 assert(SCIPcomputeVarUbLocal(scip, consdata->vars[j]) < 0.5);
2475 }
2476 if( ( cnt - consdata->rhs ) % 2 != 0 )
2477 {
2478 SCIPdebugMsg(scip, "constraint <%s> with all variables fixed is violated.\n", SCIPconsGetName(conss[i]));
2480 break;
2481 }
2482 }
2483#endif
2484 }
2485 assert(nvarsmat <= nvars);
2486 assert(nconssactive <= nconss);
2487
2488 if( nconssactive > MAXXORCONSSSYSTEM || nvarsmat > MAXXORVARSSYSTEM || *result == SCIP_CUTOFF )
2489 {
2490 SCIPdebugMsg(scip, "Skip checking the xor system over GF2 (%d conss, %d vars).\n", nconssactive, nvarsmat);
2491 SCIPfreeBufferArray(scip, &xorvals);
2492 SCIPfreeBufferArray(scip, &xoridx);
2493 SCIPfreeBufferArray(scip, &xorvars);
2494 SCIPfreeBufferArray(scip, &xoractive);
2495 SCIPhashmapFree(&varhash);
2496 return SCIP_OKAY;
2497 }
2498
2499 /* init index */
2500 for( j = 0; j < nvarsmat; ++j )
2501 xoridx[j] = j;
2502
2503 /* Sort variables non-decreasingly with respect to product of objective and 1 minus the current solution value: the
2504 * smaller the value the better it would be to set the variable to 1. This is more likely if the variable appears
2505 * towards the front of the matrix, because only the entries on the steps in the row echelon form will have the
2506 * chance to be nonzero.
2507 */
2508 SCIPsortRealIntPtr(xorvals, xoridx, (void**) xorvars, nvarsmat);
2509 SCIPfreeBufferArray(scip, &xorvals);
2510
2511 /* build back index */
2512 SCIP_CALL( SCIPallocBufferArray(scip, &xorbackidx, nvarsmat) );
2513 for( j = 0; j < nvarsmat; ++j )
2514 {
2515 assert(0 <= xoridx[j] && xoridx[j] < nvarsmat);
2516 xorbackidx[xoridx[j]] = j;
2517 }
2518
2519 /* init matrix and rhs */
2520 SCIP_CALL( SCIPallocBufferArray(scip, &b, nconssactive) );
2521 SCIP_CALL( SCIPallocBufferArray(scip, &A, nconssactive) );
2522 for( i = 0; i < nconss; ++i )
2523 {
2524 if( !xoractive[i] )
2525 continue;
2526
2527 assert(conss[i] != NULL);
2528 consdata = SCIPconsGetData(conss[i]);
2529 assert(consdata != NULL);
2530 assert(consdata->nvars > 0);
2531
2532 SCIP_CALL( SCIPallocBufferArray(scip, &(A[nconssmat]), nvarsmat) ); /*lint !e866*/
2533 BMSclearMemoryArray(A[nconssmat], nvarsmat); /*lint !e866*/
2534
2535 /* correct rhs w.r.t. to fixed variables and count nonfixed variables in constraint */
2536 b[nconssmat] = (Type) consdata->rhs;
2537 for( j = 0; j < consdata->nvars; ++j )
2538 {
2539 SCIP_VAR* var;
2540 int idx;
2541
2542 var = consdata->vars[j];
2543 assert(var != NULL);
2544
2545 /* replace negated variables */
2546 if( SCIPvarIsNegated(var) )
2547 {
2549 assert(var != NULL);
2550 b[nconssmat] = !b[nconssmat];
2551 }
2552
2553 /* replace aggregated variables */
2555 {
2556 SCIP_Real scalar;
2557 SCIP_Real constant;
2558
2559 scalar = SCIPvarGetAggrScalar(var);
2560 constant = SCIPvarGetAggrConstant(var);
2561
2562 /* the variable resolves to a constant, we just update the rhs */
2563 if( SCIPisEQ(scip, scalar, 0.0) )
2564 {
2565 assert(SCIPisEQ(scip, constant, 0.0) || SCIPisEQ(scip, constant, 1.0));
2566 if( SCIPisEQ(scip, constant, 1.0) )
2567 b[nconssmat] = !b[nconssmat];
2568 var = NULL;
2569 break;
2570 }
2571 /* replace aggregated variable by active variable and update rhs, if needed */
2572 else
2573 {
2574 assert(SCIPisEQ(scip, scalar, 1.0) || SCIPisEQ(scip, scalar, -1.0));
2575 if( SCIPisEQ(scip, constant, 1.0) )
2576 b[nconssmat] = !b[nconssmat];
2577
2579 assert(var != NULL);
2580 }
2581 }
2582 /* variable resolved to a constant */
2583 if( var == NULL )
2584 continue;
2585
2586 /* If the constraint contains multiaggregated variables, the solution might not be valid, since the
2587 * implications are not represented in the matrix.
2588 */
2590 noaggr = FALSE;
2591
2592 if( SCIPcomputeVarLbLocal(scip, var) > 0.5 )
2593 {
2594 /* variable is fixed to 1, invert rhs */
2595 b[nconssmat] = !b[nconssmat];
2596 assert(!SCIPhashmapExists(varhash, var));
2597 }
2598 else
2599 {
2603 {
2604 assert(SCIPhashmapExists(varhash, var));
2605 idx = SCIPhashmapGetImageInt(varhash, var);
2606 assert(idx >= 0);
2607 assert(idx < nvarsmat);
2608 idx = xorbackidx[idx];
2609 assert(idx >= 0);
2610 assert(idx < nvarsmat);
2611 A[nconssmat][idx] = !A[nconssmat][idx];
2612 }
2613 }
2614 }
2615 ++nconssmat;
2616 }
2617 SCIPdebugMsg(scip, "Found %d non-fixed variables in %d nonempty xor constraints.\n", nvarsmat, nconssmat);
2618 assert(nconssmat == nconssactive);
2619
2620 /* perform Gauss algorithm */
2621 SCIP_CALL( SCIPallocBufferArray(scip, &p, nconssmat) );
2622 SCIP_CALL( SCIPallocBufferArray(scip, &s, nconssmat) );
2623
2624#ifdef SCIP_OUTPUT
2625 SCIPinfoMessage(scip, NULL, "Matrix before Gauss (size: %d x %d):\n", nconssmat, nvarsmat);
2626 for( i = 0; i < nconssmat; ++i )
2627 {
2628 for( j = 0; j < nvarsmat; ++j )
2629 SCIPinfoMessage(scip, NULL, "%d ", A[i][j]);
2630 SCIPinfoMessage(scip, NULL, " = %d\n", b[i]);
2631 }
2632 SCIPinfoMessage(scip, NULL, "\n");
2633#endif
2634
2635 rank = -1;
2636 if( !SCIPisStopped(scip) )
2637 {
2638 rank = computeRowEchelonGF2(scip, nconssmat, nvarsmat, p, s, A, b);
2639 assert(rank <= nconssmat && rank <= nvarsmat);
2640 }
2641
2642 /* rank is < 0 if the solution process has been stopped */
2643 if( rank >= 0 )
2644 {
2645#ifdef SCIP_OUTPUT
2646 SCIPinfoMessage(scip, NULL, "Matrix after Gauss (rank: %d):\n", rank);
2647 for( i = 0; i < nconssmat; ++i )
2648 {
2649 for( j = 0; j < nvarsmat; ++j )
2650 SCIPinfoMessage(scip, NULL, "%d ", A[p[i]][j]);
2651 SCIPinfoMessage(scip, NULL, " = %d\n", b[p[i]]);
2652 }
2653 SCIPinfoMessage(scip, NULL, "\n");
2654#endif
2655
2656 /* check whether system is feasible */
2657 for( i = rank; i < nconssmat; ++i )
2658 {
2659 if( b[p[i]] != 0 )
2660 break;
2661 }
2662
2663 /* did not find nonzero entry in b -> equation system is feasible */
2664 if( i >= nconssmat )
2665 {
2666 SCIPdebugMsg(scip, "System feasible with rank %d (nconss=%d)\n", rank, nconssmat);
2667
2668 /* matrix has full rank, solution is unique */
2669 if( rank == nvarsmat && noaggr )
2670 {
2671 SCIP_Bool tightened;
2672 SCIP_Bool infeasible;
2673 Type* x;
2674
2675 SCIPdebugMsg(scip, "Found unique solution.\n");
2676
2677 /* construct solution */
2678 SCIP_CALL( SCIPallocBufferArray(scip, &x, nvarsmat) );
2679 solveRowEchelonGF2(nconssmat, nvarsmat, rank, p, s, A, b, x);
2680
2681#ifdef SCIP_OUTPUT
2682 SCIPinfoMessage(scip, NULL, "Solution:\n");
2683 for( j = 0; j < nvarsmat; ++j )
2684 SCIPinfoMessage(scip, NULL, "%d ", x[j]);
2685 SCIPinfoMessage(scip, NULL, "\n");
2686#endif
2687
2688 /* fix variables according to computed unique solution */
2689 for( j = 0; j < nvarsmat; ++j )
2690 {
2691 assert(SCIPhashmapGetImageInt(varhash, xorvars[j]) < nvars);
2692 assert(xorbackidx[SCIPhashmapGetImageInt(varhash, xorvars[j])] == j);
2693 assert(SCIPcomputeVarLbLocal(scip, xorvars[j]) < 0.5);
2694 if( x[j] == 0 )
2695 {
2696 SCIP_CALL( SCIPtightenVarUb(scip, xorvars[j], 0.0, FALSE, &infeasible, &tightened) );
2697 assert(tightened);
2698 assert(!infeasible);
2699 }
2700 else
2701 {
2702 assert(x[j] == 1);
2703 SCIP_CALL( SCIPtightenVarLb(scip, xorvars[j], 1.0, FALSE, &infeasible, &tightened) );
2704 assert(tightened);
2705 assert(!infeasible);
2706 }
2707 }
2709 }
2710 /* matrix does not have full rank, we add the solution, but cannot derive fixings */
2711 else
2712 {
2713 SCIP_HEUR* heurtrysol;
2714
2715 SCIPdebugMsg(scip, "Found solution.\n");
2716
2717 /* try solution */
2718 heurtrysol = SCIPfindHeur(scip, "trysol");
2719
2720 if( heurtrysol != NULL )
2721 {
2722 SCIP_Bool success;
2723 SCIP_VAR** vars;
2724 SCIP_SOL* sol;
2725 Type* x;
2726
2727 /* construct solution */
2728 SCIP_CALL( SCIPallocBufferArray(scip, &x, nvarsmat) );
2729 solveRowEchelonGF2(nconssmat, nvarsmat, rank, p, s, A, b, x);
2730
2731#ifdef SCIP_OUTPUT
2732 SCIPinfoMessage(scip, NULL, "Solution:\n");
2733 for( j = 0; j < nvarsmat; ++j )
2734 SCIPinfoMessage(scip, NULL, "%d ", x[j]);
2735 SCIPinfoMessage(scip, NULL, "\n");
2736#endif
2737
2738 /* create solution */
2739 SCIP_CALL( SCIPcreateSol(scip, &sol, heurtrysol) );
2740
2741 /* transfer solution */
2742 for( j = 0; j < nvarsmat; ++j )
2743 {
2744 if( x[j] != 0 )
2745 {
2746 assert(SCIPhashmapGetImageInt(varhash, xorvars[j]) < nvars);
2747 assert(xorbackidx[SCIPhashmapGetImageInt(varhash, xorvars[j])] == j);
2748 assert(SCIPcomputeVarLbLocal(scip, xorvars[j]) < 0.5);
2749 SCIP_CALL( SCIPsetSolVal(scip, sol, xorvars[j], 1.0) );
2750 }
2751 }
2753
2754 /* add *all* variables fixed to 1 */
2756 for( j = 0; j < nvars; ++j )
2757 {
2758 if( SCIPcomputeVarLbLocal(scip, vars[j]) > 0.5 )
2759 {
2760 SCIP_CALL( SCIPsetSolVal(scip, sol, vars[j], 1.0) );
2761 SCIPdebugMsg(scip, "Added fixed variable <%s>.\n", SCIPvarGetName(vars[j]));
2762 }
2763 }
2764
2765 /* correct integral variables if necessary */
2766 for( i = 0; i < nconss; ++i )
2767 {
2768 consdata = SCIPconsGetData(conss[i]);
2769 assert(consdata != NULL);
2770
2771 /* only try for active constraints and integral variable; hope for the best if they are not active */
2772 if( xoractive[i] && consdata->intvar != NULL && SCIPvarIsActive(consdata->intvar) )
2773 {
2774 SCIP_Real val;
2775 int nones = 0;
2776
2777 for( j = 0; j < consdata->nvars; ++j )
2778 {
2779 if( SCIPgetSolVal(scip, sol, consdata->vars[j]) > 0.5 )
2780 ++nones;
2781 }
2782 /* if there are aggregated variables, the solution might not be feasible */
2783 assert(!noaggr || nones % 2 == (int) consdata->rhs);
2784 if( (unsigned int) nones != consdata->rhs )
2785 {
2786 val = (SCIP_Real) (nones - (int) consdata->rhs)/2;
2787 if( SCIPisGE(scip, val, SCIPvarGetLbGlobal(consdata->intvar)) && SCIPisLE(scip, val, SCIPvarGetUbGlobal(consdata->intvar)) )
2788 {
2789 SCIP_CALL( SCIPsetSolVal(scip, sol, consdata->intvar, val) );
2790 }
2791 }
2792 }
2793 }
2795
2796 /* check feasibility of new solution and pass it to trysol heuristic */
2797 SCIP_CALL( SCIPcheckSol(scip, sol, FALSE, FALSE, TRUE, TRUE, TRUE, &success) );
2798 if( success )
2799 {
2800 SCIP_CALL( SCIPheurPassSolAddSol(scip, heurtrysol, sol) );
2801 SCIPdebugMsg(scip, "Creating solution was successful.\n");
2802 }
2803#ifdef SCIP_DEBUG
2804 else
2805 {
2806 /* the solution might not be feasible, because of additional constraints */
2807 SCIPdebugMsg(scip, "Creating solution was not successful.\n");
2808 }
2809#endif
2811 }
2812 }
2813 }
2814 else
2815 {
2817 SCIPdebugMsg(scip, "System not feasible.\n");
2818 }
2819 }
2820
2821 /* free storage */
2824 j = nconssmat - 1;
2825 for( i = nconss - 1; i >= 0 ; --i )
2826 {
2827 consdata = SCIPconsGetData(conss[i]);
2828 assert(consdata != NULL);
2829
2830 if( consdata->nvars == 0 )
2831 continue;
2832
2833 if( !xoractive[i] )
2834 continue;
2835
2836 SCIPfreeBufferArray(scip, &(A[j]));
2837 --j;
2838 }
2841 SCIPfreeBufferArray(scip, &xorbackidx);
2842 SCIPfreeBufferArray(scip, &xoridx);
2843 SCIPfreeBufferArray(scip, &xorvars);
2844 SCIPfreeBufferArray(scip, &xoractive);
2845 SCIPhashmapFree(&varhash);
2846
2847 return SCIP_OKAY;
2848}
2849
2850/** for each variable in the xor constraint, add it to conflict set; for integral variable add corresponding bound */
2851static
2853 SCIP* scip, /**< SCIP data structure */
2854 SCIP_CONS* cons, /**< constraint that inferred the bound change */
2855 SCIP_VAR* infervar, /**< variable that was deduced, or NULL (not equal to integral variable) */
2856 SCIP_BDCHGIDX* bdchgidx, /**< bound change index (time stamp of bound change), or NULL for current time */
2857 PROPRULE proprule /**< propagation rule */
2858 )
2859{
2860 SCIP_CONSDATA* consdata;
2861 SCIP_VAR** vars;
2862 int nvars;
2863 int i;
2864
2865 assert(cons != NULL);
2866
2867 consdata = SCIPconsGetData(cons);
2868 assert(consdata != NULL);
2869 vars = consdata->vars;
2870 nvars = consdata->nvars;
2871
2872 switch( proprule )
2873 {
2874 case PROPRULE_0:
2875 assert(infervar == NULL || infervar == consdata->intvar);
2876
2877 /* the integral variable was fixed, because all variables were fixed */
2878 for( i = 0; i < nvars; ++i )
2879 {
2882 }
2883 break;
2884
2885 case PROPRULE_1:
2886 /* the variable was inferred, because all other variables were fixed */
2887 for( i = 0; i < nvars; ++i )
2888 {
2889 /* add variables that were fixed to 1 before */
2890 if( SCIPgetVarLbAtIndex(scip, vars[i], bdchgidx, FALSE) > 0.5 )
2891 {
2892 assert(SCIPgetVarLbAtIndex(scip, vars[i], bdchgidx, TRUE) > 0.5);
2894 }
2895 /* add variables that were fixed to 0 */
2896 else if( SCIPgetVarUbAtIndex(scip, vars[i], bdchgidx, FALSE) < 0.5 )
2897 {
2898 assert(SCIPgetVarUbAtIndex(scip, vars[i], bdchgidx, TRUE) < 0.5);
2900 }
2901 else
2902 {
2903 /* check changed variable (changed variable is 0 or 1 afterwards) */
2904 assert(vars[i] == infervar);
2905 }
2906 }
2907 break;
2908
2909 case PROPRULE_INTLB:
2910 assert(consdata->intvar != NULL);
2911
2912 if( infervar != consdata->intvar )
2913 {
2914 /* the variable was fixed, because of the lower bound of the integral variable */
2915 SCIP_CALL( SCIPaddConflictLb(scip, consdata->intvar, NULL) );
2916 }
2917 /* to many and the other fixed variables */
2918 for( i = 0; i < nvars; ++i )
2919 {
2920 /* add variables that were fixed to 0 */
2921 if( SCIPgetVarUbAtIndex(scip, vars[i], bdchgidx, FALSE) < 0.5 )
2922 {
2923 assert(SCIPgetVarUbAtIndex(scip, vars[i], bdchgidx, TRUE) < 0.5);
2925 }
2926 }
2927 break;
2928
2929 case PROPRULE_INTUB:
2930 assert(consdata->intvar != NULL);
2931
2932 if( infervar != consdata->intvar )
2933 {
2934 /* the variable was fixed, because of upper bound of the integral variable and the other fixed variables */
2935 SCIP_CALL( SCIPaddConflictUb(scip, consdata->intvar, NULL) );
2936 }
2937 for( i = 0; i < nvars; ++i )
2938 {
2939 /* add variables that were fixed to 1 */
2940 if( SCIPgetVarLbAtIndex(scip, vars[i], bdchgidx, FALSE) > 0.5 )
2941 {
2942 assert(SCIPgetVarLbAtIndex(scip, vars[i], bdchgidx, TRUE) > 0.5);
2944 }
2945 }
2946 break;
2947
2948 case PROPRULE_INVALID:
2949 default:
2950 SCIPerrorMessage("invalid inference information %d in xor constraint <%s>\n", proprule, SCIPconsGetName(cons));
2951 SCIPABORT();
2952 return SCIP_INVALIDDATA; /*lint !e527*/
2953 }
2954
2955 return SCIP_OKAY;
2956}
2957
2958/** analyzes conflicting assignment on given constraint, and adds conflict constraint to problem */
2959static
2961 SCIP* scip, /**< SCIP data structure */
2962 SCIP_CONS* cons, /**< xor constraint that detected the conflict */
2963 SCIP_VAR* infervar, /**< variable that was deduced, or NULL (not equal to integral variable) */
2964 PROPRULE proprule /**< propagation rule */
2965 )
2966{
2967 /* conflict analysis can only be applied in solving stage and if it is applicable */
2969 return SCIP_OKAY;
2970
2971 /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */
2973
2974 /* add bound changes */
2975 SCIP_CALL( addConflictBounds(scip, cons, infervar, NULL, proprule) );
2976
2977 /* analyze the conflict */
2979
2980 return SCIP_OKAY;
2981}
2982
2983/** propagates constraint with the following rules:
2984 * (0) all variables are fixed => can fix integral variable
2985 * (1) all except one variable fixed => fix remaining variable and integral variable
2986 * (2) depending on the amount of fixed binary variables we can tighten the integral variable
2987 * (3) depending on the lower bound of the integral variable one can fix variables to 1
2988 * (4) depending on the upper bound of the integral variable one can fix variables to 0
2989 */
2990static
2992 SCIP* scip, /**< SCIP data structure */
2993 SCIP_CONS* cons, /**< xor constraint to be processed */
2994 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
2995 SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
2996 int* nfixedvars, /**< pointer to add up the number of fixed variables */
2997 int* nchgbds /**< pointer to add up the number of found domain reductions */
2998 )
2999{
3000 SCIP_CONSDATA* consdata;
3001 SCIP_VAR** vars;
3002 SCIP_Bool infeasible;
3003 SCIP_Bool tightened;
3004 SCIP_Bool odd;
3005 SCIP_Bool counted;
3006 int nvars;
3007 int nfixedones;
3008 int nfixedzeros;
3009 int watchedvar1;
3010 int watchedvar2;
3011 int i;
3012
3013 assert(scip != NULL);
3014 assert(cons != NULL);
3015 assert(eventhdlr != NULL);
3016 assert(cutoff != NULL);
3017 assert(nfixedvars != NULL);
3018 assert(nchgbds != NULL);
3019
3020 /* propagation can only be applied, if we know all operator variables */
3021 if( SCIPconsIsModifiable(cons) )
3022 return SCIP_OKAY;
3023
3024 consdata = SCIPconsGetData(cons);
3025 assert(consdata != NULL);
3026
3027 vars = consdata->vars;
3028 nvars = consdata->nvars;
3029
3030 /* don't process the constraint, if the watched variables weren't fixed to any value since last propagation call */
3031 if( consdata->propagated )
3032 return SCIP_OKAY;
3033
3034 /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
3036 {
3037 SCIP_CALL( SCIPincConsAge(scip, cons) );
3038 }
3039
3040 /* propagation cannot be applied, if we have at least two unfixed variables left;
3041 * that means, we only have to watch (i.e. capture events) of two variables, and switch to other variables
3042 * if these ones get fixed
3043 */
3044 watchedvar1 = consdata->watchedvar1;
3045 watchedvar2 = consdata->watchedvar2;
3046
3047 /* check, if watched variables are still unfixed */
3048 if( watchedvar1 != -1 )
3049 {
3050 if( SCIPvarGetLbLocal(vars[watchedvar1]) > 0.5 || SCIPvarGetUbLocal(vars[watchedvar1]) < 0.5 )
3051 watchedvar1 = -1;
3052 }
3053 if( watchedvar2 != -1 )
3054 {
3055 if( SCIPvarGetLbLocal(vars[watchedvar2]) > 0.5 || SCIPvarGetUbLocal(vars[watchedvar2]) < 0.5 )
3056 watchedvar2 = -1;
3057 }
3058
3059 /* if only one watched variable is still unfixed, make it the first one */
3060 if( watchedvar1 == -1 )
3061 {
3062 watchedvar1 = watchedvar2;
3063 watchedvar2 = -1;
3064 }
3065 assert(watchedvar1 != -1 || watchedvar2 == -1);
3066
3067 /* if the watched variables are invalid (fixed), find new ones if existing; count the parity */
3068 odd = consdata->rhs;
3069 nfixedones = 0;
3070 nfixedzeros = 0;
3071 counted = FALSE;
3072 if( watchedvar2 == -1 )
3073 {
3074 for( i = 0; i < nvars; ++i )
3075 {
3076 if( SCIPvarGetLbLocal(vars[i]) > 0.5 )
3077 {
3078 odd = !odd;
3079 ++nfixedones;
3080 }
3081 else if( SCIPvarGetUbLocal(vars[i]) < 0.5 )
3082 ++nfixedzeros;
3083 else
3084 {
3085 assert(SCIPvarGetUbLocal(vars[i]) > 0.5);
3086 assert(SCIPvarGetLbLocal(vars[i]) < 0.5);
3087
3088 if( watchedvar1 == -1 )
3089 {
3090 assert(watchedvar2 == -1);
3091 watchedvar1 = i;
3092 }
3093 else if( watchedvar2 == -1 && watchedvar1 != i )
3094 {
3095 watchedvar2 = i;
3096 }
3097 }
3098 }
3099 counted = TRUE;
3100 }
3101 assert(watchedvar1 != -1 || watchedvar2 == -1);
3102
3103 /* if all variables are fixed, we can decide the feasibility of the constraint */
3104 if( watchedvar1 == -1 )
3105 {
3106 assert(watchedvar2 == -1);
3107 assert(counted);
3108
3109 if( odd )
3110 {
3111 SCIPdebugMsg(scip, "constraint <%s>: all vars fixed, constraint is infeasible\n", SCIPconsGetName(cons));
3112
3113 /* use conflict analysis to get a conflict constraint out of the conflicting assignment */
3116
3117 *cutoff = TRUE;
3118 }
3119 else
3120 {
3121 /* fix integral variable if present */
3122 if( consdata->intvar != NULL )
3123 {
3124 int fixval;
3125
3126 assert(!*cutoff);
3127 assert((nfixedones - (int) consdata->rhs) % 2 == 0);
3128
3129 fixval = (nfixedones - (int) consdata->rhs)/2; /*lint !e713*/
3130
3131 SCIPdebugMsg(scip, "fix integral variable <%s> to %d\n", SCIPvarGetName(consdata->intvar), fixval);
3132
3133 /* check whether value to fix is outside bounds */
3134 if( fixval + 0.5 < SCIPvarGetLbLocal(consdata->intvar) )
3135 {
3136 /* cannot fix auxiliary variable (maybe it has been branched on): we are infeasible */
3137 SCIPdebugMsg(scip, "node infeasible: activity is %d, bounds of integral variable are [%g,%g]\n",
3138 fixval, SCIPvarGetLbLocal(consdata->intvar), SCIPvarGetUbLocal(consdata->intvar));
3139
3142
3143 *cutoff = TRUE;
3144 }
3145 else if( fixval - 0.5 > SCIPvarGetUbLocal(consdata->intvar) )
3146 {
3147 /* cannot fix auxiliary variable (maybe it has been branched on): we are infeasible */
3148 SCIPdebugMsg(scip, "node infeasible: activity is %d, bounds of integral variable are [%g,%g]\n",
3149 fixval, SCIPvarGetLbLocal(consdata->intvar), SCIPvarGetUbLocal(consdata->intvar));
3150
3153
3154 *cutoff = TRUE;
3155 }
3156 else if( SCIPvarGetStatus(consdata->intvar) != SCIP_VARSTATUS_MULTAGGR )
3157 {
3158 if( !SCIPisEQ(scip, SCIPvarGetLbLocal(consdata->intvar), (SCIP_Real) fixval) )
3159 {
3160 SCIP_CALL( SCIPinferVarLbCons(scip, consdata->intvar, (SCIP_Real) fixval, cons, (int)PROPRULE_0, FALSE, &infeasible, &tightened) );
3161 assert(tightened);
3162 assert(!infeasible);
3163 }
3164
3165 if( !SCIPisEQ(scip, SCIPvarGetUbLocal(consdata->intvar), (SCIP_Real) fixval) )
3166 {
3167 SCIP_CALL( SCIPinferVarUbCons(scip, consdata->intvar, (SCIP_Real) fixval, cons, (int)PROPRULE_0, FALSE, &infeasible, &tightened) );
3168 assert(tightened);
3169 assert(!infeasible);
3170 }
3171
3172 ++(*nfixedvars);
3173 }
3174 }
3175 else
3176 {
3177 SCIPdebugMsg(scip, "constraint <%s>: all vars fixed, constraint is feasible\n", SCIPconsGetName(cons));
3178 }
3179 }
3181
3182 return SCIP_OKAY;
3183 }
3184
3185 /* if only one variable is not fixed, this variable can be deduced */
3186 if( watchedvar2 == -1 )
3187 {
3188 assert(watchedvar1 != -1);
3189 assert(counted);
3190
3191 SCIPdebugMsg(scip, "constraint <%s>: only one unfixed variable -> fix <%s> to %u\n",
3192 SCIPconsGetName(cons), SCIPvarGetName(vars[watchedvar1]), odd);
3193
3194 SCIP_CALL( SCIPinferBinvarCons(scip, vars[watchedvar1], odd, cons, (int)PROPRULE_1, &infeasible, &tightened) );
3195 assert(!infeasible);
3196 assert(tightened);
3197
3198 (*nfixedvars)++;
3199
3200 /* fix integral variable if present and not multi-aggregated */
3201 if( consdata->intvar != NULL && SCIPvarGetStatus(consdata->intvar) != SCIP_VARSTATUS_MULTAGGR )
3202 {
3203 int fixval;
3204
3205 /* if variable has been fixed to 1, adjust number of fixed variables */
3206 if( odd )
3207 ++nfixedones;
3208
3209 assert((nfixedones - (int) consdata->rhs) % 2 == 0);
3210
3211 fixval = (nfixedones - (int) consdata->rhs)/2; /*lint !e713*/
3212 SCIPdebugMsg(scip, "should fix integral variable <%s> to %d\n", SCIPvarGetName(consdata->intvar), fixval);
3213
3214 /* check whether value to fix is outside bounds */
3215 if( fixval + 0.5 < SCIPvarGetLbLocal(consdata->intvar) )
3216 {
3217 /* cannot fix auxiliary variable (maybe it has been branched on): we are infeasible */
3218 SCIPdebugMsg(scip, "node infeasible: activity is %d, bounds of integral variable are [%g,%g]\n",
3219 fixval, SCIPvarGetLbLocal(consdata->intvar), SCIPvarGetUbLocal(consdata->intvar));
3220
3223
3224 *cutoff = TRUE;
3225 }
3226 else if( fixval - 0.5 > SCIPvarGetUbLocal(consdata->intvar) )
3227 {
3228 /* cannot fix auxiliary variable (maybe it has been branched on): we are infeasible */
3229 SCIPdebugMsg(scip, "node infeasible: activity is %d, bounds of integral variable are [%g,%g]\n",
3230 fixval, SCIPvarGetLbLocal(consdata->intvar), SCIPvarGetUbLocal(consdata->intvar));
3231
3234
3235 *cutoff = TRUE;
3236 }
3237 else
3238 {
3239 if( SCIPvarGetLbLocal(consdata->intvar) + 0.5 < (SCIP_Real) fixval )
3240 {
3241 SCIP_CALL( SCIPinferVarLbCons(scip, consdata->intvar, (SCIP_Real) fixval, cons, (int)PROPRULE_1, TRUE, &infeasible, &tightened) );
3242 assert(tightened);
3243 assert(!infeasible);
3244 }
3245
3246 if( SCIPvarGetUbLocal(consdata->intvar) - 0.5 > (SCIP_Real) fixval )
3247 {
3248 SCIP_CALL( SCIPinferVarUbCons(scip, consdata->intvar, (SCIP_Real) fixval, cons, (int)PROPRULE_1, TRUE, &infeasible, &tightened) );
3249 assert(tightened);
3250 assert(!infeasible);
3251 }
3252 assert(SCIPisFeasEQ(scip, SCIPvarGetLbLocal(consdata->intvar), SCIPvarGetUbLocal(consdata->intvar)));
3253
3254 ++(*nfixedvars);
3255 }
3256 }
3257
3260
3261 return SCIP_OKAY;
3262 }
3263
3264 /* propagate w.r.t. integral variable */
3265 if( consdata->intvar != NULL && !consdata->deleteintvar )
3266 {
3267 SCIP_Real newlb;
3268 SCIP_Real newub;
3269 int nonesmin;
3270 int nonesmax;
3271
3272 if( !counted )
3273 {
3274 assert(nfixedzeros == 0);
3275 assert(nfixedones == 0);
3276
3277 for( i = 0; i < nvars; ++i )
3278 {
3279 if( SCIPvarGetLbLocal(vars[i]) > 0.5 )
3280 ++nfixedones;
3281 else if( SCIPvarGetUbLocal(vars[i]) < 0.5 )
3282 ++nfixedzeros;
3283 }
3284 }
3285 assert(nfixedones + nfixedzeros < nvars);
3286
3287 assert(SCIPisFeasIntegral(scip, SCIPvarGetLbLocal(consdata->intvar)));
3288 assert(SCIPisFeasIntegral(scip, SCIPvarGetUbLocal(consdata->intvar)));
3289
3290 nonesmin = 2 * (int)(SCIPvarGetLbLocal(consdata->intvar) + 0.5) + (int) consdata->rhs; /*lint !e713*/
3291 nonesmax = 2 * (int)(SCIPvarGetUbLocal(consdata->intvar) + 0.5) + (int) consdata->rhs; /*lint !e713*/
3292
3293 /* the number of possible variables that can get value 1 is less than the minimum bound */
3294 if( nvars - nfixedzeros < nonesmin )
3295 {
3296 SCIPdebugMsg(scip, "constraint <%s>: at most %d variables can take value 1, but there should be at least %d.\n", SCIPconsGetName(cons), nvars - nfixedones, nonesmin);
3297
3300
3301 *cutoff = TRUE;
3302
3303 return SCIP_OKAY;
3304 }
3305
3306 /* the number of variables that are fixed to 1 is larger than the maximum bound */
3307 if( nfixedones > nonesmax )
3308 {
3309 SCIPdebugMsg(scip, "constraint <%s>: at least %d variables are fixed to 1, but there should be at most %d.\n", SCIPconsGetName(cons), nfixedones, nonesmax);
3310
3313
3314 *cutoff = TRUE;
3315
3316 return SCIP_OKAY;
3317 }
3318
3319 if( SCIPvarGetStatus(consdata->intvar) != SCIP_VARSTATUS_MULTAGGR )
3320 {
3321 /* compute new bounds on the integral variable */
3322 newlb = (SCIP_Real)((nfixedones + 1 - (int) consdata->rhs) / 2); /*lint !e653*/
3323 newub = (SCIP_Real)((nvars - nfixedzeros - (int) consdata->rhs) / 2); /*lint !e653*/
3324
3325 /* new lower bound is better */
3326 if( newlb > SCIPvarGetLbLocal(consdata->intvar) + 0.5 )
3327 {
3328 SCIPdebugMsg(scip, "constraint <%s>: propagated lower bound of integral variable <%s> to %g\n", SCIPconsGetName(cons), SCIPvarGetName(consdata->intvar), newlb);
3329 SCIP_CALL( SCIPinferVarLbCons(scip, consdata->intvar, newlb, cons, (int)PROPRULE_INTUB, TRUE, &infeasible, &tightened) );
3330 assert(tightened);
3331 assert(!infeasible);
3332
3333 ++(*nchgbds);
3334
3335 nonesmin = 2 * (int)(SCIPvarGetLbLocal(consdata->intvar) + 0.5) + (int) consdata->rhs; /*lint !e713*/
3336 }
3337
3338 /* new upper bound is better */
3339 if( newub < SCIPvarGetUbLocal(consdata->intvar) - 0.5 )
3340 {
3341 SCIPdebugMsg(scip, "constraint <%s>: propagated upper bound of integral variable <%s> to %g\n", SCIPconsGetName(cons), SCIPvarGetName(consdata->intvar), newub);
3342 SCIP_CALL( SCIPinferVarUbCons(scip, consdata->intvar, newub, cons, (int)PROPRULE_INTLB, TRUE, &infeasible, &tightened) );
3343 assert(tightened);
3344 assert(!infeasible);
3345
3346 ++(*nchgbds);
3347
3348 nonesmax = 2 * (int)(SCIPvarGetUbLocal(consdata->intvar) + 0.5) + (int) consdata->rhs; /*lint !e713*/
3349 }
3350
3351 assert(nvars - nfixedzeros >= nonesmin);
3352 assert(nfixedones <= nonesmax);
3353
3354 /* the number of variables that are free or fixed to 1 is exactly the minimum required -> fix free variables to 1 */
3355 if( nvars - nfixedzeros == nonesmin )
3356 {
3357 SCIPdebugMsg(scip, "constraint <%s>: fix %d free variables to 1 to reach lower bound of %d\n", SCIPconsGetName(cons), nvars - nfixedzeros - nfixedones, nonesmin);
3358
3359 for( i = 0; i < nvars; ++i )
3360 {
3361 if( SCIPvarGetLbLocal(vars[i]) < 0.5 && SCIPvarGetUbLocal(vars[i]) > 0.5 )
3362 {
3363 SCIP_CALL( SCIPinferBinvarCons(scip, vars[i], TRUE, cons, (int)PROPRULE_INTLB, &infeasible, &tightened) );
3364 assert(!infeasible);
3365 assert(tightened);
3366
3367 ++(*nfixedvars);
3368 }
3369 }
3372
3373 return SCIP_OKAY;
3374 }
3375
3376 /* the number of variables that are fixed to 1 is exactly the maximum required -> fix free variables to 0 */
3377 if( nfixedones == nonesmax )
3378 {
3379 SCIPdebugMsg(scip, "constraint <%s>: fix %d free variables to 0 to guarantee upper bound of %d\n", SCIPconsGetName(cons), nvars - nfixedzeros - nfixedones, nonesmax);
3380
3381 for( i = 0; i < nvars; ++i )
3382 {
3383 if( SCIPvarGetLbLocal(vars[i]) < 0.5 && SCIPvarGetUbLocal(vars[i]) > 0.5 )
3384 {
3385 SCIP_CALL( SCIPinferBinvarCons(scip, vars[i], FALSE, cons, (int)PROPRULE_INTUB, &infeasible, &tightened) );
3386 assert(!infeasible);
3387 assert(tightened);
3388 ++(*nfixedvars);
3389 }
3390 }
3393
3394 return SCIP_OKAY;
3395 }
3396 }
3397 }
3398
3399 /* switch to the new watched variables */
3400 SCIP_CALL( consdataSwitchWatchedvars(scip, consdata, eventhdlr, watchedvar1, watchedvar2) );
3401
3402 /* mark the constraint propagated */
3403 consdata->propagated = TRUE;
3404
3405 return SCIP_OKAY;
3406}
3407
3408/** resolves a conflict on the given variable by supplying the variables needed for applying the corresponding
3409 * propagation rules (see propagateCons())
3410 */
3411static
3413 SCIP* scip, /**< SCIP data structure */
3414 SCIP_CONS* cons, /**< constraint that inferred the bound change */
3415 SCIP_VAR* infervar, /**< variable that was deduced */
3416 PROPRULE proprule, /**< propagation rule that deduced the value */
3417 SCIP_BDCHGIDX* bdchgidx, /**< bound change index (time stamp of bound change), or NULL for current time */
3418 SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
3419 )
3420{
3421 assert(result != NULL);
3422
3423 SCIPdebugMsg(scip, "resolving fixations according to rule %d\n", (int) proprule);
3424
3425 SCIP_CALL( addConflictBounds(scip, cons, infervar, bdchgidx, proprule) );
3427
3428 return SCIP_OKAY;
3429}
3430
3431/** try to use clique information to delete a part of the xor constraint or even fix variables */
3432static
3434 SCIP* scip, /**< SCIP data structure */
3435 SCIP_CONS* cons, /**< constraint that inferred the bound change */
3436 int* nfixedvars, /**< pointer to add up the number of found domain reductions */
3437 int* naggrvars, /**< pointer to add up the number of aggregated variables */
3438 int* nchgcoefs, /**< pointer to add up the number of deleted entries */
3439 int* ndelconss, /**< pointer to add up the number of deleted constraints */
3440 int* naddconss, /**< pointer to add up the number of added constraints */
3441 SCIP_Bool* cutoff /**< pointer to store TRUE, if the node can be cut off */
3442 )
3443{
3444 SCIP_CONSDATA* consdata;
3445 SCIP_VAR** vars;
3446 int nvars;
3447 SCIP_Bool breaked;
3448 SCIP_Bool restart;
3449 int posnotinclq1;
3450 int posnotinclq2;
3451 int v;
3452 int v1;
3453
3454 assert(scip != NULL);
3455 assert(cons != NULL);
3456 assert(nfixedvars != NULL);
3457 assert(nchgcoefs != NULL);
3458 assert(ndelconss != NULL);
3459 assert(naddconss != NULL);
3460 assert(cutoff != NULL);
3461
3462 /* propagation can only be applied, if we know all operator variables */
3463 if( SCIPconsIsModifiable(cons) )
3464 return SCIP_OKAY;
3465
3466 consdata = SCIPconsGetData(cons);
3467 assert(consdata != NULL);
3468
3469 vars = consdata->vars;
3470 nvars = consdata->nvars;
3471
3472 if( nvars < 3 )
3473 return SCIP_OKAY;
3474
3475 /* we cannot perform this steps if the integer variables in not artificial */
3476 if( !consdata->deleteintvar )
3477 return SCIP_OKAY;
3478
3479#ifdef SCIP_DISABLED_CODE
3480 /* try to evaluate if clique presolving should only be done multiple times when the constraint changed */
3481 if( !consdata->changed )
3482 return SCIP_OKAY;
3483#endif
3484
3485 /* @todo: if clique information would have saved the type of the clique, like <= 1, or == 1 we could do more
3486 * presolving like:
3487 *
3488 * (xor(x1,x2,x3,x4) = 1 and clique(x1,x2) == 1) => xor(x3,x4) = 0
3489 * (xor(x1,x2,x3,x4) = 1 and clique(x1,x2,x3) == 1) => (x4 = 0 and delete xor constraint)
3490 */
3491
3492 /* 1. we have only clique information "<=", so we can check if all variables are in the same clique
3493 *
3494 * (xor(x1,x2,x3) = 1 and clique(x1,x2,x3) <= 1) => (add set-partioning constraint x1 + x2 + x3 = 1 and delete old
3495 * xor-constraint)
3496 *
3497 * (xor(x1,x2,x3) = 0 and clique(x1,x2,x3) <= 1) => (fix all variables x1 = x2 = x3 = 0 and delete old xor-
3498 * constraint)
3499 */
3500
3501 /* 2. we have only clique information "<=", so we can check if all but one variable are in the same clique
3502 *
3503 * (xor(x1,x2,x3,x4) = 1 and clique(x1,x2,x3) <= 1) => (add set-partioning constraint x1 + x2 + x3 + x4 = 1 and
3504 * delete old xor constraint)
3505 *
3506 * (xor(x1,x2,x3,x4) = 0 and clique(x1,x2,x3) <= 1) => (add set-partioning constraint x1 + x2 + x3 + ~x4 = 1 and
3507 * delete old xor constraint)
3508 */
3509
3510 posnotinclq1 = -1; /* index of variable that is possible not in the clique */
3511 posnotinclq2 = -1; /* index of variable that is possible not in the clique */
3512 breaked = FALSE;
3513 restart = FALSE;
3514
3515 v = nvars - 2;
3516 while( v >= 0 )
3517 {
3518 SCIP_VAR* var;
3519 SCIP_VAR* var1;
3520 SCIP_Bool value;
3521 SCIP_Bool value1;
3522
3524
3525 value = SCIPvarIsActive(vars[v]);
3526
3527 if( !value )
3529 else
3530 var = vars[v];
3531
3532 if( posnotinclq1 == v )
3533 {
3534 --v;
3535 continue;
3536 }
3537
3538 for( v1 = v+1; v1 < nvars; ++v1 )
3539 {
3540 if( posnotinclq1 == v1 )
3541 continue;
3542
3543 value1 = SCIPvarIsActive(vars[v1]);
3544
3545 if( !value1 )
3546 var1 = SCIPvarGetNegationVar(vars[v1]);
3547 else
3548 var1 = vars[v1];
3549
3550 if( !SCIPvarsHaveCommonClique(var, value, var1, value1, TRUE) )
3551 {
3552 /* if the position of the variable which is not in the clique with all other variables is not yet
3553 * initialized, than do now, one of both variables does not fit
3554 */
3555 if( posnotinclq1 == -1 )
3556 {
3557 posnotinclq1 = v;
3558 posnotinclq2 = v1;
3559 }
3560 else
3561 {
3562 /* no clique with exactly nvars-1 variables */
3563 if( restart || (posnotinclq2 != v && posnotinclq2 != v1) )
3564 {
3565 breaked = TRUE;
3566 break;
3567 }
3568
3569 /* check the second variables for not fitting into the clique of (nvars - 1) variables */
3570 posnotinclq1 = posnotinclq2;
3571 restart = TRUE;
3572 v = nvars - 1;
3573 }
3574
3575 break;
3576 }
3577 else
3578 assert(vars[v] != vars[v1]);
3579 }
3580
3581 if( breaked )
3582 break;
3583
3584 --v;
3585 }
3586
3587 /* at least nvars-1 variables are in one clique */
3588 if( !breaked ) /*lint !e774*/
3589 {
3590 SCIP_Bool replaced = FALSE;
3591
3592 /* if rhs == TRUE, all variables of xor-constraint are in one clique, so create a setpartitioning constraint with
3593 * all variables and delete this xor-constraint
3594 */
3595 if( consdata->rhs )
3596 {
3597 if( SCIPconsGetNUpgradeLocks(cons) == 0 )
3598 {
3599 SCIP_CONS* newcons;
3600 char consname[SCIP_MAXSTRLEN];
3601
3602 (void)SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_complete_clq", SCIPconsGetName(cons));
3603 SCIP_CALL( SCIPcreateConsSetpart(scip, &newcons, consname, nvars, vars,
3608 SCIPdebugMsg(scip, "adding a clique/setppc constraint <%s>\n", SCIPconsGetName(newcons));
3609 SCIPdebug( SCIP_CALL( SCIPprintCons(scip, newcons, NULL) ) );
3610 SCIP_CALL( SCIPaddConsUpgrade(scip, cons, &newcons) );
3611 ++(*naddconss);
3612 replaced = TRUE;
3613 }
3614 }
3615 /* all variables of xor-constraint are in one clique and rhs == FALSE, so fix all variables to 0, case 1 */
3616 else if( posnotinclq1 == -1 )
3617 {
3618 SCIP_Bool infeasible;
3619 SCIP_Bool fixed;
3620
3621 SCIPdebugMsg(scip, "all variables of xor constraints <%s> are in one clique, so fixed all variables to 0\n",
3622 SCIPconsGetName(cons));
3624
3625 for( v = nvars - 1; v >= 0; --v )
3626 {
3627 SCIPdebugMsg(scip, "fixing variable <%s> to 0\n", SCIPvarGetName(vars[v]));
3628 SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) );
3629 assert(infeasible || fixed);
3630
3631 if( infeasible )
3632 {
3633 *cutoff = TRUE;
3634
3635 return SCIP_OKAY;
3636 }
3637 else
3638 ++(*nfixedvars);
3639 }
3640
3641 replaced = TRUE;
3642 }
3643 /* all but one variable are in one clique and rhs == FALSE, so we need to exchange the variable not appearing in
3644 * the clique with the negated variable, case 2
3645 */
3646 else
3647 {
3648 if( SCIPconsGetNUpgradeLocks(cons) == 0 )
3649 {
3650 SCIP_CONS* newcons;
3651 char consname[SCIP_MAXSTRLEN];
3652
3653 (void)SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_completed_clq", SCIPconsGetName(cons));
3654
3655 /* complete clique by creating a set partioning constraint over all variables */
3656 SCIP_CALL( SCIPcreateConsSetpart(scip, &newcons, consname, 0, NULL,
3661
3662 for( v = 0; v < nvars; ++v )
3663 {
3664 if( v == posnotinclq1 )
3665 {
3666 SCIP_VAR* var;
3667
3669 assert(var != NULL);
3670
3671 SCIP_CALL( SCIPaddCoefSetppc(scip, newcons, var) );
3672 }
3673 else
3674 {
3675 SCIP_CALL( SCIPaddCoefSetppc(scip, newcons, vars[v]) );
3676 }
3677 }
3678
3679 SCIPdebugMsg(scip, "adding a clique/setppc constraint <%s>\n", SCIPconsGetName(newcons));
3680 SCIPdebug( SCIP_CALL( SCIPprintCons(scip, newcons, NULL) ) );
3681 SCIP_CALL( SCIPaddConsUpgrade(scip, cons, &newcons) );
3682 ++(*naddconss);
3683 replaced = TRUE;
3684 }
3685 }
3686
3687 /* remove integer variable if it exists */
3688 if( consdata->intvar != NULL )
3689 {
3690 SCIP_Bool infeasible;
3691 SCIP_Bool fixed;
3692
3693 /* fix integer variable to zero if at most one xor-variable can be one */
3694 if( consdata->rhs || posnotinclq1 == -1 )
3695 {
3696 SCIPdebugMsg(scip, "fix the integer variable <%s> to 0\n", SCIPvarGetName(consdata->intvar));
3697 SCIP_CALL( SCIPfixVar(scip, consdata->intvar, 0.0, &infeasible, &fixed) );
3698 assert(infeasible || fixed);
3699
3700 if( infeasible )
3701 {
3702 *cutoff = TRUE;
3703
3704 return SCIP_OKAY;
3705 }
3706 else
3707 ++(*nfixedvars);
3708 }
3709 /* otherwise aggregate integer variable to xor-variable not in clique */
3710 else
3711 {
3712 SCIP_Bool redundant;
3713
3714 SCIPdebugMsg(scip, "aggregate the integer variable <%s> to <%s>\n", SCIPvarGetName(consdata->intvar), SCIPvarGetName(vars[posnotinclq1]));
3715 SCIP_CALL( SCIPaggregateVars(scip, consdata->intvar, vars[posnotinclq1], 1.0, -1.0, 0.0, &infeasible, &redundant, &fixed) );
3716 assert(infeasible || redundant);
3717
3718 if( infeasible )
3719 {
3720 *cutoff = TRUE;
3721
3722 return SCIP_OKAY;
3723 }
3724 else if( fixed )
3725 ++(*naggrvars);
3726 }
3727 }
3728
3729 /* delete old replaced xor-constraint */
3730 if( replaced )
3731 {
3732 SCIP_CALL( SCIPdelCons(scip, cons) );
3733 ++(*ndelconss);
3734 }
3735 }
3736
3737 return SCIP_OKAY;
3738}
3739
3740/** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
3741 * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
3742 */
3743static
3745 SCIP* scip, /**< SCIP data structure */
3746 BMS_BLKMEM* blkmem, /**< block memory */
3747 SCIP_CONS** conss, /**< constraint set */
3748 int nconss, /**< number of constraints in constraint set */
3749 int* firstchange, /**< pointer to store first changed constraint */
3750 int* nchgcoefs, /**< pointer to add up the number of changed coefficients */
3751 int* nfixedvars, /**< pointer to add up the number of found domain reductions */
3752 int* naggrvars, /**< pointer to add up the number of aggregated variables */
3753 int* ndelconss, /**< pointer to count number of deleted constraints */
3754 int* naddconss, /**< pointer to count number of added constraints */
3755 SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was found */
3756 )
3757{
3758 SCIP_HASHTABLE* hashtable;
3759 int hashtablesize;
3760 int c;
3761
3762 assert(conss != NULL);
3763 assert(ndelconss != NULL);
3764
3765 /* create a hash table for the constraint set */
3766 hashtablesize = nconss;
3767 hashtablesize = MAX(hashtablesize, HASHSIZE_XORCONS);
3768
3769 SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
3770 hashGetKeyXorcons, hashKeyEqXorcons, hashKeyValXorcons, (void*) scip) );
3771
3772 /* check all constraints in the given set for redundancy */
3773 for( c = 0; c < nconss; ++c )
3774 {
3775 SCIP_CONS* cons0;
3776 SCIP_CONS* cons1;
3777 SCIP_CONSDATA* consdata0;
3778 SCIP_CONSHDLR* conshdlr;
3779 SCIP_CONSHDLRDATA* conshdlrdata;
3780
3781 cons0 = conss[c];
3782
3783 if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
3784 continue;
3785
3786 /* get constraint handler data */
3787 conshdlr = SCIPconsGetHdlr(cons0);
3788 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3789 assert(conshdlrdata != NULL);
3790
3791 /* it can happen that during preprocessing some variables got aggregated and a constraint now has not active
3792 * variables inside so we need to remove them for sorting
3793 */
3794 /* remove all variables that are fixed to zero and all pairs of variables fixed to one;
3795 * merge multiple entries of the same or negated variables
3796 */
3797 SCIP_CALL( applyFixings(scip, cons0, conshdlrdata->eventhdlr, nchgcoefs, naggrvars, naddconss, cutoff) );
3798 if( *cutoff )
3799 goto TERMINATE;
3800
3801 consdata0 = SCIPconsGetData(cons0);
3802
3803 assert(consdata0 != NULL);
3804
3805 /* applyFixings() led to an empty or trivial constraint */
3806 if( consdata0->nvars <= 1 )
3807 {
3808 if( consdata0->nvars == 0 )
3809 {
3810 /* the constraints activity cannot match an odd right hand side */
3811 if( consdata0->rhs )
3812 {
3813 *cutoff = TRUE;
3814 break;
3815 }
3816 }
3817 else
3818 {
3819 /* exactly 1 variable left. */
3820 SCIP_Bool infeasible;
3821 SCIP_Bool fixed;
3822
3823 /* fix remaining variable */
3824 SCIP_CALL( SCIPfixVar(scip, consdata0->vars[0], (SCIP_Real) consdata0->rhs, &infeasible, &fixed) );
3825 assert(!infeasible);
3826
3827 if( fixed )
3828 ++(*nfixedvars);
3829 }
3830
3831 /* fix integral variable if present */
3832 if( consdata0->intvar != NULL )
3833 {
3834 SCIP_Bool infeasible;
3835 SCIP_Bool fixed;
3836
3837 SCIP_CALL( SCIPfixVar(scip, consdata0->intvar, 0.0, &infeasible, &fixed) );
3838 assert(!infeasible);
3839
3840 if( fixed )
3841 ++(*nfixedvars);
3842 }
3843
3844 /* delete empty constraint */
3845 SCIP_CALL( SCIPdelCons(scip, cons0) );
3846 ++(*ndelconss);
3847
3848 continue;
3849 }
3850
3851 /* sort the constraint */
3852 consdataSort(consdata0);
3853 assert(consdata0->sorted);
3854
3855 /* get constraint from current hash table with same variables as cons0 */
3856 cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
3857
3858 if( cons1 != NULL )
3859 {
3860 SCIP_CONSDATA* consdata1;
3861
3862 assert(SCIPconsIsActive(cons1));
3864
3865 consdata1 = SCIPconsGetData(cons1);
3866
3867 assert(consdata1 != NULL);
3868 assert(consdata0->nvars >= 1 && consdata0->nvars == consdata1->nvars);
3869
3870 assert(consdata0->sorted && consdata1->sorted);
3871 assert(consdata0->vars[0] == consdata1->vars[0]);
3872
3873 if( consdata0->rhs != consdata1->rhs )
3874 {
3875 *cutoff = TRUE;
3876 goto TERMINATE;
3877 }
3878
3879 /* aggregate parity variables into each other */
3880 if( consdata0->intvar != consdata1->intvar && consdata0->intvar != NULL )
3881 {
3882 if( consdata1->intvar != NULL )
3883 {
3884 SCIP_Bool redundant;
3885 SCIP_Bool aggregated;
3886 SCIP_Bool infeasible;
3887
3888 SCIP_CALL( SCIPaggregateVars(scip, consdata0->intvar, consdata1->intvar, 1.0, -1.0, 0.0, &infeasible, &redundant, &aggregated) );
3889
3890 if( aggregated )
3891 {
3892 ++(*naggrvars);
3893 }
3894 if( infeasible )
3895 {
3896 *cutoff = TRUE;
3897 goto TERMINATE;
3898 }
3899 }
3900 /* the special case that only cons0 has a parity variable 'intvar' is treated by swapping cons0 and cons1 */
3901 else
3902 {
3903 SCIP_CALL( SCIPhashtableInsert(hashtable, (void *)cons0) );
3904 assert(SCIPhashtableRetrieve(hashtable, (void *)cons1) == cons0);
3905
3906 SCIPswapPointers((void**)&cons0, (void**)(&cons1));
3907 SCIPswapPointers((void**)&consdata0, (void**)(&consdata1));
3908 }
3909 }
3910
3911 /* delete cons0 and update flags of cons1 s.t. nonredundant information doesn't get lost */
3912 /* coverity[swapped_arguments] */
3913 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
3914 SCIP_CALL( SCIPdelCons(scip, cons0) );
3915 (*ndelconss)++;
3916
3917 /* update the first changed constraint to begin the next aggregation round with */
3918 if( consdata0->changed && SCIPconsGetPos(cons1) < *firstchange )
3919 *firstchange = SCIPconsGetPos(cons1);
3920
3921 assert(SCIPconsIsActive(cons1));
3922 }
3923 else
3924 {
3925 /* no such constraint in current hash table: insert cons0 into hash table */
3926 SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
3927 }
3928 }
3929
3930 TERMINATE:
3931 /* free hash table */
3932 SCIPhashtableFree(&hashtable);
3933
3934 return SCIP_OKAY;
3935}
3936
3937/** compares constraint with all prior constraints for possible redundancy or aggregation,
3938 * and removes or changes constraint accordingly
3939 */
3940static
3942 SCIP* scip, /**< SCIP data structure */
3943 SCIP_CONS** conss, /**< constraint set */
3944 int firstchange, /**< first constraint that changed since last pair preprocessing round */
3945 int chkind, /**< index of constraint to check against all prior indices upto startind */
3946 SCIP_Bool* cutoff, /**< pointer to store TRUE, if a cutoff was found */
3947 int* nfixedvars, /**< pointer to add up the number of found domain reductions */
3948 int* naggrvars, /**< pointer to count number of aggregated variables */
3949 int* ndelconss, /**< pointer to count number of deleted constraints */
3950 int* naddconss, /**< pointer to count number of added constraints */
3951 int* nchgcoefs /**< pointer to add up the number of changed coefficients */
3952 )
3953{
3954 SCIP_CONSHDLR* conshdlr;
3955 SCIP_CONSHDLRDATA* conshdlrdata;
3956 SCIP_CONS* cons0;
3957 SCIP_CONSDATA* consdata0;
3958 SCIP_Bool cons0changed;
3959 int c;
3960
3961 assert(conss != NULL);
3962 assert(firstchange <= chkind);
3963 assert(cutoff != NULL);
3964 assert(nfixedvars != NULL);
3965 assert(naggrvars != NULL);
3966 assert(ndelconss != NULL);
3967 assert(nchgcoefs != NULL);
3968
3969 /* get the constraint to be checked against all prior constraints */
3970 cons0 = conss[chkind];
3971 assert(SCIPconsIsActive(cons0));
3973
3974 consdata0 = SCIPconsGetData(cons0);
3975 assert(consdata0 != NULL);
3976 assert(consdata0->nvars >= 1);
3977
3978 /* get constraint handler data */
3979 conshdlr = SCIPconsGetHdlr(cons0);
3980 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3981 assert(conshdlrdata != NULL);
3982
3983 /* it can happen that during preprocessing some variables got aggregated and a constraint now has not active
3984 * variables inside so we need to remove them for sorting
3985 */
3986 /* remove all variables that are fixed to zero and all pairs of variables fixed to one;
3987 * merge multiple entries of the same or negated variables
3988 */
3989 SCIP_CALL( applyFixings(scip, cons0, conshdlrdata->eventhdlr, nchgcoefs, naggrvars, naddconss, cutoff) );
3990 if( *cutoff )
3991 return SCIP_OKAY;
3992
3993 /* sort cons0 */
3994 consdataSort(consdata0);
3995 assert(consdata0->sorted);
3996
3997 /* check constraint against all prior constraints */
3998 cons0changed = consdata0->changed;
3999 consdata0->changed = FALSE;
4000 for( c = (cons0changed ? 0 : firstchange); c < chkind && !(*cutoff) && SCIPconsIsActive(cons0) && !SCIPisStopped(scip); ++c )
4001 {
4002 SCIP_CONS* cons1;
4003 SCIP_CONSDATA* consdata1;
4004 SCIP_VAR* singlevar0;
4005 SCIP_VAR* singlevar1;
4006 SCIP_Bool parity;
4007 SCIP_Bool cons0hastwoothervars;
4008 SCIP_Bool cons1hastwoothervars;
4009 SCIP_Bool aborted;
4010 SCIP_Bool infeasible;
4011 SCIP_Bool fixed;
4012 SCIP_Bool redundant;
4013 SCIP_Bool aggregated;
4014 int v0;
4015 int v1;
4016
4017 cons1 = conss[c];
4018
4019 /* ignore inactive and modifiable constraints */
4020 if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
4021 continue;
4022
4023 consdata1 = SCIPconsGetData(cons1);
4024 assert(consdata1 != NULL);
4025
4026 if( !consdata1->deleteintvar )
4027 continue;
4028
4029 /* it can happen that during preprocessing some variables got aggregated and a constraint now has not active
4030 * variables inside so we need to remove them for sorting
4031 */
4032 /* remove all variables that are fixed to zero and all pairs of variables fixed to one;
4033 * merge multiple entries of the same or negated variables
4034 */
4035 SCIP_CALL( applyFixings(scip, cons1, conshdlrdata->eventhdlr, nchgcoefs, naggrvars, naddconss, cutoff) );
4036 assert(consdata1 == SCIPconsGetData(cons1));
4037 if( *cutoff )
4038 return SCIP_OKAY;
4039
4040 SCIPdebugMsg(scip, "preprocess xor constraint pair <%s>[chg:%u] and <%s>[chg:%u]\n",
4041 SCIPconsGetName(cons0), cons0changed, SCIPconsGetName(cons1), consdata1->changed);
4042
4043 /* if both constraints were not changed since last round, we can ignore the pair */
4044 if( !cons0changed && !consdata1->changed )
4045 continue;
4046
4047 /* applyFixings() led to an empty constraint */
4048 if( consdata1->nvars == 0 )
4049 {
4050 if( consdata1->rhs )
4051 {
4052 *cutoff = TRUE;
4053 break;
4054 }
4055 else
4056 {
4057 /* fix integral variable if present */
4058 if( consdata1->intvar != NULL )
4059 {
4060 SCIP_CALL( SCIPfixVar(scip, consdata1->intvar, 0.0, &infeasible, &fixed) );
4061 assert(!infeasible);
4062 if( fixed )
4063 ++(*nfixedvars);
4064 }
4065
4066 /* delete empty constraint */
4067 SCIP_CALL( SCIPdelCons(scip, cons1) );
4068 ++(*ndelconss);
4069
4070 continue;
4071 }
4072 }
4073 else if( consdata1->nvars == 1 )
4074 {
4075 /* fix remaining variable */
4076 SCIP_CALL( SCIPfixVar(scip, consdata1->vars[0], (SCIP_Real) consdata1->rhs, &infeasible, &fixed) );
4077 assert(!infeasible);
4078
4079 if( fixed )
4080 ++(*nfixedvars);
4081
4082 /* fix integral variable if present */
4083 if( consdata1->intvar != NULL )
4084 {
4085 SCIP_CALL( SCIPfixVar(scip, consdata1->intvar, 0.0, &infeasible, &fixed) );
4086 assert(!infeasible);
4087 if( fixed )
4088 ++(*nfixedvars);
4089 }
4090
4091 SCIP_CALL( SCIPdelCons(scip, cons1) );
4092 ++(*ndelconss);
4093
4094 /* check for fixed variable in cons0 and remove it */
4095 SCIP_CALL( applyFixings(scip, cons0, conshdlrdata->eventhdlr, nchgcoefs, naggrvars, naddconss, cutoff) );
4096 assert(!(*cutoff));
4097
4098 /* sort cons0 */
4099 consdataSort(consdata0);
4100 assert(consdata0->sorted);
4101
4102 continue;
4103 }
4104 else if( consdata1->nvars == 2 )
4105 {
4106 if( !(consdata1->rhs) )
4107 {
4108 /* aggregate var0 == var1 */
4109 SCIP_CALL( SCIPaggregateVars(scip, consdata1->vars[0], consdata1->vars[1], 1.0, -1.0, 0.0,
4110 &infeasible, &redundant, &aggregated) );
4111 }
4112 else
4113 {
4114 /* aggregate var0 == 1 - var1 */
4115 SCIP_CALL( SCIPaggregateVars(scip, consdata1->vars[0], consdata1->vars[1], 1.0, 1.0, 1.0,
4116 &infeasible, &redundant, &aggregated) );
4117 }
4118 assert(!infeasible);
4119 assert(redundant || SCIPdoNotAggr(scip));
4120
4121 if( aggregated )
4122 {
4123 ++(*naggrvars);
4124
4125 /* check for aggregated variable in cons0 and remove it */
4126 SCIP_CALL( applyFixings(scip, cons0, conshdlrdata->eventhdlr, nchgcoefs, naggrvars, naddconss, cutoff) );
4127 if( *cutoff )
4128 return SCIP_OKAY;
4129
4130 /* sort cons0 */
4131 consdataSort(consdata0);
4132 assert(consdata0->sorted);
4133 }
4134
4135 if( redundant )
4136 {
4137 /* fix or aggregate the intvar, if it exists */
4138 if( consdata1->intvar != NULL )
4139 {
4140 /* we have var0 + var1 - 2 * intvar = 1, and aggregated var1 = 1 - var0,
4141 * thus, intvar is always 0 */
4142 if( consdata1->rhs )
4143 {
4144 SCIP_CALL( SCIPfixVar(scip, consdata1->intvar, 0.0, &infeasible, &fixed) );
4145 assert(!infeasible);
4146 if( fixed )
4147 ++(*nfixedvars);
4148 }
4149 /* we have var0 + var1 - 2 * intvar = 0, and aggregated var1 = var0,
4150 * i.e., 2 * var0 - 2 * intvar = 0, so intvar = var0 holds and we aggregate */
4151 else
4152 {
4153 assert(!consdata1->rhs);
4154
4155 /* aggregate intvar == var0 */
4156 SCIP_CALL( SCIPaggregateVars(scip, consdata1->vars[0], consdata1->intvar, 1.0, -1.0, 0.0,
4157 &infeasible, &redundant, &aggregated) );
4158 assert(!infeasible);
4159 assert(redundant || SCIPdoNotAggr(scip));
4160
4161 if( aggregated )
4162 {
4163 ++(*naggrvars);
4164 }
4165 }
4166 }
4167
4168 if( redundant )
4169 {
4170 SCIP_CALL( SCIPdelCons(scip, cons1) );
4171 ++(*ndelconss);
4172 }
4173 }
4174
4175 continue;
4176 }
4177 assert(consdata0->sorted);
4178
4179 /* sort cons1 */
4180 consdataSort(consdata1);
4181 assert(consdata1->sorted);
4182
4183 /* check whether
4184 * (a) one problem variable set is a subset of the other, or
4185 * (b) the problem variable sets are almost equal with only one variable in each constraint that is not
4186 * member of the other
4187 */
4188 aborted = FALSE;
4189 parity = (consdata0->rhs ^ consdata1->rhs);
4190 cons0hastwoothervars = FALSE;
4191 cons1hastwoothervars = FALSE;
4192 singlevar0 = NULL;
4193 singlevar1 = NULL;
4194 v0 = 0;
4195 v1 = 0;
4196 while( (v0 < consdata0->nvars || v1 < consdata1->nvars) && !aborted )
4197 {
4198 int cmp;
4199
4200 assert(v0 <= consdata0->nvars);
4201 assert(v1 <= consdata1->nvars);
4202
4203 if( v0 == consdata0->nvars )
4204 cmp = +1;
4205 else if( v1 == consdata1->nvars )
4206 cmp = -1;
4207 else
4208 cmp = SCIPvarCompareActiveAndNegated(consdata0->vars[v0], consdata1->vars[v1]);
4209
4210 switch( cmp )
4211 {
4212 case -1:
4213 /* variable doesn't appear in cons1 */
4214 assert(v0 < consdata0->nvars);
4215 if( singlevar0 == NULL )
4216 {
4217 singlevar0 = consdata0->vars[v0];
4218 if( cons1hastwoothervars )
4219 aborted = TRUE;
4220 }
4221 else
4222 {
4223 cons0hastwoothervars = TRUE;
4224 if( singlevar1 != NULL )
4225 aborted = TRUE;
4226 }
4227 v0++;
4228 break;
4229
4230 case +1:
4231 /* variable doesn't appear in cons0 */
4232 assert(v1 < consdata1->nvars);
4233 if( singlevar1 == NULL )
4234 {
4235 singlevar1 = consdata1->vars[v1];
4236 if( cons0hastwoothervars )
4237 aborted = TRUE;
4238 }
4239 else
4240 {
4241 cons1hastwoothervars = TRUE;
4242 if( singlevar0 != NULL )
4243 aborted = TRUE;
4244 }
4245 v1++;
4246 break;
4247
4248 case 0:
4249 /* variable appears in both constraints */
4250 assert(v0 < consdata0->nvars);
4251 assert(v1 < consdata1->nvars);
4252 assert(SCIPvarGetProbvar(consdata0->vars[v0]) == SCIPvarGetProbvar(consdata1->vars[v1]));
4253 if( consdata0->vars[v0] != consdata1->vars[v1] )
4254 {
4255 assert(SCIPvarGetNegatedVar(consdata0->vars[v0]) == consdata1->vars[v1]);
4256 parity = !parity;
4257 }
4258 v0++;
4259 v1++;
4260 break;
4261
4262 default:
4263 SCIPerrorMessage("invalid comparison result\n");
4264 SCIPABORT();
4265 return SCIP_INVALIDDATA; /*lint !e527*/
4266 }
4267 }
4268
4269 /* check if a useful presolving is possible */
4270 if( (cons0hastwoothervars && singlevar1 != NULL) || (cons1hastwoothervars && singlevar0 != NULL) )
4271 continue;
4272
4273 /* check if one problem variable set is a subset of the other */
4274 if( singlevar0 == NULL && singlevar1 == NULL )
4275 {
4276 /* both constraints are equal */
4277 if( !parity )
4278 {
4279 /* even parity: constraints are redundant */
4280 SCIPdebugMsg(scip, "xor constraints <%s> and <%s> are redundant: delete <%s>\n",
4281 SCIPconsGetName(cons0), SCIPconsGetName(cons1), SCIPconsGetName(cons1));
4282 SCIPdebugPrintCons(scip, cons0, NULL);
4283 SCIPdebugPrintCons(scip, cons1, NULL);
4284
4285 /* delete cons1 and update flags of cons0 s.t. nonredundant information doesn't get lost */
4286 SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
4287 SCIP_CALL( SCIPdelCons(scip, cons1) );
4288 (*ndelconss)++;
4289
4290 if( consdata1->intvar != NULL )
4291 {
4292 /* need to update integer variable, consider the following case:
4293 * c1: xor(x1, x2, x3) = 1 (intvar1 = y1)
4294 * c2: xor(x1, x2, x3) = 1 (intvar0 = NULL or intvar0 = y0)
4295 *
4296 * if intvar0 = NULL we have to assign intvar0 = y1. otherwise, we have to ensure that y1 = y0 holds.
4297 * if aggregation is allowed, we can aggregate both variables. otherwise, we have to add a linear
4298 * constraint y1 - y0 = 0.
4299 */
4300 if( consdata0->intvar == NULL )
4301 {
4302 SCIP_CALL( setIntvar(scip, cons0, consdata1->intvar) );
4303 }
4304 else
4305 {
4306 /* aggregate integer variables */
4307 SCIP_CALL( SCIPaggregateVars(scip, consdata1->intvar, consdata0->intvar, 1.0, -1.0, 0.0,
4308 &infeasible, &redundant, &aggregated) );
4309
4310 *cutoff = *cutoff || infeasible;
4311
4312 if( aggregated )
4313 {
4314 ++(*naggrvars);
4315 assert(SCIPvarIsActive(consdata0->intvar));
4316 }
4317 else
4318 {
4319 SCIP_CONS* newcons;
4320 char consname[SCIP_MAXSTRLEN];
4321 SCIP_VAR* newvars[2];
4322 SCIP_Real vals[2];
4323
4324 newvars[0] = consdata1->intvar;
4325 vals[0] = 1.0;
4326 newvars[1] = consdata0->intvar;
4327 vals[1] = -1.0;
4328
4329 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "agg_%s", SCIPconsGetName(cons1));
4330
4331 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, consname, 2, newvars, vals, 0.0, 0.0,
4332 SCIPconsIsInitial(cons1), SCIPconsIsSeparated(cons1), TRUE, /*SCIPconsIsEnforced(cons),*/
4333 TRUE, TRUE, /*SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons),*/
4336
4337 SCIP_CALL( SCIPaddCons(scip, newcons) );
4338 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4339 ++(*naddconss);
4340 }
4341 }
4342 }
4343 }
4344 else
4345 {
4346 /* odd parity: constraints are contradicting */
4347 SCIPdebugMsg(scip, "xor constraints <%s> and <%s> are contradicting\n",
4348 SCIPconsGetName(cons0), SCIPconsGetName(cons1));
4349 SCIPdebugPrintCons(scip, cons0, NULL);
4350 SCIPdebugPrintCons(scip, cons1, NULL);
4351 *cutoff = TRUE;
4352 }
4353 }
4354 else if( singlevar1 == NULL )
4355 {
4356 /* cons1 is a subset of cons0 */
4357 if( !cons0hastwoothervars )
4358 {
4359 /* only one additional variable in cons0: fix this variable according to the parity */
4360 SCIPdebugMsg(scip, "xor constraints <%s> and <%s> yield sum %u == <%s>\n",
4361 SCIPconsGetName(cons0), SCIPconsGetName(cons1), parity, SCIPvarGetName(singlevar0));
4362 SCIPdebugPrintCons(scip, cons0, NULL);
4363 SCIPdebugPrintCons(scip, cons1, NULL);
4364 SCIP_CALL( SCIPfixVar(scip, singlevar0, parity ? 1.0 : 0.0, &infeasible, &fixed) );
4365 *cutoff = *cutoff || infeasible;
4366 if( fixed )
4367 (*nfixedvars)++;
4368
4369 /* delete cons1 and update flags of cons0 s.t. nonredundant information doesn't get lost */
4370 SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
4371 SCIP_CALL( SCIPdelCons(scip, cons1) );
4372 (*ndelconss)++;
4373 }
4374 else
4375 {
4376 int v;
4377
4378 /* more than one additional variable in cons0: add cons1 to cons0, thus eliminating the equal variables */
4379 SCIPdebugMsg(scip, "xor constraint <%s> is superset of <%s> with parity %u\n",
4380 SCIPconsGetName(cons0), SCIPconsGetName(cons1), parity);
4381 SCIPdebugPrintCons(scip, cons0, NULL);
4382 SCIPdebugPrintCons(scip, cons1, NULL);
4383 for( v = 0; v < consdata1->nvars; ++v )
4384 {
4385 SCIP_CALL( addCoef(scip, cons0, consdata1->vars[v]) );
4386 }
4387
4388 SCIP_CALL( applyFixings(scip, cons0, conshdlrdata->eventhdlr, nchgcoefs, naggrvars, naddconss, cutoff) );
4389 assert(SCIPconsGetData(cons0) == consdata0);
4390 assert(consdata0->nvars >= 2); /* at least the two "other" variables should remain in the constraint */
4391 }
4392
4393 if( *cutoff )
4394 return SCIP_OKAY;
4395
4396 consdataSort(consdata0);
4397 assert(consdata0->sorted);
4398 }
4399 else if( singlevar0 == NULL )
4400 {
4401 /* cons0 is a subset of cons1 */
4402 if( !cons1hastwoothervars )
4403 {
4404 /* only one additional variable in cons1: fix this variable according to the parity */
4405 SCIPdebugMsg(scip, "xor constraints <%s> and <%s> yield sum %u == <%s>\n",
4406 SCIPconsGetName(cons0), SCIPconsGetName(cons1), parity, SCIPvarGetName(singlevar1));
4407 SCIPdebugPrintCons(scip, cons0, NULL);
4408 SCIPdebugPrintCons(scip, cons1, NULL);
4409 SCIP_CALL( SCIPfixVar(scip, singlevar1, parity ? 1.0 : 0.0, &infeasible, &fixed) );
4410 assert(infeasible || fixed);
4411 *cutoff = *cutoff || infeasible;
4412 (*nfixedvars)++;
4413
4414 /* delete cons1 and update flags of cons0 s.t. nonredundant information doesn't get lost */
4415 SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
4416 SCIP_CALL( SCIPdelCons(scip, cons1) );
4417 (*ndelconss)++;
4418 }
4419 else
4420 {
4421 int v;
4422
4423 /* more than one additional variable in cons1: add cons0 to cons1, thus eliminating the equal variables */
4424 SCIPdebugMsg(scip, "xor constraint <%s> is subset of <%s> with parity %u\n",
4425 SCIPconsGetName(cons0), SCIPconsGetName(cons1), parity);
4426 SCIPdebugPrintCons(scip, cons0, NULL);
4427 SCIPdebugPrintCons(scip, cons1, NULL);
4428 for( v = 0; v < consdata0->nvars; ++v )
4429 {
4430 SCIP_CALL( addCoef(scip, cons1, consdata0->vars[v]) );
4431 }
4432 SCIP_CALL( applyFixings(scip, cons1, conshdlrdata->eventhdlr, nchgcoefs, naggrvars, naddconss, cutoff) );
4433 assert(SCIPconsGetData(cons1) == consdata1);
4434 assert(consdata1->nvars >= 2); /* at least the two "other" variables should remain in the constraint */
4435
4436 if( *cutoff )
4437 return SCIP_OKAY;
4438
4439 consdataSort(consdata1);
4440 assert(consdata1->sorted);
4441 }
4442 }
4443 else
4444 {
4445 assert(!cons0hastwoothervars);
4446 assert(!cons1hastwoothervars);
4447
4448 /* sum of constraints is parity == singlevar0 xor singlevar1: aggregate variables and delete cons1 */
4449 SCIPdebugMsg(scip, "xor constraints <%s> and <%s> yield sum %u == xor(<%s>,<%s>)\n",
4450 SCIPconsGetName(cons0), SCIPconsGetName(cons1), parity, SCIPvarGetName(singlevar0),
4451 SCIPvarGetName(singlevar1));
4452 if( !parity )
4453 {
4454 /* aggregate singlevar0 == singlevar1 */
4455 SCIP_CALL( SCIPaggregateVars(scip, singlevar1, singlevar0, 1.0, -1.0, 0.0,
4456 &infeasible, &redundant, &aggregated) );
4457 }
4458 else
4459 {
4460 /* aggregate singlevar0 == 1-singlevar1 */
4461 SCIP_CALL( SCIPaggregateVars(scip, singlevar1, singlevar0, 1.0, 1.0, 1.0,
4462 &infeasible, &redundant, &aggregated) );
4463 }
4464 assert(infeasible || redundant || SCIPdoNotAggr(scip));
4465
4466 *cutoff = *cutoff || infeasible;
4467 if( aggregated )
4468 ++(*naggrvars);
4469
4470 if( redundant )
4471 {
4472 /* delete cons1 and update flags of cons0 s.t. nonredundant information doesn't get lost */
4473 SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
4474 SCIP_CALL( SCIPdelCons(scip, cons1) );
4475 (*ndelconss)++;
4476
4477 if( consdata1->intvar != NULL )
4478 {
4479 if( consdata0->intvar == NULL )
4480 {
4481 SCIP_CALL( setIntvar(scip, cons0, consdata0->intvar) );
4482 }
4483 else
4484 {
4485 /* aggregate integer variables */
4486 SCIP_CALL( SCIPaggregateVars(scip, consdata1->intvar, consdata0->intvar, 1.0, -1.0, 0.0,
4487 &infeasible, &redundant, &aggregated) );
4488
4489 *cutoff = *cutoff || infeasible;
4490 if( aggregated )
4491 ++(*naggrvars);
4492 }
4493 }
4494 }
4495
4496 if( !consdata0->sorted )
4497 consdataSort(consdata0);
4498 assert(consdata0->sorted);
4499
4500#ifdef SCIP_DISABLED_CODE
4501 /* TODO: consider running applyFixings() on the persistent constraint to detect a cutoff */
4502 /* remove all variables that are fixed to zero and all pairs of variables fixed to one;
4503 * merge multiple entries of the same or negated variables
4504 */
4505 SCIP_CALL( applyFixings(scip, cons0, conshdlrdata->eventhdlr, nchgcoefs, naggrvars, naddconss, cutoff) );
4506
4507 if( *cutoff )
4508 return SCIP_OKAY;
4509#endif
4510 }
4511 }
4512
4513 return SCIP_OKAY;
4514}
4515
4516/** creates and captures a xor constraint x_0 xor ... xor x_{k-1} = rhs with a given artificial integer variable for the
4517 * linear relaxation
4518 *
4519 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
4520 */
4521static
4523 SCIP* scip, /**< SCIP data structure */
4524 SCIP_CONS** cons, /**< pointer to hold the created constraint */
4525 const char* name, /**< name of constraint */
4526 SCIP_Bool rhs, /**< right hand side of the constraint */
4527 int nvars, /**< number of operator variables in the constraint */
4528 SCIP_VAR** vars, /**< array with operator variables of constraint */
4529 SCIP_VAR* intvar, /**< integer variable for linear relaxation or NULL if artificial */
4530 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
4531 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
4532 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
4533 * Usually set to TRUE. */
4534 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
4535 * TRUE for model constraints, FALSE for additional, redundant constraints. */
4536 SCIP_Bool check, /**< should the constraint be checked for feasibility?
4537 * TRUE for model constraints, FALSE for additional, redundant constraints. */
4538 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
4539 * Usually set to TRUE. */
4540 SCIP_Bool local, /**< is constraint only valid locally?
4541 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
4542 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
4543 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
4544 * adds coefficients to this constraint. */
4545 SCIP_Bool dynamic, /**< is constraint subject to aging?
4546 * Usually set to FALSE. Set to TRUE for own cuts which
4547 * are separated as constraints. */
4548 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
4549 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
4550 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
4551 * if it may be moved to a more global node?
4552 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
4553 )
4554{
4555 SCIP_CONSHDLR* conshdlr;
4556 SCIP_CONSDATA* consdata;
4557 SCIP_VARTYPE intvartype;
4558 int i;
4559
4560 /* find the xor constraint handler */
4561 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
4562 if( conshdlr == NULL )
4563 {
4564 SCIPerrorMessage("xor constraint handler not found\n");
4565 return SCIP_PLUGINNOTFOUND;
4566 }
4567
4568 /* check whether int variable is integral */
4569 if( intvar != NULL )
4570 {
4571 intvartype = SCIPvarGetType(intvar);
4572
4573 if( intvartype != SCIP_VARTYPE_BINARY && intvartype != SCIP_VARTYPE_INTEGER )
4574 {
4575 SCIPerrorMessage("intvar <%s> is not enforced integral\n", SCIPvarGetName(intvar));
4576 return SCIP_INVALIDDATA;
4577 }
4578 }
4579
4580 /* check whether all variables are binary */
4581 assert(vars != NULL || nvars == 0);
4582 for( i = 0; i < nvars; ++i )
4583 {
4584 if( !SCIPvarIsBinary(vars[i]) )
4585 {
4586 SCIPerrorMessage("operand <%s> is not binary\n", SCIPvarGetName(vars[i]));
4587 return SCIP_INVALIDDATA;
4588 }
4589 }
4590
4591 /* create constraint data */
4592 SCIP_CALL( consdataCreate(scip, &consdata, rhs, nvars, vars, intvar) );
4593
4594 /* create constraint */
4595 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
4596 local, modifiable, dynamic, removable, stickingatnode) );
4597
4598 return SCIP_OKAY;
4599}
4600
4601
4602
4603/*
4604 * Linear constraint upgrading
4605 */
4606
4607/** tries to upgrade a linear constraint into an xor constraint
4608 *
4609 * Assuming all variables are binary and have coefficients with an absolute value 1, except for an integer (or binary) variable
4610 * \f$z\f$ which has coefficient \f$a \in \{-2,2\}\f$ with absolute value 2 and appears only in this constraint,
4611 * we can transform:
4612 * \f[
4613 * \begin{array}{ll}
4614 * & -\sum_{i \in I} x_i + \sum_{j \in J} x_j + a \cdot z = r \\
4615 * \Leftrightarrow & \sum_{i \in I} \bar{x}_i + \sum_{j \in J} x_j + a \cdot z = r + |I| \\
4616 * \Leftrightarrow & \sum_{i \in I} \bar{x}_i + \sum_{j \in J} x_j - 2 \cdot y = (r + |I|) \text{ mod } 2,
4617 * \end{array}
4618 * \f]
4619 * where
4620 * \f[
4621 * y = \begin{cases}
4622 * \left\lfloor \frac{r + |I|}{2} \right\rfloor + z & \text{if }a = -2\\
4623 * \left\lfloor \frac{r + |I|}{2} \right\rfloor - z & \text{if }a = 2.
4624 * \end{cases}
4625 * \f]
4626 * If \f$a = -2\f$ and \f$z \in [\ell_z, u_z]\f$, then \f$y \in [\ell_y, u_y]\f$, where \f$\ell_y = \left\lfloor
4627 * \frac{r + |I|}{2} \right\rfloor + \ell_z\f$ and \f$u_y = \left\lfloor \frac{r + |I|}{2} \right\rfloor + u_z\f$.
4628 *
4629 * If \f$a = 2\f$, then \f$\ell_y = \left\lfloor \frac{r + |I|}{2} \right\rfloor - u_z\f$ and \f$u_y = \left\lfloor
4630 * \frac{r + |I|}{2} \right\rfloor - \ell_z\f$.
4631 *
4632 * Then consider the resulting XOR-constraint
4633 * \f[
4634 * \bigoplus_{i \in I} \bar{x}_i \oplus \bigoplus_{j \in j} x_j = (r + |I|) \text{ mod } 2.
4635 * \f]
4636 * If \f$\ell_y \leq 0\f$ and \f$u_y \geq (|I| + |J|)/2\f$, then the XOR constraint is a reformulation of the above
4637 * transformed constraint, otherwise it is a relaxation because the bounds on the \f$y\f$-variable may disallow
4638 * too many (or too few) operators set to 1. Therefore, the XOR constraint handler verifies in this case that the linear
4639 * equation holds, ie., that the \f$y\f$-variable has the correct value.
4640 */
4641static
4643{ /*lint --e{715}*/
4644 assert(upgdcons != NULL);
4645 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), "linear") == 0);
4647
4648 /* check, if linear constraint can be upgraded to xor constraint */
4649 /* @todo also applicable if the integer variable has a coefficient different from 2, e.g. a coefficient like 0.5 then
4650 * we could generate a new integer variable aggregated to the old one, possibly the constraint was then
4651 * normalized and all binary variables have coefficients of 2.0, if the coefficient is 4 then we need holes ...
4652 */
4653 if( integral && nposcont + nnegcont == 0 && nposbin + nnegbin + nposimplbin + nnegimplbin >= nvars-1 && ncoeffspone + ncoeffsnone == nvars-1 && ncoeffspint + ncoeffsnint == 1 )
4654 {
4655 assert(ncoeffspfrac + ncoeffsnfrac == 0);
4656
4657 if( SCIPisEQ(scip, lhs, rhs) && SCIPisIntegral(scip, lhs) )
4658 {
4659 SCIP_VAR** xorvars;
4660 SCIP_VAR* parityvar = NULL;
4661 SCIP_VARTYPE parityvartype;
4662 SCIP_Bool postwo = FALSE;
4663 int cnt = 0;
4664 int j;
4665
4667
4668 /* check parity of constraints */
4669 for( j = nvars - 1; j >= 0; --j )
4670 {
4671 if( SCIPisEQ(scip, REALABS(vals[j]), 2.0) )
4672 {
4673 parityvar = vars[j];
4674 parityvartype = SCIPvarGetType(parityvar);
4675
4676 /* parity variable requires enforced integrality */
4677 if( parityvartype != SCIP_VARTYPE_BINARY && parityvartype != SCIP_VARTYPE_INTEGER )
4678 {
4679 parityvar = NULL;
4680 break;
4681 }
4682
4683 postwo = (vals[j] > 0.0);
4684 }
4685 else if( !SCIPisEQ(scip, REALABS(vals[j]), 1.0) )
4686 break;
4687 else
4688 {
4689 /* exit if variable is not binary or implicit binary */
4690 if( !SCIPvarIsBinary(vars[j]) )
4691 {
4692 parityvar = NULL;
4693 break;
4694 }
4695
4696 /* need negated variables for correct propagation to the integer variable */
4697 if( vals[j] < 0.0 )
4698 {
4699 SCIP_CALL( SCIPgetNegatedVar(scip, vars[j], &(xorvars[cnt])) );
4700 assert(xorvars[cnt] != NULL);
4701 }
4702 else
4703 xorvars[cnt] = vars[j];
4704 ++cnt;
4705 }
4706 }
4707
4708 if( parityvar != NULL )
4709 {
4710 assert(cnt == nvars - 1);
4711
4712 /* check whether parity variable is present only in this constraint */
4714 && SCIPvarGetNLocksUpType(parityvar, SCIP_LOCKTYPE_MODEL) <= 1 )
4715 {
4716 SCIP_VAR* intvar;
4717 SCIP_Bool rhsparity;
4718 SCIP_Bool neednew;
4719 int intrhs;
4720
4721 /* adjust the side, since we negated all binary variables with -1.0 as a coefficient */
4722 rhs += ncoeffsnone;
4723
4724 intrhs = (int) SCIPfloor(scip, rhs);
4725 rhsparity = ((SCIP_Bool) (intrhs % 2)); /*lint !e571*/
4726
4727 /* we need a new variable if the rhs is not 0 or 1 or if the coefficient was +2, since in these cases, we
4728 * need to aggregate the variables (flipping signs and/or shifting */
4729 if( (intrhs != 1 && intrhs != 0) || postwo )
4730 neednew = TRUE;
4731 else
4732 neednew = FALSE;
4733
4734 /* check if we can use the parity variable as integer variable of the XOR constraint or do we need to
4735 * create a new variable and aggregate */
4736 if( neednew )
4737 {
4738 char varname[SCIP_MAXSTRLEN];
4739 SCIP_Real lb;
4740 SCIP_Real ub;
4741 SCIP_Bool isbinary;
4742 SCIP_Bool infeasible;
4743 SCIP_Bool redundant;
4744 SCIP_Bool aggregated;
4745 int intrhshalfed;
4746
4747 intrhshalfed = intrhs / 2;
4748
4749 if( postwo )
4750 {
4751 lb = intrhshalfed - SCIPvarGetUbGlobal(parityvar);
4752 ub = intrhshalfed - SCIPvarGetLbGlobal(parityvar);
4753 }
4754 else
4755 {
4756 lb = intrhshalfed + SCIPvarGetLbGlobal(parityvar);
4757 ub = intrhshalfed + SCIPvarGetUbGlobal(parityvar);
4758 }
4759 assert(SCIPisFeasLE(scip, lb, ub));
4762
4763 /* adjust bounds to be more integral */
4764 lb = SCIPfeasFloor(scip, lb);
4765 ub = SCIPfeasFloor(scip, ub);
4766
4767 isbinary = (SCIPisZero(scip, lb) && SCIPisEQ(scip, ub, 1.0));
4768
4769 /* something is wrong if parity variable is already binary, but artificial variable is not */
4770 if( SCIPvarIsBinary(parityvar) && !isbinary )
4771 {
4772 SCIPfreeBufferArray(scip, &xorvars);
4773 return SCIP_OKAY;
4774 }
4775
4776 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "%s_xor_upgr", SCIPvarGetName(parityvar));
4777 SCIP_CALL( SCIPcreateVar(scip, &intvar, varname, lb, ub, 0.0,
4779 SCIPvarIsInitial(parityvar), SCIPvarIsRemovable(parityvar), NULL, NULL, NULL, NULL, NULL) );
4780 SCIP_CALL( SCIPaddVar(scip, intvar) );
4781
4782 SCIPdebugMsg(scip, "created new variable for aggregation:");
4783 SCIPdebug( SCIPprintVar(scip, intvar, NULL) );
4784
4785 SCIP_CALL( SCIPaggregateVars(scip, parityvar, intvar, 1.0, postwo ? 1.0 : -1.0,
4786 (SCIP_Real) (postwo ? intrhshalfed : -intrhshalfed), &infeasible, &redundant, &aggregated) );
4787 assert(!infeasible);
4788
4789 /* maybe aggregation was forbidden, than we cannot upgrade this constraint */
4790 if( !aggregated )
4791 {
4792 SCIPfreeBufferArray(scip, &xorvars);
4793 return SCIP_OKAY;
4794 }
4795
4796 assert(redundant);
4797 assert(SCIPvarIsActive(intvar));
4798
4799#ifdef SCIP_DEBUG
4801 {
4802 SCIPdebugMsg(scip, "aggregated: <%s> = %g * <%s> + %g\n", SCIPvarGetName(parityvar),
4804 SCIPvarGetAggrConstant(parityvar));
4805 }
4806 else
4807 {
4809 SCIPdebugMsg(scip, "negated: <%s> = 1 - <%s>\n", SCIPvarGetName(parityvar),
4811 }
4812#endif
4813 }
4814 else
4815 intvar = parityvar;
4816
4817 assert(intvar != NULL);
4818
4819 SCIP_CALL( createConsXorIntvar(scip, upgdcons, SCIPconsGetName(cons), rhsparity, nvars - 1, xorvars, intvar,
4824
4825 SCIPdebugMsg(scip, "upgraded constraint <%s> to XOR constraint:\n", SCIPconsGetName(cons));
4826 SCIPdebugPrintCons(scip, *upgdcons, NULL);
4827
4828 if( neednew )
4829 {
4830 assert(intvar != parityvar);
4831 SCIP_CALL( SCIPreleaseVar(scip, &intvar) );
4832 }
4833 }
4834 }
4835
4836 SCIPfreeBufferArray(scip, &xorvars);
4837 }
4838 }
4839
4840 return SCIP_OKAY;
4841}
4842
4843/** adds symmetry information of constraint to a symmetry detection graph */
4844static
4846 SCIP* scip, /**< SCIP pointer */
4847 SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */
4848 SCIP_CONS* cons, /**< constraint */
4849 SYM_GRAPH* graph, /**< symmetry detection graph */
4850 SCIP_Bool* success /**< pointer to store whether symmetry information could be added */
4851 )
4852{
4853 SCIP_CONSDATA* consdata;
4854 SCIP_VAR** xorvars;
4855 SCIP_VAR** vars;
4856 SCIP_Real* vals;
4857 SCIP_Real constant;
4858 int consnodeidx;
4859 int nlocvars;
4860 int i;
4861
4862 assert(scip != NULL);
4863 assert(cons != NULL);
4864 assert(graph != NULL);
4865 assert(success != NULL);
4866
4867 consdata = SCIPconsGetData(cons);
4868 assert(consdata != NULL);
4869
4870 /* create arrays to store active representation of variables */
4871 nlocvars = MAX(consdata->nvars, 1);
4872 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nlocvars) );
4873 SCIP_CALL( SCIPallocBufferArray(scip, &vals, nlocvars) );
4874
4875 /* add constraint node */
4876 SCIP_CALL( SCIPaddSymgraphConsnode(scip, graph, cons, 0.0, 0.0, &consnodeidx) );
4877
4878 /* add intvar to symmetry detection graph */
4879 if( consdata->intvar != NULL)
4880 {
4881 int xornodeidx;
4882
4883 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int)SYM_CONSOPTYPE_XORINT, &xornodeidx) );
4884 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, consnodeidx, xornodeidx, FALSE, 0.0) );
4885
4886 vars[0] = consdata->intvar;
4887 vals[0] = 1.0;
4888 constant = 0.0;
4889 nlocvars = 1;
4890 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &vars, &vals, &nlocvars, &constant, SCIPisTransformed(scip)) );
4891 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, xornodeidx, vars, vals, nlocvars, constant) );
4892 }
4893
4894 /* add node modeling the XOR-part and connect it with constraint node */
4895 xorvars = consdata->vars;
4896 for( i = 0; i < consdata->nvars; ++i )
4897 {
4898 assert(xorvars[i] != NULL);
4899 vars[i] = xorvars[i];
4900 vals[i] = 1.0;
4901 }
4902 constant = -(SCIP_Real)SCIPgetRhsXor(scip, cons);
4903 nlocvars = consdata->nvars;
4904 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &vars, &vals, &nlocvars, &constant, SCIPisTransformed(scip)) );
4905 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, consnodeidx, vars, vals, nlocvars, constant) );
4906
4907 SCIPfreeBufferArray(scip, &vals);
4909
4910 *success = TRUE;
4911
4912 return SCIP_OKAY;
4913}
4914
4915/*
4916 * Callback methods of constraint handler
4917 */
4918
4919/** copy method for constraint handler plugins (called when SCIP copies plugins) */
4920static
4922{ /*lint --e{715}*/
4923 assert(scip != NULL);
4924 assert(conshdlr != NULL);
4925 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
4926
4927 /* call inclusion method of constraint handler */
4929
4930 *valid = TRUE;
4931
4932 return SCIP_OKAY;
4933}
4934
4935/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
4936static
4938{ /*lint --e{715}*/
4939 SCIP_CONSHDLRDATA* conshdlrdata;
4940
4941 /* free constraint handler data */
4942 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4943 assert(conshdlrdata != NULL);
4944
4945 conshdlrdataFree(scip, &conshdlrdata);
4946
4947 SCIPconshdlrSetData(conshdlr, NULL);
4948
4949 return SCIP_OKAY;
4950}
4951
4952/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
4953static
4955{ /*lint --e{715}*/
4956 SCIP_CONSDATA* consdata;
4957 int c;
4958
4959 /* release and free the rows of all constraints */
4960 for( c = 0; c < nconss; ++c )
4961 {
4962 consdata = SCIPconsGetData(conss[c]);
4963 SCIP_CALL( consdataFreeRows(scip, consdata) );
4964 }
4965
4966 return SCIP_OKAY;
4967}
4968
4969
4970/** frees specific constraint data */
4971static
4973{ /*lint --e{715}*/
4974 SCIP_CONSHDLRDATA* conshdlrdata;
4975
4976 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4977 assert(conshdlrdata != NULL);
4978
4980 {
4981 int v;
4982
4983 for( v = (*consdata)->nvars - 1; v >= 0; --v )
4984 {
4985 SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->vars[v], SCIP_EVENTTYPE_VARFIXED, conshdlrdata->eventhdlr,
4986 (SCIP_EVENTDATA*)(*consdata), -1) );
4987 }
4988 }
4989
4990 SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
4991
4992 return SCIP_OKAY;
4993}
4994
4995
4996/** transforms constraint data into data belonging to the transformed problem */
4997static
4999{ /*lint --e{715}*/
5000 SCIP_CONSDATA* sourcedata;
5001 SCIP_CONSDATA* targetdata;
5002
5003 sourcedata = SCIPconsGetData(sourcecons);
5004 assert(sourcedata != NULL);
5005 assert(sourcedata->nvars >= 1);
5006 assert(sourcedata->vars != NULL);
5007
5008 /* create target constraint data */
5009 SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->rhs, sourcedata->nvars, sourcedata->vars, sourcedata->intvar) );
5010
5011 /* create target constraint */
5012 SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
5013 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
5014 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
5015 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
5016 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
5017
5018 return SCIP_OKAY;
5019}
5020
5021
5022/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
5023static
5025{ /*lint --e{715}*/
5026 int i;
5027
5028 assert(infeasible != NULL);
5029
5030 *infeasible = FALSE;
5031
5032 for( i = 0; i < nconss && !(*infeasible); i++ )
5033 {
5034 assert(SCIPconsIsInitial(conss[i]));
5035 SCIP_CALL( addRelaxation(scip, conss[i], infeasible) );
5036 }
5037
5038 return SCIP_OKAY;
5039}
5040
5041
5042/** separation method of constraint handler for LP solutions */
5043static
5045{ /*lint --e{715}*/
5046 SCIP_CONSHDLRDATA* conshdlrdata;
5047 SCIP_Bool separated;
5049 int c;
5050
5052
5053 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5054 assert(conshdlrdata != NULL);
5055
5056 /* separate all useful constraints */
5057 for( c = 0; c < nusefulconss; ++c )
5058 {
5059 SCIP_CALL( separateCons(scip, conss[c], NULL, conshdlrdata->separateparity, &separated, &cutoff) );
5060 if( cutoff )
5062 else if( separated )
5064 }
5065
5066 /* combine constraints to get more cuts */
5067 /**@todo combine constraints to get further cuts */
5068
5069 return SCIP_OKAY;
5070}
5071
5072
5073/** separation method of constraint handler for arbitrary primal solutions */
5074static
5076{ /*lint --e{715}*/
5077 SCIP_CONSHDLRDATA* conshdlrdata;
5078 SCIP_Bool separated;
5080 int c;
5081
5083
5084 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5085 assert(conshdlrdata != NULL);
5086
5087 /* separate all useful constraints */
5088 for( c = 0; c < nusefulconss; ++c )
5089 {
5090 SCIP_CALL( separateCons(scip, conss[c], sol, conshdlrdata->separateparity, &separated, &cutoff) );
5091 if( cutoff )
5093 else if( separated )
5095 }
5096
5097 /* combine constraints to get more cuts */
5098 /**@todo combine constraints to get further cuts */
5099
5100 return SCIP_OKAY;
5101}
5102
5103
5104/** constraint enforcing method of constraint handler for LP solutions */
5105static
5107{ /*lint --e{715}*/
5108 SCIP_CONSHDLRDATA* conshdlrdata;
5109 SCIP_Bool violated;
5111 int i;
5112
5113 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5114 assert(conshdlrdata != NULL);
5115
5116 /* method is called only for integral solutions, because the enforcing priority is negative */
5117 for( i = 0; i < nconss; i++ )
5118 {
5119 SCIP_CALL( checkCons(scip, conss[i], NULL, FALSE, FALSE, &violated) );
5120 if( violated )
5121 {
5122 SCIP_Bool separated;
5123
5124 SCIP_CALL( separateCons(scip, conss[i], NULL, conshdlrdata->separateparity, &separated, &cutoff) );
5125 if( cutoff )
5127 else
5128 {
5129 assert(separated); /* because the solution is integral, the separation always finds a cut */
5131 }
5132 return SCIP_OKAY;
5133 }
5134 }
5136
5137 return SCIP_OKAY;
5138}
5139
5140
5141/** constraint enforcing method of constraint handler for relaxation solutions */
5142static
5144{ /*lint --e{715}*/
5145 SCIP_CONSHDLRDATA* conshdlrdata;
5146 SCIP_Bool violated;
5148 int i;
5149
5150 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5151 assert(conshdlrdata != NULL);
5152
5153 /* method is called only for integral solutions, because the enforcing priority is negative */
5154 for( i = 0; i < nconss; i++ )
5155 {
5156 SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
5157 if( violated )
5158 {
5159 SCIP_Bool separated;
5160
5161 SCIP_CALL( separateCons(scip, conss[i], sol, conshdlrdata->separateparity, &separated, &cutoff) );
5162 if( cutoff )
5164 else
5165 {
5166 assert(separated); /* because the solution is integral, the separation always finds a cut */
5168 }
5169 return SCIP_OKAY;
5170 }
5171 }
5173
5174 return SCIP_OKAY;
5175}
5176
5177
5178/** constraint enforcing method of constraint handler for pseudo solutions */
5179static
5181{ /*lint --e{715}*/
5182 SCIP_Bool violated;
5183 int i;
5184
5185 /* method is called only for integral solutions, because the enforcing priority is negative */
5186 for( i = 0; i < nconss; i++ )
5187 {
5188 SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
5189 if( violated )
5190 {
5192 return SCIP_OKAY;
5193 }
5194 }
5196
5197 return SCIP_OKAY;
5198}
5199
5200/** feasibility check method of constraint handler xor */
5201static
5203{ /*lint --e{715}*/
5204 SCIP_Bool violated;
5205 int i;
5206
5208
5209 for( i = 0; i < nconss && ( *result == SCIP_FEASIBLE || completely ); ++i )
5210 {
5211 SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
5212 if( violated )
5214 }
5215
5216 return SCIP_OKAY;
5217}
5218
5219/** domain propagation method of constraint handler */
5220static
5222{ /*lint --e{715}*/
5223 SCIP_CONSHDLRDATA* conshdlrdata;
5225 int nfixedvars;
5226 int nchgbds;
5227 int c;
5228
5229 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5230 assert(conshdlrdata != NULL);
5231
5232 cutoff = FALSE;
5233 nfixedvars = 0;
5234 nchgbds = 0;
5235
5236 /* propagate all useful constraints */
5237 for( c = 0; c < nusefulconss && !cutoff; ++c )
5238 {
5239 SCIP_CALL( propagateCons(scip, conss[c], conshdlrdata->eventhdlr, &cutoff, &nfixedvars, &nchgbds) );
5240 }
5241
5242 /* return the correct result */
5243 if( cutoff )
5245 else if( nfixedvars > 0 || nchgbds > 0 )
5247 else
5248 {
5250 if( !SCIPinProbing(scip) )
5251 {
5252 int depth;
5253 int freq;
5254
5256 freq = conshdlrdata->gausspropfreq;
5257 if( (depth == 0 && freq == 0) || (freq > 0 && depth % freq == 0) )
5258 {
5259 /* take useful constraints only - might improve success rate to take all */
5260 SCIP_CALL( checkSystemGF2(scip, conss, nusefulconss, NULL, result) );
5261 }
5262 }
5263 }
5264
5265 return SCIP_OKAY;
5266}
5267
5268/** presolving initialization method of constraint handler (called when presolving is about to begin) */
5269static
5271{ /*lint --e{715}*/
5272 SCIP_CONSHDLRDATA* conshdlrdata;
5273 SCIP_CONSDATA* consdata;
5274 int c;
5275 int v;
5276
5277 assert(conshdlr != NULL);
5278 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5279 assert(conshdlrdata != NULL);
5280
5281 /* catch all variable event for deleted variables, which is only used in presolving */
5282 for( c = nconss - 1; c >= 0; --c )
5283 {
5284 consdata = SCIPconsGetData(conss[c]);
5285 assert(consdata != NULL);
5286
5287 for( v = consdata->nvars - 1; v >= 0; --v )
5288 {
5289 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[v], SCIP_EVENTTYPE_VARFIXED, conshdlrdata->eventhdlr,
5290 (SCIP_EVENTDATA*)consdata, NULL) );
5291 }
5292 }
5293
5294 return SCIP_OKAY;
5295}
5296
5297/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
5298static
5300{ /*lint --e{715}*/
5301 SCIP_CONSHDLRDATA* conshdlrdata;
5302 SCIP_CONSDATA* consdata;
5303 int c;
5304 int v;
5305
5306 assert(conshdlr != NULL);
5307 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5308 assert(conshdlrdata != NULL);
5309
5310 /* drop all variable event for deleted variables, which was only used in presolving */
5311 for( c = 0; c < nconss; ++c )
5312 {
5313 consdata = SCIPconsGetData(conss[c]);
5314 assert(consdata != NULL);
5315
5316 if( !SCIPconsIsDeleted(conss[c]) )
5317 {
5318 for( v = 0; v < consdata->nvars; ++v )
5319 {
5320 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[v], SCIP_EVENTTYPE_VARFIXED, conshdlrdata->eventhdlr,
5321 (SCIP_EVENTDATA*)consdata, -1) );
5322 }
5323 }
5324 }
5325
5326 return SCIP_OKAY;
5327}
5328
5329/** presolving method of constraint handler */
5330static
5332{ /*lint --e{715}*/
5333 SCIP_CONSHDLRDATA* conshdlrdata;
5334 SCIP_CONS* cons;
5335 SCIP_CONSDATA* consdata;
5337 SCIP_Bool redundant;
5338 SCIP_Bool aggregated;
5339 int oldnfixedvars;
5340 int oldnchgbds;
5341 int oldnaggrvars;
5342 int oldndelconss;
5343 int oldnchgcoefs;
5344 int firstchange;
5345 int c;
5346
5347 assert(result != NULL);
5348
5349 oldnfixedvars = *nfixedvars;
5350 oldnchgbds = *nchgbds;
5351 oldnaggrvars = *naggrvars;
5352 oldndelconss = *ndelconss;
5353 oldnchgcoefs = *nchgcoefs;
5354
5355 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5356 assert(conshdlrdata != NULL);
5357
5358 /* process constraints */
5359 cutoff = FALSE;
5360 firstchange = INT_MAX;
5361 for( c = 0; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
5362 {
5363 cons = conss[c];
5364 assert(cons != NULL);
5365 consdata = SCIPconsGetData(cons);
5366 assert(consdata != NULL);
5367
5368 /* force presolving the constraint in the initial round */
5369 if( nrounds == 0 )
5370 consdata->propagated = FALSE;
5371
5372 /* remember the first changed constraint to begin the next aggregation round with */
5373 if( firstchange == INT_MAX && consdata->changed )
5374 firstchange = c;
5375
5376 /* remove all variables that are fixed to zero and all pairs of variables fixed to one;
5377 * merge multiple entries of the same or negated variables
5378 */
5379 SCIP_CALL( applyFixings(scip, cons, conshdlrdata->eventhdlr, nchgcoefs, naggrvars, naddconss, &cutoff) );
5380
5381 if( cutoff )
5382 break;
5383
5384 /* propagate constraint */
5385 SCIP_CALL( propagateCons(scip, cons, conshdlrdata->eventhdlr, &cutoff, nfixedvars, nchgbds) );
5386
5387 if( !cutoff && !SCIPconsIsDeleted(cons) && !SCIPconsIsModifiable(cons) )
5388 {
5389 assert(consdata->nvars >= 2); /* otherwise, propagateCons() has deleted the constraint */
5390
5391 /* if only two variables are left, both have to be equal or opposite, depending on the rhs */
5392 if( consdata->nvars == 2 )
5393 {
5394 SCIPdebugMsg(scip, "xor constraint <%s> has only two unfixed variables, rhs=%u\n",
5395 SCIPconsGetName(cons), consdata->rhs);
5396
5397 assert(consdata->vars != NULL);
5398 assert(SCIPisEQ(scip, SCIPvarGetLbGlobal(consdata->vars[0]), 0.0));
5399 assert(SCIPisEQ(scip, SCIPvarGetUbGlobal(consdata->vars[0]), 1.0));
5400 assert(SCIPisEQ(scip, SCIPvarGetLbGlobal(consdata->vars[1]), 0.0));
5401 assert(SCIPisEQ(scip, SCIPvarGetUbGlobal(consdata->vars[1]), 1.0));
5402
5403 if( !consdata->rhs )
5404 {
5405 /* aggregate variables: vars[0] - vars[1] == 0 */
5406 SCIPdebugMsg(scip, " -> aggregate <%s> == <%s>\n", SCIPvarGetName(consdata->vars[0]),
5407 SCIPvarGetName(consdata->vars[1]));
5408 SCIP_CALL( SCIPaggregateVars(scip, consdata->vars[0], consdata->vars[1], 1.0, -1.0, 0.0,
5409 &cutoff, &redundant, &aggregated) );
5410 }
5411 else
5412 {
5413 /* aggregate variables: vars[0] + vars[1] == 1 */
5414 SCIPdebugMsg(scip, " -> aggregate <%s> == 1 - <%s>\n", SCIPvarGetName(consdata->vars[0]),
5415 SCIPvarGetName(consdata->vars[1]));
5416 SCIP_CALL( SCIPaggregateVars(scip, consdata->vars[0], consdata->vars[1], 1.0, 1.0, 1.0,
5417 &cutoff, &redundant, &aggregated) );
5418 }
5419 assert(redundant || SCIPdoNotAggr(scip));
5420
5421 if( aggregated )
5422 {
5423 assert(redundant);
5424 ++(*naggrvars);
5425 }
5426
5427 /* the constraint can be deleted if the intvar is fixed or NULL */
5428 if( redundant )
5429 {
5430 SCIP_Bool fixedintvar;
5431
5432 fixedintvar = consdata->intvar == NULL ? TRUE : SCIPisEQ(scip, SCIPvarGetLbGlobal(consdata->intvar), SCIPvarGetUbGlobal(consdata->intvar));
5433
5434 if( fixedintvar )
5435 {
5436 /* if there is an integer variable then the following
5437 * must hold:
5438 *
5439 * if consdata->rhs == 1 then the integer variable needs
5440 * to be fixed to zero, otherwise the constraint is
5441 * infeasible,
5442 *
5443 * if consdata->rhs == 0 then the integer variable needs
5444 * to be aggregated to one of the binary variables
5445 */
5446 assert(consdata->intvar == NULL || (consdata->rhs && SCIPvarGetUbGlobal(consdata->intvar) < 0.5));
5447
5448 /* delete constraint */
5449 SCIP_CALL( SCIPdelCons(scip, cons) );
5450 (*ndelconss)++;
5451 }
5452 }
5453 }
5454 else if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
5455 {
5456 /* try to use clique information to upgrade the constraint to a set-partitioning constraint or fix
5457 * variables
5458 */
5459 SCIP_CALL( cliquePresolve(scip, cons, nfixedvars, naggrvars, nchgcoefs, ndelconss, naddconss, &cutoff) );
5460 }
5461 }
5462 }
5463
5464 /* process pairs of constraints: check them for equal operands;
5465 * only apply this expensive procedure, if the single constraint preprocessing did not find any reductions
5466 */
5467 if( !cutoff && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && SCIPisPresolveFinished(scip) )
5468 {
5469 if( firstchange < nconss && conshdlrdata->presolusehashing )
5470 {
5471 /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
5472 SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &firstchange, nchgcoefs,
5473 nfixedvars, naggrvars, ndelconss, naddconss, &cutoff) );
5474 }
5475 if( conshdlrdata->presolpairwise )
5476 {
5477 SCIP_Longint npaircomparisons;
5478 int lastndelconss;
5479 npaircomparisons = 0;
5480 lastndelconss = *ndelconss;
5481
5482 for( c = firstchange; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
5483 {
5484 if( SCIPconsIsActive(conss[c]) && !SCIPconsIsModifiable(conss[c]) )
5485 {
5486 npaircomparisons += (SCIPconsGetData(conss[c])->changed) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange);
5487
5488 SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c,
5489 &cutoff, nfixedvars, naggrvars, ndelconss, naddconss, nchgcoefs) );
5490
5491 if( npaircomparisons > NMINCOMPARISONS )
5492 {
5493 if( ((SCIP_Real) (*ndelconss - lastndelconss)) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
5494 break;
5495 lastndelconss = *ndelconss;
5496 npaircomparisons = 0;
5497 }
5498 }
5499 }
5500 }
5501 }
5502
5503 /* return the correct result code */
5504 if( cutoff )
5506 else if( *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds || *naggrvars > oldnaggrvars
5507 || *ndelconss > oldndelconss || *nchgcoefs > oldnchgcoefs )
5509 else
5511
5512 /* add extended formulation at the end of presolving if required */
5513 if( conshdlrdata->addextendedform && *result == SCIP_DIDNOTFIND && SCIPisPresolveFinished(scip) )
5514 {
5515 for( c = 0; c < nconss && !SCIPisStopped(scip); ++c )
5516 {
5517 int naddedconss = 0;
5518
5519 cons = conss[c];
5520 assert(cons != NULL);
5521 consdata = SCIPconsGetData(cons);
5522 assert(consdata != NULL);
5523
5524 if( consdata->extvars != NULL )
5525 break;
5526
5527 if( conshdlrdata->addflowextended )
5528 {
5529 SCIP_CALL( addExtendedFlowFormulation(scip, cons, naggrvars, &naddedconss) );
5530 }
5531 else
5532 {
5533 SCIP_CALL( addExtendedAsymmetricFormulation(scip, cons, naggrvars, &naddedconss) );
5534 }
5535 (*naddconss) += naddedconss;
5536 }
5537 }
5538
5539 return SCIP_OKAY;
5540}
5541
5542
5543/** propagation conflict resolving method of constraint handler */
5544static
5546{ /*lint --e{715}*/
5547 SCIP_CALL( resolvePropagation(scip, cons, infervar, (PROPRULE)inferinfo, bdchgidx, result) );
5548
5549 return SCIP_OKAY;
5550}
5551
5552
5553/** variable rounding lock method of constraint handler */
5554static
5556{ /*lint --e{715}*/
5557 SCIP_CONSDATA* consdata;
5558 int i;
5559
5560 consdata = SCIPconsGetData(cons);
5561 assert(consdata != NULL);
5562
5563 /* external variables */
5564 for( i = 0; i < consdata->nvars; ++i )
5565 {
5566 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
5567 }
5568
5569 /* internal variable */
5570 if( consdata->intvar != NULL )
5571 {
5572 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->intvar, locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
5573 }
5574
5575 return SCIP_OKAY;
5576}
5577
5578
5579/** constraint display method of constraint handler */
5580static
5582{ /*lint --e{715}*/
5583 assert(scip != NULL);
5584 assert(conshdlr != NULL);
5585 assert(cons != NULL);
5586
5588
5589 return SCIP_OKAY;
5590}
5591
5592/** constraint copying method of constraint handler */
5593static
5595{ /*lint --e{715}*/
5596 SCIP_CONSDATA* sourceconsdata;
5597 SCIP_VAR** sourcevars;
5598 SCIP_VAR** targetvars;
5599 SCIP_VAR* intvar;
5600 SCIP_VAR* targetintvar;
5601 const char* consname;
5602 int nvars;
5603 int v;
5604
5605 assert(scip != NULL);
5606 assert(sourcescip != NULL);
5607 assert(sourcecons != NULL);
5608
5609 (*valid) = TRUE;
5610
5611 sourceconsdata = SCIPconsGetData(sourcecons);
5612 assert(sourceconsdata != NULL);
5613
5614 /* get variables and coefficients of the source constraint */
5615 sourcevars = sourceconsdata->vars;
5616 nvars = sourceconsdata->nvars;
5617 intvar = sourceconsdata->intvar;
5618 targetintvar = NULL;
5619
5620 if( name != NULL )
5621 consname = name;
5622 else
5623 consname = SCIPconsGetName(sourcecons);
5624
5625 if( nvars == 0 )
5626 {
5627 if( intvar != NULL )
5628 {
5629 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, intvar, &targetintvar, varmap, consmap, global, valid) );
5630 assert(!(*valid) || targetintvar != NULL);
5631
5632 if( targetintvar != NULL )
5633 {
5634 SCIPdebugMsg(scip, "Copied integral variable <%s> (bounds: [%g,%g])\n", SCIPvarGetName(targetintvar),
5635 global ? SCIPvarGetLbGlobal(intvar) : SCIPvarGetLbLocal(intvar),
5636 global ? SCIPvarGetUbGlobal(intvar) : SCIPvarGetUbLocal(intvar));
5637 }
5638 }
5639
5640 if( *valid )
5641 {
5642 SCIP_CALL( createConsXorIntvar(scip, cons, consname, SCIPgetRhsXor(sourcescip, sourcecons), 0, NULL,
5643 targetintvar, initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable,
5644 stickingatnode) );
5645 }
5646
5647 return SCIP_OKAY;
5648 }
5649
5650 /* duplicate variable array */
5651 SCIP_CALL( SCIPallocBufferArray(scip, &targetvars, nvars) );
5652
5653 /* map variables of the source constraint to variables of the target SCIP */
5654 for( v = 0; v < nvars && *valid; ++v )
5655 {
5656 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &targetvars[v], varmap, consmap, global, valid) );
5657 assert(!(*valid) || targetvars[v] != NULL);
5658 }
5659
5660 /* map artificial relaxation variable of the source constraint to variable of the target SCIP */
5661 if( *valid && intvar != NULL )
5662 {
5663 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, intvar, &targetintvar, varmap, consmap, global, valid) );
5664 assert(!(*valid) || targetintvar != NULL);
5665
5666 SCIPdebugMsg(scip, "Copied integral variable <%s> (bounds: [%g,%g])\n", SCIPvarGetName(targetintvar),
5667 global ? SCIPvarGetLbGlobal(intvar) : SCIPvarGetLbLocal(intvar),
5668 global ? SCIPvarGetUbGlobal(intvar) : SCIPvarGetUbLocal(intvar));
5669 }
5670
5671 /* only create the target constraints, if all variables could be copied */
5672 if( *valid )
5673 {
5674 SCIP_CALL( createConsXorIntvar(scip, cons, consname, SCIPgetRhsXor(sourcescip, sourcecons), nvars, targetvars,
5675 targetintvar, initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable,
5676 stickingatnode) );
5677 }
5678
5679 /* free buffer array */
5680 SCIPfreeBufferArray(scip, &targetvars);
5681
5682 return SCIP_OKAY;
5683}
5684
5685
5686/** constraint parsing method of constraint handler */
5687static
5689{ /*lint --e{715}*/
5690 SCIP_VAR** vars;
5691 char* endptr;
5692 int requiredsize;
5693 int varssize;
5694 int nvars;
5695
5696 SCIPdebugMsg(scip, "parse <%s> as xor constraint\n", str);
5697
5698 varssize = 100;
5699 nvars = 0;
5700
5701 /* allocate buffer array for variables */
5702 SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
5703
5704 /* parse string */
5705 SCIP_CALL( SCIPparseVarsList(scip, str, vars, &nvars, varssize, &requiredsize, &endptr, ',', success) );
5706
5707 if( *success )
5708 {
5709 SCIP_Real rhs;
5710
5711 /* check if the size of the variable array was big enough */
5712 if( varssize < requiredsize )
5713 {
5714 /* reallocate memory */
5715 varssize = requiredsize;
5716 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
5717
5718 /* parse string again with the correct size of the variable array */
5719 SCIP_CALL( SCIPparseVarsList(scip, str, vars, &nvars, varssize, &requiredsize, &endptr, ',', success) );
5720 }
5721
5722 assert(*success);
5723 assert(varssize >= requiredsize);
5724
5725 SCIPdebugMsg(scip, "successfully parsed %d variables\n", nvars);
5726
5727 /* find "==" */
5728 endptr = strchr(endptr, '=');
5729
5730 /* if the string end has been reached without finding the "==" */
5731 if( endptr == NULL )
5732 {
5733 SCIPerrorMessage("Could not find terminating '='.\n");
5734 *success = FALSE;
5735 goto TERMINATE;
5736 }
5737
5738 str = endptr;
5739
5740 /* skip "==" */
5741 str += *(str+1) == '=' ? 2 : 1;
5742
5743 if( SCIPparseReal(scip, str, &rhs, &endptr) )
5744 {
5745 SCIP_VAR* intvar = NULL;
5746
5747 assert(SCIPisZero(scip, rhs) || SCIPisEQ(scip, rhs, 1.0));
5748
5749 str = endptr;
5750
5751 /* skip white spaces */
5752 SCIP_CALL( SCIPskipSpace((char**)&str) );
5753
5754 /* check for integer variable, should look like (intvar = var) */
5755 if( *str == '(' )
5756 {
5757 str = strchr(str+1, '=');
5758
5759 if( str == NULL )
5760 {
5761 SCIPerrorMessage("Parsing integer variable of XOR constraint\n");
5762 *success = FALSE;
5763 goto TERMINATE;
5764 }
5765
5766 ++str;
5767
5768 /* parse variable name */
5769 SCIP_CALL( SCIPparseVarName(scip, str, &intvar, &endptr) );
5770
5771 if( intvar == NULL )
5772 {
5773 SCIPerrorMessage("Integer variable of XOR not found\n");
5774 *success = FALSE;
5775 goto TERMINATE;
5776 }
5777
5778 /* skip last ')' */
5779 endptr = strchr(endptr, ')');
5780
5781 if( endptr == NULL )
5782 {
5783 SCIPerrorMessage("Closing ')' missing\n");
5784 *success = FALSE;
5785 goto TERMINATE;
5786 }
5787 }
5788
5789 if( intvar != NULL )
5790 {
5791 /* create or constraint */
5792 SCIP_CALL( createConsXorIntvar(scip, cons, name, (rhs > 0.5 ? TRUE : FALSE), nvars, vars, intvar,
5793 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
5794 }
5795 else
5796 {
5797 /* create or constraint */
5798 SCIP_CALL( SCIPcreateConsXor(scip, cons, name, (rhs > 0.5 ? TRUE : FALSE), nvars, vars,
5799 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
5800 }
5801
5802 SCIPdebugPrintCons(scip, *cons, NULL);
5803 }
5804 else
5805 *success = FALSE;
5806 }
5807
5808 TERMINATE:
5809 /* free variable buffer */
5811
5812 return SCIP_OKAY;
5813}
5814
5815/** constraint method of constraint handler which returns the variables (if possible) */
5816static
5818{ /*lint --e{715}*/
5819 SCIP_CONSDATA* consdata;
5820 int nintvar = 0;
5821 int cnt;
5822 int j;
5823
5824 consdata = SCIPconsGetData(cons);
5825 assert(consdata != NULL);
5826
5827 if( consdata->intvar != NULL )
5828 nintvar = 1;
5829
5830 if( varssize < consdata->nvars + nintvar + consdata->nextvars )
5831 (*success) = FALSE;
5832 else
5833 {
5834 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
5835
5836 if( consdata->intvar != NULL )
5837 vars[consdata->nvars] = consdata->intvar;
5838
5839 if( consdata->nextvars > 0 )
5840 {
5841 assert(consdata->extvars != NULL);
5842 cnt = consdata->nvars + nintvar;
5843 for( j = 0; j < consdata->extvarssize; ++j )
5844 {
5845 if( consdata->extvars[j] != NULL )
5846 vars[cnt++] = consdata->extvars[j];
5847 }
5848 assert(cnt == consdata->nvars + nintvar + consdata->nextvars);
5849 }
5850
5851 (*success) = TRUE;
5852 }
5853
5854 return SCIP_OKAY;
5855}
5856
5857/** constraint method of constraint handler which returns the number of variable (if possible) */
5858static
5860{ /*lint --e{715}*/
5861 SCIP_CONSDATA* consdata;
5862
5863 assert(cons != NULL);
5864
5865 consdata = SCIPconsGetData(cons);
5866 assert(consdata != NULL);
5867
5868 if( consdata->intvar == NULL )
5869 (*nvars) = consdata->nvars + consdata->nextvars;
5870 else
5871 (*nvars) = consdata->nvars + 1 + consdata->nextvars;
5872
5873 (*success) = TRUE;
5874
5875 return SCIP_OKAY;
5876}
5877
5878/** constraint handler method which returns the permutation symmetry detection graph of a constraint */
5879static
5880SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphXor)
5881{ /*lint --e{715}*/
5882 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
5883
5884 return SCIP_OKAY;
5885}
5886
5887/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */
5888static
5889SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphXor)
5890{ /*lint --e{715}*/
5891 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
5892
5893 return SCIP_OKAY;
5894}
5895
5896/*
5897 * Callback methods of event handler
5898 */
5899
5900static
5902{ /*lint --e{715}*/
5903 SCIP_CONSDATA* consdata;
5904
5905 assert(eventhdlr != NULL);
5906 assert(eventdata != NULL);
5907 assert(event != NULL);
5908
5909 consdata = (SCIP_CONSDATA*)eventdata;
5910 assert(consdata != NULL);
5911
5913 {
5914 /* we only catch this event in presolving stage */
5916 assert(SCIPeventGetVar(event) != NULL);
5917
5918 consdata->sorted = FALSE;
5919 }
5920
5921 consdata->propagated = FALSE;
5922
5923 return SCIP_OKAY;
5924}
5925
5926
5927/*
5928 * constraint specific interface methods
5929 */
5930
5931/** creates the handler for xor constraints and includes it in SCIP */
5933 SCIP* scip /**< SCIP data structure */
5934 )
5935{
5936 SCIP_CONSHDLRDATA* conshdlrdata;
5937 SCIP_CONSHDLR* conshdlr;
5938 SCIP_EVENTHDLR* eventhdlr;
5939
5940 /* create event handler for events on variables */
5942 eventExecXor, NULL) );
5943
5944 /* create constraint handler data */
5945 SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
5946
5947 /* include constraint handler */
5950 consEnfolpXor, consEnfopsXor, consCheckXor, consLockXor,
5951 conshdlrdata) );
5952 assert(conshdlr != NULL);
5953
5954 /* set non-fundamental callbacks via specific setter functions */
5955 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyXor, consCopyXor) );
5956 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteXor) );
5957 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolXor) );
5958 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeXor) );
5959 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsXor) );
5960 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsXor) );
5961 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpXor) );
5962 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseXor) );
5963 SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreXor) );
5964 SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreXor) );
5966 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintXor) );
5969 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropXor) );
5970 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpXor, consSepasolXor, CONSHDLR_SEPAFREQ,
5972 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransXor) );
5973 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxXor) );
5974 SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphXor) );
5975 SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphXor) );
5976
5977 if( SCIPfindConshdlr(scip, "linear") != NULL )
5978 {
5979 /* include the linear constraint upgrade in the linear constraint handler */
5981 }
5982
5983 /* add xor constraint handler parameters */
5985 "constraints/xor/presolpairwise",
5986 "should pairwise constraint comparison be performed in presolving?",
5987 &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
5988
5990 "constraints/xor/presolusehashing",
5991 "should hash table be used for detecting redundant constraints in advance?",
5992 &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
5993
5995 "constraints/xor/addextendedform",
5996 "should the extended formulation be added in presolving?",
5997 &conshdlrdata->addextendedform, TRUE, DEFAULT_ADDEXTENDEDFORM, NULL, NULL) );
5998
6000 "constraints/xor/addflowextended",
6001 "should the extended flow formulation be added (nonsymmetric formulation otherwise)?",
6002 &conshdlrdata->addflowextended, TRUE, DEFAULT_ADDFLOWEXTENDED, NULL, NULL) );
6003
6005 "constraints/xor/separateparity",
6006 "should parity inequalities be separated?",
6007 &conshdlrdata->separateparity, TRUE, DEFAULT_SEPARATEPARITY, NULL, NULL) );
6008
6010 "constraints/xor/gausspropfreq",
6011 "frequency for applying the Gauss propagator",
6012 &conshdlrdata->gausspropfreq, TRUE, DEFAULT_GAUSSPROPFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
6013
6014 return SCIP_OKAY;
6015}
6016
6017/** creates and captures a xor constraint x_0 xor ... xor x_{k-1} = rhs
6018 *
6019 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
6020 */
6022 SCIP* scip, /**< SCIP data structure */
6023 SCIP_CONS** cons, /**< pointer to hold the created constraint */
6024 const char* name, /**< name of constraint */
6025 SCIP_Bool rhs, /**< right hand side of the constraint */
6026 int nvars, /**< number of operator variables in the constraint */
6027 SCIP_VAR** vars, /**< array with operator variables of constraint */
6028 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
6029 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
6030 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
6031 * Usually set to TRUE. */
6032 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
6033 * TRUE for model constraints, FALSE for additional, redundant constraints. */
6034 SCIP_Bool check, /**< should the constraint be checked for feasibility?
6035 * TRUE for model constraints, FALSE for additional, redundant constraints. */
6036 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
6037 * Usually set to TRUE. */
6038 SCIP_Bool local, /**< is constraint only valid locally?
6039 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
6040 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
6041 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
6042 * adds coefficients to this constraint. */
6043 SCIP_Bool dynamic, /**< is constraint subject to aging?
6044 * Usually set to FALSE. Set to TRUE for own cuts which
6045 * are separated as constraints. */
6046 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
6047 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
6048 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
6049 * if it may be moved to a more global node?
6050 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
6051 )
6052{
6053 SCIP_CONSHDLR* conshdlr;
6054 SCIP_CONSDATA* consdata;
6055 int i;
6056
6057 /* find the xor constraint handler */
6058 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
6059 if( conshdlr == NULL )
6060 {
6061 SCIPerrorMessage("xor constraint handler not found\n");
6062 return SCIP_PLUGINNOTFOUND;
6063 }
6064
6065 /* check whether all variables are binary */
6066 assert(vars != NULL || nvars == 0);
6067 for( i = 0; i < nvars; ++i )
6068 {
6069 if( !SCIPvarIsBinary(vars[i]) )
6070 {
6071 SCIPerrorMessage("operand <%s> is not binary\n", SCIPvarGetName(vars[i]));
6072 return SCIP_INVALIDDATA;
6073 }
6074 }
6075
6076 /* create constraint data */
6077 SCIP_CALL( consdataCreate(scip, &consdata, rhs, nvars, vars, NULL) );
6078
6079 /* create constraint */
6080 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
6081 local, modifiable, dynamic, removable, stickingatnode) );
6082
6083 return SCIP_OKAY;
6084}
6085
6086/** creates and captures a xor constraint x_0 xor ... xor x_{k-1} = rhs
6087 * with all constraint flags set to their default values
6088 *
6089 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
6090 */
6092 SCIP* scip, /**< SCIP data structure */
6093 SCIP_CONS** cons, /**< pointer to hold the created constraint */
6094 const char* name, /**< name of constraint */
6095 SCIP_Bool rhs, /**< right hand side of the constraint */
6096 int nvars, /**< number of operator variables in the constraint */
6097 SCIP_VAR** vars /**< array with operator variables of constraint */
6098 )
6099{
6100 SCIP_CALL( SCIPcreateConsXor(scip,cons, name, rhs, nvars, vars,
6102
6103 return SCIP_OKAY;
6104}
6105
6106/** gets number of variables in xor constraint */
6108 SCIP* scip, /**< SCIP data structure */
6109 SCIP_CONS* cons /**< constraint data */
6110 )
6111{
6112 SCIP_CONSDATA* consdata;
6113
6114 assert(scip != NULL);
6115
6116 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
6117 {
6118 SCIPerrorMessage("constraint is not an xor constraint\n");
6119 SCIPABORT();
6120 return -1; /*lint !e527*/
6121 }
6122
6123 consdata = SCIPconsGetData(cons);
6124 assert(consdata != NULL);
6125
6126 return consdata->nvars;
6127}
6128
6129/** gets array of variables in xor constraint */
6131 SCIP* scip, /**< SCIP data structure */
6132 SCIP_CONS* cons /**< constraint data */
6133 )
6134{
6135 SCIP_CONSDATA* consdata;
6136
6137 assert(scip != NULL);
6138
6139 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
6140 {
6141 SCIPerrorMessage("constraint is not an xor constraint\n");
6142 SCIPABORT();
6143 return NULL; /*lint !e527*/
6144 }
6145
6146 consdata = SCIPconsGetData(cons);
6147 assert(consdata != NULL);
6148
6149 return consdata->vars;
6150}
6151
6152/** gets integer variable in xor constraint */
6154 SCIP* scip, /**< SCIP data structure */
6155 SCIP_CONS* cons /**< constraint data */
6156 )
6157{
6158 SCIP_CONSDATA* consdata;
6159
6160 assert(scip != NULL);
6161
6162 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
6163 {
6164 SCIPerrorMessage("constraint is not an xor constraint\n");
6165 SCIPABORT();
6166 return NULL; /*lint !e527*/
6167 }
6168
6169 consdata = SCIPconsGetData(cons);
6170 assert(consdata != NULL);
6171
6172 return consdata->intvar;
6173}
6174
6175/** gets the right hand side of the xor constraint */
6177 SCIP* scip, /**< SCIP data structure */
6178 SCIP_CONS* cons /**< constraint data */
6179 )
6180{
6181 SCIP_CONSDATA* consdata;
6182
6183 assert(scip != NULL);
6184
6185 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
6186 {
6187 SCIPerrorMessage("constraint is not an xor constraint\n");
6188 SCIPABORT();
6189 }
6190
6191 consdata = SCIPconsGetData(cons);
6192 assert(consdata != NULL);
6193
6194 return consdata->rhs;
6195}
#define EVENTHDLR_NAME
SCIP_VAR * h
SCIP_VAR ** b
SCIP_VAR ** x
#define EVENTHDLR_DESC
enum Proprule PROPRULE
Definition cons_and.c:173
#define CONSHDLR_NEEDSCONS
Definition cons_and.c:97
#define CONSHDLR_SEPAFREQ
Definition cons_and.c:90
#define CONSHDLR_CHECKPRIORITY
Definition cons_and.c:89
#define CONSHDLR_DESC
Definition cons_and.c:86
#define CONSHDLR_PROP_TIMING
Definition cons_and.c:100
#define CONSHDLR_MAXPREROUNDS
Definition cons_and.c:94
#define DEFAULT_PRESOLPAIRWISE
Definition cons_and.c:105
#define CONSHDLR_SEPAPRIORITY
Definition cons_and.c:87
Proprule
Definition cons_and.c:166
@ PROPRULE_1
Definition cons_and.c:168
@ PROPRULE_INVALID
Definition cons_and.c:167
#define DEFAULT_PRESOLUSEHASHING
Definition cons_and.c:113
#define MINGAINPERNMINCOMPARISONS
Definition cons_and.c:115
#define CONSHDLR_PROPFREQ
Definition cons_and.c:91
#define NMINCOMPARISONS
Definition cons_and.c:114
#define CONSHDLR_PRESOLTIMING
Definition cons_and.c:99
#define CONSHDLR_EAGERFREQ
Definition cons_and.c:92
#define CONSHDLR_ENFOPRIORITY
Definition cons_and.c:88
#define CONSHDLR_DELAYSEPA
Definition cons_and.c:95
#define CONSHDLR_NAME
Definition cons_and.c:85
#define CONSHDLR_DELAYPROP
Definition cons_and.c:96
#define LINCONSUPGD_PRIORITY
Constraint handler for linear constraints in their most general form, .
Constraint handler for the set partitioning / packing / covering constraints .
static SCIP_RETCODE addRelaxation(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *infeasible)
Definition cons_xor.c:1783
static SCIP_RETCODE consdataFreeRows(SCIP *scip, SCIP_CONSDATA *consdata)
Definition cons_xor.c:417
static SCIP_RETCODE addCoef(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition cons_xor.c:586
#define DEFAULT_SEPARATEPARITY
Definition cons_xor.c:114
static SCIP_RETCODE consdataSwitchWatchedvars(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr, int watchedvar1, int watchedvar2)
Definition cons_xor.c:254
static SCIP_RETCODE addExtendedAsymmetricFormulation(SCIP *scip, SCIP_CONS *cons, int *naggrvars, int *naddedconss)
Definition cons_xor.c:1467
static SCIP_RETCODE checkSystemGF2(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *currentsol, SCIP_RESULT *result)
Definition cons_xor.c:2366
static SCIP_RETCODE delCoefPos(SCIP *scip, SCIP_CONS *cons, SCIP_EVENTHDLR *eventhdlr, int pos)
Definition cons_xor.c:652
static SCIP_RETCODE setIntvar(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition cons_xor.c:534
#define DEFAULT_ADDFLOWEXTENDED
Definition cons_xor.c:113
static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons)
Definition cons_xor.c:1650
static void conshdlrdataFree(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata)
Definition cons_xor.c:241
#define DEFAULT_GAUSSPROPFREQ
Definition cons_xor.c:115
static SCIP_RETCODE unlockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition cons_xor.c:205
#define HASHSIZE_XORCONS
Definition cons_xor.c:116
static SCIP_RETCODE analyzeConflict(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *infervar, PROPRULE proprule)
Definition cons_xor.c:2960
static SCIP_Bool allRowsInLP(SCIP_CONSDATA *consdata)
Definition cons_xor.c:1815
#define MAXXORCONSSSYSTEM
Definition cons_xor.c:120
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_Bool rhs, int nvars, SCIP_VAR **vars, SCIP_VAR *intvar)
Definition cons_xor.c:342
static SCIP_RETCODE addSymmetryInformation(SCIP *scip, SYM_SYMTYPE symtype, SCIP_CONS *cons, SYM_GRAPH *graph, SCIP_Bool *success)
Definition cons_xor.c:4845
static SCIP_RETCODE lockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition cons_xor.c:189
static SCIP_RETCODE consdataEnsureVarsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
Definition cons_xor.c:318
@ PROPRULE_INTUB
Definition cons_xor.c:177
@ PROPRULE_0
Definition cons_xor.c:174
@ PROPRULE_INTLB
Definition cons_xor.c:176
static SCIP_RETCODE checkCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool checklprows, SCIP_Bool printreason, SCIP_Bool *violated)
Definition cons_xor.c:1837
static void solveRowEchelonGF2(int m, int n, int r, int *p, int *s, Type **A, Type *b, Type *x)
Definition cons_xor.c:2305
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_EVENTHDLR *eventhdlr)
Definition cons_xor.c:439
static SCIP_RETCODE propagateCons(SCIP *scip, SCIP_CONS *cons, SCIP_EVENTHDLR *eventhdlr, SCIP_Bool *cutoff, int *nfixedvars, int *nchgbds)
Definition cons_xor.c:2991
static SCIP_RETCODE addExtendedFlowFormulation(SCIP *scip, SCIP_CONS *cons, int *naggrvars, int *naddedconss)
Definition cons_xor.c:1138
static SCIP_RETCODE addConflictBounds(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *infervar, SCIP_BDCHGIDX *bdchgidx, PROPRULE proprule)
Definition cons_xor.c:2852
static SCIP_RETCODE separateCons(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool separateparity, SCIP_Bool *separated, SCIP_Bool *cutoff)
Definition cons_xor.c:1983
static SCIP_RETCODE detectRedundantConstraints(SCIP *scip, BMS_BLKMEM *blkmem, SCIP_CONS **conss, int nconss, int *firstchange, int *nchgcoefs, int *nfixedvars, int *naggrvars, int *ndelconss, int *naddconss, SCIP_Bool *cutoff)
Definition cons_xor.c:3744
#define MAXXORVARSSYSTEM
Definition cons_xor.c:121
static void consdataSort(SCIP_CONSDATA *consdata)
Definition cons_xor.c:713
static SCIP_RETCODE preprocessConstraintPairs(SCIP *scip, SCIP_CONS **conss, int firstchange, int chkind, SCIP_Bool *cutoff, int *nfixedvars, int *naggrvars, int *ndelconss, int *naddconss, int *nchgcoefs)
Definition cons_xor.c:3941
#define DEFAULT_ADDEXTENDEDFORM
Definition cons_xor.c:112
unsigned short Type
Definition cons_xor.c:131
static SCIP_RETCODE conshdlrdataCreate(SCIP *scip, SCIP_CONSHDLRDATA **conshdlrdata, SCIP_EVENTHDLR *eventhdlr)
Definition cons_xor.c:221
static SCIP_RETCODE createConsXorIntvar(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_Bool rhs, int nvars, SCIP_VAR **vars, SCIP_VAR *intvar, 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_xor.c:4522
#define NROWS
Definition cons_xor.c:123
static SCIP_RETCODE cliquePresolve(SCIP *scip, SCIP_CONS *cons, int *nfixedvars, int *naggrvars, int *nchgcoefs, int *ndelconss, int *naddconss, SCIP_Bool *cutoff)
Definition cons_xor.c:3433
static SCIP_RETCODE resolvePropagation(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *infervar, PROPRULE proprule, SCIP_BDCHGIDX *bdchgidx, SCIP_RESULT *result)
Definition cons_xor.c:3412
static int computeRowEchelonGF2(SCIP *scip, int m, int n, int *p, int *s, Type **A, Type *b)
Definition cons_xor.c:2196
static SCIP_RETCODE applyFixings(SCIP *scip, SCIP_CONS *cons, SCIP_EVENTHDLR *eventhdlr, int *nchgcoefs, int *naggrvars, int *naddconss, SCIP_Bool *cutoff)
Definition cons_xor.c:879
static SCIP_RETCODE consdataPrint(SCIP *scip, SCIP_CONSDATA *consdata, FILE *file, SCIP_Bool endline)
Definition cons_xor.c:500
Constraint handler for XOR constraints, .
methods for debugging
#define SCIPdebugGetSolVal(scip, var, val)
Definition debug.h:312
#define SCIPdebugAddSolVal(scip, var, val)
Definition debug.h:311
#define NULL
Definition def.h:255
#define SCIP_MAXSTRLEN
Definition def.h:276
#define SCIP_Longint
Definition def.h:148
#define SCIP_MAXTREEDEPTH
Definition def.h:304
#define SCIP_Bool
Definition def.h:98
#define SCIP_Real
Definition def.h:163
#define TRUE
Definition def.h:100
#define FALSE
Definition def.h:101
#define MAX(x, y)
Definition def.h:227
#define SCIPABORT()
Definition def.h:334
#define REALABS(x)
Definition def.h:189
#define SCIP_CALL(x)
Definition def.h:362
SCIP_RETCODE SCIPincludeLinconsUpgrade(SCIP *scip, SCIP_DECL_LINCONSUPGD((*linconsupgd)), int priority, const char *conshdlrname)
int SCIPgetNVarsXor(SCIP *scip, SCIP_CONS *cons)
Definition cons_xor.c:6107
SCIP_RETCODE SCIPcreateConsBasicXor(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_Bool rhs, int nvars, SCIP_VAR **vars)
Definition cons_xor.c:6091
SCIP_VAR * SCIPgetIntVarXor(SCIP *scip, SCIP_CONS *cons)
Definition cons_xor.c:6153
SCIP_RETCODE SCIPcreateConsXor(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_Bool rhs, 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_xor.c:6021
SCIP_RETCODE SCIPaddCoefSetppc(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
#define SCIP_DECL_LINCONSUPGD(x)
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)
SCIP_Bool SCIPgetRhsXor(SCIP *scip, SCIP_CONS *cons)
Definition cons_xor.c:6176
SCIP_VAR ** SCIPgetVarsXor(SCIP *scip, SCIP_CONS *cons)
Definition cons_xor.c:6130
SCIP_RETCODE SCIPincludeConshdlrXor(SCIP *scip)
Definition cons_xor.c:5932
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_Bool SCIPisTransformed(SCIP *scip)
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
SCIP_Bool SCIPisStopped(SCIP *scip)
SCIP_STAGE SCIPgetStage(SCIP *scip)
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition scip_prob.c:1907
SCIP_RETCODE SCIPaddConsUpgrade(SCIP *scip, SCIP_CONS *oldcons, SCIP_CONS **newcons)
Definition scip_prob.c:3368
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
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition scip_prob.c:2201
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition misc.c:3095
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3304
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition misc.c:3061
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3466
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition misc.c:3179
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,...)
#define SCIPdebugMsg
SCIP_RETCODE SCIPheurPassSolAddSol(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol)
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:83
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
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition misc.c:10511
SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
SCIP_RETCODE SCIPaddConflictUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
SCIP_RETCODE SCIPaddConflictBinvar(SCIP *scip, SCIP_VAR *var)
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition cons.c:4350
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:372
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition scip_cons.c:540
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
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 SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:323
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 SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:808
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:831
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:785
SCIP_RETCODE SCIPsetConshdlrGetSignedPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:924
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4320
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)),)
Definition scip_cons.c:347
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition scip_cons.c:940
SCIP_RETCODE SCIPsetConshdlrGetPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:900
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:578
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4340
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:601
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:647
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:516
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:468
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:624
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:854
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition cons.c:8423
int SCIPconsGetPos(SCIP_CONS *cons)
Definition cons.c:8403
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition cons.c:8652
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition cons.c:8413
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition cons.c:8562
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition scip_cons.c:2536
int SCIPconsGetNUpgradeLocks(SCIP_CONS *cons)
Definition cons.c:8845
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition cons.c:8592
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition cons.c:8522
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition cons.c:8702
SCIP_Bool SCIPconsIsLockedType(SCIP_CONS *cons, SCIP_LOCKTYPE locktype)
Definition cons.c:8786
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition cons.c:8582
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition cons.c:8454
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:8612
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition cons.c:8632
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition cons.c:8393
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:1812
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition cons.c:8642
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:8672
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition scip_cons.c:1173
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition cons.c:8572
SCIP_RETCODE SCIPincConsAge(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:1784
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition cons.c:8662
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition scip_cut.c:135
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_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition event.c:1217
SCIP_HEUR * SCIPfindHeur(SCIP *scip, const char *name)
Definition scip_heur.c:263
#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 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_Bool SCIPinProbing(SCIP *scip)
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1581
SCIP_Real SCIPgetRowLPActivity(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1957
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 SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition scip_lp.c:1604
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition scip_lp.c:1646
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition scip_lp.c:2176
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
SCIP_RETCODE SCIPprintSol(SCIP *scip, SCIP_SOL *sol, FILE *file, SCIP_Bool printzeros)
Definition scip_sol.c:2353
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition scip_sol.c:453
SCIP_RETCODE SCIPcheckSol(SCIP *scip, SCIP_SOL *sol, SCIP_Bool printreason, SCIP_Bool completely, SCIP_Bool checkbounds, SCIP_Bool checkintegrality, SCIP_Bool checklprows, SCIP_Bool *feasible)
Definition scip_sol.c:4319
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition scip_sol.c:1571
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 SCIPisIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPparseReal(SCIP *scip, const char *str, SCIP_Real *value, char **endptr)
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition scip_tree.c:146
int SCIPgetDepth(SCIP *scip)
Definition scip_tree.c:672
SCIP_Bool SCIPvarIsInitial(SCIP_VAR *var)
Definition var.c:23515
int SCIPvarCompareActiveAndNegated(SCIP_VAR *var1, SCIP_VAR *var2)
Definition var.c:17237
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:6401
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition scip_var.c:5210
SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
Definition var.c:23869
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition var.c:23643
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition var.c:23479
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:23387
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition var.c:4386
SCIP_Real SCIPvarGetAggrConstant(SCIP_VAR *var)
Definition var.c:23772
SCIP_Bool SCIPdoNotAggr(SCIP *scip)
Definition scip_var.c:10909
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition var.c:24269
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition var.c:23431
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_RETCODE SCIPinferVarUbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:7069
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition var.c:23901
SCIP_Real SCIPvarGetAggrScalar(SCIP_VAR *var)
Definition var.c:23749
SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
Definition var.c:17551
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:6651
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:23454
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition var.c:24143
int SCIPvarGetIndex(SCIP_VAR *var)
Definition var.c:23653
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_RETCODE SCIPcreateVarImpl(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_IMPLINTTYPE impltype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
Definition scip_var.c:225
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition scip_var.c:2872
const char * SCIPvarGetName(SCIP_VAR *var)
Definition var.c:23268
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_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition var.c:23525
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:24235
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition var.c:23444
SCIP_Real SCIPcomputeVarLbLocal(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:8417
SCIP_VAR * SCIPvarGetNegationVar(SCIP_VAR *var)
Definition var.c:23879
SCIP_RETCODE SCIPcreateVar(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
Definition scip_var.c:120
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition var.c:24121
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition scip_var.c:10318
SCIP_RETCODE SCIPinferVarLbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:6964
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition scip_var.c:2736
SCIP_IMPLINTTYPE SCIPvarGetImplType(SCIP_VAR *var)
Definition var.c:23464
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition var.c:17275
SCIP_RETCODE SCIPprintVar(SCIP *scip, SCIP_VAR *var, FILE *file)
Definition scip_var.c:12465
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_Real SCIPcomputeVarUbLocal(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:8462
SCIP_Bool SCIPvarsHaveCommonClique(SCIP_VAR *var1, SCIP_Bool value1, SCIP_VAR *var2, SCIP_Bool value2, SCIP_Bool regardimplics)
Definition var.c:16808
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_VAR * SCIPvarGetAggrVar(SCIP_VAR *var)
Definition var.c:23737
void SCIPsortPtr(void **ptrarray, SCIP_DECL_SORTPTRCOMP((*ptrcomp)), int len)
void SCIPsortRealIntPtr(SCIP_Real *realarray, int *intarray, void **ptrarray, int len)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition misc.c:10827
SCIP_RETCODE SCIPskipSpace(char **s)
Definition misc.c:10816
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)
return SCIP_OKAY
SCIPfreeSol(scip, &heurdata->sol))
SCIPcreateSol(scip, &heurdata->sol, heur))
int c
int depth
SCIP_Bool cutoff
static SCIP_SOL * sol
int r
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
SCIP_VAR * var
static SCIP_Bool propagate
static SCIP_VAR ** vars
primal heuristic that tries a given solution
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)
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
general public methods
public methods for primal heuristic plugins and divesets
public methods for the LP relaxation, rows and columns
public methods for memory management
public methods for message handling
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.
structs for symmetry computations
methods for dealing with symmetry detection graphs
@ SCIP_CONFTYPE_PROPAGATION
#define SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(x)
Definition type_cons.h:956
#define SCIP_DECL_CONSGETPERMSYMGRAPH(x)
Definition type_cons.h:938
#define SCIP_DECL_CONSENFOLP(x)
Definition type_cons.h:363
#define SCIP_DECL_CONSINITPRE(x)
Definition type_cons.h:156
#define SCIP_DECL_CONSDELETE(x)
Definition type_cons.h:229
struct SCIP_Cons SCIP_CONS
Definition type_cons.h:63
#define SCIP_DECL_CONSGETVARS(x)
Definition type_cons.h:867
#define SCIP_DECL_CONSPRINT(x)
Definition type_cons.h:769
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition type_cons.h:64
#define SCIP_DECL_CONSSEPALP(x)
Definition type_cons.h:288
struct SYM_Graph SYM_GRAPH
Definition type_cons.h:68
#define SCIP_DECL_CONSENFORELAX(x)
Definition type_cons.h:388
#define SCIP_DECL_CONSPROP(x)
Definition type_cons.h:506
#define SCIP_DECL_CONSGETNVARS(x)
Definition type_cons.h:885
#define SCIP_DECL_CONSRESPROP(x)
Definition type_cons.h:612
#define SCIP_DECL_CONSENFOPS(x)
Definition type_cons.h:431
#define SCIP_DECL_CONSPARSE(x)
Definition type_cons.h:845
#define SCIP_DECL_CONSTRANS(x)
Definition type_cons.h:239
#define SCIP_DECL_CONSPRESOL(x)
Definition type_cons.h:561
#define SCIP_DECL_CONSINITLP(x)
Definition type_cons.h:259
#define SCIP_DECL_CONSEXITPRE(x)
Definition type_cons.h:180
#define SCIP_DECL_CONSLOCK(x)
Definition type_cons.h:676
struct SCIP_Conshdlr SCIP_CONSHDLR
Definition type_cons.h:62
#define SCIP_DECL_CONSCOPY(x)
Definition type_cons.h:810
struct SCIP_ConsData SCIP_CONSDATA
Definition type_cons.h:65
#define SCIP_DECL_CONSCHECK(x)
Definition type_cons.h:474
#define SCIP_DECL_CONSHDLRCOPY(x)
Definition type_cons.h:108
#define SCIP_DECL_CONSEXITSOL(x)
Definition type_cons.h:216
#define SCIP_DECL_CONSFREE(x)
Definition type_cons.h:116
#define SCIP_DECL_CONSSEPASOL(x)
Definition type_cons.h:320
struct SCIP_Eventhdlr SCIP_EVENTHDLR
Definition type_event.h:159
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition type_event.h:127
struct SCIP_EventData SCIP_EVENTDATA
Definition type_event.h:179
#define SCIP_EVENTTYPE_VARFIXED
Definition type_event.h:72
#define SCIP_DECL_EVENTEXEC(x)
Definition type_event.h:259
struct SCIP_Heur SCIP_HEUR
Definition type_heur.h:76
struct SCIP_Row SCIP_ROW
Definition type_lp.h:105
struct SCIP_HashMap SCIP_HASHMAP
Definition type_misc.h:106
#define SCIP_DECL_HASHKEYEQ(x)
Definition type_misc.h:195
#define SCIP_DECL_HASHGETKEY(x)
Definition type_misc.h:192
#define SCIP_DECL_HASHKEYVAL(x)
Definition type_misc.h:198
struct SCIP_HashTable SCIP_HASHTABLE
Definition type_misc.h:88
@ 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
@ SCIP_PLUGINNOTFOUND
@ SCIP_INVALIDCALL
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
@ SCIP_STAGE_INITPRESOLVE
Definition type_set.h:48
@ SCIP_STAGE_PRESOLVING
Definition type_set.h:49
@ SCIP_STAGE_EXITPRESOLVE
Definition type_set.h:50
@ SCIP_STAGE_SOLVING
Definition type_set.h:53
struct SCIP_Sol SCIP_SOL
Definition type_sol.h:57
enum SYM_Symtype SYM_SYMTYPE
@ SYM_CONSOPTYPE_XORINT
@ SYM_SYMTYPE_SIGNPERM
@ SYM_SYMTYPE_PERM
#define SCIP_PRESOLTIMING_MEDIUM
Definition type_timing.h:53
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition type_timing.h:54
struct SCIP_Var SCIP_VAR
Definition type_var.h:166
@ SCIP_IMPLINTTYPE_WEAK
Definition type_var.h:91
struct SCIP_BdChgIdx SCIP_BDCHGIDX
Definition type_var.h:151
@ SCIP_VARTYPE_INTEGER
Definition type_var.h:65
@ SCIP_VARTYPE_CONTINUOUS
Definition type_var.h:71
@ SCIP_VARTYPE_BINARY
Definition type_var.h:64
@ SCIP_VARSTATUS_FIXED
Definition type_var.h:54
@ SCIP_VARSTATUS_MULTAGGR
Definition type_var.h:56
@ SCIP_VARSTATUS_NEGATED
Definition type_var.h:57
@ SCIP_VARSTATUS_AGGREGATED
Definition type_var.h:55
@ SCIP_LOCKTYPE_CONFLICT
Definition type_var.h:142
@ SCIP_LOCKTYPE_MODEL
Definition type_var.h:141
enum SCIP_Vartype SCIP_VARTYPE
Definition type_var.h:73