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