Scippy

SCIP

Solving Constraint Integer Programs

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-2025 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file cons_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 */
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 */
198 SCIP_CALL( SCIPlockVarCons(scip, var, cons, TRUE, TRUE) );
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 */
214 SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, TRUE) );
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 {
555 SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
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 {
607 SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
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];
909 assert(SCIPvarIsBinary(var));
910
911 if( SCIPvarGetUbGlobal(var) < 0.5 )
912 {
913 assert(SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0));
914 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
915 ++(*nchgcoefs);
916 }
917 else if( SCIPvarGetLbGlobal(var) > 0.5 )
918 {
919 assert(SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0));
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 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v + 1) );
972 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
973 *nchgcoefs += 2;
974 if( consdata->intvar != NULL )
975 {
976 assert(intoffsetvars != NULL);
977 assert(intoffsetvals != NULL);
978 assert(intoffsetnvars >= 2);
979 assert(intoffsetconst >= 0);
980
981 if( consdata->intvar == consdata->vars[v] )
982 intoffsetvals[1] += 1.0;
983 else if( intoffsetvars[intoffsetnvars - 1] == consdata->vars[v] )
984 intoffsetvals[intoffsetnvars - 1] += 1.0;
985 else
986 {
987 intoffsetvars[intoffsetnvars] = consdata->vars[v];
988 intoffsetvals[intoffsetnvars] = 1.0;
989 ++intoffsetnvars;
990 }
991 }
992 --v;
993 }
994 else if( consdata->vars[v] == SCIPvarGetNegatedVar(consdata->vars[v + 1]) ) /*lint !e679*/
995 {
996 /* delete both variables and negate the rhs */
997 SCIPdebugMsg(scip, "xor constraint <%s>: deleting pair of negated variables <%s> and <%s>\n",
998 SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[v]), SCIPvarGetName(consdata->vars[v+1])); /*lint !e679*/
999 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v + 1) );
1000 SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
1001 *nchgcoefs += 2;
1002 consdata->rhs = !consdata->rhs;
1003 if( consdata->rhs )
1004 ++intoffsetconst;
1005 --v;
1006 }
1007 else
1008 assert(SCIPvarGetProbvar(consdata->vars[v]) != SCIPvarGetProbvar(consdata->vars[v + 1])); /*lint !e679*/
1009 --v;
1010 }
1011
1012 /* if there is an offset of the integer variable y, it needs to be replaced by z with
1013 * y = z + intoffsetsum and z in [max(lb_y - intoffsetmax, 0), ub_y - intoffsetmin]
1014 */
1015 if( consdata->intvar != NULL )
1016 {
1017 assert(intoffsetvars != NULL);
1018 assert(intoffsetvals != NULL);
1019 assert(intoffsetnvars >= 2);
1020 assert(intoffsetconst >= 0);
1021
1022 if( intoffsetconst >= 1 || intoffsetvals[1] != -1.0 || intoffsetnvars > 2 ) /*lint !e777*/
1023 {
1024 SCIP_Real lb = -(double)intoffsetconst;
1025 SCIP_Real ub = -(double)intoffsetconst;
1026 SCIP_Bool aggregated;
1027 SCIP_Bool infeasible = FALSE;
1028 SCIP_Bool redundant = FALSE;
1029 char varname[SCIP_MAXSTRLEN];
1030
1031 (void)SCIPsnprintf(varname, SCIP_MAXSTRLEN, "agg_%s", SCIPvarGetName(consdata->intvar));
1032
1033 if( intoffsetvals[1] < 0.0 )
1034 {
1035 lb -= intoffsetvals[1] * SCIPvarGetLbGlobal(consdata->intvar);
1036 ub -= intoffsetvals[1] * SCIPvarGetUbGlobal(consdata->intvar);
1037 }
1038 else
1039 {
1040 lb -= intoffsetvals[1] * SCIPvarGetUbGlobal(consdata->intvar);
1041 ub -= intoffsetvals[1] * SCIPvarGetLbGlobal(consdata->intvar);
1042 }
1043
1044 for( v = 2; v < intoffsetnvars; ++v )
1045 {
1046 lb -= intoffsetvals[v] * SCIPvarGetUbGlobal(intoffsetvars[v]);
1047 ub -= intoffsetvals[v] * SCIPvarGetLbGlobal(intoffsetvars[v]);
1048 }
1049
1050 if( lb < 0.0 )
1051 {
1052 lb = 0.0;
1053
1054 if( ub < 0.0 )
1055 ub = 0.0;
1056 }
1057
1058 SCIP_CALL( SCIPcreateVarImpl(scip, intoffsetvars, varname, lb, ub, 0.0,
1059 SCIPvarGetType(consdata->intvar), SCIPvarGetImplType(consdata->intvar),
1060 SCIPvarIsInitial(consdata->intvar), SCIPvarIsRemovable(consdata->intvar),
1061 NULL, NULL, NULL, NULL, NULL) );
1062 intoffsetvals[0] = 1.0;
1063 SCIP_CALL( SCIPaddVar(scip, intoffsetvars[0]) );
1064
1065 if( intoffsetnvars == 2 )
1066 {
1067 if( intoffsetvals[1] == 0.0 ) /*lint !e777*/
1068 redundant = TRUE;
1069 else
1070 {
1071 SCIP_CALL( SCIPaggregateVars(scip, intoffsetvars[1], intoffsetvars[0], -intoffsetvals[1], -intoffsetvals[0],
1072 (double)intoffsetconst, &infeasible, &redundant, &aggregated) );
1073
1074 if( aggregated )
1075 ++(*naggrvars);
1076 }
1077 assert(infeasible || redundant || SCIPdoNotAggr(scip));
1078 }
1079
1080 if( infeasible )
1081 *cutoff = TRUE;
1082 else if( redundant )
1083 {
1084 SCIP_CALL( setIntvar(scip, cons, intoffsetvars[0]) );
1085 }
1086 else
1087 {
1088 SCIP_CONS* newcons;
1089 char consname[SCIP_MAXSTRLEN];
1090
1091 (void)SCIPsnprintf(consname, SCIP_MAXSTRLEN, "agg_%s", SCIPconsGetName(cons));
1092
1093 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, consname, intoffsetnvars, intoffsetvars, intoffsetvals,
1094 -(double)intoffsetconst, -(double)intoffsetconst,
1096 TRUE, TRUE, TRUE, /*SCIPconsIsEnforced(cons), SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons),*/
1099 SCIP_CALL( SCIPaddCons(scip, newcons) );
1100 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1101 ++(*naddconss);
1102
1103 SCIP_CALL( setIntvar(scip, cons, intoffsetvars[0]) );
1104 }
1105
1106 SCIP_CALL( SCIPreleaseVar(scip, intoffsetvars) );
1107 }
1108
1109 SCIPfreeBufferArray(scip, &intoffsetvals);
1110 SCIPfreeBufferArray(scip, &intoffsetvars);
1111 }
1112
1113 SCIPdebugMsg(scip, "after fixings : ");
1114 SCIPdebug( SCIP_CALL( consdataPrint(scip, consdata, NULL, TRUE) ) );
1115
1116 return SCIP_OKAY;
1117}
1118
1119/** adds extended flow formulation
1120 *
1121 * The extended flow formulation is built as follows: Let \f$x_1, \dots, x_k\f$ be the variables contained in the given
1122 * XOR constraint. We construct a two layered flow network. The upper layer is called the north layer and the lower is
1123 * 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
1124 * (denoted by 'nn' and 'ss', respectively), as well as arcs that change the layers (denoted by 'ns' and 'sn'). For
1125 * \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
1126 * \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
1127 * located on the north or south layer. A change in the layers corresponds to a parity change, i.e., the corresponding
1128 * variable \f$x_i\f$ is 1 (and 0 otherwise).
1129 */
1130static
1132 SCIP* scip, /**< SCIP data structure */
1133 SCIP_CONS* cons, /**< constraint to check */
1134 int* naggrvars, /**< pointer to add up the number of aggregated variables */
1135 int* naddedconss /**< number of added constraints */
1136 )
1137{
1138 char name[SCIP_MAXSTRLEN];
1139 SCIP_CONSDATA* consdata;
1140 SCIP_VAR* varprevnn = NULL;
1141 SCIP_VAR* varprevns = NULL;
1142 SCIP_VAR* varprevsn = NULL;
1143 SCIP_VAR* varprevss = NULL;
1144 SCIP_VAR* vars[4];
1145 SCIP_Real vals[4];
1146 int i;
1147
1148 assert(scip != NULL);
1149 assert(cons != NULL);
1150 assert(naddedconss != NULL);
1151 *naddedconss = 0;
1152
1153 /* exit if contraints is modifiable */
1154 if( SCIPconsIsModifiable(cons) )
1155 return SCIP_OKAY;
1156
1157 consdata = SCIPconsGetData(cons);
1158 assert(consdata != NULL);
1159
1160 /* exit if extended formulation has been added already */
1161 if( consdata->extvars != NULL )
1162 return SCIP_OKAY;
1163
1164 /* xor constraints with at most 3 variables are handled directly through rows for the convex hull */
1165 if( consdata->nvars <= 3 )
1166 return SCIP_OKAY;
1167
1168 SCIPdebugMsg(scip, "Add extended formulation for xor constraint <%s> ...\n", SCIPconsGetName(cons));
1169 assert(consdata->extvars == NULL);
1170 assert(consdata->nextvars == 0);
1171 assert(consdata->extvarssize == 0);
1172
1173 /* get storage for auxiliary variables */
1174 consdata->extvarssize = 4 * (consdata->nvars);
1175 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(consdata->extvars), consdata->extvarssize) );
1176
1177 /* pass through components */
1178 for( i = 0; i < consdata->nvars; ++i )
1179 {
1180 /* variables: n - north, s - south */
1181 SCIP_VAR* varnn = NULL;
1182 SCIP_VAR* varns = NULL;
1183 SCIP_VAR* varsn = NULL;
1184 SCIP_VAR* varss = NULL;
1185 SCIP_CONS* newcons;
1186 SCIP_Real rhs = 0.0;
1187 SCIP_Bool infeasible = FALSE;
1188 SCIP_Bool redundant = FALSE;
1189 SCIP_Bool aggregated = FALSE;
1190 int cnt = 0;
1191
1192 /* create variables */
1193 if( i == 0 )
1194 {
1195 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_nn", SCIPconsGetName(cons), i);
1196 SCIP_CALL( SCIPcreateVarImpl(scip, &varnn, name, 0.0, 1.0, 0.0,
1198 NULL, NULL, NULL, NULL, NULL) );
1199 SCIP_CALL( SCIPaddVar(scip, varnn) );
1200
1201 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_ns", SCIPconsGetName(cons), i);
1202 SCIP_CALL( SCIPcreateVarImpl(scip, &varns, name, 0.0, 1.0, 0.0,
1204 NULL, NULL, NULL, NULL, NULL) );
1205 SCIP_CALL( SCIPaddVar(scip, varns) );
1206
1207 /* need to lock variables, because we aggregate them */
1208 SCIP_CALL( SCIPlockVarCons(scip, varnn, cons, TRUE, TRUE) );
1209 SCIP_CALL( SCIPlockVarCons(scip, varns, cons, TRUE, TRUE) );
1210
1211 /* aggregate ns variable with original variable */
1212 SCIP_CALL( SCIPaggregateVars(scip, varns, consdata->vars[0], 1.0, -1.0, 0.0, &infeasible, &redundant, &aggregated) );
1213 assert(!infeasible);
1214 assert(redundant);
1215 assert(aggregated);
1216 ++(*naggrvars);
1217 }
1218 else
1219 {
1220 if( i == consdata->nvars-1 )
1221 {
1222 if( consdata->rhs )
1223 {
1224 /* if the rhs is 1 (true) the flow goes to the bottom level */
1225 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_ns", SCIPconsGetName(cons), i);
1226 SCIP_CALL( SCIPcreateVarImpl(scip, &varns, name, 0.0, 1.0, 0.0,
1228 NULL, NULL, NULL, NULL, NULL) );
1229 SCIP_CALL( SCIPaddVar(scip, varns) );
1230
1231 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_ss", SCIPconsGetName(cons), i);
1232 SCIP_CALL( SCIPcreateVarImpl(scip, &varss, name, 0.0, 1.0, 0.0,
1234 NULL, NULL, NULL, NULL, NULL) );
1235 SCIP_CALL( SCIPaddVar(scip, varss) );
1236
1237 /* need to lock variables, because we aggregate them */
1238 SCIP_CALL( SCIPlockVarCons(scip, varns, cons, TRUE, TRUE) );
1239 SCIP_CALL( SCIPlockVarCons(scip, varss, cons, TRUE, TRUE) );
1240
1241 /* aggregate ns variable with original variable */
1242 SCIP_CALL( SCIPaggregateVars(scip, varns, consdata->vars[i], 1.0, -1.0, 0.0, &infeasible, &redundant, &aggregated) );
1243 assert(!infeasible);
1244 assert(redundant);
1245 assert(aggregated);
1246 ++(*naggrvars);
1247 }
1248 else
1249 {
1250 /* if the rhs is 0 (false) the flow stays on the top level */
1251 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_nn", SCIPconsGetName(cons), i);
1252 SCIP_CALL( SCIPcreateVarImpl(scip, &varnn, name, 0.0, 1.0, 0.0,
1254 NULL, NULL, NULL, NULL, NULL) );
1255 SCIP_CALL( SCIPaddVar(scip, varnn) );
1256
1257 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_sn", SCIPconsGetName(cons), i);
1258 SCIP_CALL( SCIPcreateVarImpl(scip, &varsn, name, 0.0, 1.0, 0.0,
1260 NULL, NULL, NULL, NULL, NULL) );
1261 SCIP_CALL( SCIPaddVar(scip, varsn) );
1262
1263 /* need to lock variables, because we aggregate them */
1264 SCIP_CALL( SCIPlockVarCons(scip, varnn, cons, TRUE, TRUE) );
1265 SCIP_CALL( SCIPlockVarCons(scip, varsn, cons, TRUE, TRUE) );
1266
1267 /* aggregate sn variable with original variable */
1268 SCIP_CALL( SCIPaggregateVars(scip, varsn, consdata->vars[i], 1.0, -1.0, 0.0, &infeasible, &redundant, &aggregated) );
1269 assert(!infeasible);
1270 assert(redundant);
1271 assert(aggregated);
1272 ++(*naggrvars);
1273 }
1274 }
1275 else
1276 {
1277 /* add the four flow variables */
1278 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_nn", SCIPconsGetName(cons), i);
1279 SCIP_CALL( SCIPcreateVarImpl(scip, &varnn, name, 0.0, 1.0, 0.0,
1281 NULL, NULL, NULL, NULL, NULL) );
1282 SCIP_CALL( SCIPaddVar(scip, varnn) );
1283
1284 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_ns", SCIPconsGetName(cons), i);
1285 SCIP_CALL( SCIPcreateVarImpl(scip, &varns, name, 0.0, 1.0, 0.0,
1287 NULL, NULL, NULL, NULL, NULL) );
1288 SCIP_CALL( SCIPaddVar(scip, varns) );
1289
1290 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_sn", SCIPconsGetName(cons), i);
1291 SCIP_CALL( SCIPcreateVarImpl(scip, &varsn, name, 0.0, 1.0, 0.0,
1293 NULL, NULL, NULL, NULL, NULL) );
1294 SCIP_CALL( SCIPaddVar(scip, varsn) );
1295
1296 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_ss", SCIPconsGetName(cons), i);
1297 SCIP_CALL( SCIPcreateVarImpl(scip, &varss, name, 0.0, 1.0, 0.0,
1299 NULL, NULL, NULL, NULL, NULL) );
1300 SCIP_CALL( SCIPaddVar(scip, varss) );
1301
1302 SCIP_CALL( SCIPlockVarCons(scip, varnn, cons, TRUE, TRUE) );
1303 SCIP_CALL( SCIPlockVarCons(scip, varns, cons, TRUE, TRUE) );
1304 SCIP_CALL( SCIPlockVarCons(scip, varsn, cons, TRUE, TRUE) );
1305 SCIP_CALL( SCIPlockVarCons(scip, varss, cons, TRUE, TRUE) );
1306
1307 /* add coupling constraint */
1308 cnt = 0;
1309 if( varns != NULL )
1310 {
1311 vars[cnt] = varns;
1312 vals[cnt++] = 1.0;
1313 }
1314 if( varsn != NULL )
1315 {
1316 vars[cnt] = varsn;
1317 vals[cnt++] = 1.0;
1318 }
1319 assert(SCIPvarIsTransformed(consdata->vars[i]));
1320 vars[cnt] = consdata->vars[i];
1321 vals[cnt++] = -1.0;
1322
1323 assert(cnt >= 2);
1324 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_couple", SCIPconsGetName(cons));
1325 /* not initial, separate, do not enforce, do not check, propagate, not local, not modifiable, dynamic, removable, not sticking */
1326 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, cnt, vars, vals, 0.0, 0.0,
1328 SCIP_CALL( SCIPaddCons(scip, newcons) );
1329 SCIPdebugPrintCons(scip, newcons, NULL);
1330 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1331 ++(*naddedconss);
1332 }
1333
1334 /* add south flow conservation constraint */
1335
1336 /* incoming variables */
1337 cnt = 0;
1338 if( varprevss != NULL )
1339 {
1340 vars[cnt] = varprevss;
1341 vals[cnt++] = 1.0;
1342 }
1343 if( varprevns != NULL )
1344 {
1345 vars[cnt] = varprevns;
1346 vals[cnt++] = 1.0;
1347 }
1348
1349 /* outgoing variables */
1350 if( varss != NULL )
1351 {
1352 vars[cnt] = varss;
1353 vals[cnt++] = -1.0;
1354 }
1355 if( varsn != NULL )
1356 {
1357 vars[cnt] = varsn;
1358 vals[cnt++] = -1.0;
1359 }
1360
1361 assert(cnt >= 2);
1362 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_south", SCIPconsGetName(cons));
1363 /* not initial, separate, do not enforce, do not check, propagate, not local, not modifiable, dynamic, removable, not sticking */
1364 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, cnt, vars, vals, 0.0, 0.0,
1366 SCIP_CALL( SCIPaddCons(scip, newcons) );
1367 SCIPdebugPrintCons(scip, newcons, NULL);
1368 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1369 ++(*naddedconss);
1370 }
1371
1372 /* add north flow conservation constraint */
1373
1374 /* incoming variables */
1375 cnt = 0;
1376 if( varprevnn != NULL )
1377 {
1378 vars[cnt] = varprevnn;
1379 vals[cnt++] = 1.0;
1380 }
1381 if( varprevsn != NULL )
1382 {
1383 vars[cnt] = varprevsn;
1384 vals[cnt++] = 1.0;
1385 }
1386
1387 /* outgoing variables */
1388 if( varnn != NULL )
1389 {
1390 vars[cnt] = varnn;
1391 vals[cnt++] = -1.0;
1392 }
1393 if( varns != NULL )
1394 {
1395 vars[cnt] = varns;
1396 vals[cnt++] = -1.0;
1397 }
1398
1399 assert(cnt >= 2);
1400 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_north", SCIPconsGetName(cons));
1401 if( i == 0 )
1402 rhs = -1.0;
1403 else
1404 rhs = 0.0;
1405
1406 /* not initial, separate, do not enforce, do not check, propagate, not local, not modifiable, dynamic, removable, not sticking */
1407 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, cnt, vars, vals, rhs, rhs,
1409 SCIP_CALL( SCIPaddCons(scip, newcons) );
1410 SCIPdebugPrintCons(scip, newcons, NULL);
1411 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1412 ++(*naddedconss);
1413
1414 /* store variables */
1415 consdata->extvars[4*i] = varnn; /*lint !e679*/
1416 consdata->extvars[4*i + 1] = varns; /*lint !e679*/
1417 consdata->extvars[4*i + 2] = varsn; /*lint !e679*/
1418 consdata->extvars[4*i + 3] = varss; /*lint !e679*/
1419
1420 if( varnn != NULL )
1421 ++(consdata->nextvars);
1422 if( varns != NULL )
1423 ++(consdata->nextvars);
1424 if( varsn != NULL )
1425 ++(consdata->nextvars);
1426 if( varss != NULL )
1427 ++(consdata->nextvars);
1428
1429 /* store previous variables */
1430 varprevnn = varnn;
1431 varprevns = varns;
1432 varprevsn = varsn;
1433 varprevss = varss;
1434 }
1435
1436 return SCIP_OKAY;
1437}
1438
1439/** adds extended asymmetric formulation
1440 *
1441 * The extended asymmetric formulation is constructed as follows: Let \f$x_1, \dots, x_k\f$ be the variables contained
1442 * in the given XOR constraint. We introduce variables \f$p_1, \ldots, p_k\f$ with the following constraints: \f$p_1 =
1443 * x_1\f$, \f$p_k = 1\f$, and for \f$i = 2, \ldots, k-1\f$:
1444 * \f[
1445 * \begin{array}{ll}
1446 * p_i & \leq p_{i-1} + x_i\\
1447 * p_i & \leq 2 - (p_{i-1} + x_i)\\
1448 * p_i & \geq p_{i-1} - x_i\\
1449 * p_i & \geq x_i - p_{i-1}.
1450 * \end{array}
1451 * \f]
1452 * This formulation is described in
1453 *
1454 * Robert D. Carr and Goran Konjevod@n
1455 * Polyhedral combinatorics@n
1456 * In Harvey Greenberg, editor, Tutorials on emerging methodologies and applications in Operations Research,@n
1457 * Chapter 2, pages (2-1)-(2-48). Springer, 2004.
1458 */
1459static
1461 SCIP* scip, /**< SCIP data structure */
1462 SCIP_CONS* cons, /**< constraint to check */
1463 int* naggrvars, /**< pointer to add up the number of aggregated variables */
1464 int* naddedconss /**< number of added constraints */
1465 )
1466{
1467 char name[SCIP_MAXSTRLEN];
1468 SCIP_CONSDATA* consdata;
1469 SCIP_VAR* vars[3];
1470 SCIP_Real vals[3];
1471 SCIP_VAR* prevvar = NULL;
1472 int i;
1473
1474 assert(scip != NULL);
1475 assert(cons != NULL);
1476 assert(naddedconss != NULL);
1477 *naddedconss = 0;
1478
1479 /* exit if contraints is modifiable */
1480 if( SCIPconsIsModifiable(cons) )
1481 return SCIP_OKAY;
1482
1483 consdata = SCIPconsGetData(cons);
1484 assert(consdata != NULL);
1485
1486 /* exit if extended formulation has been added already */
1487 if( consdata->extvars != NULL )
1488 return SCIP_OKAY;
1489
1490 /* xor constraints with at most 3 variables are handled directly through rows for the convex hull */
1491 if( consdata->nvars <= 3 )
1492 return SCIP_OKAY;
1493
1494 SCIPdebugMsg(scip, "Add extended formulation for xor constraint <%s> ...\n", SCIPconsGetName(cons));
1495 assert(consdata->extvars == NULL);
1496 assert(consdata->nextvars == 0);
1497
1498 /* get storage for auxiliary variables */
1499 consdata->extvarssize = consdata->nvars;
1500 consdata->nextvars = consdata->nvars;
1501 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(consdata->extvars), consdata->extvarssize ) );
1502
1503 /* pass through components */
1504 for( i = 0; i < consdata->nvars; ++i )
1505 {
1506 SCIP_Bool infeasible = FALSE;
1507 SCIP_Bool redundant = FALSE;
1508 SCIP_Bool aggregated = FALSE;
1509 SCIP_CONS* newcons;
1510 SCIP_VAR* artvar = NULL;
1511 SCIP_Real lb = 0.0;
1512 SCIP_Real ub = 1.0;
1513
1514 /* determine fixing for last variables */
1515 if( i == consdata->nvars-1 )
1516 {
1517 if( consdata->rhs )
1518 {
1519 lb = 1.0;
1520 ub = 1.0;
1521 }
1522 else
1523 {
1524 lb = 0.0;
1525 ub = 0.0;
1526 }
1527 }
1528
1529 /* create variable */
1530 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "p_%s_%d", SCIPconsGetName(cons), i);
1531 SCIP_CALL( SCIPcreateVarImpl(scip, &artvar, name, lb, ub, 0.0,
1533 NULL, NULL, NULL, NULL, NULL) );
1534 SCIP_CALL( SCIPaddVar(scip, artvar) );
1535 SCIP_CALL( SCIPlockVarCons(scip, artvar, cons, TRUE, TRUE) );
1536
1537 /* create constraints */
1538 if( i == 0 )
1539 {
1540 /* aggregate artificial variable with original variable */
1541 SCIP_CALL( SCIPaggregateVars(scip, artvar, consdata->vars[0], 1.0, -1.0, 0.0, &infeasible, &redundant, &aggregated) );
1542 assert(!infeasible);
1543 assert(redundant);
1544 assert(aggregated);
1545 ++(*naggrvars);
1546 }
1547 else
1548 {
1549 assert(SCIPvarIsTransformed(consdata->vars[i]));
1550
1551 /* add first constraint */
1552 vars[0] = artvar;
1553 vals[0] = 1.0;
1554 vars[1] = prevvar;
1555 vals[1] = -1.0;
1556 vars[2] = consdata->vars[i];
1557 vals[2] = -1.0;
1558
1559 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_1", SCIPconsGetName(cons), i);
1560 /* not initial, separate, do not enforce, do not check, propagate, not local, not modifiable, dynamic, removable, not sticking */
1561 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, 3, vars, vals, -SCIPinfinity(scip), 0.0,
1563 SCIP_CALL( SCIPaddCons(scip, newcons) );
1564 SCIPdebugPrintCons(scip, newcons, NULL);
1565 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1566 ++(*naddedconss);
1567
1568 /* add second constraint */
1569 vars[0] = artvar;
1570 vals[0] = 1.0;
1571 vars[1] = prevvar;
1572 vals[1] = 1.0;
1573 vars[2] = consdata->vars[i];
1574 vals[2] = 1.0;
1575
1576 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_2", SCIPconsGetName(cons), i);
1577 /* not initial, separate, do not enforce, do not check, propagate, not local, not modifiable, dynamic, removable, not sticking */
1578 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, 3, vars, vals, -SCIPinfinity(scip), 2.0,
1580 SCIP_CALL( SCIPaddCons(scip, newcons) );
1581 SCIPdebugPrintCons(scip, newcons, NULL);
1582 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1583 ++(*naddedconss);
1584
1585 /* add third constraint */
1586 vars[0] = artvar;
1587 vals[0] = -1.0;
1588 vars[1] = prevvar;
1589 vals[1] = 1.0;
1590 vars[2] = consdata->vars[i];
1591 vals[2] = -1.0;
1592
1593 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_3", SCIPconsGetName(cons), i);
1594 /* not initial, separate, do not enforce, do not check, propagate, not local, not modifiable, dynamic, removable, not sticking */
1595 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, 3, vars, vals, -SCIPinfinity(scip), 0.0,
1597 SCIP_CALL( SCIPaddCons(scip, newcons) );
1598 SCIPdebugPrintCons(scip, newcons, NULL);
1599 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1600 ++(*naddedconss);
1601
1602 /* add fourth constraint */
1603 vars[0] = artvar;
1604 vals[0] = -1.0;
1605 vars[1] = prevvar;
1606 vals[1] = -1.0;
1607 vars[2] = consdata->vars[i];
1608 vals[2] = 1.0;
1609
1610 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_4", SCIPconsGetName(cons), i);
1611 /* not initial, separate, do not enforce, do not check, propagate, not local, not modifiable, dynamic, removable, not sticking */
1612 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, 3, vars, vals, -SCIPinfinity(scip), 0.0,
1614 SCIP_CALL( SCIPaddCons(scip, newcons) );
1615 SCIPdebugPrintCons(scip, newcons, NULL);
1616 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1617 ++(*naddedconss);
1618 }
1619
1620 /* store variable */
1621 consdata->extvars[i] = artvar;
1622 prevvar = artvar;
1623 }
1624
1625 return SCIP_OKAY;
1626}
1627
1628/** creates LP row corresponding to xor constraint:
1629 * x1 + ... + xn - 2q == rhs
1630 * with internal integer variable q;
1631 * in the special case of 3 variables and c = 0, the following linear system is created:
1632 * + x - y - z <= 0
1633 * - x + y - z <= 0
1634 * - x - y + z <= 0
1635 * + x + y + z <= 2
1636 * in the special case of 3 variables and c = 1, the following linear system is created:
1637 * - x + y + z <= 1
1638 * + x - y + z <= 1
1639 * + x + y - z <= 1
1640 * - x - y - z <= -1
1641 */
1642static
1644 SCIP* scip, /**< SCIP data structure */
1645 SCIP_CONS* cons /**< constraint to check */
1646 )
1647{
1648 SCIP_CONSDATA* consdata;
1649 char varname[SCIP_MAXSTRLEN];
1650
1651 consdata = SCIPconsGetData(cons);
1652 assert(consdata != NULL);
1653 assert(consdata->rows[0] == NULL);
1654
1655 if( SCIPconsIsModifiable(cons) || consdata->nvars != 3 )
1656 {
1657 SCIP_Real rhsval;
1658
1659 /* create internal variable, if not yet existing */
1660 if( consdata->intvar == NULL )
1661 {
1662 int ub;
1663
1664 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "XOR_artificial_%s_int", SCIPconsGetName(cons));
1665 ub = consdata->nvars/2;
1666 SCIP_CALL( SCIPcreateVar(scip, &consdata->intvar, varname, 0.0, (SCIP_Real)ub, 0.0,
1667 consdata->nvars >= 4 ? SCIP_VARTYPE_INTEGER : SCIP_VARTYPE_BINARY,
1669 SCIP_CALL( SCIPaddVar(scip, consdata->intvar) );
1670
1671#ifdef WITH_DEBUG_SOLUTION
1672 if( SCIPdebugIsMainscip(scip) )
1673 {
1674 SCIP_Real solval;
1675 int count = 0;
1676 int v;
1677
1678 for( v = consdata->nvars - 1; v >= 0; --v )
1679 {
1680 SCIP_CALL( SCIPdebugGetSolVal(scip, consdata->vars[v], &solval) );
1681 count += (solval > 0.5 ? 1 : 0);
1682 }
1683 assert((count - consdata->rhs) % 2 == 0);
1684 solval = (SCIP_Real) ((count - consdata->rhs) / 2);
1685
1686 /* store debug sol value of artificial integer variable */
1687 SCIP_CALL( SCIPdebugAddSolVal(scip, consdata->intvar, solval) );
1688 }
1689#endif
1690
1691 /* install the rounding locks for the internal variable */
1692 SCIP_CALL( lockRounding(scip, cons, consdata->intvar) );
1693 }
1694
1695 /* create LP row */
1696 rhsval = (consdata->rhs ? 1.0 : 0.0);
1697 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->rows[0], cons, SCIPconsGetName(cons), rhsval, rhsval,
1699 SCIP_CALL( SCIPaddVarToRow(scip, consdata->rows[0], consdata->intvar, -2.0) );
1700 SCIP_CALL( SCIPaddVarsToRowSameCoef(scip, consdata->rows[0], consdata->nvars, consdata->vars, 1.0) );
1701 }
1702 else if( !consdata->rhs )
1703 {
1704 char rowname[SCIP_MAXSTRLEN];
1705 int r;
1706
1707 /* create the <= 0 rows with one positive sign */
1708 for( r = 0; r < 3; ++r )
1709 {
1710 int v;
1711
1712 (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s_%d", SCIPconsGetName(cons), r);
1713 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->rows[r], cons, rowname, -SCIPinfinity(scip), 0.0,
1715 for( v = 0; v < 3; ++v )
1716 {
1717 SCIP_CALL( SCIPaddVarToRow(scip, consdata->rows[r], consdata->vars[v], v == r ? +1.0 : -1.0) );
1718 }
1719 }
1720
1721 /* create the <= 2 row with all positive signs */
1722 (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s_3", SCIPconsGetName(cons));
1723 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->rows[3], cons, rowname, -SCIPinfinity(scip), 2.0,
1725 SCIP_CALL( SCIPaddVarsToRowSameCoef(scip, consdata->rows[3], consdata->nvars, consdata->vars, 1.0) );
1726
1727 /* create extra LP row if integer variable exists */
1728 if( consdata->intvar != NULL )
1729 {
1730 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->rows[4], cons, SCIPconsGetName(cons), 0.0, 0.0,
1732 SCIP_CALL( SCIPaddVarToRow(scip, consdata->rows[4], consdata->intvar, -2.0) );
1733 SCIP_CALL( SCIPaddVarsToRowSameCoef(scip, consdata->rows[4], consdata->nvars, consdata->vars, 1.0) );
1734 }
1735 }
1736 else
1737 {
1738 char rowname[SCIP_MAXSTRLEN];
1739 int r;
1740
1741 /* create the <= 1 rows with one negative sign */
1742 for( r = 0; r < 3; ++r )
1743 {
1744 int v;
1745
1746 (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s_%d", SCIPconsGetName(cons), r);
1747 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->rows[r], cons, rowname, -SCIPinfinity(scip), 1.0,
1749 for( v = 0; v < 3; ++v )
1750 {
1751 SCIP_CALL( SCIPaddVarToRow(scip, consdata->rows[r], consdata->vars[v], v == r ? -1.0 : +1.0) );
1752 }
1753 }
1754
1755 /* create the <= -1 row with all negative signs */
1756 (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s_3", SCIPconsGetName(cons));
1757 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->rows[3], cons, rowname, -SCIPinfinity(scip), -1.0,
1759 SCIP_CALL( SCIPaddVarsToRowSameCoef(scip, consdata->rows[3], consdata->nvars, consdata->vars, -1.0) );
1760
1761 /* create extra LP row if integer variable exists */
1762 if( consdata->intvar != NULL )
1763 {
1764 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->rows[4], cons, SCIPconsGetName(cons), 1.0, 1.0,
1766 SCIP_CALL( SCIPaddVarToRow(scip, consdata->rows[4], consdata->intvar, -2.0) );
1767 SCIP_CALL( SCIPaddVarsToRowSameCoef(scip, consdata->rows[4], consdata->nvars, consdata->vars, 1.0) );
1768 }
1769 }
1770
1771 return SCIP_OKAY;
1772}
1773
1774/** adds linear relaxation of or constraint to the LP */
1775static
1777 SCIP* scip, /**< SCIP data structure */
1778 SCIP_CONS* cons, /**< constraint to check */
1779 SCIP_Bool* infeasible /**< pointer to store whether infeasibility was detected */
1780 )
1781{
1782 SCIP_CONSDATA* consdata;
1783 int r;
1784
1785 consdata = SCIPconsGetData(cons);
1786 assert(consdata != NULL);
1787 assert(infeasible != NULL);
1788 assert(!(*infeasible));
1789
1790 if( consdata->rows[0] == NULL )
1791 {
1793 }
1794 assert(consdata->rows[0] != NULL);
1795 for( r = 0; r < NROWS && !(*infeasible); ++r )
1796 {
1797 if( consdata->rows[r] != NULL && !SCIProwIsInLP(consdata->rows[r]) )
1798 {
1799 SCIP_CALL( SCIPaddRow(scip, consdata->rows[r], FALSE, infeasible) );
1800 }
1801 }
1802
1803 return SCIP_OKAY;
1804}
1805
1806/** returns whether all rows of the LP relaxation are in the current LP */
1807static
1809 SCIP_CONSDATA* consdata /**< constraint data */
1810 )
1811{
1812 assert(consdata != NULL);
1813
1814 if( consdata->rows[0] == NULL ) /* LP relaxation does not exist */
1815 return FALSE;
1816 else
1817 {
1818 int r;
1819 for( r = 0; r < NROWS; ++r )
1820 {
1821 if( consdata->rows[r] != NULL && !SCIProwIsInLP(consdata->rows[r]) )
1822 return FALSE;
1823 }
1824 return TRUE;
1825 }
1826}
1827
1828/** checks xor constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
1829static
1831 SCIP* scip, /**< SCIP data structure */
1832 SCIP_CONS* cons, /**< constraint to check */
1833 SCIP_SOL* sol, /**< solution to check, NULL for current solution */
1834 SCIP_Bool checklprows, /**< Do constraints represented by rows in the current LP have to be checked? */
1835 SCIP_Bool printreason, /**< Should the reason for the violation be printed? */
1836 SCIP_Bool* violated /**< pointer to store whether the constraint is violated */
1837 )
1838{
1839 SCIP_CONSDATA* consdata;
1840
1841 assert(violated != NULL);
1842
1843 consdata = SCIPconsGetData(cons);
1844 assert(consdata != NULL);
1845
1846 *violated = FALSE;
1847
1848 /* check feasibility of constraint if necessary */
1849 if( checklprows || !allRowsInLP(consdata) )
1850 {
1851 SCIP_Real maxcenval = 0.0;
1852 SCIP_Real sumcenval = 0.0;
1853 SCIP_Real sumsolval = 0.0;
1854 SCIP_Real cenval;
1855 SCIP_Real solval;
1856 SCIP_Real viol;
1857 SCIP_Bool odd = consdata->rhs;
1858 int ones = 0;
1859 int i;
1860
1861 /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
1862 * enforcement
1863 */
1864 if( sol == NULL )
1865 {
1866 SCIP_CALL( SCIPincConsAge(scip, cons) );
1867 }
1868
1869 /* evaluate operator variables */
1870 for( i = 0; i < consdata->nvars; ++i )
1871 {
1872 solval = SCIPgetSolVal(scip, sol, consdata->vars[i]);
1873
1874 if( solval > 0.5 )
1875 {
1876 odd = !odd;
1877 ++ones;
1878 cenval = 1.0 - solval;
1879 }
1880 else
1881 cenval = solval;
1882
1883 if( maxcenval < cenval )
1884 maxcenval = cenval;
1885
1886 sumcenval += cenval;
1887 sumsolval += solval;
1888 }
1889
1890 /* the center value sum is the additive distance to the nearest integral solution infeasible if odd
1891 * and otherwise the additive distance to the next nearest integral solution infeasible must be at least one
1892 * see separateCons() for further intuition
1893 */
1894 viol = MAX(0.0, (odd ? 1.0 : 2.0 * maxcenval) - sumcenval);
1895
1896 /* additionally check linear feasibility of an existing integer variable */
1897 if( consdata->intvar != NULL )
1898 {
1899 solval = REALABS(sumsolval - 2 * SCIPgetSolVal(scip, sol, consdata->intvar) - (SCIP_Real)consdata->rhs);
1900
1901 if( viol < solval )
1902 viol = solval;
1903 }
1904
1905 if( SCIPisFeasPositive(scip, viol) )
1906 {
1907 *violated = TRUE;
1908
1909 /* only reset constraint age if we are in enforcement */
1910 if( sol == NULL )
1911 {
1913 }
1914
1915 if( printreason )
1916 {
1917 SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
1918 SCIPinfoMessage(scip, NULL, ";\n");
1919 SCIPinfoMessage(scip, NULL, "violation: %d operands are set to TRUE ", ones);
1920
1921 if( consdata->intvar == NULL )
1922 SCIPinfoMessage(scip, NULL, "and all sum up to %g\n", sumsolval);
1923 else
1924 SCIPinfoMessage(scip, NULL, "but integer variable is %g\n", SCIPgetSolVal(scip, sol, consdata->intvar));
1925 }
1926 }
1927
1928 /* update constraint violation in solution */
1929 if( sol != NULL )
1930 SCIPupdateSolConsViolation(scip, sol, viol, viol);
1931 }
1932
1933 return SCIP_OKAY;
1934}
1935
1936/** separates current LP solution
1937 *
1938 * Consider a XOR-constraint
1939 * \f[
1940 * x_1 \oplus x_2 \oplus \dots \oplus x_n = b
1941 * \f]
1942 * 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
1943 * inequalities of the convex hull.
1944 *
1945 * The separation of larger XOR constraints has been described by @n
1946 * Xiaojie Zhang and Paul H. Siegel@n
1947 * "Adaptive Cut Generation Algorithm for Improved Linear Programming Decoding of Binary Linear Codes"@n
1948 * IEEE Transactions on Information Theory, vol. 58, no. 10, 2012
1949 *
1950 * We separate the inequalities
1951 * \f[
1952 * \sum_{j \in S} (1 - x_j) + \sum_{j \notin S} x_j \geq 1
1953 * \f]
1954 * with \f$|S| \equiv (b+1) \mbox{ mod } 2\f$ as follows. That these inequalities are valid can be seen as follows: Let
1955 * \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
1956 * all \f$j \in S\f$ and \f$x_j = 0\f$ for all \f$j \notin S\f$. Thus we should have
1957 * \f[
1958 * \oplus_{j \in S} x_j = |S| \mbox{ mod } 2 = b+1 \mbox{ mod } 2,
1959 * \f]
1960 * which is not equal to \f$b\f$ as required by the XOR-constraint.
1961 *
1962 * 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
1963 * \f[
1964 * \sum_{j \in L} (1 - x_j) + \sum_{j \notin L} x_j \geq 1
1965 * \f]
1966 * is the only inequality that can be violated. We rewrite the inequality as
1967 * \f[
1968 * \sum_{j \in L} x_j - \sum_{j \notin L} x_j \leq |L| - 1.
1969 * \f]
1970 * These inequalities are added.
1971 *
1972 * Otherwise let \f$k = \mbox{argmin}\{x^*_j \;:\; j \in L\}\f$ and check the inequality for \f$L \setminus \{k\}\f$
1973 * and similarly for \f$k = \mbox{argmax}\{x^*_j \;:\; j \in L\}\f$.
1974 */
1975static
1977 SCIP* scip, /**< SCIP data structure */
1978 SCIP_CONS* cons, /**< constraint to check */
1979 SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
1980 SCIP_Bool separateparity, /**< should parity inequalities be separated? */
1981 SCIP_Bool* separated, /**< pointer to store whether a cut was found */
1982 SCIP_Bool* cutoff /**< whether a cutoff has been detected */
1983 )
1984{
1985 SCIP_CONSDATA* consdata;
1986 SCIP_Real feasibility;
1987 int r;
1988
1989 assert(separated != NULL);
1990 assert(cutoff != NULL);
1991 *cutoff = FALSE;
1992
1993 consdata = SCIPconsGetData(cons);
1994 assert(consdata != NULL);
1995
1996 *separated = FALSE;
1997
1998 /* create row for the linear relaxation */
1999 if( consdata->rows[0] == NULL )
2000 {
2002 }
2003 assert(consdata->rows[0] != NULL);
2004
2005 /* test rows for feasibility and add it, if it is infeasible */
2006 for( r = 0; r < NROWS; ++r )
2007 {
2008 if( consdata->rows[r] != NULL && !SCIProwIsInLP(consdata->rows[r]) )
2009 {
2010 feasibility = SCIPgetRowSolFeasibility(scip, consdata->rows[r], sol);
2011 if( SCIPisFeasNegative(scip, feasibility) )
2012 {
2013 SCIP_CALL( SCIPaddRow(scip, consdata->rows[r], FALSE, cutoff) );
2014 if( *cutoff )
2015 return SCIP_OKAY;
2016 *separated = TRUE;
2017 }
2018 }
2019 }
2020
2021 /* separate parity inequalities if required */
2022 if( separateparity && consdata->nvars > 3 )
2023 {
2024 char name[SCIP_MAXSTRLEN];
2025 SCIP_Real maxval = -1.0;
2026 SCIP_Real minval = 2.0;
2027 SCIP_Real sum = 0.0;
2028 int maxidx = -1;
2029 int minidx = -1;
2030 int ngen = 0;
2031 int cnt = 0;
2032 int j;
2033
2034 SCIPdebugMsg(scip, "separating parity inequalities ...\n");
2035
2036 /* compute value */
2037 for( j = 0; j < consdata->nvars; ++j )
2038 {
2039 SCIP_Real val;
2040
2041 val = SCIPgetSolVal(scip, sol, consdata->vars[j]);
2042 if( val > 0.5 )
2043 {
2044 if( val < minval )
2045 {
2046 minval = val;
2047 minidx = j;
2048 }
2049 ++cnt;
2050 sum += (1.0 - val);
2051 }
2052 else
2053 {
2054 if( val > maxval )
2055 {
2056 maxval = val;
2057 maxidx = j;
2058 }
2059 sum += val;
2060 }
2061 }
2062
2063 /* if size of set does not have the same parity as rhs (e.g., size is odd if rhs is 0) */
2064 if( (cnt - (int) consdata->rhs) % 2 == 1 )
2065 {
2066 if( SCIPisEfficacious(scip, 1.0 - sum) )
2067 {
2068 SCIP_ROW* row;
2069
2070 SCIPdebugMsg(scip, "found violated parity cut (efficiacy: %f)\n", 1.0 - sum);
2071
2072 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "parity#%s", SCIPconsGetName(cons));
2073 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real) (cnt - 1), FALSE, FALSE, TRUE) );
2075
2076 /* fill in row */
2077 for( j = 0; j < consdata->nvars; ++j )
2078 {
2079 if( SCIPgetSolVal(scip, sol, consdata->vars[j]) > 0.5 )
2080 {
2081 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], 1.0) );
2082 }
2083 else
2084 {
2085 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], -1.0) );
2086 }
2087 }
2090 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
2091 assert(SCIPisGT(scip, SCIPgetRowLPActivity(scip, row), (SCIP_Real) (cnt-1)));
2092 SCIP_CALL( SCIPreleaseRow(scip, &row) );
2093 ++ngen;
2094 }
2095 }
2096 else
2097 {
2098 /* If the parity is equal: check removing the element with smallest value from the set and adding the
2099 * element with largest value to the set. If we remove the element with smallest value, we have to subtract (1
2100 * - minval) and add minval to correct the sum. */
2101 if( SCIPisEfficacious(scip, 1.0 - (sum - 1.0 + 2.0 * minval)) )
2102 {
2103 SCIP_ROW* row;
2104
2105 SCIPdebugMsg(scip, "found violated parity cut (efficiacy: %f, minval: %f)\n", 1.0 - (sum - 1.0 + 2.0 * minval), minval);
2106
2107 /* the rhs of the inequality is the corrected set size minus 1 */
2108 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "parity#%s", SCIPconsGetName(cons));
2109 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real) (cnt - 2), FALSE, FALSE, TRUE) );
2111
2112 /* fill in row */
2113 for( j = 0; j < consdata->nvars; ++j )
2114 {
2115 if( SCIPgetSolVal(scip, sol, consdata->vars[j]) > 0.5 )
2116 {
2117 /* if the index corresponds to the smallest element, we reverse the sign */
2118 if( j == minidx )
2119 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], -1.0) );
2120 else
2121 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], 1.0) );
2122 }
2123 else
2124 {
2125 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], -1.0) );
2126 }
2127 }
2130 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
2131 assert(SCIPisGT(scip, SCIPgetRowLPActivity(scip, row), (SCIP_Real) (cnt-2)));
2132 SCIP_CALL( SCIPreleaseRow(scip, &row) );
2133 ++ngen;
2134 }
2135
2136 /* If we add the element with largest value, we have to add (1 - maxval) and subtract maxval to get the correct sum. */
2137 if( SCIPisEfficacious(scip, 1.0 - (sum + 1.0 - 2.0 * maxval)) )
2138 {
2139 SCIP_ROW* row;
2140
2141 SCIPdebugMsg(scip, "found violated parity cut (efficiacy: %f, maxval: %f)\n", 1.0 - (sum + 1.0 - 2.0 * maxval), maxval);
2142
2143 /* the rhs of the inequality is the size of the corrected set */
2144 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "parity#%s", SCIPconsGetName(cons));
2145 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), (SCIP_Real) cnt, FALSE, FALSE, TRUE) );
2147
2148 /* fill in row */
2149 for( j = 0; j < consdata->nvars; ++j )
2150 {
2151 if( SCIPgetSolVal(scip, sol, consdata->vars[j]) > 0.5 )
2152 {
2153 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], 1.0) );
2154 }
2155 else
2156 {
2157 /* if the index corresponds to the largest element, we reverse the sign */
2158 if( j == maxidx )
2159 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], 1.0) );
2160 else
2161 SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], -1.0) );
2162 }
2163 }
2166 SCIP_CALL( SCIPaddRow(scip, row, FALSE, cutoff) );
2167 assert(SCIPisGT(scip, SCIPgetRowLPActivity(scip, row), (SCIP_Real)cnt));
2168 SCIP_CALL( SCIPreleaseRow(scip, &row) );
2169 ++ngen;
2170 }
2171 }
2172
2173 SCIPdebugMsg(scip, "separated parity inequalites: %d\n", ngen);
2174 if( ngen > 0 )
2175 *separated = TRUE;
2176 }
2177
2178 return SCIP_OKAY;
2179}
2180
2181/** Transform linear system \f$A x = b\f$ into row echelon form via the Gauss algorithm with row pivoting over GF2
2182 * @returns the rank of @p A
2183 *
2184 * 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
2185 * 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
2186 * s[i] contains the column index of the first nonzero in row @p i.
2187 */
2188static
2190 SCIP* scip, /**< SCIP data structure */
2191 int m, /**< number of rows */
2192 int n, /**< number of columns */
2193 int* p, /**< row permutation */
2194 int* s, /**< steps indicators of the row echelon form */
2195 Type** A, /**< matrix */
2196 Type* b /**< rhs */
2197 )
2198{
2199 int pi;
2200 int i;
2201 int j;
2202 int k;
2203
2204 assert(A != NULL);
2205 assert(b != NULL);
2206 assert(p != NULL);
2207 assert(s != NULL);
2208
2209 /* init permutation and step indicators */
2210 for( i = 0; i < m; ++i )
2211 {
2212 p[i] = i;
2213 s[i] = i;
2214 }
2215
2216 /* loop through possible steps in echelon form (stop at min {n, m}) */
2217 for( i = 0; i < m && i < n; ++i )
2218 {
2219 assert(s[i] == i);
2220
2221 /* init starting column */
2222 if( i == 0 )
2223 j = 0;
2224 else
2225 j = s[i-1] + 1;
2226
2227 /* find pivot row (i.e., first nonzero entry), if all entries in current row are 0 we search the next column */
2228 do
2229 {
2230 /* search in current column j */
2231 k = i;
2232 while( k < m && A[p[k]][j] == 0 )
2233 ++k;
2234
2235 /* found pivot */
2236 if( k < m )
2237 break;
2238
2239 /* otherwise search next column */
2240 ++j;
2241 }
2242 while( j < n );
2243
2244 /* if not pivot entry was found (checked all columns), the rank of A is equal to the current index i; in this case
2245 * all entries in and below row i are 0 */
2246 if( j >= n )
2247 return i;
2248
2249 /* at this place: we have found a pivot entry (p[k], j) */
2250 assert(k < m);
2251
2252 /* store step index */
2253 s[i] = j;
2254 assert(A[p[k]][j] != 0);
2255
2256 /* swap row indices */
2257 if( k != i )
2258 {
2259 int h = p[i];
2260 p[i] = p[k];
2261 p[k] = h;
2262 }
2263 pi = p[i];
2264 assert(A[pi][s[i]] != 0);
2265
2266 /* do elimination */
2267 for( k = i+1; k < m; ++k )
2268 {
2269 int pk = p[k];
2270 /* if entry in leading column is nonzero (otherwise we already have a 0) */
2271 if( A[pk][s[i]] != 0 )
2272 {
2273 for( j = s[i]; j < n; ++j )
2274 A[pk][j] = A[pk][j] ^ A[pi][j]; /*lint !e732*/
2275 b[pk] = b[pk] ^ b[pi]; /*lint !e732*/
2276 }
2277 }
2278
2279 /* check stopped (only every 100 rows in order to save time */
2280 if( i % 100 == 99 )
2281 {
2282 if( SCIPisStopped(scip) )
2283 return -1;
2284 }
2285 }
2286
2287 /* 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
2288 * columns min {n,m}. */
2289 if( n <= m )
2290 return n;
2291 return m;
2292}
2293
2294/** Construct solution from matrix in row echelon form over GF2
2295 *
2296 * Compute solution of \f$A x = b\f$, which is already in row echelon form (@see computeRowEchelonGF2()) */
2297static
2299 int m, /**< number of rows */
2300 int n, /**< number of columns */
2301 int r, /**< rank of matrix */
2302 int* p, /**< row permutation */
2303 int* s, /**< steps indicators of the row echelon form */
2304 Type** A, /**< matrix */
2305 Type* b, /**< rhs */
2306 Type* x /**< solution vector on exit */
2307 )
2308{
2309 int i;
2310 int k;
2311
2312 assert(A != NULL);
2313 assert(b != NULL);
2314 assert(s != NULL);
2315 assert(p != NULL);
2316 assert(x != NULL);
2317 assert(r <= m && r <= n);
2318
2319 /* init solution vector to 0 */
2320 for( k = 0; k < n; ++k )
2321 x[k] = 0;
2322
2323 /* loop backwards through solution vector */
2324 for( i = r-1; i >= 0; --i )
2325 {
2326 Type val;
2327
2328 assert(i <= s[i] && s[i] <= n);
2329
2330 /* init val with rhs and then add the contributions of the components of x already computed */
2331 val = b[p[i]];
2332 for( k = i+1; k < r; ++k )
2333 {
2334 assert(i <= s[k] && s[k] <= n);
2335 if( A[p[i]][s[k]] != 0 )
2336 val = val ^ x[s[k]]; /*lint !e732*/
2337 }
2338
2339 /* store solution */
2340 x[s[i]] = val;
2341 }
2342}
2343
2344/** solve equation system over GF 2 by Gauss algorithm and create solution out of it or return cutoff
2345 *
2346 * Collect all information in xor constraints into a linear system over GF2. Then solve the system by computing a row
2347 * echelon form. If the system is infeasible, the current node is infeasible. Otherwise, we can compute a solution for
2348 * the xor constraints given. We check whether this gives a solution for the whole problem.
2349 *
2350 * We sort the columns with respect to the product of the objective coefficients and 1 minus the current LP solution
2351 * value. The idea is that columns that are likely to provide the steps in the row echelon form should appear towards
2352 * the front of the matrix. The smaller the product, the more it makes sense to set the variable to 1 (because the
2353 * solution value is already close to 1 and the objective function is small).
2354 *
2355 * Note that this function is called from propagation where usually no solution is available. However, the solution is
2356 * only used for sorting the columns. Thus, the procedure stays correct even with nonsense solutions.
2357 */
2358static
2360 SCIP* scip, /**< SCIP data structure */
2361 SCIP_CONS** conss, /**< xor constraints */
2362 int nconss, /**< number of xor constraints */
2363 SCIP_SOL* currentsol, /**< current solution (maybe NULL) */
2364 SCIP_RESULT* result /**< result of propagation (possibly cutoff, no change if primal solution has been tried) */
2365 )
2366{
2367 SCIP_CONSDATA* consdata;
2368 SCIP_HASHMAP* varhash;
2369 SCIP_Bool* xoractive;
2370 SCIP_Real* xorvals;
2371 SCIP_VAR** xorvars;
2372 SCIP_Bool noaggr = TRUE;
2373 Type** A;
2374 Type* b;
2375 int* s;
2376 int* p;
2377 int* xoridx;
2378 int* xorbackidx;
2379 int nconssactive = 0;
2380 int nconssmat = 0;
2381 int nvarsmat = 0;
2382 int nvars;
2383 int rank;
2384 int i;
2385 int j;
2386
2387 assert(scip != NULL);
2388 assert(conss != NULL);
2389 assert(result != NULL);
2390
2391 if( *result == SCIP_CUTOFF )
2392 return SCIP_OKAY;
2393
2394 SCIPdebugMsg(scip, "Checking feasibility via the linear equation system over GF2 using Gauss.\n");
2395
2396 nvars = SCIPgetNVars(scip);
2397
2398 /* set up hash map from variable to column index */
2399 SCIP_CALL( SCIPhashmapCreate(&varhash, SCIPblkmem(scip), nvars) );
2400 SCIP_CALL( SCIPallocBufferArray(scip, &xoractive, nconss) );
2401 SCIP_CALL( SCIPallocBufferArray(scip, &xorvars, nvars) );
2402 SCIP_CALL( SCIPallocBufferArray(scip, &xoridx, nvars) );
2403 SCIP_CALL( SCIPallocBufferArray(scip, &xorvals, nvars) );
2404
2405 /* collect variables */
2406 for( i = 0; i < nconss; ++i )
2407 {
2408 int cnt = 0;
2409
2410 xoractive[i] = FALSE;
2411
2412 assert(conss[i] != NULL);
2413 consdata = SCIPconsGetData(conss[i]);
2414 assert(consdata != NULL);
2415
2416 /* count nonfixed variables in constraint */
2417 for( j = 0; j < consdata->nvars; ++j )
2418 {
2419 SCIP_VAR* var;
2420
2421 var = consdata->vars[j];
2422 assert(var != NULL);
2423 assert(SCIPvarIsBinary(var));
2424
2425 /* replace negated variables */
2426 if( SCIPvarIsNegated(var) )
2427 var = SCIPvarGetNegatedVar(var);
2428 assert(var != NULL);
2429
2430 /* get the active variable */
2431 while( var != NULL && SCIPvarGetStatus(var) == SCIP_VARSTATUS_AGGREGATED )
2432 var = SCIPisEQ(scip, SCIPvarGetAggrScalar(var), 0.0) ? NULL : SCIPvarGetAggrVar(var);
2433 /* consider nonfixed variables */
2434 if( var != NULL && SCIPcomputeVarLbLocal(scip, var) < 0.5 && SCIPcomputeVarUbLocal(scip, var) > 0.5 )
2435 {
2436 /* consider active variables and collect only new ones */
2437 if( SCIPvarIsActive(var) && !SCIPhashmapExists(varhash, var) )
2438 {
2439 /* add variable in map */
2440 SCIP_CALL( SCIPhashmapInsertInt(varhash, var, nvarsmat) );
2441 assert(nvarsmat == SCIPhashmapGetImageInt(varhash, var));
2442 xorvals[nvarsmat] = SCIPvarGetObj(var) * (1.0 - SCIPgetSolVal(scip, currentsol, var));
2443 xorvars[nvarsmat++] = var;
2444 }
2445 ++cnt;
2446 }
2447 }
2448
2449 if( cnt > 0 )
2450 {
2451 xoractive[i] = TRUE;
2452 ++nconssactive;
2453 }
2454#ifdef SCIP_DISABLED_CODE
2455 /* The following can save time, if there are constraints with all variables fixed that are infeasible; this
2456 * should, however, be detected somewhere else, e.g., in propagateCons(). */
2457 else
2458 {
2459 /* all variables are fixed - check whether constraint is feasible (could be that the constraint is not propagated) */
2460 assert(cnt == 0);
2461 for( j = 0; j < consdata->nvars; ++j )
2462 {
2463 /* count variables fixed to 1 */
2464 if( SCIPcomputeVarLbLocal(scip, consdata->vars[j]) > 0.5 )
2465 ++cnt;
2466 else
2467 assert(SCIPcomputeVarUbLocal(scip, consdata->vars[j]) < 0.5);
2468 }
2469 if( ( cnt - consdata->rhs ) % 2 != 0 )
2470 {
2471 SCIPdebugMsg(scip, "constraint <%s> with all variables fixed is violated.\n", SCIPconsGetName(conss[i]));
2472 *result = SCIP_CUTOFF;
2473 break;
2474 }
2475 }
2476#endif
2477 }
2478 assert(nvarsmat <= nvars);
2479 assert(nconssactive <= nconss);
2480
2481 if( nconssactive > MAXXORCONSSSYSTEM || nvarsmat > MAXXORVARSSYSTEM || *result == SCIP_CUTOFF )
2482 {
2483 SCIPdebugMsg(scip, "Skip checking the xor system over GF2 (%d conss, %d vars).\n", nconssactive, nvarsmat);
2484 SCIPfreeBufferArray(scip, &xorvals);
2485 SCIPfreeBufferArray(scip, &xoridx);
2486 SCIPfreeBufferArray(scip, &xorvars);
2487 SCIPfreeBufferArray(scip, &xoractive);
2488 SCIPhashmapFree(&varhash);
2489 return SCIP_OKAY;
2490 }
2491
2492 /* init index */
2493 for( j = 0; j < nvarsmat; ++j )
2494 xoridx[j] = j;
2495
2496 /* Sort variables non-decreasingly with respect to product of objective and 1 minus the current solution value: the
2497 * smaller the value the better it would be to set the variable to 1. This is more likely if the variable appears
2498 * towards the front of the matrix, because only the entries on the steps in the row echelon form will have the
2499 * chance to be nonzero.
2500 */
2501 SCIPsortRealIntPtr(xorvals, xoridx, (void**) xorvars, nvarsmat);
2502 SCIPfreeBufferArray(scip, &xorvals);
2503
2504 /* build back index */
2505 SCIP_CALL( SCIPallocBufferArray(scip, &xorbackidx, nvarsmat) );
2506 for( j = 0; j < nvarsmat; ++j )
2507 {
2508 assert(0 <= xoridx[j] && xoridx[j] < nvarsmat);
2509 xorbackidx[xoridx[j]] = j;
2510 }
2511
2512 /* init matrix and rhs */
2513 SCIP_CALL( SCIPallocBufferArray(scip, &b, nconssactive) );
2514 SCIP_CALL( SCIPallocBufferArray(scip, &A, nconssactive) );
2515 for( i = 0; i < nconss; ++i )
2516 {
2517 if( !xoractive[i] )
2518 continue;
2519
2520 assert(conss[i] != NULL);
2521 consdata = SCIPconsGetData(conss[i]);
2522 assert(consdata != NULL);
2523 assert(consdata->nvars > 0);
2524
2525 SCIP_CALL( SCIPallocBufferArray(scip, &(A[nconssmat]), nvarsmat) ); /*lint !e866*/
2526 BMSclearMemoryArray(A[nconssmat], nvarsmat); /*lint !e866*/
2527
2528 /* correct rhs w.r.t. to fixed variables and count nonfixed variables in constraint */
2529 b[nconssmat] = (Type) consdata->rhs;
2530 for( j = 0; j < consdata->nvars; ++j )
2531 {
2532 SCIP_VAR* var;
2533 int idx;
2534
2535 var = consdata->vars[j];
2536 assert(var != NULL);
2537
2538 /* replace negated variables */
2539 if( SCIPvarIsNegated(var) )
2540 {
2541 var = SCIPvarGetNegatedVar(var);
2542 assert(var != NULL);
2543 b[nconssmat] = !b[nconssmat];
2544 }
2545
2546 /* replace aggregated variables */
2548 {
2549 SCIP_Real scalar;
2550 SCIP_Real constant;
2551
2552 scalar = SCIPvarGetAggrScalar(var);
2553 constant = SCIPvarGetAggrConstant(var);
2554
2555 /* the variable resolves to a constant, we just update the rhs */
2556 if( SCIPisEQ(scip, scalar, 0.0) )
2557 {
2558 assert(SCIPisEQ(scip, constant, 0.0) || SCIPisEQ(scip, constant, 1.0));
2559 if( SCIPisEQ(scip, constant, 1.0) )
2560 b[nconssmat] = !b[nconssmat];
2561 var = NULL;
2562 break;
2563 }
2564 /* replace aggregated variable by active variable and update rhs, if needed */
2565 else
2566 {
2567 assert(SCIPisEQ(scip, scalar, 1.0) || SCIPisEQ(scip, scalar, -1.0));
2568 if( SCIPisEQ(scip, constant, 1.0) )
2569 b[nconssmat] = !b[nconssmat];
2570
2571 var = SCIPvarGetAggrVar(var);
2572 assert(var != NULL);
2573 }
2574 }
2575 /* variable resolved to a constant */
2576 if( var == NULL )
2577 continue;
2578
2579 /* If the constraint contains multiaggregated variables, the solution might not be valid, since the
2580 * implications are not represented in the matrix.
2581 */
2583 noaggr = FALSE;
2584
2585 if( SCIPcomputeVarLbLocal(scip, var) > 0.5 )
2586 {
2587 /* variable is fixed to 1, invert rhs */
2588 b[nconssmat] = !b[nconssmat];
2589 assert(!SCIPhashmapExists(varhash, var));
2590 }
2591 else
2592 {
2595 if( SCIPvarIsActive(var) && SCIPcomputeVarUbLocal(scip, var) > 0.5 )
2596 {
2597 assert(SCIPhashmapExists(varhash, var));
2598 idx = SCIPhashmapGetImageInt(varhash, var);
2599 assert(idx >= 0);
2600 assert(idx < nvarsmat);
2601 idx = xorbackidx[idx];
2602 assert(idx >= 0);
2603 assert(idx < nvarsmat);
2604 A[nconssmat][idx] = !A[nconssmat][idx];
2605 }
2606 }
2607 }
2608 ++nconssmat;
2609 }
2610 SCIPdebugMsg(scip, "Found %d non-fixed variables in %d nonempty xor constraints.\n", nvarsmat, nconssmat);
2611 assert(nconssmat == nconssactive);
2612
2613 /* perform Gauss algorithm */
2614 SCIP_CALL( SCIPallocBufferArray(scip, &p, nconssmat) );
2615 SCIP_CALL( SCIPallocBufferArray(scip, &s, nconssmat) );
2616
2617#ifdef SCIP_OUTPUT
2618 SCIPinfoMessage(scip, NULL, "Matrix before Gauss (size: %d x %d):\n", nconssmat, nvarsmat);
2619 for( i = 0; i < nconssmat; ++i )
2620 {
2621 for( j = 0; j < nvarsmat; ++j )
2622 SCIPinfoMessage(scip, NULL, "%d ", A[i][j]);
2623 SCIPinfoMessage(scip, NULL, " = %d\n", b[i]);
2624 }
2625 SCIPinfoMessage(scip, NULL, "\n");
2626#endif
2627
2628 rank = -1;
2629 if( !SCIPisStopped(scip) )
2630 {
2631 rank = computeRowEchelonGF2(scip, nconssmat, nvarsmat, p, s, A, b);
2632 assert(rank <= nconssmat && rank <= nvarsmat);
2633 }
2634
2635 /* rank is < 0 if the solution process has been stopped */
2636 if( rank >= 0 )
2637 {
2638#ifdef SCIP_OUTPUT
2639 SCIPinfoMessage(scip, NULL, "Matrix after Gauss (rank: %d):\n", rank);
2640 for( i = 0; i < nconssmat; ++i )
2641 {
2642 for( j = 0; j < nvarsmat; ++j )
2643 SCIPinfoMessage(scip, NULL, "%d ", A[p[i]][j]);
2644 SCIPinfoMessage(scip, NULL, " = %d\n", b[p[i]]);
2645 }
2646 SCIPinfoMessage(scip, NULL, "\n");
2647#endif
2648
2649 /* check whether system is feasible */
2650 for( i = rank; i < nconssmat; ++i )
2651 {
2652 if( b[p[i]] != 0 )
2653 break;
2654 }
2655
2656 /* did not find nonzero entry in b -> equation system is feasible */
2657 if( i >= nconssmat )
2658 {
2659 SCIPdebugMsg(scip, "System feasible with rank %d (nconss=%d)\n", rank, nconssmat);
2660
2661 /* matrix has full rank, solution is unique */
2662 if( rank == nvarsmat && noaggr )
2663 {
2664 SCIP_Bool tightened;
2665 SCIP_Bool infeasible;
2666 Type* x;
2667
2668 SCIPdebugMsg(scip, "Found unique solution.\n");
2669
2670 /* construct solution */
2671 SCIP_CALL( SCIPallocBufferArray(scip, &x, nvarsmat) );
2672 solveRowEchelonGF2(nconssmat, nvarsmat, rank, p, s, A, b, x);
2673
2674#ifdef SCIP_OUTPUT
2675 SCIPinfoMessage(scip, NULL, "Solution:\n");
2676 for( j = 0; j < nvarsmat; ++j )
2677 SCIPinfoMessage(scip, NULL, "%d ", x[j]);
2678 SCIPinfoMessage(scip, NULL, "\n");
2679#endif
2680
2681 /* fix variables according to computed unique solution */
2682 for( j = 0; j < nvarsmat; ++j )
2683 {
2684 assert(SCIPhashmapGetImageInt(varhash, xorvars[j]) < nvars);
2685 assert(xorbackidx[SCIPhashmapGetImageInt(varhash, xorvars[j])] == j);
2686 assert(SCIPcomputeVarLbLocal(scip, xorvars[j]) < 0.5);
2687 if( x[j] == 0 )
2688 {
2689 SCIP_CALL( SCIPtightenVarUb(scip, xorvars[j], 0.0, FALSE, &infeasible, &tightened) );
2690 assert(tightened);
2691 assert(!infeasible);
2692 }
2693 else
2694 {
2695 assert(x[j] == 1);
2696 SCIP_CALL( SCIPtightenVarLb(scip, xorvars[j], 1.0, FALSE, &infeasible, &tightened) );
2697 assert(tightened);
2698 assert(!infeasible);
2699 }
2700 }
2702 }
2703 /* matrix does not have full rank, we add the solution, but cannot derive fixings */
2704 else
2705 {
2706 SCIP_HEUR* heurtrysol;
2707
2708 SCIPdebugMsg(scip, "Found solution.\n");
2709
2710 /* try solution */
2711 heurtrysol = SCIPfindHeur(scip, "trysol");
2712
2713 if( heurtrysol != NULL )
2714 {
2715 SCIP_Bool success;
2716 SCIP_VAR** vars;
2717 SCIP_SOL* sol;
2718 Type* x;
2719
2720 /* construct solution */
2721 SCIP_CALL( SCIPallocBufferArray(scip, &x, nvarsmat) );
2722 solveRowEchelonGF2(nconssmat, nvarsmat, rank, p, s, A, b, x);
2723
2724#ifdef SCIP_OUTPUT
2725 SCIPinfoMessage(scip, NULL, "Solution:\n");
2726 for( j = 0; j < nvarsmat; ++j )
2727 SCIPinfoMessage(scip, NULL, "%d ", x[j]);
2728 SCIPinfoMessage(scip, NULL, "\n");
2729#endif
2730
2731 /* create solution */
2732 SCIP_CALL( SCIPcreateSol(scip, &sol, heurtrysol) );
2733
2734 /* transfer solution */
2735 for( j = 0; j < nvarsmat; ++j )
2736 {
2737 if( x[j] != 0 )
2738 {
2739 assert(SCIPhashmapGetImageInt(varhash, xorvars[j]) < nvars);
2740 assert(xorbackidx[SCIPhashmapGetImageInt(varhash, xorvars[j])] == j);
2741 assert(SCIPcomputeVarLbLocal(scip, xorvars[j]) < 0.5);
2742 SCIP_CALL( SCIPsetSolVal(scip, sol, xorvars[j], 1.0) );
2743 }
2744 }
2746
2747 /* add *all* variables fixed to 1 */
2748 vars = SCIPgetVars(scip);
2749 for( j = 0; j < nvars; ++j )
2750 {
2751 if( SCIPcomputeVarLbLocal(scip, vars[j]) > 0.5 )
2752 {
2753 SCIP_CALL( SCIPsetSolVal(scip, sol, vars[j], 1.0) );
2754 SCIPdebugMsg(scip, "Added fixed variable <%s>.\n", SCIPvarGetName(vars[j]));
2755 }
2756 }
2757
2758 /* correct integral variables if necessary */
2759 for( i = 0; i < nconss; ++i )
2760 {
2761 consdata = SCIPconsGetData(conss[i]);
2762 assert(consdata != NULL);
2763
2764 /* only try for active constraints and integral variable; hope for the best if they are not active */
2765 if( xoractive[i] && consdata->intvar != NULL && SCIPvarIsActive(consdata->intvar) )
2766 {
2767 SCIP_Real val;
2768 int nones = 0;
2769
2770 for( j = 0; j < consdata->nvars; ++j )
2771 {
2772 if( SCIPgetSolVal(scip, sol, consdata->vars[j]) > 0.5 )
2773 ++nones;
2774 }
2775 /* if there are aggregated variables, the solution might not be feasible */
2776 assert(!noaggr || nones % 2 == (int) consdata->rhs);
2777 if( (unsigned int) nones != consdata->rhs )
2778 {
2779 val = (SCIP_Real) (nones - (int) consdata->rhs)/2;
2780 if( SCIPisGE(scip, val, SCIPvarGetLbGlobal(consdata->intvar)) && SCIPisLE(scip, val, SCIPvarGetUbGlobal(consdata->intvar)) )
2781 {
2782 SCIP_CALL( SCIPsetSolVal(scip, sol, consdata->intvar, val) );
2783 }
2784 }
2785 }
2786 }
2788
2789 /* check feasibility of new solution and pass it to trysol heuristic */
2790 SCIP_CALL( SCIPcheckSol(scip, sol, FALSE, FALSE, TRUE, TRUE, TRUE, &success) );
2791 if( success )
2792 {
2793 SCIP_CALL( SCIPheurPassSolAddSol(scip, heurtrysol, sol) );
2794 SCIPdebugMsg(scip, "Creating solution was successful.\n");
2795 }
2796#ifdef SCIP_DEBUG
2797 else
2798 {
2799 /* the solution might not be feasible, because of additional constraints */
2800 SCIPdebugMsg(scip, "Creating solution was not successful.\n");
2801 }
2802#endif
2803 SCIP_CALL( SCIPfreeSol(scip, &sol) );
2804 }
2805 }
2806 }
2807 else
2808 {
2809 *result = SCIP_CUTOFF;
2810 SCIPdebugMsg(scip, "System not feasible.\n");
2811 }
2812 }
2813
2814 /* free storage */
2817 j = nconssmat - 1;
2818 for( i = nconss - 1; i >= 0 ; --i )
2819 {
2820 consdata = SCIPconsGetData(conss[i]);
2821 assert(consdata != NULL);
2822
2823 if( consdata->nvars == 0 )
2824 continue;
2825
2826 if( !xoractive[i] )
2827 continue;
2828
2829 SCIPfreeBufferArray(scip, &(A[j]));
2830 --j;
2831 }
2834 SCIPfreeBufferArray(scip, &xorbackidx);
2835 SCIPfreeBufferArray(scip, &xoridx);
2836 SCIPfreeBufferArray(scip, &xorvars);
2837 SCIPfreeBufferArray(scip, &xoractive);
2838 SCIPhashmapFree(&varhash);
2839
2840 return SCIP_OKAY;
2841}
2842
2843/** for each variable in the xor constraint, add it to conflict set; for integral variable add corresponding bound */
2844static
2846 SCIP* scip, /**< SCIP data structure */
2847 SCIP_CONS* cons, /**< constraint that inferred the bound change */
2848 SCIP_VAR* infervar, /**< variable that was deduced, or NULL (not equal to integral variable) */
2849 SCIP_BDCHGIDX* bdchgidx, /**< bound change index (time stamp of bound change), or NULL for current time */
2850 PROPRULE proprule /**< propagation rule */
2851 )
2852{
2853 SCIP_CONSDATA* consdata;
2854 SCIP_VAR** vars;
2855 int nvars;
2856 int i;
2857
2858 assert(cons != NULL);
2859
2860 consdata = SCIPconsGetData(cons);
2861 assert(consdata != NULL);
2862 vars = consdata->vars;
2863 nvars = consdata->nvars;
2864
2865 switch( proprule )
2866 {
2867 case PROPRULE_0:
2868 assert(infervar == NULL || infervar == consdata->intvar);
2869
2870 /* the integral variable was fixed, because all variables were fixed */
2871 for( i = 0; i < nvars; ++i )
2872 {
2873 assert(SCIPisEQ(scip, SCIPgetVarLbAtIndex(scip, vars[i], bdchgidx, FALSE), SCIPgetVarUbAtIndex(scip, vars[i], bdchgidx, FALSE)));
2875 }
2876 break;
2877
2878 case PROPRULE_1:
2879 /* the variable was inferred, because all other variables were fixed */
2880 for( i = 0; i < nvars; ++i )
2881 {
2882 /* add variables that were fixed to 1 before */
2883 if( SCIPgetVarLbAtIndex(scip, vars[i], bdchgidx, FALSE) > 0.5 )
2884 {
2885 assert(SCIPgetVarLbAtIndex(scip, vars[i], bdchgidx, TRUE) > 0.5);
2887 }
2888 /* add variables that were fixed to 0 */
2889 else if( SCIPgetVarUbAtIndex(scip, vars[i], bdchgidx, FALSE) < 0.5 )
2890 {
2891 assert(SCIPgetVarUbAtIndex(scip, vars[i], bdchgidx, TRUE) < 0.5);
2893 }
2894 else
2895 {
2896 /* check changed variable (changed variable is 0 or 1 afterwards) */
2897 assert(vars[i] == infervar);
2898 }
2899 }
2900 break;
2901
2902 case PROPRULE_INTLB:
2903 assert(consdata->intvar != NULL);
2904
2905 if( infervar != consdata->intvar )
2906 {
2907 /* the variable was fixed, because of the lower bound of the integral variable */
2908 SCIP_CALL( SCIPaddConflictLb(scip, consdata->intvar, NULL) );
2909 }
2910 /* to many and the other fixed variables */
2911 for( i = 0; i < nvars; ++i )
2912 {
2913 /* add variables that were fixed to 0 */
2914 if( SCIPgetVarUbAtIndex(scip, vars[i], bdchgidx, FALSE) < 0.5 )
2915 {
2916 assert(SCIPgetVarUbAtIndex(scip, vars[i], bdchgidx, TRUE) < 0.5);
2918 }
2919 }
2920 break;
2921
2922 case PROPRULE_INTUB:
2923 assert(consdata->intvar != NULL);
2924
2925 if( infervar != consdata->intvar )
2926 {
2927 /* the variable was fixed, because of upper bound of the integral variable and the other fixed variables */
2928 SCIP_CALL( SCIPaddConflictUb(scip, consdata->intvar, NULL) );
2929 }
2930 for( i = 0; i < nvars; ++i )
2931 {
2932 /* add variables that were fixed to 1 */
2933 if( SCIPgetVarLbAtIndex(scip, vars[i], bdchgidx, FALSE) > 0.5 )
2934 {
2935 assert(SCIPgetVarLbAtIndex(scip, vars[i], bdchgidx, TRUE) > 0.5);
2937 }
2938 }
2939 break;
2940
2941 case PROPRULE_INVALID:
2942 default:
2943 SCIPerrorMessage("invalid inference information %d in xor constraint <%s>\n", proprule, SCIPconsGetName(cons));
2944 SCIPABORT();
2945 return SCIP_INVALIDDATA; /*lint !e527*/
2946 }
2947
2948 return SCIP_OKAY;
2949}
2950
2951/** analyzes conflicting assignment on given constraint, and adds conflict constraint to problem */
2952static
2954 SCIP* scip, /**< SCIP data structure */
2955 SCIP_CONS* cons, /**< xor constraint that detected the conflict */
2956 SCIP_VAR* infervar, /**< variable that was deduced, or NULL (not equal to integral variable) */
2957 PROPRULE proprule /**< propagation rule */
2958 )
2959{
2960 /* conflict analysis can only be applied in solving stage and if it is applicable */
2962 return SCIP_OKAY;
2963
2964 /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */
2966
2967 /* add bound changes */
2968 SCIP_CALL( addConflictBounds(scip, cons, infervar, NULL, proprule) );
2969
2970 /* analyze the conflict */
2972
2973 return SCIP_OKAY;
2974}
2975
2976/** propagates constraint with the following rules:
2977 * (0) all variables are fixed => can fix integral variable
2978 * (1) all except one variable fixed => fix remaining variable and integral variable
2979 * (2) depending on the amount of fixed binary variables we can tighten the integral variable
2980 * (3) depending on the lower bound of the integral variable one can fix variables to 1
2981 * (4) depending on the upper bound of the integral variable one can fix variables to 0
2982 */
2983static
2985 SCIP* scip, /**< SCIP data structure */
2986 SCIP_CONS* cons, /**< xor constraint to be processed */
2987 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
2988 SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
2989 int* nfixedvars, /**< pointer to add up the number of fixed variables */
2990 int* nchgbds /**< pointer to add up the number of found domain reductions */
2991 )
2992{
2993 SCIP_CONSDATA* consdata;
2994 SCIP_VAR** vars;
2995 SCIP_Bool infeasible;
2996 SCIP_Bool tightened;
2997 SCIP_Bool odd;
2998 SCIP_Bool counted;
2999 int nvars;
3000 int nfixedones;
3001 int nfixedzeros;
3002 int watchedvar1;
3003 int watchedvar2;
3004 int i;
3005
3006 assert(scip != NULL);
3007 assert(cons != NULL);
3008 assert(eventhdlr != NULL);
3009 assert(cutoff != NULL);
3010 assert(nfixedvars != NULL);
3011 assert(nchgbds != NULL);
3012
3013 /* propagation can only be applied, if we know all operator variables */
3014 if( SCIPconsIsModifiable(cons) )
3015 return SCIP_OKAY;
3016
3017 consdata = SCIPconsGetData(cons);
3018 assert(consdata != NULL);
3019
3020 vars = consdata->vars;
3021 nvars = consdata->nvars;
3022
3023 /* don't process the constraint, if the watched variables weren't fixed to any value since last propagation call */
3024 if( consdata->propagated )
3025 return SCIP_OKAY;
3026
3027 /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
3029 {
3030 SCIP_CALL( SCIPincConsAge(scip, cons) );
3031 }
3032
3033 /* propagation cannot be applied, if we have at least two unfixed variables left;
3034 * that means, we only have to watch (i.e. capture events) of two variables, and switch to other variables
3035 * if these ones get fixed
3036 */
3037 watchedvar1 = consdata->watchedvar1;
3038 watchedvar2 = consdata->watchedvar2;
3039
3040 /* check, if watched variables are still unfixed */
3041 if( watchedvar1 != -1 )
3042 {
3043 if( SCIPvarGetLbLocal(vars[watchedvar1]) > 0.5 || SCIPvarGetUbLocal(vars[watchedvar1]) < 0.5 )
3044 watchedvar1 = -1;
3045 }
3046 if( watchedvar2 != -1 )
3047 {
3048 if( SCIPvarGetLbLocal(vars[watchedvar2]) > 0.5 || SCIPvarGetUbLocal(vars[watchedvar2]) < 0.5 )
3049 watchedvar2 = -1;
3050 }
3051
3052 /* if only one watched variable is still unfixed, make it the first one */
3053 if( watchedvar1 == -1 )
3054 {
3055 watchedvar1 = watchedvar2;
3056 watchedvar2 = -1;
3057 }
3058 assert(watchedvar1 != -1 || watchedvar2 == -1);
3059
3060 /* if the watched variables are invalid (fixed), find new ones if existing; count the parity */
3061 odd = consdata->rhs;
3062 nfixedones = 0;
3063 nfixedzeros = 0;
3064 counted = FALSE;
3065 if( watchedvar2 == -1 )
3066 {
3067 for( i = 0; i < nvars; ++i )
3068 {
3069 if( SCIPvarGetLbLocal(vars[i]) > 0.5 )
3070 {
3071 odd = !odd;
3072 ++nfixedones;
3073 }
3074 else if( SCIPvarGetUbLocal(vars[i]) < 0.5 )
3075 ++nfixedzeros;
3076 else
3077 {
3078 assert(SCIPvarGetUbLocal(vars[i]) > 0.5);
3079 assert(SCIPvarGetLbLocal(vars[i]) < 0.5);
3080
3081 if( watchedvar1 == -1 )
3082 {
3083 assert(watchedvar2 == -1);
3084 watchedvar1 = i;
3085 }
3086 else if( watchedvar2 == -1 && watchedvar1 != i )
3087 {
3088 watchedvar2 = i;
3089 }
3090 }
3091 }
3092 counted = TRUE;
3093 }
3094 assert(watchedvar1 != -1 || watchedvar2 == -1);
3095
3096 /* if all variables are fixed, we can decide the feasibility of the constraint */
3097 if( watchedvar1 == -1 )
3098 {
3099 assert(watchedvar2 == -1);
3100 assert(counted);
3101
3102 if( odd )
3103 {
3104 SCIPdebugMsg(scip, "constraint <%s>: all vars fixed, constraint is infeasible\n", SCIPconsGetName(cons));
3105
3106 /* use conflict analysis to get a conflict constraint out of the conflicting assignment */
3109
3110 *cutoff = TRUE;
3111 }
3112 else
3113 {
3114 /* fix integral variable if present */
3115 if( consdata->intvar != NULL )
3116 {
3117 int fixval;
3118
3119 assert(!*cutoff);
3120 assert((nfixedones - (int) consdata->rhs) % 2 == 0);
3121
3122 fixval = (nfixedones - (int) consdata->rhs)/2; /*lint !e713*/
3123
3124 SCIPdebugMsg(scip, "fix integral variable <%s> to %d\n", SCIPvarGetName(consdata->intvar), fixval);
3125
3126 /* check whether value to fix is outside bounds */
3127 if( fixval + 0.5 < SCIPvarGetLbLocal(consdata->intvar) )
3128 {
3129 /* cannot fix auxiliary variable (maybe it has been branched on): we are infeasible */
3130 SCIPdebugMsg(scip, "node infeasible: activity is %d, bounds of integral variable are [%g,%g]\n",
3131 fixval, SCIPvarGetLbLocal(consdata->intvar), SCIPvarGetUbLocal(consdata->intvar));
3132
3135
3136 *cutoff = TRUE;
3137 }
3138 else if( fixval - 0.5 > SCIPvarGetUbLocal(consdata->intvar) )
3139 {
3140 /* cannot fix auxiliary variable (maybe it has been branched on): we are infeasible */
3141 SCIPdebugMsg(scip, "node infeasible: activity is %d, bounds of integral variable are [%g,%g]\n",
3142 fixval, SCIPvarGetLbLocal(consdata->intvar), SCIPvarGetUbLocal(consdata->intvar));
3143
3146
3147 *cutoff = TRUE;
3148 }
3149 else if( SCIPvarGetStatus(consdata->intvar) != SCIP_VARSTATUS_MULTAGGR )
3150 {
3151 if( !SCIPisEQ(scip, SCIPvarGetLbLocal(consdata->intvar), (SCIP_Real) fixval) )
3152 {
3153 SCIP_CALL( SCIPinferVarLbCons(scip, consdata->intvar, (SCIP_Real) fixval, cons, (int)PROPRULE_0, FALSE, &infeasible, &tightened) );
3154 assert(tightened);
3155 assert(!infeasible);
3156 }
3157
3158 if( !SCIPisEQ(scip, SCIPvarGetUbLocal(consdata->intvar), (SCIP_Real) fixval) )
3159 {
3160 SCIP_CALL( SCIPinferVarUbCons(scip, consdata->intvar, (SCIP_Real) fixval, cons, (int)PROPRULE_0, FALSE, &infeasible, &tightened) );
3161 assert(tightened);
3162 assert(!infeasible);
3163 }
3164
3165 ++(*nfixedvars);
3166 }
3167 }
3168 else
3169 {
3170 SCIPdebugMsg(scip, "constraint <%s>: all vars fixed, constraint is feasible\n", SCIPconsGetName(cons));
3171 }
3172 }
3174
3175 return SCIP_OKAY;
3176 }
3177
3178 /* if only one variable is not fixed, this variable can be deduced */
3179 if( watchedvar2 == -1 )
3180 {
3181 assert(watchedvar1 != -1);
3182 assert(counted);
3183
3184 SCIPdebugMsg(scip, "constraint <%s>: only one unfixed variable -> fix <%s> to %u\n",
3185 SCIPconsGetName(cons), SCIPvarGetName(vars[watchedvar1]), odd);
3186
3187 SCIP_CALL( SCIPinferBinvarCons(scip, vars[watchedvar1], odd, cons, (int)PROPRULE_1, &infeasible, &tightened) );
3188 assert(!infeasible);
3189 assert(tightened);
3190
3191 (*nfixedvars)++;
3192
3193 /* fix integral variable if present and not multi-aggregated */
3194 if( consdata->intvar != NULL && SCIPvarGetStatus(consdata->intvar) != SCIP_VARSTATUS_MULTAGGR )
3195 {
3196 int fixval;
3197
3198 /* if variable has been fixed to 1, adjust number of fixed variables */
3199 if( odd )
3200 ++nfixedones;
3201
3202 assert((nfixedones - (int) consdata->rhs) % 2 == 0);
3203
3204 fixval = (nfixedones - (int) consdata->rhs)/2; /*lint !e713*/
3205 SCIPdebugMsg(scip, "should fix integral variable <%s> to %d\n", SCIPvarGetName(consdata->intvar), fixval);
3206
3207 /* check whether value to fix is outside bounds */
3208 if( fixval + 0.5 < SCIPvarGetLbLocal(consdata->intvar) )
3209 {
3210 /* cannot fix auxiliary variable (maybe it has been branched on): we are infeasible */
3211 SCIPdebugMsg(scip, "node infeasible: activity is %d, bounds of integral variable are [%g,%g]\n",
3212 fixval, SCIPvarGetLbLocal(consdata->intvar), SCIPvarGetUbLocal(consdata->intvar));
3213
3216
3217 *cutoff = TRUE;
3218 }
3219 else if( fixval - 0.5 > SCIPvarGetUbLocal(consdata->intvar) )
3220 {
3221 /* cannot fix auxiliary variable (maybe it has been branched on): we are infeasible */
3222 SCIPdebugMsg(scip, "node infeasible: activity is %d, bounds of integral variable are [%g,%g]\n",
3223 fixval, SCIPvarGetLbLocal(consdata->intvar), SCIPvarGetUbLocal(consdata->intvar));
3224
3227
3228 *cutoff = TRUE;
3229 }
3230 else
3231 {
3232 if( SCIPvarGetLbLocal(consdata->intvar) + 0.5 < (SCIP_Real) fixval )
3233 {
3234 SCIP_CALL( SCIPinferVarLbCons(scip, consdata->intvar, (SCIP_Real) fixval, cons, (int)PROPRULE_1, TRUE, &infeasible, &tightened) );
3235 assert(tightened);
3236 assert(!infeasible);
3237 }
3238
3239 if( SCIPvarGetUbLocal(consdata->intvar) - 0.5 > (SCIP_Real) fixval )
3240 {
3241 SCIP_CALL( SCIPinferVarUbCons(scip, consdata->intvar, (SCIP_Real) fixval, cons, (int)PROPRULE_1, TRUE, &infeasible, &tightened) );
3242 assert(tightened);
3243 assert(!infeasible);
3244 }
3245 assert(SCIPisFeasEQ(scip, SCIPvarGetLbLocal(consdata->intvar), SCIPvarGetUbLocal(consdata->intvar)));
3246
3247 ++(*nfixedvars);
3248 }
3249 }
3250
3253
3254 return SCIP_OKAY;
3255 }
3256
3257 /* propagate w.r.t. integral variable */
3258 if( consdata->intvar != NULL && !consdata->deleteintvar )
3259 {
3260 SCIP_Real newlb;
3261 SCIP_Real newub;
3262 int nonesmin;
3263 int nonesmax;
3264
3265 if( !counted )
3266 {
3267 assert(nfixedzeros == 0);
3268 assert(nfixedones == 0);
3269
3270 for( i = 0; i < nvars; ++i )
3271 {
3272 if( SCIPvarGetLbLocal(vars[i]) > 0.5 )
3273 ++nfixedones;
3274 else if( SCIPvarGetUbLocal(vars[i]) < 0.5 )
3275 ++nfixedzeros;
3276 }
3277 }
3278 assert(nfixedones + nfixedzeros < nvars);
3279
3280 assert(SCIPisFeasIntegral(scip, SCIPvarGetLbLocal(consdata->intvar)));
3281 assert(SCIPisFeasIntegral(scip, SCIPvarGetUbLocal(consdata->intvar)));
3282
3283 nonesmin = 2 * (int)(SCIPvarGetLbLocal(consdata->intvar) + 0.5) + (int) consdata->rhs; /*lint !e713*/
3284 nonesmax = 2 * (int)(SCIPvarGetUbLocal(consdata->intvar) + 0.5) + (int) consdata->rhs; /*lint !e713*/
3285
3286 /* the number of possible variables that can get value 1 is less than the minimum bound */
3287 if( nvars - nfixedzeros < nonesmin )
3288 {
3289 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);
3290
3293
3294 *cutoff = TRUE;
3295
3296 return SCIP_OKAY;
3297 }
3298
3299 /* the number of variables that are fixed to 1 is larger than the maximum bound */
3300 if( nfixedones > nonesmax )
3301 {
3302 SCIPdebugMsg(scip, "constraint <%s>: at least %d variables are fixed to 1, but there should be at most %d.\n", SCIPconsGetName(cons), nfixedones, nonesmax);
3303
3306
3307 *cutoff = TRUE;
3308
3309 return SCIP_OKAY;
3310 }
3311
3312 if( SCIPvarGetStatus(consdata->intvar) != SCIP_VARSTATUS_MULTAGGR )
3313 {
3314 /* compute new bounds on the integral variable */
3315 newlb = (SCIP_Real)((nfixedones + 1 - (int) consdata->rhs) / 2); /*lint !e653*/
3316 newub = (SCIP_Real)((nvars - nfixedzeros - (int) consdata->rhs) / 2); /*lint !e653*/
3317
3318 /* new lower bound is better */
3319 if( newlb > SCIPvarGetLbLocal(consdata->intvar) + 0.5 )
3320 {
3321 SCIPdebugMsg(scip, "constraint <%s>: propagated lower bound of integral variable <%s> to %g\n", SCIPconsGetName(cons), SCIPvarGetName(consdata->intvar), newlb);
3322 SCIP_CALL( SCIPinferVarLbCons(scip, consdata->intvar, newlb, cons, (int)PROPRULE_INTUB, TRUE, &infeasible, &tightened) );
3323 assert(tightened);
3324 assert(!infeasible);
3325
3326 ++(*nchgbds);
3327
3328 nonesmin = 2 * (int)(SCIPvarGetLbLocal(consdata->intvar) + 0.5) + (int) consdata->rhs; /*lint !e713*/
3329 }
3330
3331 /* new upper bound is better */
3332 if( newub < SCIPvarGetUbLocal(consdata->intvar) - 0.5 )
3333 {
3334 SCIPdebugMsg(scip, "constraint <%s>: propagated upper bound of integral variable <%s> to %g\n", SCIPconsGetName(cons), SCIPvarGetName(consdata->intvar), newub);
3335 SCIP_CALL( SCIPinferVarUbCons(scip, consdata->intvar, newub, cons, (int)PROPRULE_INTLB, TRUE, &infeasible, &tightened) );
3336 assert(tightened);
3337 assert(!infeasible);
3338
3339 ++(*nchgbds);
3340
3341 nonesmax = 2 * (int)(SCIPvarGetUbLocal(consdata->intvar) + 0.5) + (int) consdata->rhs; /*lint !e713*/
3342 }
3343
3344 assert(nvars - nfixedzeros >= nonesmin);
3345 assert(nfixedones <= nonesmax);
3346
3347 /* the number of variables that are free or fixed to 1 is exactly the minimum required -> fix free variables to 1 */
3348 if( nvars - nfixedzeros == nonesmin )
3349 {
3350 SCIPdebugMsg(scip, "constraint <%s>: fix %d free variables to 1 to reach lower bound of %d\n", SCIPconsGetName(cons), nvars - nfixedzeros - nfixedones, nonesmin);
3351
3352 for( i = 0; i < nvars; ++i )
3353 {
3354 if( SCIPvarGetLbLocal(vars[i]) < 0.5 && SCIPvarGetUbLocal(vars[i]) > 0.5 )
3355 {
3356 SCIP_CALL( SCIPinferBinvarCons(scip, vars[i], TRUE, cons, (int)PROPRULE_INTLB, &infeasible, &tightened) );
3357 assert(!infeasible);
3358 assert(tightened);
3359
3360 ++(*nfixedvars);
3361 }
3362 }
3365
3366 return SCIP_OKAY;
3367 }
3368
3369 /* the number of variables that are fixed to 1 is exactly the maximum required -> fix free variables to 0 */
3370 if( nfixedones == nonesmax )
3371 {
3372 SCIPdebugMsg(scip, "constraint <%s>: fix %d free variables to 0 to guarantee upper bound of %d\n", SCIPconsGetName(cons), nvars - nfixedzeros - nfixedones, nonesmax);
3373
3374 for( i = 0; i < nvars; ++i )
3375 {
3376 if( SCIPvarGetLbLocal(vars[i]) < 0.5 && SCIPvarGetUbLocal(vars[i]) > 0.5 )
3377 {
3378 SCIP_CALL( SCIPinferBinvarCons(scip, vars[i], FALSE, cons, (int)PROPRULE_INTUB, &infeasible, &tightened) );
3379 assert(!infeasible);
3380 assert(tightened);
3381 ++(*nfixedvars);
3382 }
3383 }
3386
3387 return SCIP_OKAY;
3388 }
3389 }
3390 }
3391
3392 /* switch to the new watched variables */
3393 SCIP_CALL( consdataSwitchWatchedvars(scip, consdata, eventhdlr, watchedvar1, watchedvar2) );
3394
3395 /* mark the constraint propagated */
3396 consdata->propagated = TRUE;
3397
3398 return SCIP_OKAY;
3399}
3400
3401/** resolves a conflict on the given variable by supplying the variables needed for applying the corresponding
3402 * propagation rules (see propagateCons())
3403 */
3404static
3406 SCIP* scip, /**< SCIP data structure */
3407 SCIP_CONS* cons, /**< constraint that inferred the bound change */
3408 SCIP_VAR* infervar, /**< variable that was deduced */
3409 PROPRULE proprule, /**< propagation rule that deduced the value */
3410 SCIP_BDCHGIDX* bdchgidx, /**< bound change index (time stamp of bound change), or NULL for current time */
3411 SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
3412 )
3413{
3414 assert(result != NULL);
3415
3416 SCIPdebugMsg(scip, "resolving fixations according to rule %d\n", (int) proprule);
3417
3418 SCIP_CALL( addConflictBounds(scip, cons, infervar, bdchgidx, proprule) );
3419 *result = SCIP_SUCCESS;
3420
3421 return SCIP_OKAY;
3422}
3423
3424/** try to use clique information to delete a part of the xor constraint or even fix variables */
3425static
3427 SCIP* scip, /**< SCIP data structure */
3428 SCIP_CONS* cons, /**< constraint that inferred the bound change */
3429 int* nfixedvars, /**< pointer to add up the number of found domain reductions */
3430 int* naggrvars, /**< pointer to add up the number of aggregated variables */
3431 int* nchgcoefs, /**< pointer to add up the number of deleted entries */
3432 int* ndelconss, /**< pointer to add up the number of deleted constraints */
3433 int* naddconss, /**< pointer to add up the number of added constraints */
3434 SCIP_Bool* cutoff /**< pointer to store TRUE, if the node can be cut off */
3435 )
3436{
3437 SCIP_CONSDATA* consdata;
3438 SCIP_VAR** vars;
3439 int nvars;
3440 SCIP_Bool breaked;
3441 SCIP_Bool restart;
3442 int posnotinclq1;
3443 int posnotinclq2;
3444 int v;
3445 int v1;
3446
3447 assert(scip != NULL);
3448 assert(cons != NULL);
3449 assert(nfixedvars != NULL);
3450 assert(nchgcoefs != NULL);
3451 assert(ndelconss != NULL);
3452 assert(naddconss != NULL);
3453 assert(cutoff != NULL);
3454
3455 /* propagation can only be applied, if we know all operator variables */
3456 if( SCIPconsIsModifiable(cons) )
3457 return SCIP_OKAY;
3458
3459 consdata = SCIPconsGetData(cons);
3460 assert(consdata != NULL);
3461
3462 vars = consdata->vars;
3463 nvars = consdata->nvars;
3464
3465 if( nvars < 3 )
3466 return SCIP_OKAY;
3467
3468 /* we cannot perform this steps if the integer variables in not artificial */
3469 if( !consdata->deleteintvar )
3470 return SCIP_OKAY;
3471
3472#ifdef SCIP_DISABLED_CODE
3473 /* try to evaluate if clique presolving should only be done multiple times when the constraint changed */
3474 if( !consdata->changed )
3475 return SCIP_OKAY;
3476#endif
3477
3478 /* @todo: if clique information would have saved the type of the clique, like <= 1, or == 1 we could do more
3479 * presolving like:
3480 *
3481 * (xor(x1,x2,x3,x4) = 1 and clique(x1,x2) == 1) => xor(x3,x4) = 0
3482 * (xor(x1,x2,x3,x4) = 1 and clique(x1,x2,x3) == 1) => (x4 = 0 and delete xor constraint)
3483 */
3484
3485 /* 1. we have only clique information "<=", so we can check if all variables are in the same clique
3486 *
3487 * (xor(x1,x2,x3) = 1 and clique(x1,x2,x3) <= 1) => (add set-partioning constraint x1 + x2 + x3 = 1 and delete old
3488 * xor-constraint)
3489 *
3490 * (xor(x1,x2,x3) = 0 and clique(x1,x2,x3) <= 1) => (fix all variables x1 = x2 = x3 = 0 and delete old xor-
3491 * constraint)
3492 */
3493
3494 /* 2. we have only clique information "<=", so we can check if all but one variable are in the same clique
3495 *
3496 * (xor(x1,x2,x3,x4) = 1 and clique(x1,x2,x3) <= 1) => (add set-partioning constraint x1 + x2 + x3 + x4 = 1 and
3497 * delete old xor constraint)
3498 *
3499 * (xor(x1,x2,x3,x4) = 0 and clique(x1,x2,x3) <= 1) => (add set-partioning constraint x1 + x2 + x3 + ~x4 = 1 and
3500 * delete old xor constraint)
3501 */
3502
3503 posnotinclq1 = -1; /* index of variable that is possible not in the clique */
3504 posnotinclq2 = -1; /* index of variable that is possible not in the clique */
3505 breaked = FALSE;
3506 restart = FALSE;
3507
3508 v = nvars - 2;
3509 while( v >= 0 )
3510 {
3511 SCIP_VAR* var;
3512 SCIP_VAR* var1;
3513 SCIP_Bool value;
3514 SCIP_Bool value1;
3515
3517
3518 value = SCIPvarIsActive(vars[v]);
3519
3520 if( !value )
3521 var = SCIPvarGetNegationVar(vars[v]);
3522 else
3523 var = vars[v];
3524
3525 if( posnotinclq1 == v )
3526 {
3527 --v;
3528 continue;
3529 }
3530
3531 for( v1 = v+1; v1 < nvars; ++v1 )
3532 {
3533 if( posnotinclq1 == v1 )
3534 continue;
3535
3536 value1 = SCIPvarIsActive(vars[v1]);
3537
3538 if( !value1 )
3539 var1 = SCIPvarGetNegationVar(vars[v1]);
3540 else
3541 var1 = vars[v1];
3542
3543 if( !SCIPvarsHaveCommonClique(var, value, var1, value1, TRUE) )
3544 {
3545 /* if the position of the variable which is not in the clique with all other variables is not yet
3546 * initialized, than do now, one of both variables does not fit
3547 */
3548 if( posnotinclq1 == -1 )
3549 {
3550 posnotinclq1 = v;
3551 posnotinclq2 = v1;
3552 }
3553 else
3554 {
3555 /* no clique with exactly nvars-1 variables */
3556 if( restart || (posnotinclq2 != v && posnotinclq2 != v1) )
3557 {
3558 breaked = TRUE;
3559 break;
3560 }
3561
3562 /* check the second variables for not fitting into the clique of (nvars - 1) variables */
3563 posnotinclq1 = posnotinclq2;
3564 restart = TRUE;
3565 v = nvars - 1;
3566 }
3567
3568 break;
3569 }
3570 else
3571 assert(vars[v] != vars[v1]);
3572 }
3573
3574 if( breaked )
3575 break;
3576
3577 --v;
3578 }
3579
3580 /* at least nvars-1 variables are in one clique */
3581 if( !breaked ) /*lint !e774*/
3582 {
3583 SCIP_Bool replaced = FALSE;
3584
3585 /* if rhs == TRUE, all variables of xor-constraint are in one clique, so create a setpartitioning constraint with
3586 * all variables and delete this xor-constraint
3587 */
3588 if( consdata->rhs )
3589 {
3590 if( SCIPconsGetNUpgradeLocks(cons) == 0 )
3591 {
3592 SCIP_CONS* newcons;
3593 char consname[SCIP_MAXSTRLEN];
3594
3595 (void)SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_complete_clq", SCIPconsGetName(cons));
3596 SCIP_CALL( SCIPcreateConsSetpart(scip, &newcons, consname, nvars, vars,
3601 SCIPdebugMsg(scip, "adding a clique/setppc constraint <%s>\n", SCIPconsGetName(newcons));
3602 SCIPdebug( SCIP_CALL( SCIPprintCons(scip, newcons, NULL) ) );
3603 SCIP_CALL( SCIPaddConsUpgrade(scip, cons, &newcons) );
3604 ++(*naddconss);
3605 replaced = TRUE;
3606 }
3607 }
3608 /* all variables of xor-constraint are in one clique and rhs == FALSE, so fix all variables to 0, case 1 */
3609 else if( posnotinclq1 == -1 )
3610 {
3611 SCIP_Bool infeasible;
3612 SCIP_Bool fixed;
3613
3614 SCIPdebugMsg(scip, "all variables of xor constraints <%s> are in one clique, so fixed all variables to 0\n",
3615 SCIPconsGetName(cons));
3617
3618 for( v = nvars - 1; v >= 0; --v )
3619 {
3620 SCIPdebugMsg(scip, "fixing variable <%s> to 0\n", SCIPvarGetName(vars[v]));
3621 SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) );
3622 assert(infeasible || fixed);
3623
3624 if( infeasible )
3625 {
3626 *cutoff = TRUE;
3627
3628 return SCIP_OKAY;
3629 }
3630 else
3631 ++(*nfixedvars);
3632 }
3633
3634 replaced = TRUE;
3635 }
3636 /* all but one variable are in one clique and rhs == FALSE, so we need to exchange the variable not appearing in
3637 * the clique with the negated variable, case 2
3638 */
3639 else
3640 {
3641 if( SCIPconsGetNUpgradeLocks(cons) == 0 )
3642 {
3643 SCIP_CONS* newcons;
3644 char consname[SCIP_MAXSTRLEN];
3645
3646 (void)SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_completed_clq", SCIPconsGetName(cons));
3647
3648 /* complete clique by creating a set partioning constraint over all variables */
3649 SCIP_CALL( SCIPcreateConsSetpart(scip, &newcons, consname, 0, NULL,
3654
3655 for( v = 0; v < nvars; ++v )
3656 {
3657 if( v == posnotinclq1 )
3658 {
3659 SCIP_VAR* var;
3660
3661 SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &var) );
3662 assert(var != NULL);
3663
3664 SCIP_CALL( SCIPaddCoefSetppc(scip, newcons, var) );
3665 }
3666 else
3667 {
3668 SCIP_CALL( SCIPaddCoefSetppc(scip, newcons, vars[v]) );
3669 }
3670 }
3671
3672 SCIPdebugMsg(scip, "adding a clique/setppc constraint <%s>\n", SCIPconsGetName(newcons));
3673 SCIPdebug( SCIP_CALL( SCIPprintCons(scip, newcons, NULL) ) );
3674 SCIP_CALL( SCIPaddConsUpgrade(scip, cons, &newcons) );
3675 ++(*naddconss);
3676 replaced = TRUE;
3677 }
3678 }
3679
3680 /* remove integer variable if it exists */
3681 if( consdata->intvar != NULL )
3682 {
3683 SCIP_Bool infeasible;
3684 SCIP_Bool fixed;
3685
3686 /* fix integer variable to zero if at most one xor-variable can be one */
3687 if( consdata->rhs || posnotinclq1 == -1 )
3688 {
3689 SCIPdebugMsg(scip, "fix the integer variable <%s> to 0\n", SCIPvarGetName(consdata->intvar));
3690 SCIP_CALL( SCIPfixVar(scip, consdata->intvar, 0.0, &infeasible, &fixed) );
3691 assert(infeasible || fixed);
3692
3693 if( infeasible )
3694 {
3695 *cutoff = TRUE;
3696
3697 return SCIP_OKAY;
3698 }
3699 else
3700 ++(*nfixedvars);
3701 }
3702 /* otherwise aggregate integer variable to xor-variable not in clique */
3703 else
3704 {
3705 SCIP_Bool redundant;
3706
3707 SCIPdebugMsg(scip, "aggregate the integer variable <%s> to <%s>\n", SCIPvarGetName(consdata->intvar), SCIPvarGetName(vars[posnotinclq1]));
3708 SCIP_CALL( SCIPaggregateVars(scip, consdata->intvar, vars[posnotinclq1], 1.0, -1.0, 0.0, &infeasible, &redundant, &fixed) );
3709 assert(infeasible || redundant);
3710
3711 if( infeasible )
3712 {
3713 *cutoff = TRUE;
3714
3715 return SCIP_OKAY;
3716 }
3717 else if( fixed )
3718 ++(*naggrvars);
3719 }
3720 }
3721
3722 /* delete old replaced xor-constraint */
3723 if( replaced )
3724 {
3725 SCIP_CALL( SCIPdelCons(scip, cons) );
3726 ++(*ndelconss);
3727 }
3728 }
3729
3730 return SCIP_OKAY;
3731}
3732
3733/** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
3734 * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
3735 */
3736static
3738 SCIP* scip, /**< SCIP data structure */
3739 BMS_BLKMEM* blkmem, /**< block memory */
3740 SCIP_CONS** conss, /**< constraint set */
3741 int nconss, /**< number of constraints in constraint set */
3742 int* firstchange, /**< pointer to store first changed constraint */
3743 int* nchgcoefs, /**< pointer to add up the number of changed coefficients */
3744 int* nfixedvars, /**< pointer to add up the number of found domain reductions */
3745 int* naggrvars, /**< pointer to add up the number of aggregated variables */
3746 int* ndelconss, /**< pointer to count number of deleted constraints */
3747 int* naddconss, /**< pointer to count number of added constraints */
3748 SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was found */
3749 )
3750{
3751 SCIP_HASHTABLE* hashtable;
3752 int hashtablesize;
3753 int c;
3754
3755 assert(conss != NULL);
3756 assert(ndelconss != NULL);
3757
3758 /* create a hash table for the constraint set */
3759 hashtablesize = nconss;
3760 hashtablesize = MAX(hashtablesize, HASHSIZE_XORCONS);
3761
3762 SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
3763 hashGetKeyXorcons, hashKeyEqXorcons, hashKeyValXorcons, (void*) scip) );
3764
3765 /* check all constraints in the given set for redundancy */
3766 for( c = 0; c < nconss; ++c )
3767 {
3768 SCIP_CONS* cons0;
3769 SCIP_CONS* cons1;
3770 SCIP_CONSDATA* consdata0;
3771 SCIP_CONSHDLR* conshdlr;
3772 SCIP_CONSHDLRDATA* conshdlrdata;
3773
3774 cons0 = conss[c];
3775
3776 if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
3777 continue;
3778
3779 /* get constraint handler data */
3780 conshdlr = SCIPconsGetHdlr(cons0);
3781 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3782 assert(conshdlrdata != NULL);
3783
3784 /* it can happen that during preprocessing some variables got aggregated and a constraint now has not active
3785 * variables inside so we need to remove them for sorting
3786 */
3787 /* remove all variables that are fixed to zero and all pairs of variables fixed to one;
3788 * merge multiple entries of the same or negated variables
3789 */
3790 SCIP_CALL( applyFixings(scip, cons0, conshdlrdata->eventhdlr, nchgcoefs, naggrvars, naddconss, cutoff) );
3791 if( *cutoff )
3792 goto TERMINATE;
3793
3794 consdata0 = SCIPconsGetData(cons0);
3795
3796 assert(consdata0 != NULL);
3797
3798 /* applyFixings() led to an empty or trivial constraint */
3799 if( consdata0->nvars <= 1 )
3800 {
3801 if( consdata0->nvars == 0 )
3802 {
3803 /* the constraints activity cannot match an odd right hand side */
3804 if( consdata0->rhs )
3805 {
3806 *cutoff = TRUE;
3807 break;
3808 }
3809 }
3810 else
3811 {
3812 /* exactly 1 variable left. */
3813 SCIP_Bool infeasible;
3814 SCIP_Bool fixed;
3815
3816 /* fix remaining variable */
3817 SCIP_CALL( SCIPfixVar(scip, consdata0->vars[0], (SCIP_Real) consdata0->rhs, &infeasible, &fixed) );
3818 assert(!infeasible);
3819
3820 if( fixed )
3821 ++(*nfixedvars);
3822 }
3823
3824 /* fix integral variable if present */
3825 if( consdata0->intvar != NULL )
3826 {
3827 SCIP_Bool infeasible;
3828 SCIP_Bool fixed;
3829
3830 SCIP_CALL( SCIPfixVar(scip, consdata0->intvar, 0.0, &infeasible, &fixed) );
3831 assert(!infeasible);
3832
3833 if( fixed )
3834 ++(*nfixedvars);
3835 }
3836
3837 /* delete empty constraint */
3838 SCIP_CALL( SCIPdelCons(scip, cons0) );
3839 ++(*ndelconss);
3840
3841 continue;
3842 }
3843
3844 /* sort the constraint */
3845 consdataSort(consdata0);
3846 assert(consdata0->sorted);
3847
3848 /* get constraint from current hash table with same variables as cons0 */
3849 cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
3850
3851 if( cons1 != NULL )
3852 {
3853 SCIP_CONSDATA* consdata1;
3854
3855 assert(SCIPconsIsActive(cons1));
3856 assert(!SCIPconsIsModifiable(cons1));
3857
3858 consdata1 = SCIPconsGetData(cons1);
3859
3860 assert(consdata1 != NULL);
3861 assert(consdata0->nvars >= 1 && consdata0->nvars == consdata1->nvars);
3862
3863 assert(consdata0->sorted && consdata1->sorted);
3864 assert(consdata0->vars[0] == consdata1->vars[0]);
3865
3866 if( consdata0->rhs != consdata1->rhs )
3867 {
3868 *cutoff = TRUE;
3869 goto TERMINATE;
3870 }
3871
3872 /* aggregate parity variables into each other */
3873 if( consdata0->intvar != consdata1->intvar && consdata0->intvar != NULL )
3874 {
3875 if( consdata1->intvar != NULL )
3876 {
3877 SCIP_Bool redundant;
3878 SCIP_Bool aggregated;
3879 SCIP_Bool infeasible;
3880
3881 SCIP_CALL( SCIPaggregateVars(scip, consdata0->intvar, consdata1->intvar, 1.0, -1.0, 0.0, &infeasible, &redundant, &aggregated) );
3882
3883 if( aggregated )
3884 {
3885 ++(*naggrvars);
3886 }
3887 if( infeasible )
3888 {
3889 *cutoff = TRUE;
3890 goto TERMINATE;
3891 }
3892 }
3893 /* the special case that only cons0 has a parity variable 'intvar' is treated by swapping cons0 and cons1 */
3894 else
3895 {
3896 SCIP_CALL( SCIPhashtableInsert(hashtable, (void *)cons0) );
3897 assert(SCIPhashtableRetrieve(hashtable, (void *)cons1) == cons0);
3898
3899 SCIPswapPointers((void**)&cons0, (void**)(&cons1));
3900 SCIPswapPointers((void**)&consdata0, (void**)(&consdata1));
3901 }
3902 }
3903
3904 /* delete cons0 and update flags of cons1 s.t. nonredundant information doesn't get lost */
3905 /* coverity[swapped_arguments] */
3906 SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
3907 SCIP_CALL( SCIPdelCons(scip, cons0) );
3908 (*ndelconss)++;
3909
3910 /* update the first changed constraint to begin the next aggregation round with */
3911 if( consdata0->changed && SCIPconsGetPos(cons1) < *firstchange )
3912 *firstchange = SCIPconsGetPos(cons1);
3913
3914 assert(SCIPconsIsActive(cons1));
3915 }
3916 else
3917 {
3918 /* no such constraint in current hash table: insert cons0 into hash table */
3919 SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
3920 }
3921 }
3922
3923 TERMINATE:
3924 /* free hash table */
3925 SCIPhashtableFree(&hashtable);
3926
3927 return SCIP_OKAY;
3928}
3929
3930/** compares constraint with all prior constraints for possible redundancy or aggregation,
3931 * and removes or changes constraint accordingly
3932 */
3933static
3935 SCIP* scip, /**< SCIP data structure */
3936 SCIP_CONS** conss, /**< constraint set */
3937 int firstchange, /**< first constraint that changed since last pair preprocessing round */
3938 int chkind, /**< index of constraint to check against all prior indices upto startind */
3939 SCIP_Bool* cutoff, /**< pointer to store TRUE, if a cutoff was found */
3940 int* nfixedvars, /**< pointer to add up the number of found domain reductions */
3941 int* naggrvars, /**< pointer to count number of aggregated variables */
3942 int* ndelconss, /**< pointer to count number of deleted constraints */
3943 int* naddconss, /**< pointer to count number of added constraints */
3944 int* nchgcoefs /**< pointer to add up the number of changed coefficients */
3945 )
3946{
3947 SCIP_CONSHDLR* conshdlr;
3948 SCIP_CONSHDLRDATA* conshdlrdata;
3949 SCIP_CONS* cons0;
3950 SCIP_CONSDATA* consdata0;
3951 SCIP_Bool cons0changed;
3952 int c;
3953
3954 assert(conss != NULL);
3955 assert(firstchange <= chkind);
3956 assert(cutoff != NULL);
3957 assert(nfixedvars != NULL);
3958 assert(naggrvars != NULL);
3959 assert(ndelconss != NULL);
3960 assert(nchgcoefs != NULL);
3961
3962 /* get the constraint to be checked against all prior constraints */
3963 cons0 = conss[chkind];
3964 assert(SCIPconsIsActive(cons0));
3965 assert(!SCIPconsIsModifiable(cons0));
3966
3967 consdata0 = SCIPconsGetData(cons0);
3968 assert(consdata0 != NULL);
3969 assert(consdata0->nvars >= 1);
3970
3971 /* get constraint handler data */
3972 conshdlr = SCIPconsGetHdlr(cons0);
3973 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3974 assert(conshdlrdata != NULL);
3975
3976 /* it can happen that during preprocessing some variables got aggregated and a constraint now has not active
3977 * variables inside so we need to remove them for sorting
3978 */
3979 /* remove all variables that are fixed to zero and all pairs of variables fixed to one;
3980 * merge multiple entries of the same or negated variables
3981 */
3982 SCIP_CALL( applyFixings(scip, cons0, conshdlrdata->eventhdlr, nchgcoefs, naggrvars, naddconss, cutoff) );
3983 if( *cutoff )
3984 return SCIP_OKAY;
3985
3986 /* sort cons0 */
3987 consdataSort(consdata0);
3988 assert(consdata0->sorted);
3989
3990 /* check constraint against all prior constraints */
3991 cons0changed = consdata0->changed;
3992 consdata0->changed = FALSE;
3993 for( c = (cons0changed ? 0 : firstchange); c < chkind && !(*cutoff) && SCIPconsIsActive(cons0) && !SCIPisStopped(scip); ++c )
3994 {
3995 SCIP_CONS* cons1;
3996 SCIP_CONSDATA* consdata1;
3997 SCIP_VAR* singlevar0;
3998 SCIP_VAR* singlevar1;
3999 SCIP_Bool parity;
4000 SCIP_Bool cons0hastwoothervars;
4001 SCIP_Bool cons1hastwoothervars;
4002 SCIP_Bool aborted;
4003 SCIP_Bool infeasible;
4004 SCIP_Bool fixed;
4005 SCIP_Bool redundant;
4006 SCIP_Bool aggregated;
4007 int v0;
4008 int v1;
4009
4010 cons1 = conss[c];
4011
4012 /* ignore inactive and modifiable constraints */
4013 if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
4014 continue;
4015
4016 consdata1 = SCIPconsGetData(cons1);
4017 assert(consdata1 != NULL);
4018
4019 if( !consdata1->deleteintvar )
4020 continue;
4021
4022 /* it can happen that during preprocessing some variables got aggregated and a constraint now has not active
4023 * variables inside so we need to remove them for sorting
4024 */
4025 /* remove all variables that are fixed to zero and all pairs of variables fixed to one;
4026 * merge multiple entries of the same or negated variables
4027 */
4028 SCIP_CALL( applyFixings(scip, cons1, conshdlrdata->eventhdlr, nchgcoefs, naggrvars, naddconss, cutoff) );
4029 assert(consdata1 == SCIPconsGetData(cons1));
4030 if( *cutoff )
4031 return SCIP_OKAY;
4032
4033 SCIPdebugMsg(scip, "preprocess xor constraint pair <%s>[chg:%u] and <%s>[chg:%u]\n",
4034 SCIPconsGetName(cons0), cons0changed, SCIPconsGetName(cons1), consdata1->changed);
4035
4036 /* if both constraints were not changed since last round, we can ignore the pair */
4037 if( !cons0changed && !consdata1->changed )
4038 continue;
4039
4040 /* applyFixings() led to an empty constraint */
4041 if( consdata1->nvars == 0 )
4042 {
4043 if( consdata1->rhs )
4044 {
4045 *cutoff = TRUE;
4046 break;
4047 }
4048 else
4049 {
4050 /* fix integral variable if present */
4051 if( consdata1->intvar != NULL )
4052 {
4053 SCIP_CALL( SCIPfixVar(scip, consdata1->intvar, 0.0, &infeasible, &fixed) );
4054 assert(!infeasible);
4055 if( fixed )
4056 ++(*nfixedvars);
4057 }
4058
4059 /* delete empty constraint */
4060 SCIP_CALL( SCIPdelCons(scip, cons1) );
4061 ++(*ndelconss);
4062
4063 continue;
4064 }
4065 }
4066 else if( consdata1->nvars == 1 )
4067 {
4068 /* fix remaining variable */
4069 SCIP_CALL( SCIPfixVar(scip, consdata1->vars[0], (SCIP_Real) consdata1->rhs, &infeasible, &fixed) );
4070 assert(!infeasible);
4071
4072 if( fixed )
4073 ++(*nfixedvars);
4074
4075 /* fix integral variable if present */
4076 if( consdata1->intvar != NULL )
4077 {
4078 SCIP_CALL( SCIPfixVar(scip, consdata1->intvar, 0.0, &infeasible, &fixed) );
4079 assert(!infeasible);
4080 if( fixed )
4081 ++(*nfixedvars);
4082 }
4083
4084 SCIP_CALL( SCIPdelCons(scip, cons1) );
4085 ++(*ndelconss);
4086
4087 /* check for fixed variable in cons0 and remove it */
4088 SCIP_CALL( applyFixings(scip, cons0, conshdlrdata->eventhdlr, nchgcoefs, naggrvars, naddconss, cutoff) );
4089 assert(!(*cutoff));
4090
4091 /* sort cons0 */
4092 consdataSort(consdata0);
4093 assert(consdata0->sorted);
4094
4095 continue;
4096 }
4097 else if( consdata1->nvars == 2 )
4098 {
4099 if( !(consdata1->rhs) )
4100 {
4101 /* aggregate var0 == var1 */
4102 SCIP_CALL( SCIPaggregateVars(scip, consdata1->vars[0], consdata1->vars[1], 1.0, -1.0, 0.0,
4103 &infeasible, &redundant, &aggregated) );
4104 }
4105 else
4106 {
4107 /* aggregate var0 == 1 - var1 */
4108 SCIP_CALL( SCIPaggregateVars(scip, consdata1->vars[0], consdata1->vars[1], 1.0, 1.0, 1.0,
4109 &infeasible, &redundant, &aggregated) );
4110 }
4111 assert(!infeasible);
4112 assert(redundant || SCIPdoNotAggr(scip));
4113
4114 if( aggregated )
4115 {
4116 ++(*naggrvars);
4117
4118 /* check for aggregated variable in cons0 and remove it */
4119 SCIP_CALL( applyFixings(scip, cons0, conshdlrdata->eventhdlr, nchgcoefs, naggrvars, naddconss, cutoff) );
4120 if( *cutoff )
4121 return SCIP_OKAY;
4122
4123 /* sort cons0 */
4124 consdataSort(consdata0);
4125 assert(consdata0->sorted);
4126 }
4127
4128 if( redundant )
4129 {
4130 /* fix or aggregate the intvar, if it exists */
4131 if( consdata1->intvar != NULL )
4132 {
4133 /* we have var0 + var1 - 2 * intvar = 1, and aggregated var1 = 1 - var0,
4134 * thus, intvar is always 0 */
4135 if( consdata1->rhs )
4136 {
4137 SCIP_CALL( SCIPfixVar(scip, consdata1->intvar, 0.0, &infeasible, &fixed) );
4138 assert(!infeasible);
4139 if( fixed )
4140 ++(*nfixedvars);
4141 }
4142 /* we have var0 + var1 - 2 * intvar = 0, and aggregated var1 = var0,
4143 * i.e., 2 * var0 - 2 * intvar = 0, so intvar = var0 holds and we aggregate */
4144 else
4145 {
4146 assert(!consdata1->rhs);
4147
4148 /* aggregate intvar == var0 */
4149 SCIP_CALL( SCIPaggregateVars(scip, consdata1->vars[0], consdata1->intvar, 1.0, -1.0, 0.0,
4150 &infeasible, &redundant, &aggregated) );
4151 assert(!infeasible);
4152 assert(redundant || SCIPdoNotAggr(scip));
4153
4154 if( aggregated )
4155 {
4156 ++(*naggrvars);
4157 }
4158 }
4159 }
4160
4161 if( redundant )
4162 {
4163 SCIP_CALL( SCIPdelCons(scip, cons1) );
4164 ++(*ndelconss);
4165 }
4166 }
4167
4168 continue;
4169 }
4170 assert(consdata0->sorted);
4171
4172 /* sort cons1 */
4173 consdataSort(consdata1);
4174 assert(consdata1->sorted);
4175
4176 /* check whether
4177 * (a) one problem variable set is a subset of the other, or
4178 * (b) the problem variable sets are almost equal with only one variable in each constraint that is not
4179 * member of the other
4180 */
4181 aborted = FALSE;
4182 parity = (consdata0->rhs ^ consdata1->rhs);
4183 cons0hastwoothervars = FALSE;
4184 cons1hastwoothervars = FALSE;
4185 singlevar0 = NULL;
4186 singlevar1 = NULL;
4187 v0 = 0;
4188 v1 = 0;
4189 while( (v0 < consdata0->nvars || v1 < consdata1->nvars) && !aborted )
4190 {
4191 int cmp;
4192
4193 assert(v0 <= consdata0->nvars);
4194 assert(v1 <= consdata1->nvars);
4195
4196 if( v0 == consdata0->nvars )
4197 cmp = +1;
4198 else if( v1 == consdata1->nvars )
4199 cmp = -1;
4200 else
4201 cmp = SCIPvarCompareActiveAndNegated(consdata0->vars[v0], consdata1->vars[v1]);
4202
4203 switch( cmp )
4204 {
4205 case -1:
4206 /* variable doesn't appear in cons1 */
4207 assert(v0 < consdata0->nvars);
4208 if( singlevar0 == NULL )
4209 {
4210 singlevar0 = consdata0->vars[v0];
4211 if( cons1hastwoothervars )
4212 aborted = TRUE;
4213 }
4214 else
4215 {
4216 cons0hastwoothervars = TRUE;
4217 if( singlevar1 != NULL )
4218 aborted = TRUE;
4219 }
4220 v0++;
4221 break;
4222
4223 case +1:
4224 /* variable doesn't appear in cons0 */
4225 assert(v1 < consdata1->nvars);
4226 if( singlevar1 == NULL )
4227 {
4228 singlevar1 = consdata1->vars[v1];
4229 if( cons0hastwoothervars )
4230 aborted = TRUE;
4231 }
4232 else
4233 {
4234 cons1hastwoothervars = TRUE;
4235 if( singlevar0 != NULL )
4236 aborted = TRUE;
4237 }
4238 v1++;
4239 break;
4240
4241 case 0:
4242 /* variable appears in both constraints */
4243 assert(v0 < consdata0->nvars);
4244 assert(v1 < consdata1->nvars);
4245 assert(SCIPvarGetProbvar(consdata0->vars[v0]) == SCIPvarGetProbvar(consdata1->vars[v1]));
4246 if( consdata0->vars[v0] != consdata1->vars[v1] )
4247 {
4248 assert(SCIPvarGetNegatedVar(consdata0->vars[v0]) == consdata1->vars[v1]);
4249 parity = !parity;
4250 }
4251 v0++;
4252 v1++;
4253 break;
4254
4255 default:
4256 SCIPerrorMessage("invalid comparison result\n");
4257 SCIPABORT();
4258 return SCIP_INVALIDDATA; /*lint !e527*/
4259 }
4260 }
4261
4262 /* check if a useful presolving is possible */
4263 if( (cons0hastwoothervars && singlevar1 != NULL) || (cons1hastwoothervars && singlevar0 != NULL) )
4264 continue;
4265
4266 /* check if one problem variable set is a subset of the other */
4267 if( singlevar0 == NULL && singlevar1 == NULL )
4268 {
4269 /* both constraints are equal */
4270 if( !parity )
4271 {
4272 /* even parity: constraints are redundant */
4273 SCIPdebugMsg(scip, "xor constraints <%s> and <%s> are redundant: delete <%s>\n",
4274 SCIPconsGetName(cons0), SCIPconsGetName(cons1), SCIPconsGetName(cons1));
4275 SCIPdebugPrintCons(scip, cons0, NULL);
4276 SCIPdebugPrintCons(scip, cons1, NULL);
4277
4278 /* delete cons1 and update flags of cons0 s.t. nonredundant information doesn't get lost */
4279 SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
4280 SCIP_CALL( SCIPdelCons(scip, cons1) );
4281 (*ndelconss)++;
4282
4283 if( consdata1->intvar != NULL )
4284 {
4285 /* need to update integer variable, consider the following case:
4286 * c1: xor(x1, x2, x3) = 1 (intvar1 = y1)
4287 * c2: xor(x1, x2, x3) = 1 (intvar0 = NULL or intvar0 = y0)
4288 *
4289 * if intvar0 = NULL we have to assign intvar0 = y1. otherwise, we have to ensure that y1 = y0 holds.
4290 * if aggregation is allowed, we can aggregate both variables. otherwise, we have to add a linear
4291 * constraint y1 - y0 = 0.
4292 */
4293 if( consdata0->intvar == NULL )
4294 {
4295 SCIP_CALL( setIntvar(scip, cons0, consdata1->intvar) );
4296 }
4297 else
4298 {
4299 /* aggregate integer variables */
4300 SCIP_CALL( SCIPaggregateVars(scip, consdata1->intvar, consdata0->intvar, 1.0, -1.0, 0.0,
4301 &infeasible, &redundant, &aggregated) );
4302
4303 *cutoff = *cutoff || infeasible;
4304
4305 if( aggregated )
4306 {
4307 ++(*naggrvars);
4308 assert(SCIPvarIsActive(consdata0->intvar));
4309 }
4310 else
4311 {
4312 SCIP_CONS* newcons;
4313 char consname[SCIP_MAXSTRLEN];
4314 SCIP_VAR* newvars[2];
4315 SCIP_Real vals[2];
4316
4317 newvars[0] = consdata1->intvar;
4318 vals[0] = 1.0;
4319 newvars[1] = consdata0->intvar;
4320 vals[1] = -1.0;
4321
4322 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "agg_%s", SCIPconsGetName(cons1));
4323
4324 SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, consname, 2, newvars, vals, 0.0, 0.0,
4325 SCIPconsIsInitial(cons1), SCIPconsIsSeparated(cons1), TRUE, /*SCIPconsIsEnforced(cons),*/
4326 TRUE, TRUE, /*SCIPconsIsChecked(cons), SCIPconsIsPropagated(cons),*/
4329
4330 SCIP_CALL( SCIPaddCons(scip, newcons) );
4331 SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
4332 ++(*naddconss);
4333 }
4334 }
4335 }
4336 }
4337 else
4338 {
4339 /* odd parity: constraints are contradicting */
4340 SCIPdebugMsg(scip, "xor constraints <%s> and <%s> are contradicting\n",
4341 SCIPconsGetName(cons0), SCIPconsGetName(cons1));
4342 SCIPdebugPrintCons(scip, cons0, NULL);
4343 SCIPdebugPrintCons(scip, cons1, NULL);
4344 *cutoff = TRUE;
4345 }
4346 }
4347 else if( singlevar1 == NULL )
4348 {
4349 /* cons1 is a subset of cons0 */
4350 if( !cons0hastwoothervars )
4351 {
4352 /* only one additional variable in cons0: fix this variable according to the parity */
4353 SCIPdebugMsg(scip, "xor constraints <%s> and <%s> yield sum %u == <%s>\n",
4354 SCIPconsGetName(cons0), SCIPconsGetName(cons1), parity, SCIPvarGetName(singlevar0));
4355 SCIPdebugPrintCons(scip, cons0, NULL);
4356 SCIPdebugPrintCons(scip, cons1, NULL);
4357 SCIP_CALL( SCIPfixVar(scip, singlevar0, parity ? 1.0 : 0.0, &infeasible, &fixed) );
4358 *cutoff = *cutoff || infeasible;
4359 if( fixed )
4360 (*nfixedvars)++;
4361
4362 /* delete cons1 and update flags of cons0 s.t. nonredundant information doesn't get lost */
4363 SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
4364 SCIP_CALL( SCIPdelCons(scip, cons1) );
4365 (*ndelconss)++;
4366 }
4367 else
4368 {
4369 int v;
4370
4371 /* more than one additional variable in cons0: add cons1 to cons0, thus eliminating the equal variables */
4372 SCIPdebugMsg(scip, "xor constraint <%s> is superset of <%s> with parity %u\n",
4373 SCIPconsGetName(cons0), SCIPconsGetName(cons1), parity);
4374 SCIPdebugPrintCons(scip, cons0, NULL);
4375 SCIPdebugPrintCons(scip, cons1, NULL);
4376 for( v = 0; v < consdata1->nvars; ++v )
4377 {
4378 SCIP_CALL( addCoef(scip, cons0, consdata1->vars[v]) );
4379 }
4380
4381 SCIP_CALL( applyFixings(scip, cons0, conshdlrdata->eventhdlr, nchgcoefs, naggrvars, naddconss, cutoff) );
4382 assert(SCIPconsGetData(cons0) == consdata0);
4383 assert(consdata0->nvars >= 2); /* at least the two "other" variables should remain in the constraint */
4384 }
4385
4386 if( *cutoff )
4387 return SCIP_OKAY;
4388
4389 consdataSort(consdata0);
4390 assert(consdata0->sorted);
4391 }
4392 else if( singlevar0 == NULL )
4393 {
4394 /* cons0 is a subset of cons1 */
4395 if( !cons1hastwoothervars )
4396 {
4397 /* only one additional variable in cons1: fix this variable according to the parity */
4398 SCIPdebugMsg(scip, "xor constraints <%s> and <%s> yield sum %u == <%s>\n",
4399 SCIPconsGetName(cons0), SCIPconsGetName(cons1), parity, SCIPvarGetName(singlevar1));
4400 SCIPdebugPrintCons(scip, cons0, NULL);
4401 SCIPdebugPrintCons(scip, cons1, NULL);
4402 SCIP_CALL( SCIPfixVar(scip, singlevar1, parity ? 1.0 : 0.0, &infeasible, &fixed) );
4403 assert(infeasible || fixed);
4404 *cutoff = *cutoff || infeasible;
4405 (*nfixedvars)++;
4406
4407 /* delete cons1 and update flags of cons0 s.t. nonredundant information doesn't get lost */
4408 SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
4409 SCIP_CALL( SCIPdelCons(scip, cons1) );
4410 (*ndelconss)++;
4411 }
4412 else
4413 {
4414 int v;
4415
4416 /* more than one additional variable in cons1: add cons0 to cons1, thus eliminating the equal variables */
4417 SCIPdebugMsg(scip, "xor constraint <%s> is subset of <%s> with parity %u\n",
4418 SCIPconsGetName(cons0), SCIPconsGetName(cons1), parity);
4419 SCIPdebugPrintCons(scip, cons0, NULL);
4420 SCIPdebugPrintCons(scip, cons1, NULL);
4421 for( v = 0; v < consdata0->nvars; ++v )
4422 {
4423 SCIP_CALL( addCoef(scip, cons1, consdata0->vars[v]) );
4424 }
4425 SCIP_CALL( applyFixings(scip, cons1, conshdlrdata->eventhdlr, nchgcoefs, naggrvars, naddconss, cutoff) );
4426 assert(SCIPconsGetData(cons1) == consdata1);
4427 assert(consdata1->nvars >= 2); /* at least the two "other" variables should remain in the constraint */
4428
4429 if( *cutoff )
4430 return SCIP_OKAY;
4431
4432 consdataSort(consdata1);
4433 assert(consdata1->sorted);
4434 }
4435 }
4436 else
4437 {
4438 assert(!cons0hastwoothervars);
4439 assert(!cons1hastwoothervars);
4440
4441 /* sum of constraints is parity == singlevar0 xor singlevar1: aggregate variables and delete cons1 */
4442 SCIPdebugMsg(scip, "xor constraints <%s> and <%s> yield sum %u == xor(<%s>,<%s>)\n",
4443 SCIPconsGetName(cons0), SCIPconsGetName(cons1), parity, SCIPvarGetName(singlevar0),
4444 SCIPvarGetName(singlevar1));
4445 if( !parity )
4446 {
4447 /* aggregate singlevar0 == singlevar1 */
4448 SCIP_CALL( SCIPaggregateVars(scip, singlevar1, singlevar0, 1.0, -1.0, 0.0,
4449 &infeasible, &redundant, &aggregated) );
4450 }
4451 else
4452 {
4453 /* aggregate singlevar0 == 1-singlevar1 */
4454 SCIP_CALL( SCIPaggregateVars(scip, singlevar1, singlevar0, 1.0, 1.0, 1.0,
4455 &infeasible, &redundant, &aggregated) );
4456 }
4457 assert(infeasible || redundant || SCIPdoNotAggr(scip));
4458
4459 *cutoff = *cutoff || infeasible;
4460 if( aggregated )
4461 ++(*naggrvars);
4462
4463 if( redundant )
4464 {
4465 /* delete cons1 and update flags of cons0 s.t. nonredundant information doesn't get lost */
4466 SCIP_CALL( SCIPupdateConsFlags(scip, cons0, cons1) );
4467 SCIP_CALL( SCIPdelCons(scip, cons1) );
4468 (*ndelconss)++;
4469
4470 if( consdata1->intvar != NULL )
4471 {
4472 if( consdata0->intvar == NULL )
4473 {
4474 SCIP_CALL( setIntvar(scip, cons0, consdata0->intvar) );
4475 }
4476 else
4477 {
4478 /* aggregate integer variables */
4479 SCIP_CALL( SCIPaggregateVars(scip, consdata1->intvar, consdata0->intvar, 1.0, -1.0, 0.0,
4480 &infeasible, &redundant, &aggregated) );
4481
4482 *cutoff = *cutoff || infeasible;
4483 if( aggregated )
4484 ++(*naggrvars);
4485 }
4486 }
4487 }
4488
4489 if( !consdata0->sorted )
4490 consdataSort(consdata0);
4491 assert(consdata0->sorted);
4492
4493#ifdef SCIP_DISABLED_CODE
4494 /* TODO: consider running applyFixings() on the persistent constraint to detect a cutoff */
4495 /* remove all variables that are fixed to zero and all pairs of variables fixed to one;
4496 * merge multiple entries of the same or negated variables
4497 */
4498 SCIP_CALL( applyFixings(scip, cons0, conshdlrdata->eventhdlr, nchgcoefs, naggrvars, naddconss, cutoff) );
4499
4500 if( *cutoff )
4501 return SCIP_OKAY;
4502#endif
4503 }
4504 }
4505
4506 return SCIP_OKAY;
4507}
4508
4509/** creates and captures a xor constraint x_0 xor ... xor x_{k-1} = rhs with a given artificial integer variable for the
4510 * linear relaxation
4511 *
4512 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
4513 */
4514static
4516 SCIP* scip, /**< SCIP data structure */
4517 SCIP_CONS** cons, /**< pointer to hold the created constraint */
4518 const char* name, /**< name of constraint */
4519 SCIP_Bool rhs, /**< right hand side of the constraint */
4520 int nvars, /**< number of operator variables in the constraint */
4521 SCIP_VAR** vars, /**< array with operator variables of constraint */
4522 SCIP_VAR* intvar, /**< integer variable for linear relaxation or NULL if artificial */
4523 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
4524 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
4525 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
4526 * Usually set to TRUE. */
4527 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
4528 * TRUE for model constraints, FALSE for additional, redundant constraints. */
4529 SCIP_Bool check, /**< should the constraint be checked for feasibility?
4530 * TRUE for model constraints, FALSE for additional, redundant constraints. */
4531 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
4532 * Usually set to TRUE. */
4533 SCIP_Bool local, /**< is constraint only valid locally?
4534 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
4535 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
4536 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
4537 * adds coefficients to this constraint. */
4538 SCIP_Bool dynamic, /**< is constraint subject to aging?
4539 * Usually set to FALSE. Set to TRUE for own cuts which
4540 * are separated as constraints. */
4541 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
4542 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
4543 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
4544 * if it may be moved to a more global node?
4545 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
4546 )
4547{
4548 SCIP_CONSHDLR* conshdlr;
4549 SCIP_CONSDATA* consdata;
4550 SCIP_VARTYPE intvartype;
4551 int i;
4552
4553 /* find the xor constraint handler */
4554 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
4555 if( conshdlr == NULL )
4556 {
4557 SCIPerrorMessage("xor constraint handler not found\n");
4558 return SCIP_PLUGINNOTFOUND;
4559 }
4560
4561 /* check whether int variable is integral */
4562 if( intvar != NULL )
4563 {
4564 intvartype = SCIPvarGetType(intvar);
4565
4566 if( intvartype != SCIP_VARTYPE_BINARY && intvartype != SCIP_VARTYPE_INTEGER )
4567 {
4568 SCIPerrorMessage("intvar <%s> is not enforced integral\n", SCIPvarGetName(intvar));
4569 return SCIP_INVALIDDATA;
4570 }
4571 }
4572
4573 /* check whether all variables are binary */
4574 assert(vars != NULL || nvars == 0);
4575 for( i = 0; i < nvars; ++i )
4576 {
4577 if( !SCIPvarIsBinary(vars[i]) )
4578 {
4579 SCIPerrorMessage("operand <%s> is not binary\n", SCIPvarGetName(vars[i]));
4580 return SCIP_INVALIDDATA;
4581 }
4582 }
4583
4584 /* create constraint data */
4585 SCIP_CALL( consdataCreate(scip, &consdata, rhs, nvars, vars, intvar) );
4586
4587 /* create constraint */
4588 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
4589 local, modifiable, dynamic, removable, stickingatnode) );
4590
4591 return SCIP_OKAY;
4592}
4593
4594
4595
4596/*
4597 * Linear constraint upgrading
4598 */
4599
4600/** tries to upgrade a linear constraint into an xor constraint
4601 *
4602 * Assuming all variables are binary and have coefficients with an absolute value 1, except for an integer (or binary) variable
4603 * \f$z\f$ which has coefficient \f$a \in \{-2,2\}\f$ with absolute value 2 and appears only in this constraint,
4604 * we can transform:
4605 * \f[
4606 * \begin{array}{ll}
4607 * & -\sum_{i \in I} x_i + \sum_{j \in J} x_j + a \cdot z = r \\
4608 * \Leftrightarrow & \sum_{i \in I} \bar{x}_i + \sum_{j \in J} x_j + a \cdot z = r + |I| \\
4609 * \Leftrightarrow & \sum_{i \in I} \bar{x}_i + \sum_{j \in J} x_j - 2 \cdot y = (r + |I|) \text{ mod } 2,
4610 * \end{array}
4611 * \f]
4612 * where
4613 * \f[
4614 * y = \begin{cases}
4615 * \left\lfloor \frac{r + |I|}{2} \right\rfloor + z & \text{if }a = -2\\
4616 * \left\lfloor \frac{r + |I|}{2} \right\rfloor - z & \text{if }a = 2.
4617 * \end{cases}
4618 * \f]
4619 * 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
4620 * \frac{r + |I|}{2} \right\rfloor + \ell_z\f$ and \f$u_y = \left\lfloor \frac{r + |I|}{2} \right\rfloor + u_z\f$.
4621 *
4622 * 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
4623 * \frac{r + |I|}{2} \right\rfloor - \ell_z\f$.
4624 *
4625 * Then consider the resulting XOR-constraint
4626 * \f[
4627 * \bigoplus_{i \in I} \bar{x}_i \oplus \bigoplus_{j \in j} x_j = (r + |I|) \text{ mod } 2.
4628 * \f]
4629 * 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
4630 * transformed constraint, otherwise it is a relaxation because the bounds on the \f$y\f$-variable may disallow
4631 * too many (or too few) operators set to 1. Therefore, the XOR constraint handler verifies in this case that the linear
4632 * equation holds, ie., that the \f$y\f$-variable has the correct value.
4633 */
4634static
4636{ /*lint --e{715}*/
4637 assert(upgdcons != NULL);
4638 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), "linear") == 0);
4639 assert(!SCIPconsIsModifiable(cons));
4640
4641 /* check, if linear constraint can be upgraded to xor constraint */
4642 /* @todo also applicable if the integer variable has a coefficient different from 2, e.g. a coefficient like 0.5 then
4643 * we could generate a new integer variable aggregated to the old one, possibly the constraint was then
4644 * normalized and all binary variables have coefficients of 2.0, if the coefficient is 4 then we need holes ...
4645 */
4646 if( integral && nposcont + nnegcont == 0 && nposbin + nnegbin + nposimplbin + nnegimplbin >= nvars-1 && ncoeffspone + ncoeffsnone == nvars-1 && ncoeffspint + ncoeffsnint == 1 )
4647 {
4648 assert(ncoeffspfrac + ncoeffsnfrac == 0);
4649
4650 if( SCIPisEQ(scip, lhs, rhs) && SCIPisIntegral(scip, lhs) )
4651 {
4652 SCIP_VAR** xorvars;
4653 SCIP_VAR* parityvar = NULL;
4654 SCIP_VARTYPE parityvartype;
4655 SCIP_Bool postwo = FALSE;
4656 int cnt = 0;
4657 int j;
4658
4659 SCIP_CALL( SCIPallocBufferArray(scip, &xorvars, nvars) );
4660
4661 /* check parity of constraints */
4662 for( j = nvars - 1; j >= 0; --j )
4663 {
4664 if( SCIPisEQ(scip, REALABS(vals[j]), 2.0) )
4665 {
4666 parityvar = vars[j];
4667 parityvartype = SCIPvarGetType(parityvar);
4668
4669 /* parity variable requires enforced integrality */
4670 if( parityvartype != SCIP_VARTYPE_BINARY && parityvartype != SCIP_VARTYPE_INTEGER )
4671 {
4672 parityvar = NULL;
4673 break;
4674 }
4675
4676 postwo = (vals[j] > 0.0);
4677 }
4678 else if( !SCIPisEQ(scip, REALABS(vals[j]), 1.0) )
4679 break;
4680 else
4681 {
4682 /* exit if variable is not binary or implicit binary */
4683 if( !SCIPvarIsBinary(vars[j]) )
4684 {
4685 parityvar = NULL;
4686 break;
4687 }
4688
4689 /* need negated variables for correct propagation to the integer variable */
4690 if( vals[j] < 0.0 )
4691 {
4692 SCIP_CALL( SCIPgetNegatedVar(scip, vars[j], &(xorvars[cnt])) );
4693 assert(xorvars[cnt] != NULL);
4694 }
4695 else
4696 xorvars[cnt] = vars[j];
4697 ++cnt;
4698 }
4699 }
4700
4701 if( parityvar != NULL )
4702 {
4703 assert(cnt == nvars - 1);
4704
4705 /* check whether parity variable is present only in this constraint */
4707 && SCIPvarGetNLocksUpType(parityvar, SCIP_LOCKTYPE_MODEL) <= 1 )
4708 {
4709 SCIP_VAR* intvar;
4710 SCIP_Bool rhsparity;
4711 SCIP_Bool neednew;
4712 int intrhs;
4713
4714 /* adjust the side, since we negated all binary variables with -1.0 as a coefficient */
4715 rhs += ncoeffsnone;
4716
4717 intrhs = (int) SCIPfloor(scip, rhs);
4718 rhsparity = ((SCIP_Bool) (intrhs % 2)); /*lint !e571*/
4719
4720 /* we need a new variable if the rhs is not 0 or 1 or if the coefficient was +2, since in these cases, we
4721 * need to aggregate the variables (flipping signs and/or shifting */
4722 if( (intrhs != 1 && intrhs != 0) || postwo )
4723 neednew = TRUE;
4724 else
4725 neednew = FALSE;
4726
4727 /* check if we can use the parity variable as integer variable of the XOR constraint or do we need to
4728 * create a new variable and aggregate */
4729 if( neednew )
4730 {
4731 char varname[SCIP_MAXSTRLEN];
4732 SCIP_Real lb;
4733 SCIP_Real ub;
4734 SCIP_Bool isbinary;
4735 SCIP_Bool infeasible;
4736 SCIP_Bool redundant;
4737 SCIP_Bool aggregated;
4738 int intrhshalfed;
4739
4740 intrhshalfed = intrhs / 2;
4741
4742 if( postwo )
4743 {
4744 lb = intrhshalfed - SCIPvarGetUbGlobal(parityvar);
4745 ub = intrhshalfed - SCIPvarGetLbGlobal(parityvar);
4746 }
4747 else
4748 {
4749 lb = intrhshalfed + SCIPvarGetLbGlobal(parityvar);
4750 ub = intrhshalfed + SCIPvarGetUbGlobal(parityvar);
4751 }
4752 assert(SCIPisFeasLE(scip, lb, ub));
4753 assert(SCIPisFeasIntegral(scip, lb));
4754 assert(SCIPisFeasIntegral(scip, ub));
4755
4756 /* adjust bounds to be more integral */
4757 lb = SCIPfeasFloor(scip, lb);
4758 ub = SCIPfeasFloor(scip, ub);
4759
4760 isbinary = (SCIPisZero(scip, lb) && SCIPisEQ(scip, ub, 1.0));
4761
4762 /* something is wrong if parity variable is already binary, but artificial variable is not */
4763 if( SCIPvarIsBinary(parityvar) && !isbinary )
4764 {
4765 SCIPfreeBufferArray(scip, &xorvars);
4766 return SCIP_OKAY;
4767 }
4768
4769 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "%s_xor_upgr", SCIPvarGetName(parityvar));
4770 SCIP_CALL( SCIPcreateVar(scip, &intvar, varname, lb, ub, 0.0,
4772 SCIPvarIsInitial(parityvar), SCIPvarIsRemovable(parityvar), NULL, NULL, NULL, NULL, NULL) );
4773 SCIP_CALL( SCIPaddVar(scip, intvar) );
4774
4775 SCIPdebugMsg(scip, "created new variable for aggregation:");
4776 SCIPdebug( SCIPprintVar(scip, intvar, NULL) );
4777
4778 SCIP_CALL( SCIPaggregateVars(scip, parityvar, intvar, 1.0, postwo ? 1.0 : -1.0,
4779 (SCIP_Real) (postwo ? intrhshalfed : -intrhshalfed), &infeasible, &redundant, &aggregated) );
4780 assert(!infeasible);
4781
4782 /* maybe aggregation was forbidden, than we cannot upgrade this constraint */
4783 if( !aggregated )
4784 {
4785 SCIPfreeBufferArray(scip, &xorvars);
4786 return SCIP_OKAY;
4787 }
4788
4789 assert(redundant);
4790 assert(SCIPvarIsActive(intvar));
4791
4792#ifdef SCIP_DEBUG
4794 {
4795 SCIPdebugMsg(scip, "aggregated: <%s> = %g * <%s> + %g\n", SCIPvarGetName(parityvar),
4797 SCIPvarGetAggrConstant(parityvar));
4798 }
4799 else
4800 {
4801 assert(SCIPvarGetStatus(parityvar) == SCIP_VARSTATUS_NEGATED);
4802 SCIPdebugMsg(scip, "negated: <%s> = 1 - <%s>\n", SCIPvarGetName(parityvar),
4804 }
4805#endif
4806 }
4807 else
4808 intvar = parityvar;
4809
4810 assert(intvar != NULL);
4811
4812 SCIP_CALL( createConsXorIntvar(scip, upgdcons, SCIPconsGetName(cons), rhsparity, nvars - 1, xorvars, intvar,
4817
4818 SCIPdebugMsg(scip, "upgraded constraint <%s> to XOR constraint:\n", SCIPconsGetName(cons));
4819 SCIPdebugPrintCons(scip, *upgdcons, NULL);
4820
4821 if( neednew )
4822 {
4823 assert(intvar != parityvar);
4824 SCIP_CALL( SCIPreleaseVar(scip, &intvar) );
4825 }
4826 }
4827 }
4828
4829 SCIPfreeBufferArray(scip, &xorvars);
4830 }
4831 }
4832
4833 return SCIP_OKAY;
4834}
4835
4836/** adds symmetry information of constraint to a symmetry detection graph */
4837static
4839 SCIP* scip, /**< SCIP pointer */
4840 SYM_SYMTYPE symtype, /**< type of symmetries that need to be added */
4841 SCIP_CONS* cons, /**< constraint */
4842 SYM_GRAPH* graph, /**< symmetry detection graph */
4843 SCIP_Bool* success /**< pointer to store whether symmetry information could be added */
4844 )
4845{
4846 SCIP_CONSDATA* consdata;
4847 SCIP_VAR** xorvars;
4848 SCIP_VAR** vars;
4849 SCIP_Real* vals;
4850 SCIP_Real constant;
4851 int consnodeidx;
4852 int nlocvars;
4853 int i;
4854
4855 assert(scip != NULL);
4856 assert(cons != NULL);
4857 assert(graph != NULL);
4858 assert(success != NULL);
4859
4860 consdata = SCIPconsGetData(cons);
4861 assert(consdata != NULL);
4862
4863 /* create arrays to store active representation of variables */
4864 nlocvars = MAX(consdata->nvars, 1);
4865 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nlocvars) );
4866 SCIP_CALL( SCIPallocBufferArray(scip, &vals, nlocvars) );
4867
4868 /* add constraint node */
4869 SCIP_CALL( SCIPaddSymgraphConsnode(scip, graph, cons, 0.0, 0.0, &consnodeidx) );
4870
4871 /* add intvar to symmetry detection graph */
4872 if( consdata->intvar != NULL)
4873 {
4874 int xornodeidx;
4875
4876 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int)SYM_CONSOPTYPE_XORINT, &xornodeidx) );
4877 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, consnodeidx, xornodeidx, FALSE, 0.0) );
4878
4879 vars[0] = consdata->intvar;
4880 vals[0] = 1.0;
4881 constant = 0.0;
4882 nlocvars = 1;
4883 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &vars, &vals, &nlocvars, &constant, SCIPisTransformed(scip)) );
4884 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, xornodeidx, vars, vals, nlocvars, constant) );
4885 }
4886
4887 /* add node modeling the XOR-part and connect it with constraint node */
4888 xorvars = consdata->vars;
4889 for( i = 0; i < consdata->nvars; ++i )
4890 {
4891 assert(xorvars[i] != NULL);
4892 vars[i] = xorvars[i];
4893 vals[i] = 1.0;
4894 }
4895 constant = -(SCIP_Real)SCIPgetRhsXor(scip, cons);
4896 nlocvars = consdata->nvars;
4897 SCIP_CALL( SCIPgetSymActiveVariables(scip, symtype, &vars, &vals, &nlocvars, &constant, SCIPisTransformed(scip)) );
4898 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, consnodeidx, vars, vals, nlocvars, constant) );
4899
4900 SCIPfreeBufferArray(scip, &vals);
4901 SCIPfreeBufferArray(scip, &vars);
4902
4903 *success = TRUE;
4904
4905 return SCIP_OKAY;
4906}
4907
4908/*
4909 * Callback methods of constraint handler
4910 */
4911
4912/** copy method for constraint handler plugins (called when SCIP copies plugins) */
4913static
4915{ /*lint --e{715}*/
4916 assert(scip != NULL);
4917 assert(conshdlr != NULL);
4918 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
4919
4920 /* call inclusion method of constraint handler */
4922
4923 *valid = TRUE;
4924
4925 return SCIP_OKAY;
4926}
4927
4928/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
4929static
4931{ /*lint --e{715}*/
4932 SCIP_CONSHDLRDATA* conshdlrdata;
4933
4934 /* free constraint handler data */
4935 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4936 assert(conshdlrdata != NULL);
4937
4938 conshdlrdataFree(scip, &conshdlrdata);
4939
4940 SCIPconshdlrSetData(conshdlr, NULL);
4941
4942 return SCIP_OKAY;
4943}
4944
4945/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
4946static
4948{ /*lint --e{715}*/
4949 SCIP_CONSDATA* consdata;
4950 int c;
4951
4952 /* release and free the rows of all constraints */
4953 for( c = 0; c < nconss; ++c )
4954 {
4955 consdata = SCIPconsGetData(conss[c]);
4956 SCIP_CALL( consdataFreeRows(scip, consdata) );
4957 }
4958
4959 return SCIP_OKAY;
4960}
4961
4962
4963/** frees specific constraint data */
4964static
4966{ /*lint --e{715}*/
4967 SCIP_CONSHDLRDATA* conshdlrdata;
4968
4969 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4970 assert(conshdlrdata != NULL);
4971
4973 {
4974 int v;
4975
4976 for( v = (*consdata)->nvars - 1; v >= 0; --v )
4977 {
4978 SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->vars[v], SCIP_EVENTTYPE_VARFIXED, conshdlrdata->eventhdlr,
4979 (SCIP_EVENTDATA*)(*consdata), -1) );
4980 }
4981 }
4982
4983 SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
4984
4985 return SCIP_OKAY;
4986}
4987
4988
4989/** transforms constraint data into data belonging to the transformed problem */
4990static
4992{ /*lint --e{715}*/
4993 SCIP_CONSDATA* sourcedata;
4994 SCIP_CONSDATA* targetdata;
4995
4996 sourcedata = SCIPconsGetData(sourcecons);
4997 assert(sourcedata != NULL);
4998 assert(sourcedata->nvars >= 1);
4999 assert(sourcedata->vars != NULL);
5000
5001 /* create target constraint data */
5002 SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->rhs, sourcedata->nvars, sourcedata->vars, sourcedata->intvar) );
5003
5004 /* create target constraint */
5005 SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
5006 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
5007 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
5008 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
5009 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
5010
5011 return SCIP_OKAY;
5012}
5013
5014
5015/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
5016static
5018{ /*lint --e{715}*/
5019 int i;
5020
5021 assert(infeasible != NULL);
5022
5023 *infeasible = FALSE;
5024
5025 for( i = 0; i < nconss && !(*infeasible); i++ )
5026 {
5027 assert(SCIPconsIsInitial(conss[i]));
5028 SCIP_CALL( addRelaxation(scip, conss[i], infeasible) );
5029 }
5030
5031 return SCIP_OKAY;
5032}
5033
5034
5035/** separation method of constraint handler for LP solutions */
5036static
5038{ /*lint --e{715}*/
5039 SCIP_CONSHDLRDATA* conshdlrdata;
5040 SCIP_Bool separated;
5041 SCIP_Bool cutoff;
5042 int c;
5043
5044 *result = SCIP_DIDNOTFIND;
5045
5046 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5047 assert(conshdlrdata != NULL);
5048
5049 /* separate all useful constraints */
5050 for( c = 0; c < nusefulconss; ++c )
5051 {
5052 SCIP_CALL( separateCons(scip, conss[c], NULL, conshdlrdata->separateparity, &separated, &cutoff) );
5053 if( cutoff )
5054 *result = SCIP_CUTOFF;
5055 else if( separated )
5056 *result = SCIP_SEPARATED;
5057 }
5058
5059 /* combine constraints to get more cuts */
5060 /**@todo combine constraints to get further cuts */
5061
5062 return SCIP_OKAY;
5063}
5064
5065
5066/** separation method of constraint handler for arbitrary primal solutions */
5067static
5069{ /*lint --e{715}*/
5070 SCIP_CONSHDLRDATA* conshdlrdata;
5071 SCIP_Bool separated;
5072 SCIP_Bool cutoff;
5073 int c;
5074
5075 *result = SCIP_DIDNOTFIND;
5076
5077 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5078 assert(conshdlrdata != NULL);
5079
5080 /* separate all useful constraints */
5081 for( c = 0; c < nusefulconss; ++c )
5082 {
5083 SCIP_CALL( separateCons(scip, conss[c], sol, conshdlrdata->separateparity, &separated, &cutoff) );
5084 if( cutoff )
5085 *result = SCIP_CUTOFF;
5086 else if( separated )
5087 *result = SCIP_SEPARATED;
5088 }
5089
5090 /* combine constraints to get more cuts */
5091 /**@todo combine constraints to get further cuts */
5092
5093 return SCIP_OKAY;
5094}
5095
5096
5097/** constraint enforcing method of constraint handler for LP solutions */
5098static
5100{ /*lint --e{715}*/
5101 SCIP_CONSHDLRDATA* conshdlrdata;
5102 SCIP_Bool violated;
5103 SCIP_Bool cutoff;
5104 int i;
5105
5106 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5107 assert(conshdlrdata != NULL);
5108
5109 /* method is called only for integral solutions, because the enforcing priority is negative */
5110 for( i = 0; i < nconss; i++ )
5111 {
5112 SCIP_CALL( checkCons(scip, conss[i], NULL, FALSE, FALSE, &violated) );
5113 if( violated )
5114 {
5115 SCIP_Bool separated;
5116
5117 SCIP_CALL( separateCons(scip, conss[i], NULL, conshdlrdata->separateparity, &separated, &cutoff) );
5118 if( cutoff )
5119 *result = SCIP_CUTOFF;
5120 else
5121 {
5122 assert(separated); /* because the solution is integral, the separation always finds a cut */
5123 *result = SCIP_SEPARATED;
5124 }
5125 return SCIP_OKAY;
5126 }
5127 }
5128 *result = SCIP_FEASIBLE;
5129
5130 return SCIP_OKAY;
5131}
5132
5133
5134/** constraint enforcing method of constraint handler for relaxation solutions */
5135static
5137{ /*lint --e{715}*/
5138 SCIP_CONSHDLRDATA* conshdlrdata;
5139 SCIP_Bool violated;
5140 SCIP_Bool cutoff;
5141 int i;
5142
5143 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5144 assert(conshdlrdata != NULL);
5145
5146 /* method is called only for integral solutions, because the enforcing priority is negative */
5147 for( i = 0; i < nconss; i++ )
5148 {
5149 SCIP_CALL( checkCons(scip, conss[i], sol, FALSE, FALSE, &violated) );
5150 if( violated )
5151 {
5152 SCIP_Bool separated;
5153
5154 SCIP_CALL( separateCons(scip, conss[i], sol, conshdlrdata->separateparity, &separated, &cutoff) );
5155 if( cutoff )
5156 *result = SCIP_CUTOFF;
5157 else
5158 {
5159 assert(separated); /* because the solution is integral, the separation always finds a cut */
5160 *result = SCIP_SEPARATED;
5161 }
5162 return SCIP_OKAY;
5163 }
5164 }
5165 *result = SCIP_FEASIBLE;
5166
5167 return SCIP_OKAY;
5168}
5169
5170
5171/** constraint enforcing method of constraint handler for pseudo solutions */
5172static
5174{ /*lint --e{715}*/
5175 SCIP_Bool violated;
5176 int i;
5177
5178 /* method is called only for integral solutions, because the enforcing priority is negative */
5179 for( i = 0; i < nconss; i++ )
5180 {
5181 SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, FALSE, &violated) );
5182 if( violated )
5183 {
5184 *result = SCIP_INFEASIBLE;
5185 return SCIP_OKAY;
5186 }
5187 }
5188 *result = SCIP_FEASIBLE;
5189
5190 return SCIP_OKAY;
5191}
5192
5193/** feasibility check method of constraint handler xor */
5194static
5196{ /*lint --e{715}*/
5197 SCIP_Bool violated;
5198 int i;
5199
5200 *result = SCIP_FEASIBLE;
5201
5202 for( i = 0; i < nconss && ( *result == SCIP_FEASIBLE || completely ); ++i )
5203 {
5204 SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, printreason, &violated) );
5205 if( violated )
5206 *result = SCIP_INFEASIBLE;
5207 }
5208
5209 return SCIP_OKAY;
5210}
5211
5212/** domain propagation method of constraint handler */
5213static
5215{ /*lint --e{715}*/
5216 SCIP_CONSHDLRDATA* conshdlrdata;
5217 SCIP_Bool cutoff;
5218 int nfixedvars;
5219 int nchgbds;
5220 int c;
5221
5222 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5223 assert(conshdlrdata != NULL);
5224
5225 cutoff = FALSE;
5226 nfixedvars = 0;
5227 nchgbds = 0;
5228
5229 /* propagate all useful constraints */
5230 for( c = 0; c < nusefulconss && !cutoff; ++c )
5231 {
5232 SCIP_CALL( propagateCons(scip, conss[c], conshdlrdata->eventhdlr, &cutoff, &nfixedvars, &nchgbds) );
5233 }
5234
5235 /* return the correct result */
5236 if( cutoff )
5237 *result = SCIP_CUTOFF;
5238 else if( nfixedvars > 0 || nchgbds > 0 )
5239 *result = SCIP_REDUCEDDOM;
5240 else
5241 {
5242 *result = SCIP_DIDNOTFIND;
5243 if( !SCIPinProbing(scip) )
5244 {
5245 int depth;
5246 int freq;
5247
5248 depth = SCIPgetDepth(scip);
5249 freq = conshdlrdata->gausspropfreq;
5250 if( (depth == 0 && freq == 0) || (freq > 0 && depth % freq == 0) )
5251 {
5252 /* take useful constraints only - might improve success rate to take all */
5253 SCIP_CALL( checkSystemGF2(scip, conss, nusefulconss, NULL, result) );
5254 }
5255 }
5256 }
5257
5258 return SCIP_OKAY;
5259}
5260
5261/** presolving initialization method of constraint handler (called when presolving is about to begin) */
5262static
5264{ /*lint --e{715}*/
5265 SCIP_CONSHDLRDATA* conshdlrdata;
5266 SCIP_CONSDATA* consdata;
5267 int c;
5268 int v;
5269
5270 assert(conshdlr != NULL);
5271 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5272 assert(conshdlrdata != NULL);
5273
5274 /* catch all variable event for deleted variables, which is only used in presolving */
5275 for( c = nconss - 1; c >= 0; --c )
5276 {
5277 consdata = SCIPconsGetData(conss[c]);
5278 assert(consdata != NULL);
5279
5280 for( v = consdata->nvars - 1; v >= 0; --v )
5281 {
5282 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[v], SCIP_EVENTTYPE_VARFIXED, conshdlrdata->eventhdlr,
5283 (SCIP_EVENTDATA*)consdata, NULL) );
5284 }
5285 }
5286
5287 return SCIP_OKAY;
5288}
5289
5290/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
5291static
5293{ /*lint --e{715}*/
5294 SCIP_CONSHDLRDATA* conshdlrdata;
5295 SCIP_CONSDATA* consdata;
5296 int c;
5297 int v;
5298
5299 assert(conshdlr != NULL);
5300 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5301 assert(conshdlrdata != NULL);
5302
5303 /* drop all variable event for deleted variables, which was only used in presolving */
5304 for( c = 0; c < nconss; ++c )
5305 {
5306 consdata = SCIPconsGetData(conss[c]);
5307 assert(consdata != NULL);
5308
5309 if( !SCIPconsIsDeleted(conss[c]) )
5310 {
5311 for( v = 0; v < consdata->nvars; ++v )
5312 {
5313 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[v], SCIP_EVENTTYPE_VARFIXED, conshdlrdata->eventhdlr,
5314 (SCIP_EVENTDATA*)consdata, -1) );
5315 }
5316 }
5317 }
5318
5319 return SCIP_OKAY;
5320}
5321
5322/** presolving method of constraint handler */
5323static
5325{ /*lint --e{715}*/
5326 SCIP_CONSHDLRDATA* conshdlrdata;
5327 SCIP_CONS* cons;
5328 SCIP_CONSDATA* consdata;
5329 SCIP_Bool cutoff;
5330 SCIP_Bool redundant;
5331 SCIP_Bool aggregated;
5332 int oldnfixedvars;
5333 int oldnchgbds;
5334 int oldnaggrvars;
5335 int oldndelconss;
5336 int oldnchgcoefs;
5337 int firstchange;
5338 int c;
5339
5340 assert(result != NULL);
5341
5342 oldnfixedvars = *nfixedvars;
5343 oldnchgbds = *nchgbds;
5344 oldnaggrvars = *naggrvars;
5345 oldndelconss = *ndelconss;
5346 oldnchgcoefs = *nchgcoefs;
5347
5348 conshdlrdata = SCIPconshdlrGetData(conshdlr);
5349 assert(conshdlrdata != NULL);
5350
5351 /* process constraints */
5352 cutoff = FALSE;
5353 firstchange = INT_MAX;
5354 for( c = 0; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
5355 {
5356 cons = conss[c];
5357 assert(cons != NULL);
5358 consdata = SCIPconsGetData(cons);
5359 assert(consdata != NULL);
5360
5361 /* force presolving the constraint in the initial round */
5362 if( nrounds == 0 )
5363 consdata->propagated = FALSE;
5364
5365 /* remember the first changed constraint to begin the next aggregation round with */
5366 if( firstchange == INT_MAX && consdata->changed )
5367 firstchange = c;
5368
5369 /* remove all variables that are fixed to zero and all pairs of variables fixed to one;
5370 * merge multiple entries of the same or negated variables
5371 */
5372 SCIP_CALL( applyFixings(scip, cons, conshdlrdata->eventhdlr, nchgcoefs, naggrvars, naddconss, &cutoff) );
5373
5374 if( cutoff )
5375 break;
5376
5377 /* propagate constraint */
5378 SCIP_CALL( propagateCons(scip, cons, conshdlrdata->eventhdlr, &cutoff, nfixedvars, nchgbds) );
5379
5380 if( !cutoff && !SCIPconsIsDeleted(cons) && !SCIPconsIsModifiable(cons) )
5381 {
5382 assert(consdata->nvars >= 2); /* otherwise, propagateCons() has deleted the constraint */
5383
5384 /* if only two variables are left, both have to be equal or opposite, depending on the rhs */
5385 if( consdata->nvars == 2 )
5386 {
5387 SCIPdebugMsg(scip, "xor constraint <%s> has only two unfixed variables, rhs=%u\n",
5388 SCIPconsGetName(cons), consdata->rhs);
5389
5390 assert(consdata->vars != NULL);
5391 assert(SCIPisEQ(scip, SCIPvarGetLbGlobal(consdata->vars[0]), 0.0));
5392 assert(SCIPisEQ(scip, SCIPvarGetUbGlobal(consdata->vars[0]), 1.0));
5393 assert(SCIPisEQ(scip, SCIPvarGetLbGlobal(consdata->vars[1]), 0.0));
5394 assert(SCIPisEQ(scip, SCIPvarGetUbGlobal(consdata->vars[1]), 1.0));
5395
5396 if( !consdata->rhs )
5397 {
5398 /* aggregate variables: vars[0] - vars[1] == 0 */
5399 SCIPdebugMsg(scip, " -> aggregate <%s> == <%s>\n", SCIPvarGetName(consdata->vars[0]),
5400 SCIPvarGetName(consdata->vars[1]));
5401 SCIP_CALL( SCIPaggregateVars(scip, consdata->vars[0], consdata->vars[1], 1.0, -1.0, 0.0,
5402 &cutoff, &redundant, &aggregated) );
5403 }
5404 else
5405 {
5406 /* aggregate variables: vars[0] + vars[1] == 1 */
5407 SCIPdebugMsg(scip, " -> aggregate <%s> == 1 - <%s>\n", SCIPvarGetName(consdata->vars[0]),
5408 SCIPvarGetName(consdata->vars[1]));
5409 SCIP_CALL( SCIPaggregateVars(scip, consdata->vars[0], consdata->vars[1], 1.0, 1.0, 1.0,
5410 &cutoff, &redundant, &aggregated) );
5411 }
5412 assert(redundant || SCIPdoNotAggr(scip));
5413
5414 if( aggregated )
5415 {
5416 assert(redundant);
5417 ++(*naggrvars);
5418 }
5419
5420 /* the constraint can be deleted if the intvar is fixed or NULL */
5421 if( redundant )
5422 {
5423 SCIP_Bool fixedintvar;
5424
5425 fixedintvar = consdata->intvar == NULL ? TRUE : SCIPisEQ(scip, SCIPvarGetLbGlobal(consdata->intvar), SCIPvarGetUbGlobal(consdata->intvar));
5426
5427 if( fixedintvar )
5428 {
5429 /* if there is an integer variable then the following
5430 * must hold:
5431 *
5432 * if consdata->rhs == 1 then the integer variable needs
5433 * to be fixed to zero, otherwise the constraint is
5434 * infeasible,
5435 *
5436 * if consdata->rhs == 0 then the integer variable needs
5437 * to be aggregated to one of the binary variables
5438 */
5439 assert(consdata->intvar == NULL || (consdata->rhs && SCIPvarGetUbGlobal(consdata->intvar) < 0.5));
5440
5441 /* delete constraint */
5442 SCIP_CALL( SCIPdelCons(scip, cons) );
5443 (*ndelconss)++;
5444 }
5445 }
5446 }
5447 else if( (presoltiming & SCIP_PRESOLTIMING_MEDIUM) != 0 )
5448 {
5449 /* try to use clique information to upgrade the constraint to a set-partitioning constraint or fix
5450 * variables
5451 */
5452 SCIP_CALL( cliquePresolve(scip, cons, nfixedvars, naggrvars, nchgcoefs, ndelconss, naddconss, &cutoff) );
5453 }
5454 }
5455 }
5456
5457 /* process pairs of constraints: check them for equal operands;
5458 * only apply this expensive procedure, if the single constraint preprocessing did not find any reductions
5459 */
5460 if( !cutoff && (presoltiming & SCIP_PRESOLTIMING_EXHAUSTIVE) != 0 && SCIPisPresolveFinished(scip) )
5461 {
5462 if( firstchange < nconss && conshdlrdata->presolusehashing )
5463 {
5464 /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
5465 SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &firstchange, nchgcoefs,
5466 nfixedvars, naggrvars, ndelconss, naddconss, &cutoff) );
5467 }
5468 if( conshdlrdata->presolpairwise )
5469 {
5470 SCIP_Longint npaircomparisons;
5471 int lastndelconss;
5472 npaircomparisons = 0;
5473 lastndelconss = *ndelconss;
5474
5475 for( c = firstchange; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
5476 {
5477 if( SCIPconsIsActive(conss[c]) && !SCIPconsIsModifiable(conss[c]) )
5478 {
5479 npaircomparisons += (SCIPconsGetData(conss[c])->changed) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange);
5480
5481 SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c,
5482 &cutoff, nfixedvars, naggrvars, ndelconss, naddconss, nchgcoefs) );
5483
5484 if( npaircomparisons > NMINCOMPARISONS )
5485 {
5486 if( ((SCIP_Real) (*ndelconss - lastndelconss)) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
5487 break;
5488 lastndelconss = *ndelconss;
5489 npaircomparisons = 0;
5490 }
5491 }
5492 }
5493 }
5494 }
5495
5496 /* return the correct result code */
5497 if( cutoff )
5498 *result = SCIP_CUTOFF;
5499 else if( *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds || *naggrvars > oldnaggrvars
5500 || *ndelconss > oldndelconss || *nchgcoefs > oldnchgcoefs )
5501 *result = SCIP_SUCCESS;
5502 else
5503 *result = SCIP_DIDNOTFIND;
5504
5505 /* add extended formulation at the end of presolving if required */
5506 if( conshdlrdata->addextendedform && *result == SCIP_DIDNOTFIND && SCIPisPresolveFinished(scip) )
5507 {
5508 for( c = 0; c < nconss && !SCIPisStopped(scip); ++c )
5509 {
5510 int naddedconss = 0;
5511
5512 cons = conss[c];
5513 assert(cons != NULL);
5514 consdata = SCIPconsGetData(cons);
5515 assert(consdata != NULL);
5516
5517 if( consdata->extvars != NULL )
5518 break;
5519
5520 if( conshdlrdata->addflowextended )
5521 {
5522 SCIP_CALL( addExtendedFlowFormulation(scip, cons, naggrvars, &naddedconss) );
5523 }
5524 else
5525 {
5526 SCIP_CALL( addExtendedAsymmetricFormulation(scip, cons, naggrvars, &naddedconss) );
5527 }
5528 (*naddconss) += naddedconss;
5529 }
5530 }
5531
5532 return SCIP_OKAY;
5533}
5534
5535
5536/** propagation conflict resolving method of constraint handler */
5537static
5539{ /*lint --e{715}*/
5540 SCIP_CALL( resolvePropagation(scip, cons, infervar, (PROPRULE)inferinfo, bdchgidx, result) );
5541
5542 return SCIP_OKAY;
5543}
5544
5545
5546/** variable rounding lock method of constraint handler */
5547static
5549{ /*lint --e{715}*/
5550 SCIP_CONSDATA* consdata;
5551 int i;
5552
5553 consdata = SCIPconsGetData(cons);
5554 assert(consdata != NULL);
5555
5556 /* external variables */
5557 for( i = 0; i < consdata->nvars; ++i )
5558 {
5559 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->vars[i], locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
5560 }
5561
5562 /* internal variable */
5563 if( consdata->intvar != NULL )
5564 {
5565 SCIP_CALL( SCIPaddVarLocksType(scip, consdata->intvar, locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
5566 }
5567
5568 return SCIP_OKAY;
5569}
5570
5571
5572/** constraint display method of constraint handler */
5573static
5575{ /*lint --e{715}*/
5576 assert(scip != NULL);
5577 assert(conshdlr != NULL);
5578 assert(cons != NULL);
5579
5581
5582 return SCIP_OKAY;
5583}
5584
5585/** constraint copying method of constraint handler */
5586static
5588{ /*lint --e{715}*/
5589 SCIP_CONSDATA* sourceconsdata;
5590 SCIP_VAR** sourcevars;
5591 SCIP_VAR** targetvars;
5592 SCIP_VAR* intvar;
5593 SCIP_VAR* targetintvar;
5594 const char* consname;
5595 int nvars;
5596 int v;
5597
5598 assert(scip != NULL);
5599 assert(sourcescip != NULL);
5600 assert(sourcecons != NULL);
5601
5602 (*valid) = TRUE;
5603
5604 sourceconsdata = SCIPconsGetData(sourcecons);
5605 assert(sourceconsdata != NULL);
5606
5607 /* get variables and coefficients of the source constraint */
5608 sourcevars = sourceconsdata->vars;
5609 nvars = sourceconsdata->nvars;
5610 intvar = sourceconsdata->intvar;
5611 targetintvar = NULL;
5612
5613 if( name != NULL )
5614 consname = name;
5615 else
5616 consname = SCIPconsGetName(sourcecons);
5617
5618 if( nvars == 0 )
5619 {
5620 if( intvar != NULL )
5621 {
5622 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, intvar, &targetintvar, varmap, consmap, global, valid) );
5623 assert(!(*valid) || targetintvar != NULL);
5624
5625 if( targetintvar != NULL )
5626 {
5627 SCIPdebugMsg(scip, "Copied integral variable <%s> (bounds: [%g,%g])\n", SCIPvarGetName(targetintvar),
5628 global ? SCIPvarGetLbGlobal(intvar) : SCIPvarGetLbLocal(intvar),
5629 global ? SCIPvarGetUbGlobal(intvar) : SCIPvarGetUbLocal(intvar));
5630 }
5631 }
5632
5633 if( *valid )
5634 {
5635 SCIP_CALL( createConsXorIntvar(scip, cons, consname, SCIPgetRhsXor(sourcescip, sourcecons), 0, NULL,
5636 targetintvar, initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable,
5637 stickingatnode) );
5638 }
5639
5640 return SCIP_OKAY;
5641 }
5642
5643 /* duplicate variable array */
5644 SCIP_CALL( SCIPallocBufferArray(scip, &targetvars, nvars) );
5645
5646 /* map variables of the source constraint to variables of the target SCIP */
5647 for( v = 0; v < nvars && *valid; ++v )
5648 {
5649 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &targetvars[v], varmap, consmap, global, valid) );
5650 assert(!(*valid) || targetvars[v] != NULL);
5651 }
5652
5653 /* map artificial relaxation variable of the source constraint to variable of the target SCIP */
5654 if( *valid && intvar != NULL )
5655 {
5656 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, intvar, &targetintvar, varmap, consmap, global, valid) );
5657 assert(!(*valid) || targetintvar != NULL);
5658
5659 SCIPdebugMsg(scip, "Copied integral variable <%s> (bounds: [%g,%g])\n", SCIPvarGetName(targetintvar),
5660 global ? SCIPvarGetLbGlobal(intvar) : SCIPvarGetLbLocal(intvar),
5661 global ? SCIPvarGetUbGlobal(intvar) : SCIPvarGetUbLocal(intvar));
5662 }
5663
5664 /* only create the target constraints, if all variables could be copied */
5665 if( *valid )
5666 {
5667 SCIP_CALL( createConsXorIntvar(scip, cons, consname, SCIPgetRhsXor(sourcescip, sourcecons), nvars, targetvars,
5668 targetintvar, initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable,
5669 stickingatnode) );
5670 }
5671
5672 /* free buffer array */
5673 SCIPfreeBufferArray(scip, &targetvars);
5674
5675 return SCIP_OKAY;
5676}
5677
5678
5679/** constraint parsing method of constraint handler */
5680static
5682{ /*lint --e{715}*/
5683 SCIP_VAR** vars;
5684 char* endptr;
5685 int requiredsize;
5686 int varssize;
5687 int nvars;
5688
5689 SCIPdebugMsg(scip, "parse <%s> as xor constraint\n", str);
5690
5691 varssize = 100;
5692 nvars = 0;
5693
5694 /* allocate buffer array for variables */
5695 SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
5696
5697 /* parse string */
5698 SCIP_CALL( SCIPparseVarsList(scip, str, vars, &nvars, varssize, &requiredsize, &endptr, ',', success) );
5699
5700 if( *success )
5701 {
5702 SCIP_Real rhs;
5703
5704 /* check if the size of the variable array was big enough */
5705 if( varssize < requiredsize )
5706 {
5707 /* reallocate memory */
5708 varssize = requiredsize;
5709 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
5710
5711 /* parse string again with the correct size of the variable array */
5712 SCIP_CALL( SCIPparseVarsList(scip, str, vars, &nvars, varssize, &requiredsize, &endptr, ',', success) );
5713 }
5714
5715 assert(*success);
5716 assert(varssize >= requiredsize);
5717
5718 SCIPdebugMsg(scip, "successfully parsed %d variables\n", nvars);
5719
5720 /* find "==" */
5721 endptr = strchr(endptr, '=');
5722
5723 /* if the string end has been reached without finding the "==" */
5724 if( endptr == NULL )
5725 {
5726 SCIPerrorMessage("Could not find terminating '='.\n");
5727 *success = FALSE;
5728 goto TERMINATE;
5729 }
5730
5731 str = endptr;
5732
5733 /* skip "==" */
5734 str += *(str+1) == '=' ? 2 : 1;
5735
5736 if( SCIPparseReal(scip, str, &rhs, &endptr) )
5737 {
5738 SCIP_VAR* intvar = NULL;
5739
5740 assert(SCIPisZero(scip, rhs) || SCIPisEQ(scip, rhs, 1.0));
5741
5742 str = endptr;
5743
5744 /* skip white spaces */
5745 SCIP_CALL( SCIPskipSpace((char**)&str) );
5746
5747 /* check for integer variable, should look like (intvar = var) */
5748 if( *str == '(' )
5749 {
5750 str = strchr(str+1, '=');
5751
5752 if( str == NULL )
5753 {
5754 SCIPerrorMessage("Parsing integer variable of XOR constraint\n");
5755 *success = FALSE;
5756 goto TERMINATE;
5757 }
5758
5759 ++str;
5760
5761 /* parse variable name */
5762 SCIP_CALL( SCIPparseVarName(scip, str, &intvar, &endptr) );
5763
5764 if( intvar == NULL )
5765 {
5766 SCIPerrorMessage("Integer variable of XOR not found\n");
5767 *success = FALSE;
5768 goto TERMINATE;
5769 }
5770
5771 /* skip last ')' */
5772 endptr = strchr(endptr, ')');
5773
5774 if( endptr == NULL )
5775 {
5776 SCIPerrorMessage("Closing ')' missing\n");
5777 *success = FALSE;
5778 goto TERMINATE;
5779 }
5780 }
5781
5782 if( intvar != NULL )
5783 {
5784 /* create or constraint */
5785 SCIP_CALL( createConsXorIntvar(scip, cons, name, (rhs > 0.5 ? TRUE : FALSE), nvars, vars, intvar,
5786 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
5787 }
5788 else
5789 {
5790 /* create or constraint */
5791 SCIP_CALL( SCIPcreateConsXor(scip, cons, name, (rhs > 0.5 ? TRUE : FALSE), nvars, vars,
5792 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
5793 }
5794
5795 SCIPdebugPrintCons(scip, *cons, NULL);
5796 }
5797 else
5798 *success = FALSE;
5799 }
5800
5801 TERMINATE:
5802 /* free variable buffer */
5803 SCIPfreeBufferArray(scip, &vars);
5804
5805 return SCIP_OKAY;
5806}
5807
5808/** constraint method of constraint handler which returns the variables (if possible) */
5809static
5811{ /*lint --e{715}*/
5812 SCIP_CONSDATA* consdata;
5813 int nintvar = 0;
5814 int cnt;
5815 int j;
5816
5817 consdata = SCIPconsGetData(cons);
5818 assert(consdata != NULL);
5819
5820 if( consdata->intvar != NULL )
5821 nintvar = 1;
5822
5823 if( varssize < consdata->nvars + nintvar + consdata->nextvars )
5824 (*success) = FALSE;
5825 else
5826 {
5827 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
5828
5829 if( consdata->intvar != NULL )
5830 vars[consdata->nvars] = consdata->intvar;
5831
5832 if( consdata->nextvars > 0 )
5833 {
5834 assert(consdata->extvars != NULL);
5835 cnt = consdata->nvars + nintvar;
5836 for( j = 0; j < consdata->extvarssize; ++j )
5837 {
5838 if( consdata->extvars[j] != NULL )
5839 vars[cnt++] = consdata->extvars[j];
5840 }
5841 assert(cnt == consdata->nvars + nintvar + consdata->nextvars);
5842 }
5843
5844 (*success) = TRUE;
5845 }
5846
5847 return SCIP_OKAY;
5848}
5849
5850/** constraint method of constraint handler which returns the number of variable (if possible) */
5851static
5853{ /*lint --e{715}*/
5854 SCIP_CONSDATA* consdata;
5855
5856 assert(cons != NULL);
5857
5858 consdata = SCIPconsGetData(cons);
5859 assert(consdata != NULL);
5860
5861 if( consdata->intvar == NULL )
5862 (*nvars) = consdata->nvars + consdata->nextvars;
5863 else
5864 (*nvars) = consdata->nvars + 1 + consdata->nextvars;
5865
5866 (*success) = TRUE;
5867
5868 return SCIP_OKAY;
5869}
5870
5871/** constraint handler method which returns the permutation symmetry detection graph of a constraint */
5872static
5873SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphXor)
5874{ /*lint --e{715}*/
5875 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_PERM, cons, graph, success) );
5876
5877 return SCIP_OKAY;
5878}
5879
5880/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */
5881static
5882SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphXor)
5883{ /*lint --e{715}*/
5884 SCIP_CALL( addSymmetryInformation(scip, SYM_SYMTYPE_SIGNPERM, cons, graph, success) );
5885
5886 return SCIP_OKAY;
5887}
5888
5889/*
5890 * Callback methods of event handler
5891 */
5892
5893static
5895{ /*lint --e{715}*/
5896 SCIP_CONSDATA* consdata;
5897
5898 assert(eventhdlr != NULL);
5899 assert(eventdata != NULL);
5900 assert(event != NULL);
5901
5902 consdata = (SCIP_CONSDATA*)eventdata;
5903 assert(consdata != NULL);
5904
5906 {
5907 /* we only catch this event in presolving stage */
5909 assert(SCIPeventGetVar(event) != NULL);
5910
5911 consdata->sorted = FALSE;
5912 }
5913
5914 consdata->propagated = FALSE;
5915
5916 return SCIP_OKAY;
5917}
5918
5919
5920/*
5921 * constraint specific interface methods
5922 */
5923
5924/** creates the handler for xor constraints and includes it in SCIP */
5926 SCIP* scip /**< SCIP data structure */
5927 )
5928{
5929 SCIP_CONSHDLRDATA* conshdlrdata;
5930 SCIP_CONSHDLR* conshdlr;
5931 SCIP_EVENTHDLR* eventhdlr;
5932
5933 /* create event handler for events on variables */
5935 eventExecXor, NULL) );
5936
5937 /* create constraint handler data */
5938 SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
5939
5940 /* include constraint handler */
5943 consEnfolpXor, consEnfopsXor, consCheckXor, consLockXor,
5944 conshdlrdata) );
5945 assert(conshdlr != NULL);
5946
5947 /* set non-fundamental callbacks via specific setter functions */
5948 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyXor, consCopyXor) );
5949 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteXor) );
5950 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolXor) );
5951 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeXor) );
5952 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsXor) );
5953 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsXor) );
5954 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpXor) );
5955 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseXor) );
5956 SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreXor) );
5957 SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreXor) );
5959 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintXor) );
5962 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropXor) );
5963 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpXor, consSepasolXor, CONSHDLR_SEPAFREQ,
5965 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransXor) );
5966 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxXor) );
5967 SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphXor) );
5968 SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphXor) );
5969
5970 if( SCIPfindConshdlr(scip, "linear") != NULL )
5971 {
5972 /* include the linear constraint upgrade in the linear constraint handler */
5974 }
5975
5976 /* add xor constraint handler parameters */
5978 "constraints/xor/presolpairwise",
5979 "should pairwise constraint comparison be performed in presolving?",
5980 &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
5981
5983 "constraints/xor/presolusehashing",
5984 "should hash table be used for detecting redundant constraints in advance?",
5985 &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
5986
5988 "constraints/xor/addextendedform",
5989 "should the extended formulation be added in presolving?",
5990 &conshdlrdata->addextendedform, TRUE, DEFAULT_ADDEXTENDEDFORM, NULL, NULL) );
5991
5993 "constraints/xor/addflowextended",
5994 "should the extended flow formulation be added (nonsymmetric formulation otherwise)?",
5995 &conshdlrdata->addflowextended, TRUE, DEFAULT_ADDFLOWEXTENDED, NULL, NULL) );
5996
5998 "constraints/xor/separateparity",
5999 "should parity inequalities be separated?",
6000 &conshdlrdata->separateparity, TRUE, DEFAULT_SEPARATEPARITY, NULL, NULL) );
6001
6003 "constraints/xor/gausspropfreq",
6004 "frequency for applying the Gauss propagator",
6005 &conshdlrdata->gausspropfreq, TRUE, DEFAULT_GAUSSPROPFREQ, -1, SCIP_MAXTREEDEPTH, NULL, NULL) );
6006
6007 return SCIP_OKAY;
6008}
6009
6010/** creates and captures a xor constraint x_0 xor ... xor x_{k-1} = rhs
6011 *
6012 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
6013 */
6015 SCIP* scip, /**< SCIP data structure */
6016 SCIP_CONS** cons, /**< pointer to hold the created constraint */
6017 const char* name, /**< name of constraint */
6018 SCIP_Bool rhs, /**< right hand side of the constraint */
6019 int nvars, /**< number of operator variables in the constraint */
6020 SCIP_VAR** vars, /**< array with operator variables of constraint */
6021 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
6022 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
6023 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
6024 * Usually set to TRUE. */
6025 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
6026 * TRUE for model constraints, FALSE for additional, redundant constraints. */
6027 SCIP_Bool check, /**< should the constraint be checked for feasibility?
6028 * TRUE for model constraints, FALSE for additional, redundant constraints. */
6029 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
6030 * Usually set to TRUE. */
6031 SCIP_Bool local, /**< is constraint only valid locally?
6032 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
6033 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
6034 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
6035 * adds coefficients to this constraint. */
6036 SCIP_Bool dynamic, /**< is constraint subject to aging?
6037 * Usually set to FALSE. Set to TRUE for own cuts which
6038 * are separated as constraints. */
6039 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
6040 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
6041 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
6042 * if it may be moved to a more global node?
6043 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
6044 )
6045{
6046 SCIP_CONSHDLR* conshdlr;
6047 SCIP_CONSDATA* consdata;
6048 int i;
6049
6050 /* find the xor constraint handler */
6051 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
6052 if( conshdlr == NULL )
6053 {
6054 SCIPerrorMessage("xor constraint handler not found\n");
6055 return SCIP_PLUGINNOTFOUND;
6056 }
6057
6058 /* check whether all variables are binary */
6059 assert(vars != NULL || nvars == 0);
6060 for( i = 0; i < nvars; ++i )
6061 {
6062 if( !SCIPvarIsBinary(vars[i]) )
6063 {
6064 SCIPerrorMessage("operand <%s> is not binary\n", SCIPvarGetName(vars[i]));
6065 return SCIP_INVALIDDATA;
6066 }
6067 }
6068
6069 /* create constraint data */
6070 SCIP_CALL( consdataCreate(scip, &consdata, rhs, nvars, vars, NULL) );
6071
6072 /* create constraint */
6073 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
6074 local, modifiable, dynamic, removable, stickingatnode) );
6075
6076 return SCIP_OKAY;
6077}
6078
6079/** creates and captures a xor constraint x_0 xor ... xor x_{k-1} = rhs
6080 * with all constraint flags set to their default values
6081 *
6082 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
6083 */
6085 SCIP* scip, /**< SCIP data structure */
6086 SCIP_CONS** cons, /**< pointer to hold the created constraint */
6087 const char* name, /**< name of constraint */
6088 SCIP_Bool rhs, /**< right hand side of the constraint */
6089 int nvars, /**< number of operator variables in the constraint */
6090 SCIP_VAR** vars /**< array with operator variables of constraint */
6091 )
6092{
6093 SCIP_CALL( SCIPcreateConsXor(scip,cons, name, rhs, nvars, vars,
6095
6096 return SCIP_OKAY;
6097}
6098
6099/** gets number of variables in xor constraint */
6101 SCIP* scip, /**< SCIP data structure */
6102 SCIP_CONS* cons /**< constraint data */
6103 )
6104{
6105 SCIP_CONSDATA* consdata;
6106
6107 assert(scip != NULL);
6108
6109 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
6110 {
6111 SCIPerrorMessage("constraint is not an xor constraint\n");
6112 SCIPABORT();
6113 return -1; /*lint !e527*/
6114 }
6115
6116 consdata = SCIPconsGetData(cons);
6117 assert(consdata != NULL);
6118
6119 return consdata->nvars;
6120}
6121
6122/** gets array of variables in xor constraint */
6124 SCIP* scip, /**< SCIP data structure */
6125 SCIP_CONS* cons /**< constraint data */
6126 )
6127{
6128 SCIP_CONSDATA* consdata;
6129
6130 assert(scip != NULL);
6131
6132 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
6133 {
6134 SCIPerrorMessage("constraint is not an xor constraint\n");
6135 SCIPABORT();
6136 return NULL; /*lint !e527*/
6137 }
6138
6139 consdata = SCIPconsGetData(cons);
6140 assert(consdata != NULL);
6141
6142 return consdata->vars;
6143}
6144
6145/** gets integer variable in xor constraint */
6147 SCIP* scip, /**< SCIP data structure */
6148 SCIP_CONS* cons /**< constraint data */
6149 )
6150{
6151 SCIP_CONSDATA* consdata;
6152
6153 assert(scip != NULL);
6154
6155 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
6156 {
6157 SCIPerrorMessage("constraint is not an xor constraint\n");
6158 SCIPABORT();
6159 return NULL; /*lint !e527*/
6160 }
6161
6162 consdata = SCIPconsGetData(cons);
6163 assert(consdata != NULL);
6164
6165 return consdata->intvar;
6166}
6167
6168/** gets the right hand side of the xor constraint */
6170 SCIP* scip, /**< SCIP data structure */
6171 SCIP_CONS* cons /**< constraint data */
6172 )
6173{
6174 SCIP_CONSDATA* consdata;
6175
6176 assert(scip != NULL);
6177
6178 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
6179 {
6180 SCIPerrorMessage("constraint is not an xor constraint\n");
6181 SCIPABORT();
6182 }
6183
6184 consdata = SCIPconsGetData(cons);
6185 assert(consdata != NULL);
6186
6187 return consdata->rhs;
6188}
SCIP_VAR * h
Definition: circlepacking.c:68
SCIP_VAR ** b
Definition: circlepacking.c:65
SCIP_Real * r
Definition: circlepacking.c:59
SCIP_VAR ** x
Definition: circlepacking.c:63
enum Proprule PROPRULE
Definition: cons_and.c:173
Proprule
Definition: cons_and.c:166
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:1776
enum Proprule PROPRULE
Definition: cons_xor.c:180
static SCIP_DECL_CONSDELETE(consDeleteXor)
Definition: cons_xor.c:4965
static SCIP_DECL_CONSGETVARS(consGetVarsXor)
Definition: cons_xor.c:5810
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
static SCIP_DECL_CONSSEPASOL(consSepasolXor)
Definition: cons_xor.c:5068
static SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphXor)
Definition: cons_xor.c:5873
#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
#define CONSHDLR_NEEDSCONS
Definition: cons_xor.c:101
#define CONSHDLR_SEPAFREQ
Definition: cons_xor.c:94
static SCIP_RETCODE addExtendedAsymmetricFormulation(SCIP *scip, SCIP_CONS *cons, int *naggrvars, int *naddedconss)
Definition: cons_xor.c:1460
static SCIP_DECL_CONSLOCK(consLockXor)
Definition: cons_xor.c:5548
static SCIP_DECL_HASHKEYEQ(hashKeyEqXorcons)
Definition: cons_xor.c:805
static SCIP_RETCODE checkSystemGF2(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *currentsol, SCIP_RESULT *result)
Definition: cons_xor.c:2359
static SCIP_DECL_EVENTEXEC(eventExecXor)
Definition: cons_xor.c:5894
static SCIP_RETCODE delCoefPos(SCIP *scip, SCIP_CONS *cons, SCIP_EVENTHDLR *eventhdlr, int pos)
Definition: cons_xor.c:652
#define CONSHDLR_CHECKPRIORITY
Definition: cons_xor.c:93
static SCIP_RETCODE setIntvar(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition: cons_xor.c:534
#define CONSHDLR_DESC
Definition: cons_xor.c:90
static SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphXor)
Definition: cons_xor.c:5882
static SCIP_DECL_CONSEXITSOL(consExitsolXor)
Definition: cons_xor.c:4947
#define DEFAULT_ADDFLOWEXTENDED
Definition: cons_xor.c:113
static SCIP_RETCODE createRelaxation(SCIP *scip, SCIP_CONS *cons)
Definition: cons_xor.c:1643
static SCIP_DECL_CONSPRINT(consPrintXor)
Definition: cons_xor.c:5574
#define CONSHDLR_PROP_TIMING
Definition: cons_xor.c:103
static SCIP_DECL_CONSINITPRE(consInitpreXor)
Definition: cons_xor.c:5263
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
#define CONSHDLR_MAXPREROUNDS
Definition: cons_xor.c:98
static SCIP_DECL_CONSCHECK(consCheckXor)
Definition: cons_xor.c:5195
#define DEFAULT_PRESOLPAIRWISE
Definition: cons_xor.c:111
static SCIP_DECL_HASHKEYVAL(hashKeyValXorcons)
Definition: cons_xor.c:847
static SCIP_DECL_CONSGETNVARS(consGetNVarsXor)
Definition: cons_xor.c:5852
#define CONSHDLR_SEPAPRIORITY
Definition: cons_xor.c:91
static SCIP_RETCODE analyzeConflict(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *infervar, PROPRULE proprule)
Definition: cons_xor.c:2953
static SCIP_Bool allRowsInLP(SCIP_CONSDATA *consdata)
Definition: cons_xor.c:1808
#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_DECL_CONSENFOPS(consEnfopsXor)
Definition: cons_xor.c:5173
static SCIP_RETCODE addSymmetryInformation(SCIP *scip, SYM_SYMTYPE symtype, SCIP_CONS *cons, SYM_GRAPH *graph, SCIP_Bool *success)
Definition: cons_xor.c:4838
static SCIP_DECL_CONSPARSE(consParseXor)
Definition: cons_xor.c:5681
static SCIP_DECL_CONSINITLP(consInitlpXor)
Definition: cons_xor.c:5017
static SCIP_RETCODE lockRounding(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition: cons_xor.c:189
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyXor)
Definition: cons_xor.c:4914
static SCIP_RETCODE consdataEnsureVarsSize(SCIP *scip, SCIP_CONSDATA *consdata, int num)
Definition: cons_xor.c:318
@ PROPRULE_1
Definition: cons_xor.c:175
@ PROPRULE_INTUB
Definition: cons_xor.c:177
@ PROPRULE_0
Definition: cons_xor.c:174
@ PROPRULE_INTLB
Definition: cons_xor.c:176
@ PROPRULE_INVALID
Definition: cons_xor.c:178
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:1830
#define DEFAULT_PRESOLUSEHASHING
Definition: cons_xor.c:117
static void solveRowEchelonGF2(int m, int n, int r, int *p, int *s, Type **A, Type *b, Type *x)
Definition: cons_xor.c:2298
static SCIP_DECL_CONSENFOLP(consEnfolpXor)
Definition: cons_xor.c:5099
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:2984
static SCIP_DECL_CONSENFORELAX(consEnforelaxXor)
Definition: cons_xor.c:5136
#define MINGAINPERNMINCOMPARISONS
Definition: cons_xor.c:119
static SCIP_RETCODE addExtendedFlowFormulation(SCIP *scip, SCIP_CONS *cons, int *naggrvars, int *naddedconss)
Definition: cons_xor.c:1131
static SCIP_DECL_CONSFREE(consFreeXor)
Definition: cons_xor.c:4930
static SCIP_RETCODE addConflictBounds(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *infervar, SCIP_BDCHGIDX *bdchgidx, PROPRULE proprule)
Definition: cons_xor.c:2845
#define CONSHDLR_PROPFREQ
Definition: cons_xor.c:95
static SCIP_DECL_CONSEXITPRE(consExitpreXor)
Definition: cons_xor.c:5292
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:1976
#define NMINCOMPARISONS
Definition: cons_xor.c:118
#define CONSHDLR_PRESOLTIMING
Definition: cons_xor.c:104
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:3737
#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:3934
#define CONSHDLR_EAGERFREQ
Definition: cons_xor.c:96
#define DEFAULT_ADDEXTENDEDFORM
Definition: cons_xor.c:112
unsigned short Type
Definition: cons_xor.c:131
#define EVENTHDLR_DESC
Definition: cons_xor.c:107
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:4515
static SCIP_DECL_HASHGETKEY(hashGetKeyXorcons)
Definition: cons_xor.c:797
#define NROWS
Definition: cons_xor.c:123
static SCIP_DECL_CONSCOPY(consCopyXor)
Definition: cons_xor.c:5587
#define CONSHDLR_ENFOPRIORITY
Definition: cons_xor.c:92
static SCIP_DECL_LINCONSUPGD(linconsUpgdXor)
Definition: cons_xor.c:4635
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:3426
static SCIP_DECL_CONSPRESOL(consPresolXor)
Definition: cons_xor.c:5324
#define LINCONSUPGD_PRIORITY
Definition: cons_xor.c:109
static SCIP_RETCODE resolvePropagation(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *infervar, PROPRULE proprule, SCIP_BDCHGIDX *bdchgidx, SCIP_RESULT *result)
Definition: cons_xor.c:3405
#define CONSHDLR_DELAYSEPA
Definition: cons_xor.c:99
static int computeRowEchelonGF2(SCIP *scip, int m, int n, int *p, int *s, Type **A, Type *b)
Definition: cons_xor.c:2189
static SCIP_DECL_CONSRESPROP(consRespropXor)
Definition: cons_xor.c:5538
static SCIP_DECL_CONSTRANS(consTransXor)
Definition: cons_xor.c:4991
#define CONSHDLR_NAME
Definition: cons_xor.c:89
#define EVENTHDLR_NAME
Definition: cons_xor.c:106
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_DECL_CONSSEPALP(consSepalpXor)
Definition: cons_xor.c:5037
#define CONSHDLR_DELAYPROP
Definition: cons_xor.c:100
static SCIP_RETCODE consdataPrint(SCIP *scip, SCIP_CONSDATA *consdata, FILE *file, SCIP_Bool endline)
Definition: cons_xor.c:500
static SCIP_DECL_CONSPROP(consPropXor)
Definition: cons_xor.c:5214
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:248
#define SCIP_MAXSTRLEN
Definition: def.h:269
#define SCIP_Longint
Definition: def.h:141
#define SCIP_MAXTREEDEPTH
Definition: def.h:297
#define SCIP_Bool
Definition: def.h:91
#define SCIP_Real
Definition: def.h:156
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:220
#define SCIPABORT()
Definition: def.h:327
#define REALABS(x)
Definition: def.h:182
#define SCIP_CALL(x)
Definition: def.h:355
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:6100
SCIP_RETCODE SCIPcreateConsBasicXor(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_Bool rhs, int nvars, SCIP_VAR **vars)
Definition: cons_xor.c:6084
SCIP_VAR * SCIPgetIntVarXor(SCIP *scip, SCIP_CONS *cons)
Definition: cons_xor.c:6146
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:6014
SCIP_RETCODE SCIPaddCoefSetppc(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition: cons_setppc.c:9573
SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPcreateConsSetpart(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: cons_setppc.c:9402
SCIP_Bool SCIPgetRhsXor(SCIP *scip, SCIP_CONS *cons)
Definition: cons_xor.c:6169
SCIP_VAR ** SCIPgetVarsXor(SCIP *scip, SCIP_CONS *cons)
Definition: cons_xor.c:6123
SCIP_RETCODE SCIPincludeConshdlrXor(SCIP *scip)
Definition: cons_xor.c:5925
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)
Definition: scip_general.c:647
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip_general.c:668
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:759
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:444
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,...)
Definition: scip_message.c:208
#define SCIPdebugMsg
Definition: scip_message.h:78
SCIP_RETCODE SCIPheurPassSolAddSol(SCIP *scip, SCIP_HEUR *heur, SCIP_SOL *sol)
Definition: heur_trysol.c:296
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)
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip_cons.c:808
void SCIPconshdlrSetData(SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons.c:4346
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:540
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:831
SCIP_RETCODE SCIPsetConshdlrInitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITPRE((*consinitpre)))
Definition: scip_cons.c:492
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition: scip_cons.c:235
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip_cons.c:281
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip_cons.c:181
SCIP_RETCODE SCIPsetConshdlrGetPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETPERMSYMGRAPH((*consgetpermsymgraph)))
Definition: scip_cons.c:900
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:578
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:372
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip_cons.c:323
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4316
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip_cons.c:516
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:347
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:940
SCIP_RETCODE SCIPsetConshdlrGetSignedPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH((*consgetsignedpermsymgraph)))
Definition: scip_cons.c:924
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip_cons.c:468
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip_cons.c:624
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4336
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:601
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip_cons.c:647
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:854
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip_cons.c:785
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8419
int SCIPconsGetPos(SCIP_CONS *cons)
Definition: cons.c:8399
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8648
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8409
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8558
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2536
int SCIPconsGetNUpgradeLocks(SCIP_CONS *cons)
Definition: cons.c:8841
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8588
SCIP_Bool SCIPconsIsDeleted(SCIP_CONS *cons)
Definition: cons.c:8518
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8698
SCIP_Bool SCIPconsIsLockedType(SCIP_CONS *cons, SCIP_LOCKTYPE locktype)
Definition: cons.c:8782
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8578
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8450
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip_cons.c:997
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8608
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8628
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8389
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1812
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8638
SCIP_RETCODE SCIPupdateConsFlags(SCIP *scip, SCIP_CONS *cons0, SCIP_CONS *cons1)
Definition: scip_cons.c:1524
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8668
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1173
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8568
SCIP_RETCODE SCIPincConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1784
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8658
SCIP_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)
Definition: scip_probing.c:98
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 SCIPcreateSol(SCIP *scip, SCIP_SOL **sol, SCIP_HEUR *heur)
Definition: scip_sol.c:516
SCIP_RETCODE SCIPfreeSol(SCIP *scip, SCIP_SOL **sol)
Definition: scip_sol.c:1252
SCIP_RETCODE SCIPprintSol(SCIP *scip, SCIP_SOL *sol, FILE *file, SCIP_Bool printzeros)
Definition: scip_sol.c:2349
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:4312
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:23514
int SCIPvarCompareActiveAndNegated(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:17236
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:23868
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:23642
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:23478
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition: scip_var.c:2119
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:23386
int SCIPvarGetNLocksUpType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:4386
SCIP_Real SCIPvarGetAggrConstant(SCIP_VAR *var)
Definition: var.c:23771
SCIP_Bool SCIPdoNotAggr(SCIP *scip)
Definition: scip_var.c:10909
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:24268
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:23430
SCIP_RETCODE SCIPparseVarsList(SCIP *scip, const char *str, SCIP_VAR **vars, int *nvars, int varssize, int *requiredsize, char **endptr, char delimiter, SCIP_Bool *success)
Definition: scip_var.c:805
SCIP_RETCODE SCIPaggregateVars(SCIP *scip, SCIP_VAR *varx, SCIP_VAR *vary, SCIP_Real scalarx, SCIP_Real scalary, SCIP_Real rhs, SCIP_Bool *infeasible, SCIP_Bool *redundant, SCIP_Bool *aggregated)
Definition: scip_var.c:10550
SCIP_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:23900
SCIP_Real SCIPvarGetAggrScalar(SCIP_VAR *var)
Definition: var.c:23748
SCIP_VAR * SCIPvarGetProbvar(SCIP_VAR *var)
Definition: var.c:17550
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:23453
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:24142
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:23652
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:5118
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:5296
SCIP_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:23267
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1887
SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
Definition: scip_var.c:2166
SCIP_Bool SCIPvarIsRemovable(SCIP_VAR *var)
Definition: var.c:23524
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:24234
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition: var.c:23443
SCIP_Real SCIPcomputeVarLbLocal(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:8417
SCIP_VAR * SCIPvarGetNegationVar(SCIP_VAR *var)
Definition: var.c:23878
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:24120
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:23463
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:17274
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:16807
int SCIPvarGetNLocksDownType(SCIP_VAR *var, SCIP_LOCKTYPE locktype)
Definition: var.c:4328
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip_var.c:2078
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1853
SCIP_VAR * SCIPvarGetAggrVar(SCIP_VAR *var)
Definition: var.c:23736
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)
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)
Definition: pub_message.h:102
public data structures and miscellaneous methods
methods for sorting joint arrays of various types
public methods for problem variables
public methods for conflict handler plugins and conflict analysis
public methods for constraint handler plugins and constraints
public methods for problem copies
public methods for cuts and aggregation rows
public methods for event handler plugins and event handlers
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.
Definition: sepa_flower.c:1221
structs for symmetry computations
methods for dealing with symmetry detection graphs
@ SCIP_CONFTYPE_PROPAGATION
Definition: type_conflict.h:62
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:64
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:65
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition: type_event.h:127
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:179
#define SCIP_EVENTTYPE_VARFIXED
Definition: type_event.h:72
@ SCIP_CUTOFF
Definition: type_result.h:48
@ SCIP_FEASIBLE
Definition: type_result.h:45
@ SCIP_REDUCEDDOM
Definition: type_result.h:51
@ SCIP_DIDNOTFIND
Definition: type_result.h:44
@ SCIP_SEPARATED
Definition: type_result.h:49
@ SCIP_SUCCESS
Definition: type_result.h:58
@ SCIP_INFEASIBLE
Definition: type_result.h:46
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:61
@ SCIP_INVALIDDATA
Definition: type_retcode.h:52
@ SCIP_PLUGINNOTFOUND
Definition: type_retcode.h:54
@ SCIP_OKAY
Definition: type_retcode.h:42
@ SCIP_INVALIDCALL
Definition: type_retcode.h:51
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_STAGE_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
enum SYM_Symtype SYM_SYMTYPE
Definition: type_symmetry.h:64
@ SYM_CONSOPTYPE_XORINT
Definition: type_symmetry.h:94
@ SYM_SYMTYPE_SIGNPERM
Definition: type_symmetry.h:62
@ SYM_SYMTYPE_PERM
Definition: type_symmetry.h:61
#define SCIP_PRESOLTIMING_MEDIUM
Definition: type_timing.h:53
#define SCIP_PRESOLTIMING_EXHAUSTIVE
Definition: type_timing.h:54
@ SCIP_IMPLINTTYPE_WEAK
Definition: type_var.h:91
@ 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