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-2014 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_xor.c
17  * @brief Constraint handler for "xor" constraints, \f$rhs = x_1 \oplus x_2 \oplus \dots \oplus x_n\f$
18  * @author Tobias Achterberg
19  * @author Stefan Heinz
20  * @author Marc Pfetsch
21  * @author Michael Winkler
22  *
23  * This constraint handler deals with "xor" constraint. These are constraint of the form:
24  *
25  * \f[
26  * rhs = x_1 \oplus x_2 \oplus \dots \oplus x_n
27  * \f]
28  *
29  * 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
30  * operators. This constraint is satisfied if \f$rhs\f$ is TRUE and an odd number of the operators are TRUE or if the
31  * \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.
32  */
33 
34 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
35 
36 #include <assert.h>
37 #include <string.h>
38 
39 #include "scip/pub_misc.h"
40 #include "scip/cons_xor.h"
41 #include "scip/cons_setppc.h"
42 #include "scip/cons_linear.h"
43 #include "scip/heur_trysol.h"
44 #include "scip/debug.h"
45 
46 
47 /* constraint handler properties */
48 #define CONSHDLR_NAME "xor"
49 #define CONSHDLR_DESC "constraint handler for xor constraints: r = xor(x1, ..., xn)"
50 #define CONSHDLR_SEPAPRIORITY +850200 /**< priority of the constraint handler for separation */
51 #define CONSHDLR_ENFOPRIORITY -850200 /**< priority of the constraint handler for constraint enforcing */
52 #define CONSHDLR_CHECKPRIORITY -850200 /**< priority of the constraint handler for checking feasibility */
53 #define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
54 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
55 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
56  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
57 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
58 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
59 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
60 #define CONSHDLR_DELAYPRESOL FALSE /**< should presolving method be delayed, if other presolvers found reductions? */
61 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
62 
63 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
64 
65 #define EVENTHDLR_NAME "xor"
66 #define EVENTHDLR_DESC "event handler for xor constraints"
67 
68 #define DEFAULT_PRESOLPAIRWISE TRUE /**< should pairwise constraint comparison be performed in presolving? */
69 #define DEFAULT_ADDEXTENDEDFORM FALSE /**< should the extended formulation be added in presolving? */
70 #define DEFAULT_ADDFLOWEXTENDED FALSE /**< should the extended flow formulation be added (nonsymmetric formulation otherwise)? */
71 #define DEFAULT_SEPARATEPARITY FALSE /**< should parity inequalities be separated? */
72 #define DEFAULT_GAUSSPROPFREQ 5 /**< frequency for applying the Gauss propagator */
73 #define HASHSIZE_XORCONS 131101 /**< minimal size of hash table in logicor constraint tables */
74 #define DEFAULT_PRESOLUSEHASHING TRUE /**< should hash table be used for detecting redundant constraints in advance */
75 #define NMINCOMPARISONS 200000 /**< number for minimal pairwise presolving comparisons */
76 #define MINGAINPERNMINCOMPARISONS 1e-06 /**< minimal gain per minimal pairwise presolving comparisons to repeat pairwise comparison round */
77 #define MAXXORCONSSSYSTEM 1000 /**< maximal number of active constraints for which checking the system over GF2 is performed */
78 #define MAXXORVARSSYSTEM 1000 /**< maximal number of variables in xor constraints for which checking the system over GF2 is performed */
79 
80 #define NROWS 4
81 
82 
83 /*
84  * Data structures
85  */
86 
87 /** type used for matrix entries in function checkGauss() */
88 typedef unsigned short Type;
89 
90 /** constraint data for xor constraints */
91 struct SCIP_ConsData
92 {
93  SCIP_VAR** vars; /**< variables in the xor operation */
94  SCIP_VAR* intvar; /**< internal variable for LP relaxation */
95  SCIP_VAR** extvars; /**< variables in extended (flow|asymmetric) formulation (order for flow formulation: nn, ns, sn, ss) */
96  SCIP_ROW* rows[NROWS]; /**< rows for linear relaxation of xor constraint */
97  int nvars; /**< number of variables in xor operation */
98  int nextvars; /**< number of variables in extended flow formulation */
99  int varssize; /**< size of vars array */
100  int extvarssize; /**< size of extvars array */
101  int watchedvar1; /**< position of first watched operator variable */
102  int watchedvar2; /**< position of second watched operator variable */
103  int filterpos1; /**< event filter position of first watched operator variable */
104  int filterpos2; /**< event filter position of second watched operator variable */
105  SCIP_Bool rhs; /**< right hand side of the constraint */
106  unsigned int deleteintvar:1; /**< should artificial variable be deleted */
107  unsigned int propagated:1; /**< is constraint already preprocessed/propagated? */
108  unsigned int sorted:1; /**< are the constraint's variables sorted? */
109  unsigned int changed:1; /**< was constraint changed since last pair preprocessing round? */
110 };
111 
112 /** constraint handler data */
113 struct SCIP_ConshdlrData
114 {
115  SCIP_EVENTHDLR* eventhdlr; /**< event handler for events on watched variables */
116  SCIP_Bool presolpairwise; /**< should pairwise constraint comparison be performed in presolving? */
117  SCIP_Bool presolusehashing; /**< should hash table be used for detecting redundant constraints in advance? */
118  SCIP_Bool addextendedform; /**< should the extended formulation be added in presolving? */
119  SCIP_Bool addflowextended; /**< should the extended flow formulation be added (nonsymmetric formulation otherwise)? */
120  SCIP_Bool separateparity; /**< should parity inequalities be separated? */
121  int gausspropfreq; /**< frequency for applying the Gauss propagator */
122 };
123 
124 
125 /*
126  * Propagation rules
127  */
128 
130 {
131  PROPRULE_0, /**< all variables are fixed => fix integral variable */
132  PROPRULE_1, /**< all except one variable fixed => fix remaining variable */
133  PROPRULE_INTLB, /**< lower bound propagation of integral variable */
134  PROPRULE_INTUB, /**< upper bound propagation of integral variable */
135  PROPRULE_INVALID /**< propagation was applied without a specific propagation rule */
136 };
137 typedef enum Proprule PROPRULE;
138 
139 
140 /*
141  * Local methods
142  */
143 
144 /** installs rounding locks for the given variable in the given xor constraint */
145 static
147  SCIP* scip, /**< SCIP data structure */
148  SCIP_CONS* cons, /**< xor constraint */
149  SCIP_VAR* var /**< variable of constraint entry */
150  )
151 {
152  /* rounding in both directions may violate the constraint */
153  SCIP_CALL( SCIPlockVarCons(scip, var, cons, TRUE, TRUE) );
154 
155  return SCIP_OKAY;
156 }
157 
158 /** removes rounding locks for the given variable in the given xor constraint */
159 static
161  SCIP* scip, /**< SCIP data structure */
162  SCIP_CONS* cons, /**< xor constraint */
163  SCIP_VAR* var /**< variable of constraint entry */
164  )
165 {
166  /* rounding in both directions may violate the constraint */
167  SCIP_CALL( SCIPunlockVarCons(scip, var, cons, TRUE, TRUE) );
168 
169  return SCIP_OKAY;
170 }
171 
172 /** creates constraint handler data */
173 static
175  SCIP* scip, /**< SCIP data structure */
176  SCIP_CONSHDLRDATA** conshdlrdata, /**< pointer to store the constraint handler data */
177  SCIP_EVENTHDLR* eventhdlr /**< event handler */
178  )
179 {
180  assert(scip != NULL);
181  assert(conshdlrdata != NULL);
182  assert(eventhdlr != NULL);
183 
184  SCIP_CALL( SCIPallocMemory(scip, conshdlrdata) );
185 
186  /* set event handler for catching events on watched variables */
187  (*conshdlrdata)->eventhdlr = eventhdlr;
188 
189  return SCIP_OKAY;
190 }
191 
192 /** frees constraint handler data */
193 static
195  SCIP* scip, /**< SCIP data structure */
196  SCIP_CONSHDLRDATA** conshdlrdata /**< pointer to the constraint handler data */
197  )
198 {
199  assert(conshdlrdata != NULL);
200  assert(*conshdlrdata != NULL);
201 
202  SCIPfreeMemory(scip, conshdlrdata);
203 
204  return SCIP_OKAY;
205 }
206 
207 /** stores the given variable numbers as watched variables, and updates the event processing */
208 static
210  SCIP* scip, /**< SCIP data structure */
211  SCIP_CONSDATA* consdata, /**< xor constraint data */
212  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
213  int watchedvar1, /**< new first watched variable */
214  int watchedvar2 /**< new second watched variable */
215  )
216 {
217  assert(consdata != NULL);
218  assert(watchedvar1 == -1 || watchedvar1 != watchedvar2);
219  assert(watchedvar1 != -1 || watchedvar2 == -1);
220  assert(watchedvar1 == -1 || (0 <= watchedvar1 && watchedvar1 < consdata->nvars));
221  assert(watchedvar2 == -1 || (0 <= watchedvar2 && watchedvar2 < consdata->nvars));
222 
223  /* if one watched variable is equal to the old other watched variable, just switch positions */
224  if( watchedvar1 == consdata->watchedvar2 || watchedvar2 == consdata->watchedvar1 )
225  {
226  int tmp;
227 
228  tmp = consdata->watchedvar1;
229  consdata->watchedvar1 = consdata->watchedvar2;
230  consdata->watchedvar2 = tmp;
231  tmp = consdata->filterpos1;
232  consdata->filterpos1 = consdata->filterpos2;
233  consdata->filterpos2 = tmp;
234  }
235  assert(watchedvar1 == -1 || watchedvar1 != consdata->watchedvar2);
236  assert(watchedvar2 == -1 || watchedvar2 != consdata->watchedvar1);
237 
238  /* drop events on old watched variables */
239  if( consdata->watchedvar1 != -1 && consdata->watchedvar1 != watchedvar1 )
240  {
241  assert(consdata->filterpos1 != -1);
242  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[consdata->watchedvar1], SCIP_EVENTTYPE_BOUNDCHANGED, eventhdlr,
243  (SCIP_EVENTDATA*)consdata, consdata->filterpos1) );
244  }
245  if( consdata->watchedvar2 != -1 && consdata->watchedvar2 != watchedvar2 )
246  {
247  assert(consdata->filterpos2 != -1);
248  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[consdata->watchedvar2], SCIP_EVENTTYPE_BOUNDCHANGED, eventhdlr,
249  (SCIP_EVENTDATA*)consdata, consdata->filterpos2) );
250  }
251 
252  /* catch events on new watched variables */
253  if( watchedvar1 != -1 && watchedvar1 != consdata->watchedvar1 )
254  {
255  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[watchedvar1], SCIP_EVENTTYPE_BOUNDCHANGED, eventhdlr,
256  (SCIP_EVENTDATA*)consdata, &consdata->filterpos1) );
257  }
258  if( watchedvar2 != -1 && watchedvar2 != consdata->watchedvar2 )
259  {
260  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[watchedvar2], SCIP_EVENTTYPE_BOUNDCHANGED, eventhdlr,
261  (SCIP_EVENTDATA*)consdata, &consdata->filterpos2) );
262  }
263 
264  /* set the new watched variables */
265  consdata->watchedvar1 = watchedvar1;
266  consdata->watchedvar2 = watchedvar2;
267 
268  return SCIP_OKAY;
269 }
270 
271 /** ensures, that the vars array can store at least num entries */
272 static
274  SCIP* scip, /**< SCIP data structure */
275  SCIP_CONSDATA* consdata, /**< linear constraint data */
276  int num /**< minimum number of entries to store */
277  )
278 {
279  assert(consdata != NULL);
280  assert(consdata->nvars <= consdata->varssize);
281 
282  if( num > consdata->varssize )
283  {
284  int newsize;
285 
286  newsize = SCIPcalcMemGrowSize(scip, num);
287  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->varssize, newsize) );
288  consdata->varssize = newsize;
289  }
290  assert(num <= consdata->varssize);
291 
292  return SCIP_OKAY;
293 }
294 
295 /** creates constraint data for xor constraint */
296 static
298  SCIP* scip, /**< SCIP data structure */
299  SCIP_CONSDATA** consdata, /**< pointer to store the constraint data */
300  SCIP_Bool rhs, /**< right hand side of the constraint */
301  int nvars, /**< number of variables in the xor operation */
302  SCIP_VAR** vars, /**< variables in xor operation */
303  SCIP_VAR* intvar /**< artificial integer variable for linear relaxation */
304  )
305 {
306  int r;
307 
308  assert(consdata != NULL);
309  assert(nvars == 0 || vars != NULL);
310 
311  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
312  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars, vars, nvars) );
313 
314  (*consdata)->rhs = rhs;
315  (*consdata)->intvar = intvar;
316  for( r = 0; r < NROWS; ++r )
317  (*consdata)->rows[r] = NULL;
318  (*consdata)->nvars = nvars;
319  (*consdata)->varssize = nvars;
320  (*consdata)->watchedvar1 = -1;
321  (*consdata)->watchedvar2 = -1;
322  (*consdata)->filterpos1 = -1;
323  (*consdata)->filterpos2 = -1;
324  (*consdata)->deleteintvar = (intvar == NULL);
325  (*consdata)->propagated = FALSE;
326  (*consdata)->sorted = FALSE;
327  (*consdata)->changed = TRUE;
328  (*consdata)->extvars = NULL;
329  (*consdata)->nextvars = 0;
330  (*consdata)->extvarssize = 0;
331 
332  /* get transformed variables, if we are in the transformed problem */
333  if( SCIPisTransformed(scip) )
334  {
335  SCIP_CALL( SCIPgetTransformedVars(scip, (*consdata)->nvars, (*consdata)->vars, (*consdata)->vars) );
336 
337  if( (*consdata)->intvar != NULL )
338  {
339  SCIP_CALL( SCIPgetTransformedVar(scip, (*consdata)->intvar, &((*consdata)->intvar)) );
340  }
341  }
342 
343  if( (*consdata)->intvar != NULL )
344  {
345  /* capture artificial variable */
346  SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->intvar) );
347  }
348 
349  return SCIP_OKAY;
350 }
351 
352 /** releases LP row of constraint data */
353 static
355  SCIP* scip, /**< SCIP data structure */
356  SCIP_CONSDATA* consdata /**< constraint data */
357  )
358 {
359  int r;
360 
361  assert(consdata != NULL);
362 
363  for( r = 0; r < NROWS; ++r )
364  {
365  if( consdata->rows[r] != NULL )
366  {
367  SCIP_CALL( SCIPreleaseRow(scip, &consdata->rows[r]) );
368  }
369  }
370 
371  return SCIP_OKAY;
372 }
373 
374 /** frees constraint data for xor constraint */
375 static
377  SCIP* scip, /**< SCIP data structure */
378  SCIP_CONSDATA** consdata, /**< pointer to the constraint data */
379  SCIP_EVENTHDLR* eventhdlr /**< event handler to call for the event processing */
380  )
381 {
382  assert(consdata != NULL);
383  assert(*consdata != NULL);
384 
385  if( SCIPisTransformed(scip) )
386  {
387  int j;
388 
389  /* drop events for watched variables */
390  SCIP_CALL( consdataSwitchWatchedvars(scip, *consdata, eventhdlr, -1, -1) );
391 
392  /* release flow variables */
393  if ( (*consdata)->nextvars > 0 )
394  {
395  assert( (*consdata)->extvars != NULL );
396  for (j = 0; j < (*consdata)->extvarssize; ++j)
397  {
398  if ( (*consdata)->extvars[j] != NULL )
399  {
400  SCIP_CALL( SCIPreleaseVar(scip, &((*consdata)->extvars[j])) );
401  }
402  }
403 
404  SCIPfreeBlockMemoryArray(scip, &((*consdata)->extvars), (*consdata)->extvarssize);
405  (*consdata)->nextvars = 0;
406  (*consdata)->extvarssize = 0;
407  }
408  }
409  else
410  {
411  assert((*consdata)->watchedvar1 == -1);
412  assert((*consdata)->watchedvar2 == -1);
413  }
414 
415  /* release LP row */
416  SCIP_CALL( consdataFreeRows(scip, *consdata) );
417 
418  /* release internal variable */
419  if( (*consdata)->intvar != NULL )
420  {
421  /* if the constraint is deleted and the integral variable is present, it should be fixed */
422  assert( SCIPisEQ(scip, SCIPvarGetLbGlobal((*consdata)->intvar), SCIPvarGetLbGlobal((*consdata)->intvar)) );
423 
424  /* We do not delete the integral variable, but leave the handling to SCIP, because it might happen that the
425  integral variable is stored in some basis information somewhere. */
426  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->intvar) );
427  }
428 
429  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->varssize);
430  SCIPfreeBlockMemory(scip, consdata);
431 
432  return SCIP_OKAY;
433 }
434 
435 /** prints xor constraint to file stream */
436 static
438  SCIP* scip, /**< SCIP data structure */
439  SCIP_CONSDATA* consdata, /**< xor constraint data */
440  FILE* file, /**< output file (or NULL for standard output) */
441  SCIP_Bool endline /**< should an endline be set? */
442  )
443 {
444  assert(consdata != NULL);
445 
446  /* start variable list */
447  SCIPinfoMessage(scip, file, "xor(");
448 
449  /* print variable list */
450  SCIP_CALL( SCIPwriteVarsList(scip, file, consdata->vars, consdata->nvars, TRUE, ',') );
451 
452  /* close variable list and write right hand side */
453  SCIPinfoMessage(scip, file, ") = %d", consdata->rhs);
454 
455  if( endline )
456  SCIPinfoMessage(scip, file, "\n");
457 
458  return SCIP_OKAY;
459 }
460 
461 /** adds coefficient to xor constraint */
462 static
464  SCIP* scip, /**< SCIP data structure */
465  SCIP_CONS* cons, /**< linear constraint */
466  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
467  SCIP_VAR* var /**< variable to add to the constraint */
468  )
469 { /*lint --e{715}*/
470  SCIP_CONSDATA* consdata;
471  SCIP_Bool transformed;
472 
473  assert(var != NULL);
474 
475  consdata = SCIPconsGetData(cons);
476  assert(consdata != NULL);
477  assert(consdata->rows[0] == NULL);
478 
479  /* are we in the transformed problem? */
480  transformed = SCIPconsIsTransformed(cons);
481 
482  /* always use transformed variables in transformed constraints */
483  if( transformed )
484  {
485  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
486  }
487  assert(var != NULL);
488  assert(transformed == SCIPvarIsTransformed(var));
489 
490  SCIP_CALL( consdataEnsureVarsSize(scip, consdata, consdata->nvars+1) );
491  consdata->vars[consdata->nvars] = var;
492  consdata->nvars++;
493  consdata->sorted = (consdata->nvars == 1);
494  consdata->changed = TRUE;
495 
496  /* install the rounding locks for the new variable */
497  SCIP_CALL( lockRounding(scip, cons, var) );
498 
499  /**@todo update LP rows */
500  if( consdata->rows[0] != NULL )
501  {
502  SCIPerrorMessage("cannot add coefficients to xor constraint after LP relaxation was created\n");
503  return SCIP_INVALIDCALL;
504  }
505 
506  return SCIP_OKAY;
507 }
508 
509 /** deletes coefficient at given position from xor constraint data */
510 static
512  SCIP* scip, /**< SCIP data structure */
513  SCIP_CONS* cons, /**< xor constraint */
514  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
515  int pos /**< position of coefficient to delete */
516  )
517 {
518  SCIP_CONSDATA* consdata;
519 
520  assert(eventhdlr != NULL);
521 
522  consdata = SCIPconsGetData(cons);
523  assert(consdata != NULL);
524  assert(0 <= pos && pos < consdata->nvars);
525  assert(SCIPconsIsTransformed(cons) == SCIPvarIsTransformed(consdata->vars[pos]));
526 
527  /* remove the rounding locks of the deleted variable */
528  SCIP_CALL( unlockRounding(scip, cons, consdata->vars[pos]) );
529 
530  if( SCIPconsIsTransformed(cons) )
531  {
532  /* if the position is watched, stop watching the position */
533  if( consdata->watchedvar1 == pos )
534  {
535  SCIP_CALL( consdataSwitchWatchedvars(scip, consdata, eventhdlr, consdata->watchedvar2, -1) );
536  }
537  if( consdata->watchedvar2 == pos )
538  {
539  SCIP_CALL( consdataSwitchWatchedvars(scip, consdata, eventhdlr, consdata->watchedvar1, -1) );
540  }
541  }
542  assert(pos != consdata->watchedvar1);
543  assert(pos != consdata->watchedvar2);
544 
545  /* move the last variable to the free slot */
546  consdata->vars[pos] = consdata->vars[consdata->nvars-1];
547  consdata->nvars--;
548 
549  /* if the last variable (that moved) was watched, update the watched position */
550  if( consdata->watchedvar1 == consdata->nvars )
551  consdata->watchedvar1 = pos;
552  if( consdata->watchedvar2 == consdata->nvars )
553  consdata->watchedvar2 = pos;
554 
555  consdata->propagated = FALSE;
556  consdata->sorted = FALSE;
557  consdata->changed = TRUE;
558 
559  return SCIP_OKAY;
560 }
561 
562 /** sorts and constraint's variables by non-decreasing variable index */
563 static
565  SCIP_CONSDATA* consdata /**< constraint data */
566  )
567 {
568  assert(consdata != NULL);
569 
570  if( !consdata->sorted )
571  {
572  if( consdata->nvars <= 1 )
573  consdata->sorted = TRUE;
574  else
575  {
576  SCIP_VAR* var1 = NULL;
577  SCIP_VAR* var2 = NULL;
578 
579  /* remember watch variables */
580  if( consdata->watchedvar1 != -1 )
581  {
582  var1 = consdata->vars[consdata->watchedvar1];
583  assert(var1 != NULL);
584  consdata->watchedvar1 = -1;
585  if( consdata->watchedvar2 != -1 )
586  {
587  var2 = consdata->vars[consdata->watchedvar2];
588  assert(var2 != NULL);
589  consdata->watchedvar2 = -1;
590  }
591  }
592  assert(consdata->watchedvar1 == -1);
593  assert(consdata->watchedvar2 == -1);
594  assert(var1 != NULL || var2 == NULL);
595 
596  /* sort variables after index */
597  SCIPsortPtr((void**)consdata->vars, SCIPvarCompActiveAndNegated, consdata->nvars);
598  consdata->sorted = TRUE;
599 
600  /* correct watched variables */
601  if( var1 != NULL )
602  {
603  int pos;
604 #ifndef NDEBUG
605  SCIP_Bool found;
606 
607  found = SCIPsortedvecFindPtr((void**)consdata->vars, SCIPvarCompActiveAndNegated, (void*)var1, consdata->nvars, &pos);
608  assert(found);
609 #else
610  SCIPsortedvecFindPtr((void**)consdata->vars, SCIPvarCompActiveAndNegated, (void*)var1, consdata->nvars, &pos);
611 #endif
612  assert(pos >= 0 && pos < consdata->nvars);
613  consdata->watchedvar1 = pos;
614 
615  if( var2 != NULL )
616  {
617 #ifndef NDEBUG
618  found = SCIPsortedvecFindPtr((void**)consdata->vars, SCIPvarCompActiveAndNegated, (void*)var2, consdata->nvars, &pos);
619  assert(found);
620 #else
621  SCIPsortedvecFindPtr((void**)consdata->vars, SCIPvarCompActiveAndNegated, (void*)var2, consdata->nvars, &pos);
622 #endif
623  assert(pos >= 0 && pos < consdata->nvars);
624  consdata->watchedvar2 = pos;
625  }
626  }
627  }
628  }
629 
630 #ifdef SCIP_DEBUG
631  /* check sorting */
632  {
633  int v;
634 
635  for( v = 0; v < consdata->nvars; ++v )
636  {
637  assert(v == consdata->nvars-1 || SCIPvarCompareActiveAndNegated(consdata->vars[v], consdata->vars[v+1]) <= 0);
638  }
639  }
640 #endif
641 }
642 
643 
644 /** gets the key of the given element */
645 static
646 SCIP_DECL_HASHGETKEY(hashGetKeyXorcons)
647 { /*lint --e{715}*/
648  /* the key is the element itself */
649  return elem;
650 }
651 
652 /** returns TRUE iff both keys are equal; two constraints are equal if they have the same variables */
653 static
654 SCIP_DECL_HASHKEYEQ(hashKeyEqXorcons)
655 {
656  SCIP_CONSDATA* consdata1;
657  SCIP_CONSDATA* consdata2;
658  int i;
659 #ifndef NDEBUG
660  SCIP* scip;
661 
662  scip = (SCIP*)userptr;
663  assert(scip != NULL);
664 #endif
665 
666  consdata1 = SCIPconsGetData((SCIP_CONS*)key1);
667  consdata2 = SCIPconsGetData((SCIP_CONS*)key2);
668 
669  /* checks trivial case */
670  if( consdata1->nvars != consdata2->nvars )
671  return FALSE;
672 
673  /* sorts the constraints */
674  consdataSort(consdata1);
675  consdataSort(consdata2);
676  assert(consdata1->sorted);
677  assert(consdata2->sorted);
678 
679  for( i = 0; i < consdata1->nvars ; ++i )
680  {
681  /* tests if variables are equal */
682  if( consdata1->vars[i] != consdata2->vars[i] )
683  {
684  assert(SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == 1 ||
685  SCIPvarCompare(consdata1->vars[i], consdata2->vars[i]) == -1);
686  return FALSE;
687  }
688  assert(SCIPvarCompareActiveAndNegated(consdata1->vars[i], consdata2->vars[i]) == 0);
689  }
690 
691  return TRUE;
692 }
693 
694 /** returns the hash value of the key */
695 static
696 SCIP_DECL_HASHKEYVAL(hashKeyValXorcons)
697 { /*lint --e{715}*/
698  SCIP_CONSDATA* consdata;
699  unsigned int hashval;
700  int minidx;
701  int mididx;
702  int maxidx;
703 
704  consdata = SCIPconsGetData((SCIP_CONS*)key);
705  assert(consdata != NULL);
706  assert(consdata->sorted);
707  assert(consdata->nvars > 0);
708 
709  /* only active, fixed or negated variables are allowed */
710  assert(consdata->vars[0] != NULL);
711  assert(consdata->vars[consdata->nvars / 2] != NULL);
712  assert(consdata->vars[consdata->nvars - 1] != NULL);
713  assert(SCIPvarIsActive(consdata->vars[0]) || SCIPvarGetStatus(consdata->vars[0]) == SCIP_VARSTATUS_NEGATED || SCIPvarGetStatus(consdata->vars[0]) == SCIP_VARSTATUS_FIXED);
714  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);
715  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);
716 
717  minidx = SCIPvarGetIndex(consdata->vars[0]);
718  mididx = SCIPvarGetIndex(consdata->vars[consdata->nvars / 2]);
719  maxidx = SCIPvarGetIndex(consdata->vars[consdata->nvars - 1]);
720  /* note that for all indices it does not hold that they are sorted, because variables are sorted with
721  * SCIPvarCompareActiveAndNegated (see var.c)
722  */
723 
724  hashval = (consdata->nvars << 29) + (minidx << 22) + (mididx << 11) + maxidx; /*lint !e701*/
725 
726  return hashval;
727 }
728 
729 /** deletes all fixed variables and all pairs equal variables variables */
730 static
732  SCIP* scip, /**< SCIP data structure */
733  SCIP_CONS* cons, /**< xor constraint */
734  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
735  int* nchgcoefs /**< pointer to add up the number of changed coefficients */
736  )
737 {
738  SCIP_CONSDATA* consdata;
739  int v;
740 
741  consdata = SCIPconsGetData(cons);
742  assert(consdata != NULL);
743  assert(consdata->nvars == 0 || consdata->vars != NULL);
744  assert(nchgcoefs != NULL);
745 
746  SCIPdebugMessage("before fixings: ");
747  SCIPdebug( SCIP_CALL(consdataPrint(scip, consdata, NULL, TRUE)) );
748 
749  v = 0;
750  while( v < consdata->nvars )
751  {
752  SCIP_VAR* var;
753 
754  var = consdata->vars[v];
755  assert(SCIPvarIsBinary(var));
756 
757  if( SCIPvarGetUbGlobal(var) < 0.5 )
758  {
759  assert(SCIPisEQ(scip, SCIPvarGetLbGlobal(var), 0.0));
760  SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
761  (*nchgcoefs)++;
762  }
763  else if( SCIPvarGetLbGlobal(var) > 0.5 )
764  {
765  assert(SCIPisEQ(scip, SCIPvarGetUbGlobal(var), 1.0));
766  SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
767  consdata->rhs = !consdata->rhs;
768  (*nchgcoefs)++;
769  }
770  else
771  {
772  SCIP_VAR* repvar;
773  SCIP_Bool negated;
774 
775  /* get binary representative of variable */
776  SCIP_CALL( SCIPgetBinvarRepresentative(scip, var, &repvar, &negated) );
777 
778  /* remove all negations by replacing them with the active variable
779  * it holds that xor(x1, ~x2) = 0 <=> xor(x1, x2) = 1
780  */
781  if( negated )
782  {
783  assert(SCIPvarIsNegated(repvar));
784 
785  repvar = SCIPvarGetNegationVar(repvar);
786  consdata->rhs = !consdata->rhs;
787  }
788 
789  /* check, if the variable should be replaced with the representative */
790  if( repvar != var )
791  {
792  /* delete old (aggregated) variable */
793  SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
794 
795  /* add representative instead */
796  SCIP_CALL( addCoef(scip, cons, eventhdlr, repvar) );
797  }
798  else
799  ++v;
800  }
801  }
802 
803  /* sort the variables in the constraint */
804  consdataSort(consdata);
805  assert(consdata->sorted);
806 
807  SCIPdebugMessage("after sort : ");
808  SCIPdebug( SCIP_CALL(consdataPrint(scip, consdata, NULL, TRUE)) );
809 
810  /* delete pairs of equal or negated variables; scan from back to front because deletion doesn't affect the
811  * order of the front variables
812  */
813  v = consdata->nvars-2;
814  while ( v >= 0 )
815  {
816  if( consdata->vars[v] == consdata->vars[v+1] )
817  {
818  /* delete both variables */
819  SCIPdebugMessage("xor constraint <%s>: deleting pair of equal variables <%s>\n",
820  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[v]));
821  SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v+1) );
822  SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
823  (*nchgcoefs) += 2;
824  v = MIN(v, consdata->nvars-1);
825  }
826  else if( consdata->vars[v] == SCIPvarGetNegatedVar(consdata->vars[v+1]) )
827  {
828  /* delete both variables and negate the rhs */
829  SCIPdebugMessage("xor constraint <%s>: deleting pair of negated variables <%s> and <%s>\n",
830  SCIPconsGetName(cons), SCIPvarGetName(consdata->vars[v]), SCIPvarGetName(consdata->vars[v+1]));
831  SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v+1) );
832  SCIP_CALL( delCoefPos(scip, cons, eventhdlr, v) );
833  (*nchgcoefs) += 2;
834  consdata->rhs = !consdata->rhs;
835  v = MIN(v, consdata->nvars-1);
836  }
837  else
838  assert(SCIPvarGetProbvar(consdata->vars[v]) != SCIPvarGetProbvar(consdata->vars[v+1]));
839  --v;
840  }
841 
842  SCIPdebugMessage("after fixings : ");
843  SCIPdebug( SCIP_CALL(consdataPrint(scip, consdata, NULL, TRUE)) );
844 
845  return SCIP_OKAY;
846 }
847 
848 /** adds extended flow formulation
849  *
850  * The extended flow formulation is built as follows: Let \f$x_1, \dots, x_k\f$ be the variables contained in the given
851  * XOR constraint. We construct a two layered flow network. The upper layer is called the north layer and the lower is
852  * 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
853  * (denoted by 'nn' and 'ss', respectively), as well as arcs that change the layers (denoted by 'ns' and 'sn'). For
854  * \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
855  * \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
856  * located on the north or south layer. A change in the layers corresponds to a parity change, i.e., the corresponding
857  * variable \f$x_i\f$ is 1 (and 0 otherwise).
858  */
859 static
861  SCIP* scip, /**< SCIP data structure */
862  SCIP_CONS* cons, /**< constraint to check */
863  int* naddedconss /**< number of added constraints */
864  )
865 {
866  char name[SCIP_MAXSTRLEN];
867  SCIP_CONSDATA* consdata;
868  SCIP_VAR* varprevnn = NULL;
869  SCIP_VAR* varprevns = NULL;
870  SCIP_VAR* varprevsn = NULL;
871  SCIP_VAR* varprevss = NULL;
872  SCIP_VAR* vars[4];
873  SCIP_Real vals[4];
874  int i;
875 
876  assert( scip != NULL );
877  assert( cons != NULL );
878  assert( naddedconss != NULL );
879  *naddedconss = 0;
880 
881  /* exit if contraints is modifiable */
882  if ( SCIPconsIsModifiable(cons) )
883  return SCIP_OKAY;
884 
885  consdata = SCIPconsGetData(cons);
886  assert( consdata != NULL );
887 
888  /* exit if extended formulation has been added already */
889  if ( consdata->extvars != NULL )
890  return SCIP_OKAY;
891 
892  /* xor constraints with at most 3 variables are handled directly through rows for the convex hull */
893  if ( consdata->nvars <= 3 )
894  return SCIP_OKAY;
895 
896  SCIPdebugMessage("Add extended formulation for xor constraint <%s> ...\n", SCIPconsGetName(cons));
897  assert( consdata->extvars == NULL );
898  assert( consdata->nextvars == 0 );
899  assert( consdata->extvarssize == 0 );
900 
901  /* get storage for auxiliary variables */
902  consdata->extvarssize = 4 * (consdata->nvars);
903  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(consdata->extvars), consdata->extvarssize) );
904 
905  /* pass through components */
906  for (i = 0; i < consdata->nvars; ++i)
907  {
908  /* variables: n - north, s - south */
909  SCIP_VAR* varnn = NULL;
910  SCIP_VAR* varns = NULL;
911  SCIP_VAR* varsn = NULL;
912  SCIP_VAR* varss = NULL;
913  SCIP_CONS* newcons;
914  SCIP_Real rhs = 0.0;
915  SCIP_Bool infeasible = FALSE;
916  SCIP_Bool redundant = FALSE;
917  SCIP_Bool aggregated = FALSE;
918  int cnt = 0;
919 
920  /* create variables */
921  if ( i == 0 )
922  {
923  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_nn", SCIPconsGetName(cons), i);
924  SCIP_CALL( SCIPcreateVar(scip, &varnn, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT, SCIPconsIsInitial(cons), SCIPconsIsRemovable(cons), NULL, NULL, NULL, NULL, NULL) );
925  SCIP_CALL( SCIPaddVar(scip, varnn) );
926 
927  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_ns", SCIPconsGetName(cons), i);
928  SCIP_CALL( SCIPcreateVar(scip, &varns, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT, SCIPconsIsInitial(cons), SCIPconsIsRemovable(cons), NULL, NULL, NULL, NULL, NULL) );
929  SCIP_CALL( SCIPaddVar(scip, varns) );
930 
931  /* need to lock variables, because we aggregate them */
932  SCIP_CALL( SCIPlockVarCons(scip, varnn, cons, TRUE, TRUE) );
933  SCIP_CALL( SCIPlockVarCons(scip, varns, cons, TRUE, TRUE) );
934 
935  /* aggregate ns variable with original variable */
936  SCIP_CALL( SCIPaggregateVars(scip, varns, consdata->vars[0], 1.0, -1.0, 0.0, &infeasible, &redundant, &aggregated) );
937  assert( ! infeasible );
938  assert( redundant );
939  assert( aggregated );
940  }
941  else
942  {
943  if ( i == consdata->nvars-1 )
944  {
945  if ( consdata->rhs )
946  {
947  /* if the rhs is 1 (true) the flow goes to the bottom level */
948  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_ns", SCIPconsGetName(cons), i);
949  SCIP_CALL( SCIPcreateVar(scip, &varns, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT, SCIPconsIsInitial(cons), SCIPconsIsRemovable(cons), NULL, NULL, NULL, NULL, NULL) );
950  SCIP_CALL( SCIPaddVar(scip, varns) );
951 
952  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_ss", SCIPconsGetName(cons), i);
953  SCIP_CALL( SCIPcreateVar(scip, &varss, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT, SCIPconsIsInitial(cons), SCIPconsIsRemovable(cons), NULL, NULL, NULL, NULL, NULL) );
954  SCIP_CALL( SCIPaddVar(scip, varss) );
955 
956  /* need to lock variables, because we aggregate them */
957  SCIP_CALL( SCIPlockVarCons(scip, varns, cons, TRUE, TRUE) );
958  SCIP_CALL( SCIPlockVarCons(scip, varss, cons, TRUE, TRUE) );
959 
960  /* aggregate ns variable with original variable */
961  SCIP_CALL( SCIPaggregateVars(scip, varns, consdata->vars[i], 1.0, -1.0, 0.0, &infeasible, &redundant, &aggregated) );
962  assert( ! infeasible );
963  assert( redundant );
964  assert( aggregated );
965  }
966  else
967  {
968  /* if the rhs is 0 (false) the flow stays on the top level */
969  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_nn", SCIPconsGetName(cons), i);
970  SCIP_CALL( SCIPcreateVar(scip, &varnn, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT, SCIPconsIsInitial(cons), SCIPconsIsRemovable(cons), NULL, NULL, NULL, NULL, NULL) );
971  SCIP_CALL( SCIPaddVar(scip, varnn) );
972 
973  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_sn", SCIPconsGetName(cons), i);
974  SCIP_CALL( SCIPcreateVar(scip, &varsn, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT, SCIPconsIsInitial(cons), SCIPconsIsRemovable(cons), NULL, NULL, NULL, NULL, NULL) );
975  SCIP_CALL( SCIPaddVar(scip, varsn) );
976 
977  /* need to lock variables, because we aggregate them */
978  SCIP_CALL( SCIPlockVarCons(scip, varnn, cons, TRUE, TRUE) );
979  SCIP_CALL( SCIPlockVarCons(scip, varsn, cons, TRUE, TRUE) );
980 
981  /* aggregate sn variable with original variable */
982  SCIP_CALL( SCIPaggregateVars(scip, varsn, consdata->vars[i], 1.0, -1.0, 0.0, &infeasible, &redundant, &aggregated) );
983  assert( ! infeasible );
984  assert( redundant );
985  assert( aggregated );
986  }
987  }
988  else
989  {
990  /* add the four flow variables */
991  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_nn", SCIPconsGetName(cons), i);
992  SCIP_CALL( SCIPcreateVar(scip, &varnn, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT, SCIPconsIsInitial(cons), SCIPconsIsRemovable(cons), NULL, NULL, NULL, NULL, NULL) );
993  SCIP_CALL( SCIPaddVar(scip, varnn) );
994 
995  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_ns", SCIPconsGetName(cons), i);
996  SCIP_CALL( SCIPcreateVar(scip, &varns, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT, SCIPconsIsInitial(cons), SCIPconsIsRemovable(cons), NULL, NULL, NULL, NULL, NULL) );
997  SCIP_CALL( SCIPaddVar(scip, varns) );
998 
999  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_sn", SCIPconsGetName(cons), i);
1000  SCIP_CALL( SCIPcreateVar(scip, &varsn, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT, SCIPconsIsInitial(cons), SCIPconsIsRemovable(cons), NULL, NULL, NULL, NULL, NULL) );
1001  SCIP_CALL( SCIPaddVar(scip, varsn) );
1002 
1003  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_ss", SCIPconsGetName(cons), i);
1004  SCIP_CALL( SCIPcreateVar(scip, &varss, name, 0.0, 1.0, 0.0, SCIP_VARTYPE_IMPLINT, SCIPconsIsInitial(cons), SCIPconsIsRemovable(cons), NULL, NULL, NULL, NULL, NULL) );
1005  SCIP_CALL( SCIPaddVar(scip, varss) );
1006 
1007  SCIP_CALL( SCIPlockVarCons(scip, varnn, cons, TRUE, TRUE) );
1008  SCIP_CALL( SCIPlockVarCons(scip, varns, cons, TRUE, TRUE) );
1009  SCIP_CALL( SCIPlockVarCons(scip, varsn, cons, TRUE, TRUE) );
1010  SCIP_CALL( SCIPlockVarCons(scip, varss, cons, TRUE, TRUE) );
1011 
1012  /* add coupling constraint */
1013  cnt = 0;
1014  if ( varns != NULL )
1015  {
1016  vars[cnt] = varns;
1017  vals[cnt++] = 1.0;
1018  }
1019  if ( varsn != NULL )
1020  {
1021  vars[cnt] = varsn;
1022  vals[cnt++] = 1.0;
1023  }
1024  assert( SCIPvarIsTransformed(consdata->vars[i]) );
1025  vars[cnt] = consdata->vars[i];
1026  vals[cnt++] = -1.0;
1027 
1028  assert( cnt >= 2 );
1029  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_couple", SCIPconsGetName(cons));
1030  /* not initial, separate, do not enforce, do not check, propagate, not local, not modifiable, dynamic, removable, not sticking */
1031  SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, cnt, vars, vals, 0.0, 0.0,
1033  SCIP_CALL( SCIPaddCons(scip, newcons) );
1034  SCIPdebugPrintCons(scip, newcons, NULL);
1035  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1036  ++(*naddedconss);
1037  }
1038 
1039  /* add south flow conservation constraint */
1040 
1041  /* incoming variables */
1042  cnt = 0;
1043  if ( varprevss != NULL )
1044  {
1045  vars[cnt] = varprevss;
1046  vals[cnt++] = 1.0;
1047  }
1048  if ( varprevns != NULL )
1049  {
1050  vars[cnt] = varprevns;
1051  vals[cnt++] = 1.0;
1052  }
1053 
1054  /* outgoing variables */
1055  if ( varss != NULL )
1056  {
1057  vars[cnt] = varss;
1058  vals[cnt++] = -1.0;
1059  }
1060  if ( varsn != NULL )
1061  {
1062  vars[cnt] = varsn;
1063  vals[cnt++] = -1.0;
1064  }
1065 
1066  assert( cnt >= 2 );
1067  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_south", SCIPconsGetName(cons));
1068  /* not initial, separate, do not enforce, do not check, propagate, not local, not modifiable, dynamic, removable, not sticking */
1069  SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, cnt, vars, vals, 0.0, 0.0,
1071  SCIP_CALL( SCIPaddCons(scip, newcons) );
1072  SCIPdebugPrintCons(scip, newcons, NULL);
1073  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1074  ++(*naddedconss);
1075  }
1076 
1077  /* add north flow conservation constraint */
1078 
1079  /* incoming variables */
1080  cnt = 0;
1081  if ( varprevnn != NULL )
1082  {
1083  vars[cnt] = varprevnn;
1084  vals[cnt++] = 1.0;
1085  }
1086  if ( varprevsn != NULL )
1087  {
1088  vars[cnt] = varprevsn;
1089  vals[cnt++] = 1.0;
1090  }
1091 
1092  /* outgoing variables */
1093  if ( varnn != NULL )
1094  {
1095  vars[cnt] = varnn;
1096  vals[cnt++] = -1.0;
1097  }
1098  if ( varns != NULL )
1099  {
1100  vars[cnt] = varns;
1101  vals[cnt++] = -1.0;
1102  }
1103 
1104  assert( cnt >= 2 );
1105  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_north", SCIPconsGetName(cons));
1106  if ( i == 0 )
1107  rhs = -1.0;
1108  else
1109  rhs = 0.0;
1110 
1111  /* not initial, separate, do not enforce, do not check, propagate, not local, not modifiable, dynamic, removable, not sticking */
1112  SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, cnt, vars, vals, rhs, rhs,
1114  SCIP_CALL( SCIPaddCons(scip, newcons) );
1115  SCIPdebugPrintCons(scip, newcons, NULL);
1116  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1117  ++(*naddedconss);
1118 
1119  /* store variables */
1120  consdata->extvars[4*i] = varnn;
1121  consdata->extvars[4*i + 1] = varns;
1122  consdata->extvars[4*i + 2] = varsn;
1123  consdata->extvars[4*i + 3] = varss;
1124 
1125  if ( varnn != NULL )
1126  ++(consdata->nextvars);
1127  if ( varns != NULL )
1128  ++(consdata->nextvars);
1129  if ( varsn != NULL )
1130  ++(consdata->nextvars);
1131  if ( varss != NULL )
1132  ++(consdata->nextvars);
1133 
1134  /* store previous variables */
1135  varprevnn = varnn;
1136  varprevns = varns;
1137  varprevsn = varsn;
1138  varprevss = varss;
1139  }
1140 
1141  return SCIP_OKAY;
1142 }
1143 
1144 /** adds extended asymmetric formulation
1145  *
1146  * The extended asymmetric formulation is constructed as follows: Let \f$x_1, \dots, x_k\f$ be the variables contained
1147  * in the given XOR constraint. We introduce variables \f$p_1, \ldots, p_k\f$ with the following constraints: \f$p_1 =
1148  * x_1\f$, \f$p_k = 1\f$, and for \f$i = 2, \ldots, k-1\f$:
1149  * \f[
1150  * \begin{array}{ll}
1151  * p_i & \leq p_{i-1} + x_i\\
1152  * p_i & \leq 2 - (p_{i-1} + x_i)\\
1153  * p_i & \geq p_{i-1} - x_i\\
1154  * p_i & \geq x_i - p_{i-1}.
1155  * \end{array}
1156  * \f]
1157  * This formulation is described in
1158  *
1159  * Robert D. Carr and Goran Konjevod@n
1160  * Polyhedral combinatorics@n
1161  * In Harvey Greenberg, editor, Tutorials on emerging methodologies and applications in Operations Research,@n
1162  * Chapter 2, pages (2-1)-(2-48). Springer, 2004.
1163  */
1164 static
1166  SCIP* scip, /**< SCIP data structure */
1167  SCIP_CONS* cons, /**< constraint to check */
1168  int* naddedconss /**< number of added constraints */
1169  )
1170 {
1171  char name[SCIP_MAXSTRLEN];
1172  SCIP_CONSDATA* consdata;
1173  SCIP_VAR* vars[3];
1174  SCIP_Real vals[3];
1175  SCIP_VAR* prevvar = NULL;
1176  int i;
1177 
1178  assert( scip != NULL );
1179  assert( cons != NULL );
1180  assert( naddedconss != NULL );
1181  *naddedconss = 0;
1182 
1183  /* exit if contraints is modifiable */
1184  if ( SCIPconsIsModifiable(cons) )
1185  return SCIP_OKAY;
1186 
1187  consdata = SCIPconsGetData(cons);
1188  assert( consdata != NULL );
1189 
1190  /* exit if extended formulation has been added already */
1191  if ( consdata->extvars != NULL )
1192  return SCIP_OKAY;
1193 
1194  /* xor constraints with at most 3 variables are handled directly through rows for the convex hull */
1195  if ( consdata->nvars <= 3 )
1196  return SCIP_OKAY;
1197 
1198  SCIPdebugMessage("Add extended formulation for xor constraint <%s> ...\n", SCIPconsGetName(cons));
1199  assert( consdata->extvars == NULL );
1200  assert( consdata->nextvars == 0 );
1201 
1202  /* get storage for auxiliary variables */
1203  consdata->extvarssize = consdata->nvars;
1204  consdata->nextvars = consdata->nvars;
1205  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(consdata->extvars), consdata->extvarssize ) );
1206 
1207  /* pass through components */
1208  for (i = 0; i < consdata->nvars; ++i)
1209  {
1210  SCIP_Bool infeasible = FALSE;
1211  SCIP_Bool redundant = FALSE;
1212  SCIP_Bool aggregated = FALSE;
1213  SCIP_CONS* newcons;
1214  SCIP_VAR* artvar = NULL;
1215  SCIP_Real lb = 0.0;
1216  SCIP_Real ub = 1.0;
1217 
1218  /* determine fixing for last variables */
1219  if ( i == consdata->nvars-1 )
1220  {
1221  if ( consdata->rhs )
1222  {
1223  lb = 1.0;
1224  ub = 1.0;
1225  }
1226  else
1227  {
1228  lb = 0.0;
1229  ub = 0.0;
1230  }
1231  }
1232 
1233  /* create variable */
1234  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "p_%s_%d", SCIPconsGetName(cons), i);
1235  SCIP_CALL( SCIPcreateVar(scip, &artvar, name, lb, ub, 0.0, SCIP_VARTYPE_IMPLINT, SCIPconsIsInitial(cons), SCIPconsIsRemovable(cons), NULL, NULL, NULL, NULL, NULL) );
1236  SCIP_CALL( SCIPaddVar(scip, artvar) );
1237  SCIP_CALL( SCIPlockVarCons(scip, artvar, cons, TRUE, TRUE) );
1238 
1239  /* create constraints */
1240  if ( i == 0 )
1241  {
1242  /* aggregate artificial variable with original variable */
1243  SCIP_CALL( SCIPaggregateVars(scip, artvar, consdata->vars[0], 1.0, -1.0, 0.0, &infeasible, &redundant, &aggregated) );
1244  assert( ! infeasible );
1245  assert( redundant );
1246  assert( aggregated );
1247  }
1248  else
1249  {
1250  assert( SCIPvarIsTransformed(consdata->vars[i]) );
1251 
1252  /* add first constraint */
1253  vars[0] = artvar;
1254  vals[0] = 1.0;
1255  vars[1] = prevvar;
1256  vals[1] = -1.0;
1257  vars[2] = consdata->vars[i];
1258  vals[2] = -1.0;
1259 
1260  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_1", SCIPconsGetName(cons), i);
1261  /* not initial, separate, do not enforce, do not check, propagate, not local, not modifiable, dynamic, removable, not sticking */
1262  SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, 3, vars, vals, -SCIPinfinity(scip), 0.0,
1264  SCIP_CALL( SCIPaddCons(scip, newcons) );
1265  SCIPdebugPrintCons(scip, newcons, NULL);
1266  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1267  ++(*naddedconss);
1268 
1269  /* add second constraint */
1270  vars[0] = artvar;
1271  vals[0] = 1.0;
1272  vars[1] = prevvar;
1273  vals[1] = 1.0;
1274  vars[2] = consdata->vars[i];
1275  vals[2] = 1.0;
1276 
1277  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_2", SCIPconsGetName(cons), i);
1278  /* not initial, separate, do not enforce, do not check, propagate, not local, not modifiable, dynamic, removable, not sticking */
1279  SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, 3, vars, vals, -SCIPinfinity(scip), 2.0,
1281  SCIP_CALL( SCIPaddCons(scip, newcons) );
1282  SCIPdebugPrintCons(scip, newcons, NULL);
1283  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1284  ++(*naddedconss);
1285 
1286  /* add third constraint */
1287  vars[0] = artvar;
1288  vals[0] = -1.0;
1289  vars[1] = prevvar;
1290  vals[1] = 1.0;
1291  vars[2] = consdata->vars[i];
1292  vals[2] = -1.0;
1293 
1294  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_3", SCIPconsGetName(cons), i);
1295  /* not initial, separate, do not enforce, do not check, propagate, not local, not modifiable, dynamic, removable, not sticking */
1296  SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, 3, vars, vals, -SCIPinfinity(scip), 0.0,
1298  SCIP_CALL( SCIPaddCons(scip, newcons) );
1299  SCIPdebugPrintCons(scip, newcons, NULL);
1300  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1301  ++(*naddedconss);
1302 
1303  /* add fourth constraint */
1304  vars[0] = artvar;
1305  vals[0] = -1.0;
1306  vars[1] = prevvar;
1307  vals[1] = -1.0;
1308  vars[2] = consdata->vars[i];
1309  vals[2] = 1.0;
1310 
1311  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_%d_4", SCIPconsGetName(cons), i);
1312  /* not initial, separate, do not enforce, do not check, propagate, not local, not modifiable, dynamic, removable, not sticking */
1313  SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, 3, vars, vals, -SCIPinfinity(scip), 0.0,
1315  SCIP_CALL( SCIPaddCons(scip, newcons) );
1316  SCIPdebugPrintCons(scip, newcons, NULL);
1317  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1318  ++(*naddedconss);
1319  }
1320 
1321  /* store variable */
1322  consdata->extvars[i] = artvar;
1323  prevvar = artvar;
1324  }
1325 
1326  return SCIP_OKAY;
1327 }
1328 
1329 /** creates LP row corresponding to xor constraint:
1330  * x1 + ... + xn - 2q == rhs
1331  * with internal integer variable q;
1332  * in the special case of 3 variables and c = 0, the following linear system is created:
1333  * + x - y - z <= 0
1334  * - x + y - z <= 0
1335  * - x - y + z <= 0
1336  * + x + y + z <= 2
1337  * in the special case of 3 variables and c = 1, the following linear system is created:
1338  * - x + y + z <= 1
1339  * + x - y + z <= 1
1340  * + x + y - z <= 1
1341  * - x - y - z <= -1
1342  */
1343 static
1345  SCIP* scip, /**< SCIP data structure */
1346  SCIP_CONS* cons /**< constraint to check */
1347  )
1348 {
1349  SCIP_CONSDATA* consdata;
1350  char varname[SCIP_MAXSTRLEN];
1351 
1352  consdata = SCIPconsGetData(cons);
1353  assert(consdata != NULL);
1354  assert(consdata->rows[0] == NULL);
1355 
1356  if( SCIPconsIsModifiable(cons) || consdata->nvars != 3 )
1357  {
1358  SCIP_Real rhsval;
1359 
1360  /* create internal variable, if not yet existing */
1361  if( consdata->intvar == NULL )
1362  {
1363  int ub;
1364 
1365  (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "XOR_artificial_%s_int", SCIPconsGetName(cons));
1366  ub = consdata->nvars/2;
1367  SCIP_CALL( SCIPcreateVar(scip, &consdata->intvar, varname, 0.0, (SCIP_Real)ub, 0.0,
1368  consdata->nvars >= 4 ? SCIP_VARTYPE_INTEGER : SCIP_VARTYPE_BINARY,
1370  SCIP_CALL( SCIPaddVar(scip, consdata->intvar) );
1371 
1372 #ifdef SCIP_DEBUG_SOLUTION
1373  if( SCIPdebugIsMainscip(scip) )
1374  {
1375  SCIP_Real solval;
1376  int count = 0;
1377  int v;
1378 
1379  for( v = consdata->nvars - 1; v >= 0; --v )
1380  {
1381  SCIP_CALL( SCIPdebugGetSolVal(scip, consdata->vars[v], &solval) );
1382  count += (solval > 0.5 ? 1 : 0);
1383  }
1384  assert((count - consdata->rhs) % 2 == 0);
1385  solval = (SCIP_Real) ((count - consdata->rhs) / 2);
1386 
1387  /* store debug sol value of artificial integer variable */
1388  SCIP_CALL( SCIPdebugAddSolVal(scip, consdata->intvar, solval) );
1389  }
1390 #endif
1391 
1392  /* install the rounding locks for the internal variable */
1393  SCIP_CALL( lockRounding(scip, cons, consdata->intvar) );
1394  }
1395 
1396  /* create LP row */
1397  rhsval = (consdata->rhs ? 1.0 : 0.0);
1398  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->rows[0], SCIPconsGetHdlr(cons), SCIPconsGetName(cons), rhsval, rhsval,
1400  SCIP_CALL( SCIPaddVarToRow(scip, consdata->rows[0], consdata->intvar, -2.0) );
1401  SCIP_CALL( SCIPaddVarsToRowSameCoef(scip, consdata->rows[0], consdata->nvars, consdata->vars, 1.0) );
1402  }
1403  else if( !consdata->rhs )
1404  {
1405  char rowname[SCIP_MAXSTRLEN];
1406  int r;
1407 
1408  /* create the <= 0 rows with one positive sign */
1409  for( r = 0; r < 3; ++r )
1410  {
1411  int v;
1412 
1413  (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s_%d", SCIPconsGetName(cons), r);
1414  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->rows[r], SCIPconsGetHdlr(cons), rowname, -SCIPinfinity(scip), 0.0,
1416  for( v = 0; v < 3; ++v )
1417  {
1418  SCIP_CALL( SCIPaddVarToRow(scip, consdata->rows[r], consdata->vars[v], v == r ? +1.0 : -1.0) );
1419  }
1420  }
1421 
1422  /* create the <= 2 row with all positive signs */
1423  (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s_3", SCIPconsGetName(cons));
1424  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->rows[3], SCIPconsGetHdlr(cons), rowname, -SCIPinfinity(scip), 2.0,
1426  SCIP_CALL( SCIPaddVarsToRowSameCoef(scip, consdata->rows[3], consdata->nvars, consdata->vars, 1.0) );
1427  }
1428  else
1429  {
1430  char rowname[SCIP_MAXSTRLEN];
1431  int r;
1432 
1433  /* create the <= 1 rows with one negative sign */
1434  for( r = 0; r < 3; ++r )
1435  {
1436  int v;
1437 
1438  (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s_%d", SCIPconsGetName(cons), r);
1439  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->rows[r], SCIPconsGetHdlr(cons), rowname, -SCIPinfinity(scip), 1.0,
1441  for( v = 0; v < 3; ++v )
1442  {
1443  SCIP_CALL( SCIPaddVarToRow(scip, consdata->rows[r], consdata->vars[v], v == r ? -1.0 : +1.0) );
1444  }
1445  }
1446 
1447  /* create the <= -1 row with all negative signs */
1448  (void) SCIPsnprintf(rowname, SCIP_MAXSTRLEN, "%s_3", SCIPconsGetName(cons));
1449  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &consdata->rows[3], SCIPconsGetHdlr(cons), rowname, -SCIPinfinity(scip), -1.0,
1451  SCIP_CALL( SCIPaddVarsToRowSameCoef(scip, consdata->rows[3], consdata->nvars, consdata->vars, -1.0) );
1452  }
1453 
1454  return SCIP_OKAY;
1455 }
1456 
1457 /** adds linear relaxation of or constraint to the LP */
1458 static
1460  SCIP* scip, /**< SCIP data structure */
1461  SCIP_CONS* cons /**< constraint to check */
1462  )
1463 {
1464  SCIP_CONSDATA* consdata;
1465  SCIP_Bool infeasible;
1466  int r;
1467 
1468  consdata = SCIPconsGetData(cons);
1469  assert(consdata != NULL);
1470 
1471  if( consdata->rows[0] == NULL )
1472  {
1473  SCIP_CALL( createRelaxation(scip, cons) );
1474  }
1475  assert(consdata->rows[0] != NULL);
1476  for( r = 0; r < NROWS; ++r )
1477  {
1478  if( consdata->rows[r] != NULL && !SCIProwIsInLP(consdata->rows[r]) )
1479  {
1480  SCIP_CALL( SCIPaddCut(scip, NULL, consdata->rows[r], FALSE, &infeasible) );
1481  assert( ! infeasible ); /* function is only called from initlp -> row should be feasible */
1482  }
1483  }
1484 
1485  return SCIP_OKAY;
1486 }
1487 
1488 /** returns whether all rows of the LP relaxation are in the current LP */
1489 static
1491  SCIP_CONSDATA* consdata /**< constraint data */
1492  )
1493 {
1494  assert(consdata != NULL);
1495 
1496  if( consdata->rows[0] == NULL ) /* LP relaxation does not exist */
1497  return FALSE;
1498  else
1499  {
1500  int r;
1501  for( r = 0; r < NROWS; ++r )
1502  {
1503  if( consdata->rows[r] != NULL && !SCIProwIsInLP(consdata->rows[r]) )
1504  return FALSE;
1505  }
1506  return TRUE;
1507  }
1508 }
1509 
1510 /** checks xor constraint for feasibility of given solution: returns TRUE iff constraint is feasible */
1511 static
1513  SCIP* scip, /**< SCIP data structure */
1514  SCIP_CONS* cons, /**< constraint to check */
1515  SCIP_SOL* sol, /**< solution to check, NULL for current solution */
1516  SCIP_Bool checklprows, /**< should LP rows be checked? */
1517  SCIP_Bool* violated /**< pointer to store whether the constraint is violated */
1518  )
1519 {
1520  SCIP_CONSDATA* consdata;
1521 
1522  assert(violated != NULL);
1523 
1524  consdata = SCIPconsGetData(cons);
1525  assert(consdata != NULL);
1526 
1527  *violated = FALSE;
1528 
1529  /* check feasibility of constraint if necessary */
1530  if( checklprows || !allRowsInLP(consdata) )
1531  {
1532  SCIP_Real solval;
1533  int i;
1534  SCIP_Bool odd;
1535 
1536  /* increase age of constraint; age is reset to zero, if a violation was found only in case we are in
1537  * enforcement
1538  */
1539  if( sol == NULL )
1540  {
1541  SCIP_CALL( SCIPincConsAge(scip, cons) );
1542  }
1543 
1544  /* check, if all variables and the rhs sum up to an even value */
1545  odd = consdata->rhs;
1546  for( i = 0; i < consdata->nvars; ++i )
1547  {
1548  solval = SCIPgetSolVal(scip, sol, consdata->vars[i]);
1549  assert(SCIPisFeasIntegral(scip, solval));
1550  odd = (odd != (solval > 0.5));
1551  }
1552  if( odd )
1553  {
1554  *violated = TRUE;
1555 
1556  /* only reset constraint age if we are in enforcement */
1557  if( sol == NULL )
1558  {
1559  SCIP_CALL( SCIPresetConsAge(scip, cons) );
1560  }
1561  }
1562  }
1563 
1564  return SCIP_OKAY;
1565 }
1566 
1567 /** separates current LP solution
1568  *
1569  * Consider a XOR-constraint
1570  * \f[
1571  * x_1 \oplus x_2 \oplus \dots \oplus x_n = b
1572  * \f]
1573  * 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
1574  * inequalities of the convex hull.
1575  *
1576  * The separation of larger XOR constraints has been described by @n
1577  * Xiaojie Zhang and Paul H. Siegel@n
1578  * "Adaptive Cut Generation Algorithm for Improved Linear Programming Decoding of Binary Linear Codes"@n
1579  * IEEE Transactions on Information Theory, vol. 58, no. 10, 2012
1580  *
1581  * We separate the inequalities
1582  * \f[
1583  * \sum_{j \in S} (1 - x_j) + \sum_{j \notin S} x_j \geq 1
1584  * \f]
1585  * with \f$|S| \equiv (b+1) \mbox{ mod } 2\f$ as follows. That these inequalities are valid can be seen as follows: Let
1586  * \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
1587  * all \f$j \in S\f$ and \f$x_j = 0\f$ for all \f$j \notin S\f$. Thus we should have
1588  * \f[
1589  * \oplus_{j \in S} x_j = |S| \mbox{ mod } 2 = b+1 \mbox{ mod } 2,
1590  * \f]
1591  * which is not equal to \f$b\f$ as required by the XOR-constraint.
1592  *
1593  * 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
1594  * \f[
1595  * \sum_{j \in L} (1 - x_j) + \sum_{j \notin L} x_j \geq 1
1596  * \f]
1597  * is the only inequality that can be violated. We rewrite the inequality as
1598  * \f[
1599  * \sum_{j \in L} x_j - \sum_{j \notin L} x_j \leq |L| - 1.
1600  * \f]
1601  * These inequalities are added.
1602  *
1603  * Otherwise let \f$k = \mbox{argmin}\{x^*_j \;:\; j \in L\}\f$ and check the inequality for \f$L \setminus \{k\}\f$
1604  * and similarly for \f$k = \mbox{argmax}\{x^*_j \;:\; j \in L\}\f$.
1605  */
1606 static
1608  SCIP* scip, /**< SCIP data structure */
1609  SCIP_CONS* cons, /**< constraint to check */
1610  SCIP_SOL* sol, /**< primal CIP solution, NULL for current LP solution */
1611  SCIP_Bool separateparity, /**< should parity inequalities be separated? */
1612  SCIP_Bool* separated, /**< pointer to store whether a cut was found */
1613  SCIP_Bool* cutoff /**< whether a cutoff has been detected */
1614  )
1615 {
1616  SCIP_CONSDATA* consdata;
1617  SCIP_Real feasibility;
1618  int r;
1619 
1620  assert( separated != NULL );
1621  assert( cutoff != NULL );
1622  *cutoff = FALSE;
1623 
1624  consdata = SCIPconsGetData(cons);
1625  assert(consdata != NULL);
1626 
1627  *separated = FALSE;
1628 
1629  /* create row for the linear relaxation */
1630  if( consdata->rows[0] == NULL )
1631  {
1632  SCIP_CALL( createRelaxation(scip, cons) );
1633  }
1634  assert(consdata->rows[0] != NULL);
1635 
1636  /* test rows for feasibility and add it, if it is infeasible */
1637  for( r = 0; r < NROWS; ++r )
1638  {
1639  if( consdata->rows[r] != NULL && ((sol == NULL && !SCIProwIsInLP(consdata->rows[r])) || sol != NULL) )
1640  {
1641  feasibility = SCIPgetRowSolFeasibility(scip, consdata->rows[r], sol);
1642  if( SCIPisFeasNegative(scip, feasibility) )
1643  {
1644  SCIP_CALL( SCIPaddCut(scip, sol, consdata->rows[r], FALSE, cutoff) );
1645  if ( *cutoff )
1646  return SCIP_OKAY;
1647  *separated = TRUE;
1648  }
1649  }
1650  }
1651 
1652  /* separate parity inequalities if required */
1653  if ( separateparity && consdata->nvars > 3 )
1654  {
1655  char name[SCIP_MAXSTRLEN];
1656  SCIP_Real maxval = -1.0;
1657  SCIP_Real minval = 2.0;
1658  SCIP_Real sum = 0.0;
1659  int maxidx = -1;
1660  int minidx = -1;
1661  int ngen = 0;
1662  int cnt = 0;
1663  int j;
1664 
1665  SCIPdebugMessage("separating parity inequalities ...\n");
1666 
1667  /* compute value */
1668  for (j = 0; j < consdata->nvars; ++j)
1669  {
1670  SCIP_Real val;
1671 
1672  val = SCIPgetSolVal(scip, sol, consdata->vars[j]);
1673  if ( SCIPisFeasGT(scip, val, 0.5) )
1674  {
1675  if ( val < minval )
1676  {
1677  minval = val;
1678  minidx = j;
1679  }
1680  ++cnt;
1681  sum += (1.0 - val);
1682  }
1683  else
1684  {
1685  if ( val > maxval )
1686  {
1687  maxval = val;
1688  maxidx = j;
1689  }
1690  sum += val;
1691  }
1692  }
1693 
1694  /* if size of set does not have the same parity as rhs (e.g., size is odd if rhs is 0) */
1695  if ( (cnt - consdata->rhs) % 2 == 1 )
1696  {
1697  if ( SCIPisEfficacious(scip, 1.0 - sum) )
1698  {
1699  SCIP_ROW* row;
1700 
1701  SCIPdebugMessage("found violated parity cut (efficiacy: %f)\n", 1.0 - sum);
1702 
1703  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "parity#%s", SCIPconsGetName(cons));
1704  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real) (cnt - 1), FALSE, FALSE, TRUE) );
1705  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
1706 
1707  /* fill in row */
1708  for (j = 0; j < consdata->nvars; ++j)
1709  {
1710  if ( SCIPisFeasGT(scip, SCIPgetSolVal(scip, sol, consdata->vars[j]), 0.5) )
1711  {
1712  SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], 1.0) );
1713  }
1714  else
1715  {
1716  SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], -1.0) );
1717  }
1718  }
1719  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
1720  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
1721  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, cutoff) );
1722  assert( SCIPisGT(scip, SCIPgetRowLPActivity(scip, row), (SCIP_Real) (cnt-1)) );
1723  SCIP_CALL( SCIPreleaseRow(scip, &row) );
1724  ++ngen;
1725  }
1726  }
1727  else
1728  {
1729  /* If the parity is equal: check removing the element with smallest value from the set and adding the
1730  * element with largest value to the set. If we remove the element with smallest value, we have to subtract (1
1731  * - minval) and add minval to correct the sum. */
1732  if ( SCIPisEfficacious(scip, 1.0 - (sum - 1.0 + 2.0 * minval)) )
1733  {
1734  SCIP_ROW* row;
1735 
1736  SCIPdebugMessage("found violated parity cut (efficiacy: %f, minval: %f)\n", 1.0 - (sum - 1.0 + 2.0 * minval), minval);
1737 
1738  /* the rhs of the inequality is the corrected set size minus 1 */
1739  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "parity#%s", SCIPconsGetName(cons));
1740  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real) (cnt - 2), FALSE, FALSE, TRUE) );
1741  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
1742 
1743  /* fill in row */
1744  for (j = 0; j < consdata->nvars; ++j)
1745  {
1746  if ( SCIPisFeasGT(scip, SCIPgetSolVal(scip, sol, consdata->vars[j]), 0.5) )
1747  {
1748  /* if the index corresponds to the smallest element, we reverse the sign */
1749  if ( j == minidx )
1750  SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], -1.0) );
1751  else
1752  SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], 1.0) );
1753  }
1754  else
1755  {
1756  SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], -1.0) );
1757  }
1758  }
1759  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
1760  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
1761  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, cutoff) );
1762  assert( SCIPisGT(scip, SCIPgetRowLPActivity(scip, row), (SCIP_Real) (cnt-2)) );
1763  SCIP_CALL( SCIPreleaseRow(scip, &row) );
1764  ++ngen;
1765  }
1766 
1767  /* If we add the element with largest value, we have to add (1 - maxval) and subtract maxval to get the correct sum. */
1768  if ( SCIPisEfficacious(scip, 1.0 - (sum + 1.0 - 2.0 * maxval)) )
1769  {
1770  SCIP_ROW* row;
1771 
1772  SCIPdebugMessage("found violated parity cut (efficiacy: %f, maxval: %f)\n", 1.0 - (sum + 1.0 - 2.0 * maxval), maxval);
1773 
1774  /* the rhs of the inequality is the size of the corrected set */
1775  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "parity#%s", SCIPconsGetName(cons));
1776  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, SCIPconsGetHdlr(cons), name, -SCIPinfinity(scip), (SCIP_Real) cnt, FALSE, FALSE, TRUE) );
1777  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
1778 
1779  /* fill in row */
1780  for (j = 0; j < consdata->nvars; ++j)
1781  {
1782  if ( SCIPisFeasGT(scip, SCIPgetSolVal(scip, sol, consdata->vars[j]), 0.5) )
1783  {
1784  SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], 1.0) );
1785  }
1786  else
1787  {
1788  /* if the index corresponds to the largest element, we reverse the sign */
1789  if ( j == maxidx )
1790  SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], 1.0) );
1791  else
1792  SCIP_CALL( SCIPaddVarToRow(scip, row, consdata->vars[j], -1.0) );
1793  }
1794  }
1795  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
1796  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
1797  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, cutoff) );
1798  assert( *cutoff || SCIPisGT(scip, SCIPgetRowLPActivity(scip, row), (SCIP_Real)(j-1)) );
1799  SCIP_CALL( SCIPreleaseRow(scip, &row) );
1800  ++ngen;
1801  }
1802  }
1803 
1804  SCIPdebugMessage("separated parity inequalites: %d\n", ngen);
1805  if ( ngen > 0 )
1806  *separated = TRUE;
1807  }
1808 
1809  return SCIP_OKAY;
1810 }
1811 
1812 /** Transform linear system \f$A x = b\f$ into row echolon form via the Gauss algorithm with row pivoting over GF2
1813  * @returns the rank of @p A
1814  *
1815  * 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
1816  * 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
1817  * s[i] contains the column index of the first nonzero in row @p i.
1818  */
1819 static
1821  SCIP* scip, /**< SCIP data structure */
1822  int m, /**< number of rows */
1823  int n, /**< number of columns */
1824  int* p, /**< row permutation */
1825  int* s, /**< steps indicators of the row echolon form */
1826  Type** A, /**< matrix */
1827  Type* b /**< rhs */
1828  )
1829 {
1830  int pi;
1831  int i;
1832  int j;
1833  int k;
1834 
1835  assert( A != NULL );
1836  assert( b != NULL );
1837  assert( p != NULL );
1838  assert( s != NULL );
1839 
1840  /* init permutation and step indicators */
1841  for (i = 0; i < m; ++i)
1842  {
1843  p[i] = i;
1844  s[i] = i;
1845  }
1846 
1847  /* loop through possible steps in echolon form (stop at min {n, m}) */
1848  for (i = 0; i < m && i < n; ++i)
1849  {
1850  assert( s[i] == i );
1851 
1852  /* init starting column */
1853  if ( i == 0 )
1854  j = 0;
1855  else
1856  j = s[i-1] + 1;
1857 
1858  /* find pivot row (i.e., first nonzero entry), if all entries in current row are 0 we search the next column */
1859  do
1860  {
1861  /* search in current column j */
1862  k = i;
1863  while ( k < m && A[p[k]][j] == 0 )
1864  ++k;
1865 
1866  /* found pivot */
1867  if ( k < m )
1868  break;
1869 
1870  /* otherwise search next column */
1871  ++j;
1872  }
1873  while ( j < n );
1874 
1875  /* if not pivot entry was found (checked all columns), the rank of A is equal to the current index i; in this case
1876  * all entries in and below row i are 0 */
1877  if ( j >= n )
1878  return i;
1879 
1880  /* at this place: we have found a pivot entry (p[k], j) */
1881  assert( k < m );
1882 
1883  /* store step index */
1884  s[i] = j;
1885  assert( A[p[k]][j] != 0 );
1886 
1887  /* swap row indices */
1888  if ( k != i )
1889  {
1890  int h = p[i];
1891  p[i] = p[k];
1892  p[k] = h;
1893  }
1894  pi = p[i];
1895  assert( A[pi][s[i]] != 0 );
1896 
1897  /* do elimination */
1898  for (k = i+1; k < m; ++k)
1899  {
1900  int pk = p[k];
1901  /* if entry in leading column is nonzero (otherwise we already have a 0) */
1902  if ( A[pk][s[i]] != 0 )
1903  {
1904  for (j = s[i]; j < n; ++j)
1905  A[pk][j] = A[pk][j] ^ A[pi][j];
1906  b[pk] = b[pk] ^ b[pi];
1907  }
1908  }
1909 
1910  /* check stopped (only every 100 rows in order to save time */
1911  if ( i % 100 == 99 )
1912  {
1913  if ( SCIPisStopped(scip) )
1914  return -1;
1915  }
1916  }
1917 
1918  /* 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
1919  * columns min {n,m}. */
1920  if ( n <= m )
1921  return n;
1922  return m;
1923 }
1924 
1925 /** Construct solution from matrix in row echolon form over GF2
1926  *
1927  * Compute solution of \f$A x = b\f$, which is already in row echolon form (@see computeRowEcholonGF2()) */
1928 static
1930  int m, /**< number of rows */
1931  int n, /**< number of columns */
1932  int r, /**< rank of matrix */
1933  int* p, /**< row permutation */
1934  int* s, /**< steps indicators of the row echolon form */
1935  Type** A, /**< matrix */
1936  Type* b, /**< rhs */
1937  Type* x /**< solution vector on exit */
1938  )
1939 {
1940  int i;
1941  int k;
1942 
1943  assert( A != NULL );
1944  assert( b != NULL );
1945  assert( s != NULL );
1946  assert( p != NULL );
1947  assert( x != NULL );
1948  assert( r <= m && r <= n );
1949 
1950  /* init solution vector to 0 */
1951  for (k = 0; k < n; ++k)
1952  x[k] = 0;
1953 
1954  /* init last entry */
1955  x[s[r-1]] = b[p[r-1]];
1956 
1957  /* loop backwards through solution vector */
1958  for (i = r-2; i >= 0; --i)
1959  {
1960  Type val;
1961 
1962  assert( i <= s[i] && s[i] <= n );
1963 
1964  /* init val with rhs and then add the contributions of the components of x already computed */
1965  val = b[p[i]];
1966  for (k = i+1; k < r; ++k)
1967  {
1968  assert( i <= s[k] && s[k] <= n );
1969  if ( A[p[i]][s[k]] != 0 )
1970  val = val ^ x[s[k]];
1971  }
1972 
1973  /* store solution */
1974  x[s[i]] = val;
1975  }
1976 }
1977 
1978 /** solve equation system over GF 2 by Gauss algorithm and create solution out of it or return cutoff
1979  *
1980  * Collect all information in xor constraints into a linear system over GF2. Then solve the system by computing a row
1981  * echolon form. If the system is infeasible, the current node is infeasible. Otherwise, we can compute a solution for
1982  * the xor constraints given. We check whether this gives a solution for the whole problem.
1983  *
1984  * We sort the columns with respect to the product of the objective coefficients and 1 minus the current LP solution
1985  * value. The idea is that columns that are likely to provide the steps in the row echolon form should appear towards
1986  * the front of the matrix. The smaller the product, the more it makes sense to set the variable to 1 (because the
1987  * solution value is already close to 1 and the objective function is small).
1988  *
1989  * Note that this function is called from propagation where usually no solution is available. However, the solution is
1990  * only used for sorting the columns. Thus, the procedure stays correct even with nonsense solutions.
1991  */
1992 static
1994  SCIP* scip, /**< SCIP data structure */
1995  SCIP_CONS** conss, /**< xor constraints */
1996  int nconss, /**< number of xor constraints */
1997  SCIP_SOL* currentsol, /**< current solution (maybe NULL) */
1998  SCIP_RESULT* result /**< result of propagation (possibly cutoff, no change if primal solution has been tried) */
1999  )
2000 {
2001  SCIP_CONSDATA* consdata;
2002  SCIP_HASHMAP* varhash;
2003  SCIP_Bool* xoractive;
2004  SCIP_Real* xorvals;
2005  SCIP_VAR** xorvars;
2006 #ifndef NDEBUG
2007  SCIP_Bool noaggr = TRUE;
2008 #endif
2009  Type** A;
2010  Type* b;
2011  int* s;
2012  int* p;
2013  int* xoridx;
2014  int* xorbackidx;
2015  int nconssactive = 0;
2016  int nconssmat = 0;
2017  int nvarsmat = 0;
2018  int nvars;
2019  int rank;
2020  int i;
2021  int j;
2022 
2023  assert( scip != NULL );
2024  assert( conss != NULL );
2025  assert( result != NULL );
2026 
2027  if ( *result == SCIP_CUTOFF )
2028  return SCIP_OKAY;
2029 
2030  SCIPdebugMessage("Checking feasibility via the linear equation system over GF2 using Gauss.\n");
2031 
2032  nvars = SCIPgetNVars(scip);
2033 
2034  /* set up hash map from variable to column index */
2035  SCIP_CALL( SCIPhashmapCreate(&varhash, SCIPblkmem(scip), SCIPcalcHashtableSize(10 * nvars)) );
2036  SCIP_CALL( SCIPallocBufferArray(scip, &xoractive, nconss) );
2037  SCIP_CALL( SCIPallocBufferArray(scip, &xorvars, nvars) );
2038  SCIP_CALL( SCIPallocBufferArray(scip, &xoridx, nvars) );
2039  SCIP_CALL( SCIPallocBufferArray(scip, &xorvals, nvars) );
2040 
2041  /* collect variables */
2042  for (i = 0; i < nconss; ++i)
2043  {
2044  int cnt = 0;
2045 
2046  xoractive[i] = FALSE;
2047 
2048  assert( conss[i] != NULL );
2049  consdata = SCIPconsGetData(conss[i]);
2050  assert( consdata != NULL );
2051 
2052  /* count nonfixed variables in constraint */
2053  for (j = 0; j < consdata->nvars; ++j)
2054  {
2055  SCIP_VAR* var;
2056 
2057  var = consdata->vars[j];
2058  assert( var != NULL );
2059  assert( SCIPvarGetType(var) == SCIP_VARTYPE_BINARY );
2060 
2061  /* consider nonfixed variables */
2062  if ( SCIPcomputeVarLbLocal(scip, var) < 0.5 && SCIPcomputeVarUbLocal(scip, var) > 0.5 )
2063  {
2064  /* consider active variables and collect only new ones */
2065  if ( SCIPvarIsActive(var) && ! SCIPhashmapExists(varhash, var) )
2066  {
2067  /* add variable in map */
2068  SCIP_CALL( SCIPhashmapInsert(varhash, var, (void*) (size_t) nvarsmat) );
2069  assert( nvarsmat == (int) (size_t) SCIPhashmapGetImage(varhash, var) );
2070  xorvals[nvarsmat] = SCIPvarGetObj(var) * (1.0 - SCIPgetSolVal(scip, currentsol, var));
2071  xorvars[nvarsmat++] = var;
2072  }
2073  ++cnt;
2074  }
2075  }
2076 
2077  if ( cnt > 0 )
2078  {
2079  xoractive[i] = TRUE;
2080  ++nconssactive;
2081  }
2082 #if 0
2083  /* The following can save time, if there are constraints with all variables fixed that are infeasible; this
2084  * should, however, be detected somewhere else, e.g., in propagateCons(). */
2085  else
2086  {
2087  /* all variables are fixed - check whether constraint is feasible (could be that the constraint is not propagated) */
2088  assert( cnt == 0 );
2089  for (j = 0; j < consdata->nvars; ++j)
2090  {
2091  /* count variables fixed to 1 */
2092  if ( SCIPcomputeVarLbLocal(scip, consdata->vars[j]) > 0.5 )
2093  ++cnt;
2094  else
2095  assert( SCIPcomputeVarUbLocal(scip, consdata->vars[j]) < 0.5 );
2096  }
2097  if ( ( cnt - consdata->rhs ) % 2 != 0 )
2098  {
2099  SCIPdebugMessage("constraint <%s> with all variables fixed is violated.\n", SCIPconsGetName(conss[i]));
2100  *result = SCIP_CUTOFF;
2101  break;
2102  }
2103  }
2104 #endif
2105  }
2106  assert( nvarsmat <= nvars );
2107  assert( nconssactive <= nconss );
2108 
2109  if ( nconssactive > MAXXORCONSSSYSTEM || nvarsmat > MAXXORVARSSYSTEM || *result == SCIP_CUTOFF )
2110  {
2111  SCIPdebugMessage("Skip checking the xor system over GF2 (%d conss, %d vars).\n", nconssactive, nvarsmat);
2112  SCIPfreeBufferArray(scip, &xorvals);
2113  SCIPfreeBufferArray(scip, &xoridx);
2114  SCIPfreeBufferArray(scip, &xorvars);
2115  SCIPfreeBufferArray(scip, &xoractive);
2116  SCIPhashmapFree(&varhash);
2117  return SCIP_OKAY;
2118  }
2119 
2120  /* init index */
2121  for (j = 0; j < nvarsmat; ++j)
2122  xoridx[j] = j;
2123 
2124  /* Sort variables non-decreasingly with respect to product of objective and 1 minus the current solution value: the
2125  * smaller the value the better it would be to set the variable to 1. This is more likely if the variable appears
2126  * towards the front of the matrix, because only the entries on the steps in the row echolon form will have the
2127  * chance to be nonzero.
2128  */
2129  SCIPsortRealIntPtr(xorvals, xoridx, (void**) xorvars, nvarsmat);
2130  SCIPfreeBufferArray(scip, &xorvals);
2131 
2132  /* build back index */
2133  SCIP_CALL( SCIPallocBufferArray(scip, &xorbackidx, nvarsmat) );
2134  for (j = 0; j < nvarsmat; ++j)
2135  {
2136  assert( 0 <= xoridx[j] && xoridx[j] < nvarsmat );
2137  xorbackidx[xoridx[j]] = j;
2138  }
2139 
2140  /* init matrix and rhs */
2141  SCIP_CALL( SCIPallocBufferArray(scip, &b, nconssactive) );
2142  SCIP_CALL( SCIPallocBufferArray(scip, &A, nconssactive) );
2143  for (i = 0; i < nconss; ++i)
2144  {
2145  if ( ! xoractive[i] )
2146  continue;
2147 
2148  assert( conss[i] != NULL );
2149  consdata = SCIPconsGetData(conss[i]);
2150  assert( consdata != NULL );
2151  assert( consdata->nvars > 0 );
2152 
2153  SCIP_CALL( SCIPallocBufferArray(scip, &(A[nconssmat]), nvarsmat) ); /*lint !e866*/
2154  BMSclearMemoryArray(A[nconssmat], nvarsmat); /*lint !e866*/
2155 
2156  /* correct rhs w.r.t. to fixed variables and count nonfixed variables in constraint */
2157  b[nconssmat] = (Type) consdata->rhs;
2158  for (j = 0; j < consdata->nvars; ++j)
2159  {
2160  SCIP_VAR* var;
2161  int idx;
2162 
2163  var = consdata->vars[j];
2164  assert( var != NULL );
2165 
2166  /* replace negated variables */
2167  if ( SCIPvarIsNegated(var) )
2168  {
2169  var = SCIPvarGetNegatedVar(var);
2170  assert( var != NULL );
2171  b[nconssmat] = ! b[nconssmat];
2172  }
2173 
2174  /* If the constraint contains (multi-)aggregated variables, the solution might not be valid, since the
2175  * implications are not represented in the matrix. */
2176 #ifndef NDEBUG
2178  noaggr = FALSE;
2179 #endif
2180  /** @todo possibly treat aggregated variables here */
2181 
2182  if ( SCIPcomputeVarLbLocal(scip, var) > 0.5 )
2183  {
2184  /* variable is fixed to 1, invert rhs */
2185  b[nconssmat] = ! b[nconssmat];
2186  assert( ! SCIPhashmapExists(varhash, var) );
2187  }
2188  else
2189  {
2190  if ( SCIPvarIsActive(var) && SCIPcomputeVarUbLocal(scip, var) > 0.5 )
2191  {
2192  assert( SCIPhashmapExists(varhash, var) );
2193  idx = (int) (size_t) SCIPhashmapGetImage(varhash, var);
2194  assert( idx < nvarsmat );
2195  assert( 0 <= xorbackidx[idx] && xorbackidx[idx] < nvarsmat );
2196  A[nconssmat][xorbackidx[idx]] = 1;
2197  }
2198  }
2199  }
2200  ++nconssmat;
2201  }
2202  SCIPdebugMessage("Found %d non-fixed variables in %d nonempty xor constraints.\n", nvarsmat, nconssmat);
2203  assert( nconssmat == nconssactive );
2204 
2205  /* perform Gauss algorithm */
2206  SCIP_CALL( SCIPallocBufferArray(scip, &p, nconssmat) );
2207  SCIP_CALL( SCIPallocBufferArray(scip, &s, nconssmat) );
2208 
2209 #ifdef SCIP_OUTPUT
2210  SCIPinfoMessage(scip, NULL, "Matrix before Gauss (size: %d x %d):\n", nconssmat, nvarsmat);
2211  for (i = 0; i < nconssmat; ++i)
2212  {
2213  for (j = 0; j < nvarsmat; ++j)
2214  SCIPinfoMessage(scip, NULL, "%d ", A[i][j]);
2215  SCIPinfoMessage(scip, NULL, " = %d\n", b[i]);
2216  }
2217  SCIPinfoMessage(scip, NULL, "\n");
2218 #endif
2219 
2220  rank = -1;
2221  if ( ! SCIPisStopped(scip) )
2222  {
2223  rank = computeRowEcholonGF2(scip, nconssmat, nvarsmat, p, s, A, b);
2224  assert( rank <= nconssmat && rank <= nvarsmat );
2225  }
2226 
2227  /* rank is < 0 if the solution process has been stopped */
2228  if ( rank >= 0 )
2229  {
2230 #ifdef SCIP_OUTPUT
2231  SCIPinfoMessage(scip, NULL, "Matrix after Gauss (rank: %d):\n", rank);
2232  for (i = 0; i < nconssmat; ++i)
2233  {
2234  for (j = 0; j < nvarsmat; ++j)
2235  SCIPinfoMessage(scip, NULL, "%d ", A[p[i]][j]);
2236  SCIPinfoMessage(scip, NULL, " = %d\n", b[p[i]]);
2237  }
2238  SCIPinfoMessage(scip, NULL, "\n");
2239 #endif
2240 
2241  /* check whether system is feasible */
2242  for (i = rank; i < nconssmat; ++i)
2243  {
2244  if ( b[p[i]] != 0 )
2245  break;
2246  }
2247  /* did not find nonzero entry in b -> equation system is feasible */
2248  if ( i >= nconssmat )
2249  {
2250  SCIP_HEUR* heurtrysol;
2251 
2252  SCIPdebugMessage("Found solution.\n");
2253 
2254  /* try solution */
2255  heurtrysol = SCIPfindHeur(scip, "trysol");
2256 
2257  if ( heurtrysol != NULL )
2258  {
2259  SCIP_Bool success;
2260  SCIP_VAR** vars;
2261  SCIP_SOL* sol;
2262  Type* x;
2263 
2264  /* construct solution */
2265  SCIP_CALL( SCIPallocBufferArray(scip, &x, nvarsmat) );
2266  solveRowEcholonGF2(nconssmat, nvarsmat, rank, p, s, A, b, x);
2267 
2268 #ifdef SCIP_OUTPUT
2269  SCIPinfoMessage(scip, NULL, "Solution:\n");
2270  for (j = 0; j < nvarsmat; ++j)
2271  SCIPinfoMessage(scip, NULL, "%d ", x[j]);
2272  SCIPinfoMessage(scip, NULL, "\n");
2273 #endif
2274 
2275  /* create solution */
2276  SCIP_CALL( SCIPcreateSol(scip, &sol, heurtrysol) );
2277 
2278  /* transfer solution */
2279  for (j = 0; j < nvarsmat; ++j)
2280  {
2281  if ( x[j] != 0 )
2282  {
2283  assert( (int) (size_t) SCIPhashmapGetImage(varhash, xorvars[j]) < nvars );
2284  assert( xorbackidx[(int) (size_t) SCIPhashmapGetImage(varhash, xorvars[j])] == j );
2285  assert( SCIPcomputeVarLbLocal(scip, xorvars[j]) < 0.5 );
2286  SCIP_CALL( SCIPsetSolVal(scip, sol, xorvars[j], 1.0) );
2287  }
2288  }
2289  SCIPfreeBufferArray(scip, &x);
2290 
2291  /* add *all* variables fixed to 1 */
2292  vars = SCIPgetVars(scip);
2293  for (j = 0; j < nvars; ++j)
2294  {
2295  if ( SCIPcomputeVarLbLocal(scip, vars[j]) > 0.5 )
2296  {
2297  SCIP_CALL( SCIPsetSolVal(scip, sol, vars[j], 1.0) );
2298  SCIPdebugMessage("Added fixed variable <%s>.\n", SCIPvarGetName(vars[j]));
2299  }
2300  }
2301 
2302  /* correct integral variables if necessary */
2303  for (i = 0; i < nconss; ++i)
2304  {
2305  consdata = SCIPconsGetData(conss[i]);
2306  assert(consdata != NULL);
2307 
2308  if ( xoractive[i] && consdata->intvar != NULL )
2309  {
2310  SCIP_Real val;
2311  int nones = 0;
2312 
2313  for (j = 0; j < consdata->nvars; ++j)
2314  {
2315  if ( SCIPgetSolVal(scip, sol, consdata->vars[j]) > 0.5 )
2316  ++nones;
2317  }
2318  /* if there are aggregated variables, the solution might not be feasible */
2319  assert( ! noaggr || nones % 2 == (int) consdata->rhs );
2320  if ( (unsigned int) nones != consdata->rhs )
2321  {
2322  val = (SCIP_Real) (nones - consdata->rhs)/2;
2323  if ( SCIPisGE(scip, val, SCIPvarGetLbGlobal(consdata->intvar)) && SCIPisLE(scip, val, SCIPvarGetUbGlobal(consdata->intvar)) )
2324  {
2325  SCIP_CALL( SCIPsetSolVal(scip, sol, consdata->intvar, val) );
2326  }
2327  }
2328  }
2329  }
2330  SCIPdebug( SCIP_CALL( SCIPprintSol(scip, sol, NULL, FALSE) ) );
2331 
2332  /* check feasibility of new solution and pass it to trysol heuristic */
2333  SCIP_CALL( SCIPcheckSol(scip, sol, FALSE, TRUE, TRUE, TRUE, &success) );
2334  if ( success )
2335  {
2336  SCIP_CALL( SCIPheurPassSolAddSol(scip, heurtrysol, sol) );
2337  SCIPdebugMessage("Creating solution was successful.\n");
2338  }
2339 #ifdef SCIP_DEBUG
2340  else
2341  {
2342  /* the solution might not be feasible, because of additional constraints */
2343  SCIPdebugMessage("Creating solution was not successful.\n");
2344  }
2345 #endif
2346  SCIP_CALL( SCIPfreeSol(scip, &sol) );
2347  }
2348  }
2349  else
2350  {
2351  *result = SCIP_CUTOFF;
2352  SCIPdebugMessage("System not feasible.\n");
2353  }
2354  }
2355 
2356  /* free storage */
2357  SCIPfreeBufferArray(scip, &s);
2358  SCIPfreeBufferArray(scip, &p);
2359  SCIPfreeBufferArray(scip, &xorbackidx);
2360  j = 0;
2361  for (i = 0; i < nconss; ++i)
2362  {
2363  consdata = SCIPconsGetData(conss[i]);
2364  assert(consdata != NULL);
2365 
2366  if ( consdata->nvars == 0 )
2367  continue;
2368 
2369  if( !xoractive[i] )
2370  continue;
2371 
2372  SCIPfreeBufferArray(scip, &(A[j++]));
2373  }
2374  SCIPfreeBufferArray(scip, &A);
2375  SCIPfreeBufferArray(scip, &b);
2376  SCIPfreeBufferArray(scip, &xoridx);
2377  SCIPfreeBufferArray(scip, &xorvars);
2378  SCIPfreeBufferArray(scip, &xoractive);
2379  SCIPhashmapFree(&varhash);
2380 
2381  return SCIP_OKAY;
2382 }
2383 
2384 /** for each variable in the xor constraint, add it to conflict set; for integral variable add corresponding bound */
2385 static
2387  SCIP* scip, /**< SCIP data structure */
2388  SCIP_CONS* cons, /**< constraint that inferred the bound change */
2389  SCIP_VAR* infervar, /**< variable that was deduced, or NULL (not equal to integral variable) */
2390  SCIP_BDCHGIDX* bdchgidx, /**< bound change index (time stamp of bound change), or NULL for current time */
2391  PROPRULE proprule /**< propagation rule */
2392  )
2393 {
2394  SCIP_CONSDATA* consdata;
2395  SCIP_VAR** vars;
2396  int nvars;
2397  int i;
2398 
2399  assert( cons != NULL );
2400 
2401  consdata = SCIPconsGetData(cons);
2402  assert(consdata != NULL);
2403  vars = consdata->vars;
2404  nvars = consdata->nvars;
2405 
2406  switch( proprule )
2407  {
2408  case PROPRULE_0:
2409  assert( infervar == NULL || infervar == consdata->intvar );
2410 
2411  /* the integral variable was fixed, because all variables were fixed */
2412  for (i = 0; i < nvars; ++i)
2413  {
2414  assert( SCIPisEQ(scip, SCIPvarGetLbAtIndex(vars[i], bdchgidx, FALSE), SCIPvarGetUbAtIndex(vars[i], bdchgidx, FALSE)) );
2415  SCIP_CALL( SCIPaddConflictBinvar(scip, vars[i]) );
2416  }
2417  break;
2418 
2419  case PROPRULE_1:
2420  /* the variable was inferred, because all other variables were fixed */
2421  for (i = 0; i < nvars; ++i)
2422  {
2423  /* add variables that were fixed to 1 before */
2424  if ( SCIPvarGetLbAtIndex(vars[i], bdchgidx, FALSE) > 0.5 )
2425  {
2426  assert( SCIPvarGetLbAtIndex(vars[i], bdchgidx, TRUE) > 0.5 );
2427  SCIP_CALL( SCIPaddConflictBinvar(scip, vars[i]) );
2428  }
2429  /* add variables that were fixed to 0 */
2430  else if ( SCIPvarGetUbAtIndex(vars[i], bdchgidx, FALSE) < 0.5 )
2431  {
2432  assert( SCIPvarGetUbAtIndex(vars[i], bdchgidx, TRUE) < 0.5 );
2433  SCIP_CALL( SCIPaddConflictBinvar(scip, vars[i]) );
2434  }
2435  else
2436  {
2437  /* check changed variable (changed variable is 0 or 1 afterwards) */
2438  assert( vars[i] == infervar );
2439  }
2440  }
2441  break;
2442 
2443  case PROPRULE_INTLB:
2444  assert( consdata->intvar != NULL );
2445 
2446  if( infervar != consdata->intvar )
2447  {
2448  /* the variable was fixed, because of the lower bound of the integral variable */
2449  SCIP_CALL( SCIPaddConflictLb(scip, consdata->intvar, NULL) );
2450  }
2451  /* to many and the other fixed variables */
2452  for (i = 0; i < nvars; ++i)
2453  {
2454  /* add variables that were fixed to 0 */
2455  if ( SCIPvarGetUbAtIndex(vars[i], bdchgidx, FALSE) < 0.5 )
2456  {
2457  assert( SCIPvarGetUbAtIndex(vars[i], bdchgidx, TRUE) < 0.5 );
2458  SCIP_CALL( SCIPaddConflictBinvar(scip, vars[i]) );
2459  }
2460  }
2461  break;
2462 
2463  case PROPRULE_INTUB:
2464  assert( consdata->intvar != NULL );
2465 
2466  if( infervar != consdata->intvar )
2467  {
2468  /* the variable was fixed, because of upper bound of the integral variable and the other fixed variables */
2469  SCIP_CALL( SCIPaddConflictUb(scip, consdata->intvar, NULL) );
2470  }
2471  for (i = 0; i < nvars; ++i)
2472  {
2473  /* add variables that were fixed to 1 */
2474  if ( SCIPvarGetLbAtIndex(vars[i], bdchgidx, FALSE) > 0.5 )
2475  {
2476  assert( SCIPvarGetLbAtIndex(vars[i], bdchgidx, TRUE) > 0.5 );
2477  SCIP_CALL( SCIPaddConflictBinvar(scip, vars[i]) );
2478  }
2479  }
2480  break;
2481 
2482  case PROPRULE_INVALID:
2483  default:
2484  SCIPerrorMessage("invalid inference information %d in xor constraint <%s>\n", proprule, SCIPconsGetName(cons));
2485  SCIPABORT();
2486  return SCIP_INVALIDDATA; /*lint !e527*/
2487  }
2488 
2489  return SCIP_OKAY;
2490 }
2491 
2492 /** analyzes conflicting assignment on given constraint, and adds conflict constraint to problem */
2493 static
2495  SCIP* scip, /**< SCIP data structure */
2496  SCIP_CONS* cons, /**< xor constraint that detected the conflict */
2497  SCIP_VAR* infervar, /**< variable that was deduced, or NULL (not equal to integral variable) */
2498  PROPRULE proprule /**< propagation rule */
2499  )
2500 {
2501  /* conflict analysis can only be applied in solving stage and if it is applicable */
2503  return SCIP_OKAY;
2504 
2505  /* initialize conflict analysis, and add all variables of infeasible constraint to conflict candidate queue */
2507 
2508  /* add bound changes */
2509  SCIP_CALL( addConflictBounds(scip, cons, infervar, NULL, proprule) );
2510 
2511  /* analyze the conflict */
2512  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
2513 
2514  return SCIP_OKAY;
2515 }
2516 
2517 /** propagates constraint with the following rules:
2518  * (0) all variables are fixed => can fix integral variable
2519  * (1) all except one variable fixed => fix remaining variable and integral variable
2520  * (2) depending on the amount of fixed binary variables we can tighten the integral variable
2521  * (3) depending on the lower bound of the integral variable one can fix variables to 1
2522  * (4) depending on the upper bound of the integral variable one can fix variables to 0
2523  */
2524 static
2526  SCIP* scip, /**< SCIP data structure */
2527  SCIP_CONS* cons, /**< xor constraint to be processed */
2528  SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */
2529  SCIP_Bool* cutoff, /**< pointer to store TRUE, if the node can be cut off */
2530  int* nfixedvars, /**< pointer to add up the number of fixed variables */
2531  int* nchgbds /**< pointer to add up the number of found domain reductions */
2532  )
2533 {
2534  SCIP_CONSDATA* consdata;
2535  SCIP_VAR** vars;
2536  SCIP_Bool infeasible;
2537  SCIP_Bool tightened;
2538  SCIP_Bool odd;
2539  int nvars;
2540  int nfixedones;
2541  int nfixedzeros;
2542  int watchedvar1;
2543  int watchedvar2;
2544  int i;
2545 
2546  assert(scip != NULL);
2547  assert(cons != NULL);
2548  assert(eventhdlr != NULL);
2549  assert(cutoff != NULL);
2550  assert(nfixedvars != NULL);
2551  assert(nchgbds != NULL);
2552 
2553  /* propagation can only be applied, if we know all operator variables */
2554  if( SCIPconsIsModifiable(cons) )
2555  return SCIP_OKAY;
2556 
2557  consdata = SCIPconsGetData(cons);
2558  assert(consdata != NULL);
2559 
2560  vars = consdata->vars;
2561  nvars = consdata->nvars;
2562 
2563  /* don't process the constraint, if the watched variables weren't fixed to any value since last propagation call */
2564  if( consdata->propagated )
2565  return SCIP_OKAY;
2566 
2567  /* increase age of constraint; age is reset to zero, if a conflict or a propagation was found */
2568  if( !SCIPinRepropagation(scip) )
2569  {
2570  SCIP_CALL( SCIPincConsAge(scip, cons) );
2571  }
2572 
2573  /* propagation cannot be applied, if we have at least two unfixed variables left;
2574  * that means, we only have to watch (i.e. capture events) of two variables, and switch to other variables
2575  * if these ones get fixed
2576  */
2577  watchedvar1 = consdata->watchedvar1;
2578  watchedvar2 = consdata->watchedvar2;
2579 
2580  /* check, if watched variables are still unfixed */
2581  if( watchedvar1 != -1 )
2582  {
2583  if( SCIPvarGetLbLocal(vars[watchedvar1]) > 0.5 || SCIPvarGetUbLocal(vars[watchedvar1]) < 0.5 )
2584  watchedvar1 = -1;
2585  }
2586  if( watchedvar2 != -1 )
2587  {
2588  if( SCIPvarGetLbLocal(vars[watchedvar2]) > 0.5 || SCIPvarGetUbLocal(vars[watchedvar2]) < 0.5 )
2589  watchedvar2 = -1;
2590  }
2591 
2592  /* if only one watched variable is still unfixed, make it the first one */
2593  if( watchedvar1 == -1 )
2594  {
2595  watchedvar1 = watchedvar2;
2596  watchedvar2 = -1;
2597  }
2598  assert(watchedvar1 != -1 || watchedvar2 == -1);
2599 
2600  /* if the watched variables are invalid (fixed), find new ones if existing; count the parity */
2601  odd = consdata->rhs;
2602  nfixedones = 0;
2603  nfixedzeros = 0;
2604  if( watchedvar2 == -1 )
2605  {
2606  for( i = 0; i < nvars; ++i )
2607  {
2608  if( SCIPvarGetLbLocal(vars[i]) > 0.5 )
2609  {
2610  odd = !odd;
2611  ++nfixedones;
2612  }
2613  else if( SCIPvarGetUbLocal(vars[i]) > 0.5 )
2614  {
2615  if( watchedvar1 == -1 )
2616  {
2617  assert(watchedvar2 == -1);
2618  watchedvar1 = i;
2619  }
2620  else if( watchedvar1 != i )
2621  {
2622  watchedvar2 = i;
2623  break;
2624  }
2625  }
2626  else if ( SCIPvarGetUbLocal(vars[i]) < 0.5 )
2627  ++nfixedzeros;
2628  }
2629  }
2630  assert(watchedvar1 != -1 || watchedvar2 == -1);
2631 
2632  /* if all variables are fixed, we can decide the feasibility of the constraint */
2633  if( watchedvar1 == -1 )
2634  {
2635  assert(watchedvar2 == -1);
2636 
2637  if( odd )
2638  {
2639  SCIPdebugMessage("constraint <%s>: all vars fixed, constraint is infeasible\n", SCIPconsGetName(cons));
2640 
2641  /* use conflict analysis to get a conflict constraint out of the conflicting assignment */
2642  SCIP_CALL( analyzeConflict(scip, cons, NULL, PROPRULE_0) );
2643  SCIP_CALL( SCIPresetConsAge(scip, cons) );
2644 
2645  *cutoff = TRUE;
2646  }
2647  else
2648  {
2649  /* fix integral variable if present */
2650  if ( consdata->intvar != NULL )
2651  {
2652  int fixval;
2653 
2654  assert( ! *cutoff );
2655  assert( (nfixedones - consdata->rhs) % 2 == 0 );
2656 
2657  fixval = (nfixedones - consdata->rhs)/2; /*lint !e713*/
2658 
2659  SCIPdebugMessage("fix integral variable <%s> to %d\n", SCIPvarGetName(consdata->intvar), fixval);
2660 
2661  /* check whether value to fix is outside bounds */
2662  if ( fixval + 0.5 < SCIPvarGetLbLocal(consdata->intvar) )
2663  {
2664  /* cannot fix auxiliary variable (maybe it has been branched on): we are infeasible */
2665  SCIPdebugMessage("node infeasible: activity is %d, bounds of integral variable are [%g,%g]\n",
2666  fixval, SCIPvarGetLbLocal(consdata->intvar), SCIPvarGetUbLocal(consdata->intvar));
2667 
2668  SCIP_CALL( analyzeConflict(scip, cons, NULL, PROPRULE_INTLB) );
2669  SCIP_CALL( SCIPresetConsAge(scip, cons) );
2670 
2671  *cutoff = TRUE;
2672  }
2673  else if ( fixval - 0.5 > SCIPvarGetUbLocal(consdata->intvar) )
2674  {
2675  /* cannot fix auxiliary variable (maybe it has been branched on): we are infeasible */
2676  SCIPdebugMessage("node infeasible: activity is %d, bounds of integral variable are [%g,%g]\n",
2677  fixval, SCIPvarGetLbLocal(consdata->intvar), SCIPvarGetUbLocal(consdata->intvar));
2678 
2679  SCIP_CALL( analyzeConflict(scip, cons, NULL, PROPRULE_INTUB) );
2680  SCIP_CALL( SCIPresetConsAge(scip, cons) );
2681 
2682  *cutoff = TRUE;
2683  }
2684  else
2685  {
2686  if ( ! SCIPisEQ(scip, SCIPvarGetLbLocal(consdata->intvar), (SCIP_Real) fixval) )
2687  {
2688  SCIP_CALL( SCIPinferVarLbCons(scip, consdata->intvar, (SCIP_Real) fixval, cons, (int)PROPRULE_0, FALSE, &infeasible, &tightened) );
2689  assert( tightened );
2690  assert( ! infeasible );
2691  }
2692 
2693  if ( ! SCIPisEQ(scip, SCIPvarGetUbLocal(consdata->intvar), (SCIP_Real) fixval) )
2694  {
2695  SCIP_CALL( SCIPinferVarUbCons(scip, consdata->intvar, (SCIP_Real) fixval, cons, (int)PROPRULE_0, FALSE, &infeasible, &tightened) );
2696  assert( tightened );
2697  assert( ! infeasible );
2698  }
2699 
2700  ++(*nfixedvars);
2701  }
2702  }
2703  else
2704  {
2705  SCIPdebugMessage("constraint <%s>: all vars fixed, constraint is feasible\n", SCIPconsGetName(cons));
2706  }
2707  }
2708  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
2709 
2710  return SCIP_OKAY;
2711  }
2712 
2713  /* if only one variable is not fixed, this variable can be deduced */
2714  if( watchedvar2 == -1 )
2715  {
2716  assert(watchedvar1 != -1);
2717 
2718  SCIPdebugMessage("constraint <%s>: only one unfixed variable -> fix <%s> to %u\n",
2719  SCIPconsGetName(cons), SCIPvarGetName(vars[watchedvar1]), odd);
2720 
2721  SCIP_CALL( SCIPinferBinvarCons(scip, vars[watchedvar1], odd, cons, (int)PROPRULE_1, &infeasible, &tightened) );
2722  assert(!infeasible);
2723  assert(tightened);
2724 
2725  (*nfixedvars)++;
2726 
2727  /* fix integral variable if present */
2728  if ( consdata->intvar != NULL )
2729  {
2730  int fixval;
2731 
2732  /* if variable has been fixed to 1, adjust number of fixed variables */
2733  if ( odd )
2734  ++nfixedones;
2735 
2736  assert( (nfixedones - consdata->rhs) % 2 == 0 );
2737 
2738  fixval = (nfixedones - consdata->rhs)/2; /*lint !e713*/
2739  SCIPdebugMessage("should fix integral variable <%s> to %d\n", SCIPvarGetName(consdata->intvar), fixval);
2740 
2741  /* check whether value to fix is outside bounds */
2742  if ( fixval + 0.5 < SCIPvarGetLbLocal(consdata->intvar) )
2743  {
2744  /* cannot fix auxiliary variable (maybe it has been branched on): we are infeasible */
2745  SCIPdebugMessage("node infeasible: activity is %d, bounds of integral variable are [%g,%g]\n",
2746  fixval, SCIPvarGetLbLocal(consdata->intvar), SCIPvarGetUbLocal(consdata->intvar));
2747 
2748  SCIP_CALL( analyzeConflict(scip, cons, NULL, PROPRULE_INTLB) );
2749  SCIP_CALL( SCIPresetConsAge(scip, cons) );
2750 
2751  *cutoff = TRUE;
2752  }
2753  else if ( fixval - 0.5 > SCIPvarGetUbLocal(consdata->intvar) )
2754  {
2755  /* cannot fix auxiliary variable (maybe it has been branched on): we are infeasible */
2756  SCIPdebugMessage("node infeasible: activity is %d, bounds of integral variable are [%g,%g]\n",
2757  fixval, SCIPvarGetLbLocal(consdata->intvar), SCIPvarGetUbLocal(consdata->intvar));
2758 
2759  SCIP_CALL( analyzeConflict(scip, cons, NULL, PROPRULE_INTUB) );
2760  SCIP_CALL( SCIPresetConsAge(scip, cons) );
2761 
2762  *cutoff = TRUE;
2763  }
2764  else
2765  {
2766  if( SCIPvarGetLbLocal(consdata->intvar) + 0.5 < (SCIP_Real) fixval )
2767  {
2768  SCIP_CALL( SCIPinferVarLbCons(scip, consdata->intvar, (SCIP_Real) fixval, cons, (int)PROPRULE_1, TRUE, &infeasible, &tightened) );
2769  assert( tightened );
2770  assert( ! infeasible );
2771  }
2772 
2773  if( SCIPvarGetUbLocal(consdata->intvar) - 0.5 > (SCIP_Real) fixval )
2774  {
2775  SCIP_CALL( SCIPinferVarUbCons(scip, consdata->intvar, (SCIP_Real) fixval, cons, (int)PROPRULE_1, TRUE, &infeasible, &tightened) );
2776  assert( tightened );
2777  assert( ! infeasible );
2778  }
2779  assert(SCIPisFeasEQ(scip, SCIPvarGetLbLocal(consdata->intvar), SCIPvarGetUbLocal(consdata->intvar)));
2780 
2781  ++(*nfixedvars);
2782  }
2783  }
2784 
2785  SCIP_CALL( SCIPresetConsAge(scip, cons) );
2786  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
2787 
2788  return SCIP_OKAY;
2789  }
2790 
2791  /* propagate w.r.t. integral variable */
2792  if ( consdata->intvar != NULL )
2793  {
2794  SCIP_Real newlb;
2795  SCIP_Real newub;
2796  int nonesmin;
2797  int nonesmax;
2798 
2799  assert( nfixedones + nfixedzeros < nvars );
2800 
2801  assert( SCIPisFeasIntegral(scip, SCIPvarGetLbLocal(consdata->intvar)) );
2802  assert( SCIPisFeasIntegral(scip, SCIPvarGetUbLocal(consdata->intvar)) );
2803 
2804  nonesmin = 2 * (int)(SCIPvarGetLbLocal(consdata->intvar) + 0.5) + consdata->rhs; /*lint !e713*/
2805  nonesmax = 2 * (int)(SCIPvarGetUbLocal(consdata->intvar) + 0.5) + consdata->rhs; /*lint !e713*/
2806 
2807  /* the number of possible variables that can get value 1 is less than the minimum bound */
2808  if ( nvars - nfixedzeros < nonesmin )
2809  {
2810  SCIPdebugMessage("constraint <%s>: at most %d variables can take value 1, but there should be at least %d.\n", SCIPconsGetName(cons), nvars - nfixedones, nonesmin);
2811 
2812  SCIP_CALL( analyzeConflict(scip, cons, NULL, PROPRULE_INTLB) );
2813  SCIP_CALL( SCIPresetConsAge(scip, cons) );
2814 
2815  *cutoff = TRUE;
2816 
2817  return SCIP_OKAY;
2818  }
2819 
2820  /* the number of variables that are fixed to 1 is larger than the maximum bound */
2821  if ( nfixedones > nonesmax )
2822  {
2823  SCIPdebugMessage("constraint <%s>: at least %d variables are fixed to 1, but there should be at most %d.\n", SCIPconsGetName(cons), nfixedones, nonesmax);
2824 
2825  SCIP_CALL( analyzeConflict(scip, cons, NULL, PROPRULE_INTUB) );
2826  SCIP_CALL( SCIPresetConsAge(scip, cons) );
2827 
2828  *cutoff = TRUE;
2829 
2830  return SCIP_OKAY;
2831  }
2832 
2833  /* compute new bounds on the integral variable */
2834  newlb = (SCIP_Real)((nfixedones + 1 - consdata->rhs) / 2); /*lint !e653*/
2835  newub = (SCIP_Real)((nvars - nfixedzeros - consdata->rhs) / 2); /*lint !e653*/
2836 
2837  /* new lower bound is better */
2838  if( newlb > SCIPvarGetLbLocal(consdata->intvar) + 0.5 )
2839  {
2840  SCIPdebugMessage("constraint <%s>: propagated lower bound of integral variable <%s> to %g\n", SCIPconsGetName(cons), SCIPvarGetName(consdata->intvar), newlb);
2841  SCIP_CALL( SCIPinferVarLbCons(scip, consdata->intvar, newlb, cons, (int)PROPRULE_INTUB, TRUE, &infeasible, &tightened) );
2842  assert(tightened);
2843  assert(!infeasible);
2844 
2845  ++(*nchgbds);
2846 
2847  nonesmin = 2 * (int)(SCIPvarGetLbLocal(consdata->intvar) + 0.5) + consdata->rhs; /*lint !e713*/
2848  }
2849 
2850  /* new upper bound is better */
2851  if( newub < SCIPvarGetUbLocal(consdata->intvar) - 0.5 )
2852  {
2853  SCIPdebugMessage("constraint <%s>: propagated upper bound of integral variable <%s> to %g\n", SCIPconsGetName(cons), SCIPvarGetName(consdata->intvar), newub);
2854  SCIP_CALL( SCIPinferVarUbCons(scip, consdata->intvar, newub, cons, (int)PROPRULE_INTLB, TRUE, &infeasible, &tightened) );
2855  assert(tightened);
2856  assert(!infeasible);
2857 
2858  ++(*nchgbds);
2859 
2860  nonesmax = 2 * (int)(SCIPvarGetUbLocal(consdata->intvar) + 0.5) + consdata->rhs; /*lint !e713*/
2861  }
2862 
2863  assert(nvars - nfixedzeros >= nonesmin);
2864  assert(nfixedones <= nonesmax);
2865 
2866  /* the number of variables that are free or fixed to 1 is exactly the minimum required -> fix free variables to 1 */
2867  if ( nvars - nfixedzeros == nonesmin )
2868  {
2869  SCIPdebugMessage("constraint <%s>: fix %d free variables to 1 to reach lower bound of %d\n", SCIPconsGetName(cons), nvars - nfixedzeros - nfixedones, nonesmin);
2870 
2871  for (i = 0; i < nvars; ++i)
2872  {
2873  if ( SCIPvarGetLbLocal(vars[i]) < 0.5 && SCIPvarGetUbLocal(vars[i]) > 0.5 )
2874  {
2875  SCIP_CALL( SCIPinferBinvarCons(scip, vars[i], TRUE, cons, (int)PROPRULE_INTLB, &infeasible, &tightened) );
2876  assert( !infeasible );
2877  assert( tightened );
2878 
2879  ++(*nfixedvars);
2880  }
2881  }
2882  SCIP_CALL( SCIPresetConsAge(scip, cons) );
2883  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
2884 
2885  return SCIP_OKAY;
2886  }
2887 
2888  /* the number of variables that are fixed to 1 is exactly the maximum required -> fix free variables to 0 */
2889  if ( nfixedones == nonesmax )
2890  {
2891  SCIPdebugMessage("constraint <%s>: fix %d free variables to 0 to guarantee upper bound of %d\n", SCIPconsGetName(cons), nvars - nfixedzeros - nfixedones, nonesmax);
2892 
2893  for (i = 0; i < nvars; ++i)
2894  {
2895  if ( SCIPvarGetLbLocal(vars[i]) < 0.5 && SCIPvarGetUbLocal(vars[i]) > 0.5 )
2896  {
2897  SCIP_CALL( SCIPinferBinvarCons(scip, vars[i], FALSE, cons, (int)PROPRULE_INTUB, &infeasible, &tightened) );
2898  assert(!infeasible);
2899  assert(tightened);
2900  ++(*nfixedvars);
2901  }
2902  }
2903  SCIP_CALL( SCIPresetConsAge(scip, cons) );
2904  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
2905 
2906  return SCIP_OKAY;
2907  }
2908  }
2909 
2910  /* switch to the new watched variables */
2911  SCIP_CALL( consdataSwitchWatchedvars(scip, consdata, eventhdlr, watchedvar1, watchedvar2) );
2912 
2913  /* mark the constraint propagated */
2914  consdata->propagated = TRUE;
2915 
2916  return SCIP_OKAY;
2917 }
2918 
2919 /** resolves a conflict on the given variable by supplying the variables needed for applying the corresponding
2920  * propagation rules (see propagateCons())
2921  */
2922 static
2924  SCIP* scip, /**< SCIP data structure */
2925  SCIP_CONS* cons, /**< constraint that inferred the bound change */
2926  SCIP_VAR* infervar, /**< variable that was deduced */
2927  PROPRULE proprule, /**< propagation rule that deduced the value */
2928  SCIP_BDCHGIDX* bdchgidx, /**< bound change index (time stamp of bound change), or NULL for current time */
2929  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
2930  )
2931 {
2932  assert(result != NULL);
2933 
2934  SCIPdebugMessage("resolving fixations according to rule %d\n", (int) proprule);
2935 
2936  SCIP_CALL( addConflictBounds(scip, cons, infervar, bdchgidx, proprule) );
2937  *result = SCIP_SUCCESS;
2938 
2939  return SCIP_OKAY;
2940 }
2941 
2942 /** try to use clique information to delete a part of the xor constraint or even fix variables */
2943 static
2945  SCIP* scip, /**< SCIP data structure */
2946  SCIP_CONS* cons, /**< constraint that inferred the bound change */
2947  int* nfixedvars, /**< pointer to add up the number of found domain reductions */
2948  int* nchgcoefs, /**< pointer to add up the number of deleted entries */
2949  int* ndelconss, /**< pointer to add up the number of deleted constraints */
2950  int* naddconss, /**< pointer to add up the number of added constraints */
2951  SCIP_Bool* cutoff /**< pointer to store TRUE, if the node can be cut off */
2952  )
2953 {
2954  SCIP_CONSDATA* consdata;
2955  SCIP_VAR** vars;
2956  int nvars;
2957  SCIP_Bool breaked;
2958  SCIP_Bool restart;
2959  int posnotinclq1;
2960  int posnotinclq2;
2961  int v;
2962  int v1;
2963 
2964  assert(scip != NULL);
2965  assert(cons != NULL);
2966  assert(nfixedvars != NULL);
2967  assert(nchgcoefs != NULL);
2968  assert(ndelconss != NULL);
2969  assert(naddconss != NULL);
2970  assert(cutoff != NULL);
2971 
2972  /* propagation can only be applied, if we know all operator variables */
2973  if( SCIPconsIsModifiable(cons) )
2974  return SCIP_OKAY;
2975 
2976  consdata = SCIPconsGetData(cons);
2977  assert(consdata != NULL);
2978 
2979  vars = consdata->vars;
2980  nvars = consdata->nvars;
2981 
2982  if( nvars < 3 )
2983  return SCIP_OKAY;
2984 
2985 #if 0 /* try to evaluate if clique presolving should only be done multiple times when the constraint changed */
2986  if( !consdata->changed )
2987  return SCIP_OKAY;
2988 #endif
2989 
2990  /* @todo: if clique information would have saved the type of the clique, like <= 1, or == 1 we could do more
2991  * presolving like:
2992  *
2993  * (xor(x1,x2,x3,x4) = 1 and clique(x1,x2) == 1) => xor(x3,x4) = 0
2994  * (xor(x1,x2,x3,x4) = 1 and clique(x1,x2,x3) == 1) => (x4 = 0 and delete xor constraint)
2995  */
2996 
2997  /* 1. we have only clique information "<=", so we can check if all variables are in the same clique
2998  *
2999  * (xor(x1,x2,x3) = 1 and clique(x1,x2,x3) <= 1) => (add set-partioning constraint x1 + x2 + x3 = 1 and delete old
3000  * xor-constraint)
3001  *
3002  * (xor(x1,x2,x3) = 0 and clique(x1,x2,x3) <= 1) => (fix all variables x1 = x2 = x3 = 0 and delete old xor-
3003  * constraint)
3004  */
3005 
3006  /* 2. we have only clique information "<=", so we can check if all but one variable are in the same clique
3007  *
3008  * (xor(x1,x2,x3,x4) = 1 and clique(x1,x2,x3) <= 1) => (add set-partioning constraint x1 + x2 + x3 + x4 = 1 and
3009  * delete old xor constraint)
3010  *
3011  * (xor(x1,x2,x3,x4) = 0 and clique(x1,x2,x3) <= 1) => (add set-partioning constraint x1 + x2 + x3 + ~x4 = 1 and
3012  * delete old xor constraint)
3013  */
3014 
3015  posnotinclq1 = -1; /* index of variable that is possible not in the clique */
3016  posnotinclq2 = -1; /* index of variable that is possible not in the clique */
3017  breaked = FALSE;
3018  restart = FALSE;
3019 
3020  v = nvars - 2;
3021  while( v >= 0 )
3022  {
3023  assert(SCIPvarIsActive(vars[v]));
3024 
3025  if( posnotinclq1 == v )
3026  {
3027  --v;
3028  continue;
3029  }
3030 
3031  for( v1 = v+1; v1 < nvars; ++v1 )
3032  {
3033  if( posnotinclq1 == v1 )
3034  continue;
3035 
3036  if( !SCIPvarsHaveCommonClique(vars[v], TRUE, vars[v1], TRUE, TRUE) )
3037  {
3038  /* if the position of the variable which is not in the clique with all other variables is not yet
3039  * initialized, than do now, one of both variables does not fit
3040  */
3041  if( posnotinclq1 == -1 )
3042  {
3043  posnotinclq1 = v;
3044  posnotinclq2 = v1;
3045  }
3046  else
3047  {
3048  /* no clique with exactly nvars-1 variables */
3049  if( restart || (posnotinclq2 != v && posnotinclq2 != v1) )
3050  {
3051  breaked = TRUE;
3052  break;
3053  }
3054 
3055  /* check the second variables for not fitting into the clique of (nvars - 1) variables */
3056  posnotinclq1 = posnotinclq2;
3057  restart = TRUE;
3058  v = nvars - 1;
3059  }
3060 
3061  break;
3062  }
3063  else
3064  assert(vars[v] != vars[v1]);
3065  }
3066 
3067  if( breaked )
3068  break;
3069 
3070  --v;
3071  }
3072 
3073  /* at least nvars-1 variables are in one clique */
3074  if( !breaked )
3075  {
3076  /* all variables are in one clique, case 1 */
3077  if( posnotinclq1 == -1 )
3078  {
3079  /* all variables of xor constraints <%s> (with rhs == 1) are in one clique, so create a setpartitioning
3080  * constraint with all variables and delete this xor-constraint
3081  */
3082  if( consdata->rhs )
3083  {
3084  SCIP_CONS* newcons;
3085  char consname[SCIP_MAXSTRLEN];
3086 
3087  (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_complete_clq", SCIPconsGetName(cons));
3088  SCIP_CALL( SCIPcreateConsSetpart(scip, &newcons, consname, nvars, vars,
3093 
3094  SCIP_CALL( SCIPaddCons(scip, newcons) );
3095  SCIPdebugMessage("added a clique/setppc constraint <%s> \n", SCIPconsGetName(newcons));
3096  SCIPdebug( SCIP_CALL( SCIPprintCons(scip, newcons, NULL) ) );
3097  ++(*naddconss);
3098 
3099  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3100  }
3101  /* all variables of xor constraints <%s> (with rhs == 0) are in one clique, so fixed all variables to 0 */
3102  else
3103  {
3104  SCIP_Bool infeasible;
3105  SCIP_Bool fixed;
3106 
3107  SCIPdebugMessage("all variables of xor constraints <%s> are in one clique, so fixed all variables to 0\n",
3108  SCIPconsGetName(cons));
3109  SCIPdebug( SCIP_CALL( SCIPprintCons(scip, cons, NULL) ) );
3110 
3111  for( v = nvars - 1; v >= 0; --v )
3112  {
3113  SCIP_CALL( SCIPfixVar(scip, vars[v], 0.0, &infeasible, &fixed) );
3114 
3115  assert(infeasible || fixed);
3116 
3117  if( infeasible )
3118  {
3119  *cutoff = infeasible;
3120 
3121  return SCIP_OKAY;
3122  }
3123  else
3124  ++(*nfixedvars);
3125  }
3126 
3127  }
3128  }
3129  /* all but one variable are in one clique, case 2 */
3130  else
3131  {
3132  SCIP_CONS* newcons;
3133  char consname[SCIP_MAXSTRLEN];
3134 
3135  (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_completed_clq", SCIPconsGetName(cons));
3136 
3137  /* complete clique by creating a set partioning constraint over all variables */
3138 
3139  /* if rhs == FALSE we need to exchange the variable not appaering in the clique with the negated variables */
3140  if( !consdata->rhs )
3141  {
3142  SCIP_CALL( SCIPcreateConsSetpart(scip, &newcons, consname, 0, NULL,
3147 
3148  for( v = 0; v < nvars; ++v )
3149  {
3150  if( v == posnotinclq1 )
3151  {
3152  SCIP_VAR* var;
3153 
3154  SCIP_CALL( SCIPgetNegatedVar(scip, vars[v], &var) );
3155  assert(var != NULL);
3156 
3157  SCIP_CALL( SCIPaddCoefSetppc(scip, newcons, var) );
3158  }
3159  else
3160  {
3161  SCIP_CALL( SCIPaddCoefSetppc(scip, newcons, vars[v]) );
3162  }
3163  }
3164  }
3165  /* if rhs == TRUE we can add all variables to the clique constraint directly */
3166  else
3167  {
3168  SCIP_CALL( SCIPcreateConsSetpart(scip, &newcons, consname, nvars, vars,
3173  }
3174 
3175  SCIP_CALL( SCIPaddCons(scip, newcons) );
3176  SCIPdebugMessage("added a clique/setppc constraint <%s> \n", SCIPconsGetName(newcons));
3177  SCIPdebug( SCIP_CALL( SCIPprintCons(scip, newcons, NULL) ) );
3178  ++(*naddconss);
3179 
3180  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
3181  }
3182 
3183  /* delete old redundant xor-constraint */
3184  SCIP_CALL( SCIPdelCons(scip, cons) );
3185  ++(*ndelconss);
3186  }
3187 
3188  return SCIP_OKAY;
3189 }
3190 
3191 /** compares each constraint with all other constraints for possible redundancy and removes or changes constraint
3192  * accordingly; in contrast to preprocessConstraintPairs(), it uses a hash table
3193  */
3194 static
3196  SCIP* scip, /**< SCIP data structure */
3197  BMS_BLKMEM* blkmem, /**< block memory */
3198  SCIP_CONS** conss, /**< constraint set */
3199  int nconss, /**< number of constraints in constraint set */
3200  int* firstchange, /**< pointer to store first changed constraint */
3201  int* nchgcoefs, /**< pointer to add up the number of changed coefficients */
3202  int* ndelconss, /**< pointer to count number of deleted constraints */
3203  SCIP_Bool* cutoff /**< pointer to store TRUE, if a cutoff was found */
3204 )
3205 {
3206  SCIP_HASHTABLE* hashtable;
3207  int hashtablesize;
3208  int c;
3209 
3210  assert(conss != NULL);
3211  assert(ndelconss != NULL);
3212 
3213  /* create a hash table for the constraint set */
3214  hashtablesize = SCIPcalcHashtableSize(10*nconss);
3215  hashtablesize = MAX(hashtablesize, HASHSIZE_XORCONS);
3216  SCIP_CALL( SCIPhashtableCreate(&hashtable, blkmem, hashtablesize,
3217  hashGetKeyXorcons, hashKeyEqXorcons, hashKeyValXorcons, (void*) scip) );
3218 
3219  /* check all constraints in the given set for redundancy */
3220  for( c = 0; c < nconss; ++c )
3221  {
3222  SCIP_CONS* cons0;
3223  SCIP_CONS* cons1;
3224  SCIP_CONSDATA* consdata0;
3225  SCIP_CONSHDLR* conshdlr;
3226  SCIP_CONSHDLRDATA* conshdlrdata;
3227 
3228  cons0 = conss[c];
3229 
3230  if( !SCIPconsIsActive(cons0) || SCIPconsIsModifiable(cons0) )
3231  continue;
3232 
3233  /* get constraint handler data */
3234  conshdlr = SCIPconsGetHdlr(cons0);
3235  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3236  assert(conshdlrdata != NULL);
3237 
3238  /* it can happen that during preprocessing some variables got aggregated and a constraint now has not active
3239  * variables inside so we need to remove them for sorting
3240  */
3241  /* remove all variables that are fixed to zero and all pairs of variables fixed to one;
3242  * merge multiple entries of the same or negated variables
3243  */
3244  SCIP_CALL( applyFixings(scip, cons0, conshdlrdata->eventhdlr, nchgcoefs) );
3245 
3246  consdata0 = SCIPconsGetData(cons0);
3247  /* sort the constraint */
3248  consdataSort(consdata0);
3249  assert(consdata0->sorted);
3250 
3251  /* get constraint from current hash table with same variables as cons0 */
3252  cons1 = (SCIP_CONS*)(SCIPhashtableRetrieve(hashtable, (void*)cons0));
3253 
3254  if( cons1 != NULL )
3255  {
3256  SCIP_CONSDATA* consdata1;
3257 
3258  assert(SCIPconsIsActive(cons1));
3259  assert(!SCIPconsIsModifiable(cons1));
3260 
3261  consdata1 = SCIPconsGetData(cons1);
3262 
3263  assert(consdata0 != NULL && consdata1 != NULL);
3264  assert(consdata0->nvars >= 1 && consdata0->nvars == consdata1->nvars);
3265 
3266  assert(consdata0->sorted && consdata1->sorted);
3267  assert(consdata0->vars[0] == consdata1->vars[0]);
3268 
3269  if( consdata0->rhs != consdata1->rhs )
3270  {
3271  *cutoff = TRUE;
3272  goto TERMINATE;
3273  }
3274 
3275  /* update flags of constraint which caused the redundancy s.t. nonredundant information doesn't get lost */
3276  SCIP_CALL( SCIPupdateConsFlags(scip, cons1, cons0) );
3277 
3278  /* delete consdel */
3279  SCIP_CALL( SCIPdelCons(scip, cons0) );
3280  (*ndelconss)++;
3281 
3282  /* update the first changed constraint to begin the next aggregation round with */
3283  if( consdata0->changed && SCIPconsGetPos(cons1) < *firstchange )
3284  *firstchange = SCIPconsGetPos(cons1);
3285 
3286  assert(SCIPconsIsActive(cons1));
3287  }
3288  else
3289  {
3290  /* no such constraint in current hash table: insert cons0 into hash table */
3291  SCIP_CALL( SCIPhashtableInsert(hashtable, (void*) cons0) );
3292  }
3293  }
3294 
3295  TERMINATE:
3296  /* free hash table */
3297  SCIPhashtableFree(&hashtable);
3298 
3299  return SCIP_OKAY;
3300 }
3301 
3302 /** compares constraint with all prior constraints for possible redundancy or aggregation,
3303  * and removes or changes constraint accordingly
3304  */
3305 static
3307  SCIP* scip, /**< SCIP data structure */
3308  SCIP_CONS** conss, /**< constraint set */
3309  int firstchange, /**< first constraint that changed since last pair preprocessing round */
3310  int chkind, /**< index of constraint to check against all prior indices upto startind */
3311  SCIP_Bool* cutoff, /**< pointer to store TRUE, if a cutoff was found */
3312  int* nfixedvars, /**< pointer to add up the number of found domain reductions */
3313  int* naggrvars, /**< pointer to count number of aggregated variables */
3314  int* ndelconss, /**< pointer to count number of deleted constraints */
3315  int* nchgcoefs /**< pointer to add up the number of changed coefficients */
3316  )
3317 {
3318  SCIP_CONSHDLR* conshdlr;
3319  SCIP_CONSHDLRDATA* conshdlrdata;
3320  SCIP_CONS* cons0;
3321  SCIP_CONSDATA* consdata0;
3322  SCIP_Bool cons0changed;
3323  int c;
3324 
3325  assert(conss != NULL);
3326  assert(firstchange <= chkind);
3327  assert(cutoff != NULL);
3328  assert(nfixedvars != NULL);
3329  assert(naggrvars != NULL);
3330  assert(ndelconss != NULL);
3331  assert(nchgcoefs != NULL);
3332 
3333  /* get the constraint to be checked against all prior constraints */
3334  cons0 = conss[chkind];
3335  assert(SCIPconsIsActive(cons0));
3336  assert(!SCIPconsIsModifiable(cons0));
3337 
3338  consdata0 = SCIPconsGetData(cons0);
3339  assert(consdata0 != NULL);
3340  assert(consdata0->nvars >= 1);
3341 
3342  /* get constraint handler data */
3343  conshdlr = SCIPconsGetHdlr(cons0);
3344  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3345  assert(conshdlrdata != NULL);
3346 
3347  /* it can happen that during preprocessing some variables got aggregated and a constraint now has not active
3348  * variables inside so we need to remove them for sorting
3349  */
3350  /* remove all variables that are fixed to zero and all pairs of variables fixed to one;
3351  * merge multiple entries of the same or negated variables
3352  */
3353  SCIP_CALL( applyFixings(scip, cons0, conshdlrdata->eventhdlr, nchgcoefs) );
3354 
3355  /* sort cons0 */
3356  consdataSort(consdata0);
3357  assert(consdata0->sorted);
3358 
3359  /* check constraint against all prior constraints */
3360  cons0changed = consdata0->changed;
3361  consdata0->changed = FALSE;
3362  for( c = (cons0changed ? 0 : firstchange); c < chkind && !(*cutoff) && SCIPconsIsActive(cons0) && !SCIPisStopped(scip); ++c )
3363  {
3364  SCIP_CONS* cons1;
3365  SCIP_CONSDATA* consdata1;
3366  SCIP_VAR* singlevar0;
3367  SCIP_VAR* singlevar1;
3368  SCIP_Bool parity;
3369  SCIP_Bool cons0hastwoothervars;
3370  SCIP_Bool cons1hastwoothervars;
3371  SCIP_Bool aborted;
3372  SCIP_Bool infeasible;
3373  SCIP_Bool fixed;
3374  SCIP_Bool redundant;
3375  SCIP_Bool aggregated;
3376  int v0;
3377  int v1;
3378 
3379  cons1 = conss[c];
3380 
3381  /* ignore inactive and modifiable constraints */
3382  if( !SCIPconsIsActive(cons1) || SCIPconsIsModifiable(cons1) )
3383  continue;
3384 
3385  consdata1 = SCIPconsGetData(cons1);
3386  assert(consdata1 != NULL);
3387 
3388  /* it can happen that during preprocessing some variables got aggregated and a constraint now has not active
3389  * variables inside so we need to remove them for sorting
3390  */
3391  /* remove all variables that are fixed to zero and all pairs of variables fixed to one;
3392  * merge multiple entries of the same or negated variables
3393  */
3394  SCIP_CALL( applyFixings(scip, cons1, conshdlrdata->eventhdlr, nchgcoefs) );
3395  assert(consdata1 == SCIPconsGetData(cons1));
3396 
3397  SCIPdebugMessage("preprocess xor constraint pair <%s>[chg:%u] and <%s>[chg:%u]\n",
3398  SCIPconsGetName(cons0), cons0changed, SCIPconsGetName(cons1), consdata1->changed);
3399 
3400  /* if both constraints were not changed since last round, we can ignore the pair */
3401  if( !cons0changed && !consdata1->changed )
3402  continue;
3403 
3404  /* applyFixings() led to an empty constraint */
3405  if( consdata1->nvars == 0 )
3406  {
3407  if( consdata1->rhs )
3408  {
3409  *cutoff = TRUE;
3410  break;
3411  }
3412  else
3413  {
3414  /* delete empty constraint */
3415  SCIP_CALL( SCIPdelCons(scip, cons1) );
3416  ++(*ndelconss);
3417 
3418  continue;
3419  }
3420  }
3421  else if( consdata1->nvars == 1 )
3422  {
3423  /* fix remaining variable */
3424  SCIP_CALL( SCIPfixVar(scip, consdata1->vars[0], (SCIP_Real) consdata1->rhs, &infeasible, &fixed) );
3425  assert(!infeasible);
3426 
3427  if( fixed )
3428  ++(*nfixedvars);
3429 
3430  SCIP_CALL( SCIPdelCons(scip, cons1) );
3431  ++(*ndelconss);
3432 
3433  /* check for fixed variable in cons0 and remove it */
3434  SCIP_CALL( applyFixings(scip, cons0, conshdlrdata->eventhdlr, nchgcoefs) );
3435 
3436  /* sort cons0 */
3437  consdataSort(consdata0);
3438  assert(consdata0->sorted);
3439 
3440  continue;
3441  }
3442  else if( consdata1->nvars == 2 )
3443  {
3444  if( !(consdata1->rhs) )
3445  {
3446  /* aggregate var0 == var1 */
3447  SCIP_CALL( SCIPaggregateVars(scip, consdata1->vars[0], consdata1->vars[1], 1.0, -1.0, 0.0,
3448  &infeasible, &redundant, &aggregated) );
3449  }
3450  else
3451  {
3452  /* aggregate var0 == 1 - var1 */
3453  SCIP_CALL( SCIPaggregateVars(scip, consdata1->vars[0], consdata1->vars[1], 1.0, 1.0, 1.0,
3454  &infeasible, &redundant, &aggregated) );
3455  }
3456  assert(!infeasible);
3457  assert(redundant || SCIPdoNotAggr(scip));
3458 
3459  if( aggregated )
3460  {
3461  ++(*naggrvars);
3462 
3463  /* check for aggregated variable in cons0 and remove it */
3464  SCIP_CALL( applyFixings(scip, cons0, conshdlrdata->eventhdlr, nchgcoefs) );
3465 
3466  /* sort cons0 */
3467  consdataSort(consdata0);
3468  assert(consdata0->sorted);
3469  }
3470 
3471  if( redundant )
3472  {
3473  SCIP_CALL( SCIPdelCons(scip, cons1) );
3474  ++(*ndelconss);
3475  }
3476 
3477  continue;
3478  }
3479  assert(consdata0->sorted);
3480 
3481  /* sort cons1 */
3482  consdataSort(consdata1);
3483  assert(consdata1->sorted);
3484 
3485  /* check whether
3486  * (a) one problem variable set is a subset of the other, or
3487  * (b) the problem variable sets are almost equal with only one variable in each constraint that is not
3488  * member of the other
3489  */
3490  aborted = FALSE;
3491  parity = (consdata0->rhs ^ consdata1->rhs);
3492  cons0hastwoothervars = FALSE;
3493  cons1hastwoothervars = FALSE;
3494  singlevar0 = NULL;
3495  singlevar1 = NULL;
3496  v0 = 0;
3497  v1 = 0;
3498  while( (v0 < consdata0->nvars || v1 < consdata1->nvars) && !aborted )
3499  {
3500  int cmp;
3501 
3502  assert(v0 <= consdata0->nvars);
3503  assert(v1 <= consdata1->nvars);
3504 
3505  if( v0 == consdata0->nvars )
3506  cmp = +1;
3507  else if( v1 == consdata1->nvars )
3508  cmp = -1;
3509  else
3510  cmp = SCIPvarCompareActiveAndNegated(consdata0->vars[v0], consdata1->vars[v1]);
3511 
3512  switch( cmp )
3513  {
3514  case -1:
3515  /* variable doesn't appear in cons1 */
3516  assert(v0 < consdata0->nvars);
3517  if( singlevar0 == NULL )
3518  {
3519  singlevar0 = consdata0->vars[v0];
3520  if( cons1hastwoothervars )
3521  aborted = TRUE;
3522  }
3523  else
3524  {
3525  cons0hastwoothervars = TRUE;
3526  if( singlevar1 != NULL )
3527  aborted = TRUE;
3528  }
3529  v0++;
3530  break;
3531 
3532  case +1:
3533  /* variable doesn't appear in cons0 */
3534  assert(v1 < consdata1->nvars);
3535  if( singlevar1 == NULL )
3536  {
3537  singlevar1 = consdata1->vars[v1];
3538  if( cons0hastwoothervars )
3539  aborted = TRUE;
3540  }
3541  else
3542  {
3543  cons1hastwoothervars = TRUE;
3544  if( singlevar0 != NULL )
3545  aborted = TRUE;
3546  }
3547  v1++;
3548  break;
3549 
3550  case 0:
3551  /* variable appears in both constraints */
3552  assert(v0 < consdata0->nvars);
3553  assert(v1 < consdata1->nvars);
3554  assert(SCIPvarGetProbvar(consdata0->vars[v0]) == SCIPvarGetProbvar(consdata1->vars[v1]));
3555  if( consdata0->vars[v0] != consdata1->vars[v1] )
3556  {
3557  assert(SCIPvarGetNegatedVar(consdata0->vars[v0]) == consdata1->vars[v1]);
3558  parity = !parity;
3559  }
3560  v0++;
3561  v1++;
3562  break;
3563 
3564  default:
3565  SCIPerrorMessage("invalid comparison result\n");
3566  SCIPABORT();
3567  return SCIP_INVALIDDATA; /*lint !e527*/
3568  }
3569  }
3570 
3571  /* check if a useful presolving is possible */
3572  if( (cons0hastwoothervars && singlevar1 != NULL) || (cons1hastwoothervars && singlevar0 != NULL) )
3573  continue;
3574 
3575  /* check if one problem variable set is a subset of the other */
3576  if( singlevar0 == NULL && singlevar1 == NULL )
3577  {
3578  /* both constraints are equal */
3579  if( !parity )
3580  {
3581  /* even parity: constraints are redundant */
3582  SCIPdebugMessage("xor constraints <%s> and <%s> are redundant: delete <%s>\n",
3583  SCIPconsGetName(cons0), SCIPconsGetName(cons1), SCIPconsGetName(cons1));
3584  SCIPdebugPrintCons(scip, cons0, NULL);
3585  SCIPdebugPrintCons(scip, cons1, NULL);
3586  SCIP_CALL( SCIPdelCons(scip, cons1) );
3587  (*ndelconss)++;
3588  }
3589  else
3590  {
3591  /* odd parity: constraints are contradicting */
3592  SCIPdebugMessage("xor constraints <%s> and <%s> are contradicting\n",
3593  SCIPconsGetName(cons0), SCIPconsGetName(cons1));
3594  SCIPdebugPrintCons(scip, cons0, NULL);
3595  SCIPdebugPrintCons(scip, cons1, NULL);
3596  *cutoff = TRUE;
3597  }
3598  }
3599  else if( singlevar1 == NULL )
3600  {
3601  /* cons1 is a subset of cons0 */
3602  if( !cons0hastwoothervars )
3603  {
3604  /* only one additional variable in cons0: fix this variable according to the parity */
3605  SCIPdebugMessage("xor constraints <%s> and <%s> yield sum %u == <%s>\n",
3606  SCIPconsGetName(cons0), SCIPconsGetName(cons1), parity, SCIPvarGetName(singlevar0));
3607  SCIPdebugPrintCons(scip, cons0, NULL);
3608  SCIPdebugPrintCons(scip, cons1, NULL);
3609  SCIP_CALL( SCIPfixVar(scip, singlevar0, parity ? 1.0 : 0.0, &infeasible, &fixed) );
3610  *cutoff = *cutoff || infeasible;
3611  if ( fixed )
3612  (*nfixedvars)++;
3613  SCIP_CALL( SCIPdelCons(scip, cons1) );
3614  (*ndelconss)++;
3615  }
3616  else
3617  {
3618  int v;
3619 
3620  /* more than one additional variable in cons0: add cons1 to cons0, thus eliminating the equal variables */
3621  SCIPdebugMessage("xor constraint <%s> is superset of <%s> with parity %u\n",
3622  SCIPconsGetName(cons0), SCIPconsGetName(cons1), parity);
3623  SCIPdebugPrintCons(scip, cons0, NULL);
3624  SCIPdebugPrintCons(scip, cons1, NULL);
3625  for( v = 0; v < consdata1->nvars; ++v )
3626  {
3627  SCIP_CALL( addCoef(scip, cons0, conshdlrdata->eventhdlr, consdata1->vars[v]) );
3628  }
3629  SCIP_CALL( applyFixings(scip, cons0, conshdlrdata->eventhdlr, nchgcoefs) );
3630  assert(SCIPconsGetData(cons0) == consdata0);
3631  assert(consdata0->nvars >= 2); /* at least the two "other" variables should remain in the constraint */
3632 
3633  consdataSort(consdata0);
3634  assert(consdata0->sorted);
3635  }
3636  }
3637  else if( singlevar0 == NULL )
3638  {
3639  /* cons0 is a subset of cons1 */
3640  if( !cons1hastwoothervars )
3641  {
3642  /* only one additional variable in cons1: fix this variable according to the parity */
3643  SCIPdebugMessage("xor constraints <%s> and <%s> yield sum %u == <%s>\n",
3644  SCIPconsGetName(cons0), SCIPconsGetName(cons1), parity, SCIPvarGetName(singlevar1));
3645  SCIPdebugPrintCons(scip, cons0, NULL);
3646  SCIPdebugPrintCons(scip, cons1, NULL);
3647  SCIP_CALL( SCIPfixVar(scip, singlevar1, parity ? 1.0 : 0.0, &infeasible, &fixed) );
3648  assert(infeasible || fixed);
3649  *cutoff = *cutoff || infeasible;
3650  (*nfixedvars)++;
3651  SCIP_CALL( SCIPdelCons(scip, cons1) );
3652  (*ndelconss)++;
3653  }
3654  else
3655  {
3656  int v;
3657 
3658  /* more than one additional variable in cons1: add cons0 to cons1, thus eliminating the equal variables */
3659  SCIPdebugMessage("xor constraint <%s> is subset of <%s> with parity %u\n",
3660  SCIPconsGetName(cons0), SCIPconsGetName(cons1), parity);
3661  SCIPdebugPrintCons(scip, cons0, NULL);
3662  SCIPdebugPrintCons(scip, cons1, NULL);
3663  for( v = 0; v < consdata0->nvars; ++v )
3664  {
3665  SCIP_CALL( addCoef(scip, cons1, conshdlrdata->eventhdlr, consdata0->vars[v]) );
3666  }
3667  SCIP_CALL( applyFixings(scip, cons1, conshdlrdata->eventhdlr, nchgcoefs) );
3668  assert(SCIPconsGetData(cons1) == consdata1);
3669  assert(consdata1->nvars >= 2); /* at least the two "other" variables should remain in the constraint */
3670 
3671  consdataSort(consdata1);
3672  assert(consdata1->sorted);
3673  }
3674  }
3675  else
3676  {
3677  assert(!cons0hastwoothervars);
3678  assert(!cons1hastwoothervars);
3679 
3680  /* sum of constraints is parity == singlevar0 xor singlevar1: aggregate variables and delete cons1 */
3681  SCIPdebugMessage("xor constraints <%s> and <%s> yield sum %u == xor(<%s>,<%s>)\n",
3682  SCIPconsGetName(cons0), SCIPconsGetName(cons1), parity, SCIPvarGetName(singlevar0),
3683  SCIPvarGetName(singlevar1));
3684  if( !parity )
3685  {
3686  /* aggregate singlevar0 == singlevar1 */
3687  SCIP_CALL( SCIPaggregateVars(scip, singlevar1, singlevar0, 1.0, -1.0, 0.0,
3688  &infeasible, &redundant, &aggregated) );
3689  }
3690  else
3691  {
3692  /* aggregate singlevar0 == 1-singlevar1 */
3693  SCIP_CALL( SCIPaggregateVars(scip, singlevar1, singlevar0, 1.0, 1.0, 1.0,
3694  &infeasible, &redundant, &aggregated) );
3695  }
3696  assert(infeasible || redundant || SCIPdoNotAggr(scip));
3697 
3698  *cutoff = *cutoff || infeasible;
3699  if( aggregated )
3700  (*naggrvars)++;
3701 
3702  if( redundant )
3703  {
3704  SCIP_CALL( SCIPdelCons(scip, cons1) );
3705  (*ndelconss)++;
3706  }
3707 #if 0
3708  /* if aggregation in the core of SCIP is not changed we do not need to call applyFixing, this would be the correct
3709  * way
3710  */
3711  /* remove all variables that are fixed to zero and all pairs of variables fixed to one;
3712  * merge multiple entries of the same or negated variables
3713  */
3714  SCIP_CALL( applyFixings(scip, cons0, conshdlrdata->eventhdlr, nchgcoefs) );
3715 #endif
3716 
3717  }
3718  }
3719 
3720  return SCIP_OKAY;
3721 }
3722 
3723 /** creates and captures a xor constraint x_0 xor ... xor x_{k-1} = rhs with a given artificial integer variable for the
3724  * linear relaxation
3725  *
3726  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
3727  */
3728 static
3730  SCIP* scip, /**< SCIP data structure */
3731  SCIP_CONS** cons, /**< pointer to hold the created constraint */
3732  const char* name, /**< name of constraint */
3733  SCIP_Bool rhs, /**< right hand side of the constraint */
3734  int nvars, /**< number of operator variables in the constraint */
3735  SCIP_VAR** vars, /**< array with operator variables of constraint */
3736  SCIP_VAR* intvar, /**< artificial integer variable for linear relaxation */
3737  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
3738  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
3739  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
3740  * Usually set to TRUE. */
3741  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
3742  * TRUE for model constraints, FALSE for additional, redundant constraints. */
3743  SCIP_Bool check, /**< should the constraint be checked for feasibility?
3744  * TRUE for model constraints, FALSE for additional, redundant constraints. */
3745  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
3746  * Usually set to TRUE. */
3747  SCIP_Bool local, /**< is constraint only valid locally?
3748  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
3749  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
3750  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
3751  * adds coefficients to this constraint. */
3752  SCIP_Bool dynamic, /**< is constraint subject to aging?
3753  * Usually set to FALSE. Set to TRUE for own cuts which
3754  * are separated as constraints. */
3755  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
3756  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
3757  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
3758  * if it may be moved to a more global node?
3759  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
3760  )
3761 {
3762  SCIP_CONSHDLR* conshdlr;
3763  SCIP_CONSDATA* consdata;
3764 
3765  /* find the xor constraint handler */
3766  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
3767  if( conshdlr == NULL )
3768  {
3769  SCIPerrorMessage("xor constraint handler not found\n");
3770  return SCIP_PLUGINNOTFOUND;
3771  }
3772 
3773  /* create constraint data */
3774  SCIP_CALL( consdataCreate(scip, &consdata, rhs, nvars, vars, intvar) );
3775 
3776  /* create constraint */
3777  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
3778  local, modifiable, dynamic, removable, stickingatnode) );
3779 
3780  return SCIP_OKAY;
3781 }
3782 
3783 
3784 /*
3785  * Callback methods of constraint handler
3786  */
3787 
3788 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
3789 static
3790 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyXor)
3791 { /*lint --e{715}*/
3792  assert(scip != NULL);
3793  assert(conshdlr != NULL);
3794  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
3795 
3796  /* call inclusion method of constraint handler */
3798 
3799  *valid = TRUE;
3800 
3801  return SCIP_OKAY;
3802 }
3803 
3804 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
3805 static
3807 { /*lint --e{715}*/
3808  SCIP_CONSHDLRDATA* conshdlrdata;
3809 
3810  /* free constraint handler data */
3811  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3812  assert(conshdlrdata != NULL);
3813 
3814  SCIP_CALL( conshdlrdataFree(scip, &conshdlrdata) );
3815 
3816  SCIPconshdlrSetData(conshdlr, NULL);
3817 
3818  return SCIP_OKAY;
3819 }
3820 
3821 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
3822 static
3823 SCIP_DECL_CONSEXITSOL(consExitsolXor)
3824 { /*lint --e{715}*/
3825  SCIP_CONSDATA* consdata;
3826  int c;
3827 
3828  /* release and free the rows of all constraints */
3829  for( c = 0; c < nconss; ++c )
3830  {
3831  consdata = SCIPconsGetData(conss[c]);
3832  SCIP_CALL( consdataFreeRows(scip, consdata) );
3833  }
3834 
3835  return SCIP_OKAY;
3836 }
3837 
3838 
3839 /** frees specific constraint data */
3840 static
3841 SCIP_DECL_CONSDELETE(consDeleteXor)
3842 { /*lint --e{715}*/
3843  SCIP_CONSHDLRDATA* conshdlrdata;
3844 
3845  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3846  assert(conshdlrdata != NULL);
3847 
3848  SCIP_CALL( consdataFree(scip, consdata, conshdlrdata->eventhdlr) );
3849 
3850  return SCIP_OKAY;
3851 }
3852 
3853 
3854 /** transforms constraint data into data belonging to the transformed problem */
3855 static
3856 SCIP_DECL_CONSTRANS(consTransXor)
3857 { /*lint --e{715}*/
3858  SCIP_CONSDATA* sourcedata;
3859  SCIP_CONSDATA* targetdata;
3860 
3861  sourcedata = SCIPconsGetData(sourcecons);
3862  assert(sourcedata != NULL);
3863  assert(sourcedata->nvars >= 1);
3864  assert(sourcedata->vars != NULL);
3865 
3866  /* create target constraint data */
3867  SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->rhs, sourcedata->nvars, sourcedata->vars, sourcedata->intvar) );
3868 
3869  /* create target constraint */
3870  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
3871  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
3872  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
3873  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
3874  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
3875 
3876  return SCIP_OKAY;
3877 }
3878 
3879 
3880 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
3881 static
3882 SCIP_DECL_CONSINITLP(consInitlpXor)
3883 { /*lint --e{715}*/
3884  int i;
3885 
3886  for( i = 0; i < nconss; i++ )
3887  {
3888  assert(SCIPconsIsInitial(conss[i]));
3889  SCIP_CALL( addRelaxation(scip, conss[i]) );
3890  }
3891 
3892  return SCIP_OKAY;
3893 }
3894 
3895 
3896 /** separation method of constraint handler for LP solutions */
3897 static
3898 SCIP_DECL_CONSSEPALP(consSepalpXor)
3899 { /*lint --e{715}*/
3900  SCIP_CONSHDLRDATA* conshdlrdata;
3901  SCIP_Bool separated;
3902  SCIP_Bool cutoff;
3903  int c;
3904 
3905  *result = SCIP_DIDNOTFIND;
3906 
3907  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3908  assert( conshdlrdata != NULL );
3909 
3910  /* separate all useful constraints */
3911  for( c = 0; c < nusefulconss; ++c )
3912  {
3913  SCIP_CALL( separateCons(scip, conss[c], NULL, conshdlrdata->separateparity, &separated, &cutoff) );
3914  if ( cutoff )
3915  *result = SCIP_CUTOFF;
3916  else if ( separated )
3917  *result = SCIP_SEPARATED;
3918  }
3919 
3920  /* combine constraints to get more cuts */
3921  /**@todo combine constraints to get further cuts */
3922 
3923  return SCIP_OKAY;
3924 }
3925 
3926 
3927 /** separation method of constraint handler for arbitrary primal solutions */
3928 static
3929 SCIP_DECL_CONSSEPASOL(consSepasolXor)
3930 { /*lint --e{715}*/
3931  SCIP_CONSHDLRDATA* conshdlrdata;
3932  SCIP_Bool separated;
3933  SCIP_Bool cutoff;
3934  int c;
3935 
3936  *result = SCIP_DIDNOTFIND;
3937 
3938  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3939  assert( conshdlrdata != NULL );
3940 
3941  /* separate all useful constraints */
3942  for( c = 0; c < nusefulconss; ++c )
3943  {
3944  SCIP_CALL( separateCons(scip, conss[c], sol, conshdlrdata->separateparity, &separated, &cutoff) );
3945  if ( cutoff )
3946  *result = SCIP_CUTOFF;
3947  else if ( separated )
3948  *result = SCIP_SEPARATED;
3949  }
3950 
3951  /* combine constraints to get more cuts */
3952  /**@todo combine constraints to get further cuts */
3953 
3954  return SCIP_OKAY;
3955 }
3956 
3957 
3958 /** constraint enforcing method of constraint handler for LP solutions */
3959 static
3960 SCIP_DECL_CONSENFOLP(consEnfolpXor)
3961 { /*lint --e{715}*/
3962  SCIP_CONSHDLRDATA* conshdlrdata;
3963  SCIP_Bool violated;
3964  SCIP_Bool cutoff;
3965  int i;
3966 
3967  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3968  assert( conshdlrdata != NULL );
3969 
3970  /* method is called only for integral solutions, because the enforcing priority is negative */
3971  for( i = 0; i < nconss; i++ )
3972  {
3973  SCIP_CALL( checkCons(scip, conss[i], NULL, FALSE, &violated) );
3974  if( violated )
3975  {
3976  SCIP_Bool separated;
3977 
3978  SCIP_CALL( separateCons(scip, conss[i], NULL, conshdlrdata->separateparity, &separated, &cutoff) );
3979  if ( cutoff )
3980  *result = SCIP_CUTOFF;
3981  else
3982  {
3983  assert(separated); /* because the solution is integral, the separation always finds a cut */
3984  *result = SCIP_SEPARATED;
3985  }
3986  return SCIP_OKAY;
3987  }
3988  }
3989  *result = SCIP_FEASIBLE;
3990 
3991  return SCIP_OKAY;
3992 }
3993 
3994 
3995 /** constraint enforcing method of constraint handler for pseudo solutions */
3996 static
3997 SCIP_DECL_CONSENFOPS(consEnfopsXor)
3998 { /*lint --e{715}*/
3999  SCIP_Bool violated;
4000  int i;
4001 
4002  /* method is called only for integral solutions, because the enforcing priority is negative */
4003  for( i = 0; i < nconss; i++ )
4004  {
4005  SCIP_CALL( checkCons(scip, conss[i], NULL, TRUE, &violated) );
4006  if( violated )
4007  {
4008  *result = SCIP_INFEASIBLE;
4009  return SCIP_OKAY;
4010  }
4011  }
4012  *result = SCIP_FEASIBLE;
4013 
4014  return SCIP_OKAY;
4015 }
4016 
4017 
4018 /** feasibility check method of constraint handler for integral solutions */
4019 static
4020 SCIP_DECL_CONSCHECK(consCheckXor)
4021 { /*lint --e{715}*/
4022  SCIP_Bool violated;
4023  int i;
4024 
4025  /* method is called only for integral solutions, because the enforcing priority is negative */
4026  for( i = 0; i < nconss; i++ )
4027  {
4028  SCIP_CALL( checkCons(scip, conss[i], sol, checklprows, &violated) );
4029  if( violated )
4030  {
4031  *result = SCIP_INFEASIBLE;
4032 
4033  if( printreason )
4034  {
4035  int v;
4036  int sum = 0;
4037  SCIP_CONSDATA* consdata;
4038 
4039  consdata = SCIPconsGetData(conss[i]);
4040  assert( consdata != NULL );
4041 
4042  SCIP_CALL( SCIPprintCons(scip, conss[i], NULL) );
4043 
4044  for( v = 0; v < consdata->nvars; ++v )
4045  {
4046  if( SCIPgetSolVal(scip, sol, consdata->vars[v]) > 0.5 )
4047  sum++;
4048  }
4049  SCIPinfoMessage(scip, NULL, ";\nviolation: %d operands are set to TRUE\n", sum );
4050  }
4051 
4052  return SCIP_OKAY;
4053  }
4054  }
4055  *result = SCIP_FEASIBLE;
4056 
4057  return SCIP_OKAY;
4058 }
4059 
4060 
4061 /** domain propagation method of constraint handler */
4062 static
4064 { /*lint --e{715}*/
4065  SCIP_CONSHDLRDATA* conshdlrdata;
4066  SCIP_Bool cutoff;
4067  int nfixedvars;
4068  int nchgbds;
4069  int c;
4070 
4071  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4072  assert(conshdlrdata != NULL);
4073 
4074  cutoff = FALSE;
4075  nfixedvars = 0;
4076  nchgbds = 0;
4077 
4078  /* propagate all useful constraints */
4079  for( c = 0; c < nusefulconss && !cutoff; ++c )
4080  {
4081  SCIP_CALL( propagateCons(scip, conss[c], conshdlrdata->eventhdlr, &cutoff, &nfixedvars, &nchgbds) );
4082  }
4083 
4084  /* return the correct result */
4085  if( cutoff )
4086  *result = SCIP_CUTOFF;
4087  else if( nfixedvars > 0 || nchgbds > 0 )
4088  *result = SCIP_REDUCEDDOM;
4089  else
4090  {
4091  *result = SCIP_DIDNOTFIND;
4092  if ( ! SCIPinProbing(scip) )
4093  {
4094  int depth;
4095  int freq;
4096 
4097  depth = SCIPgetDepth(scip);
4098  freq = conshdlrdata->gausspropfreq;
4099  if ( (depth == 0 && freq == 0) || (freq > 0 && depth % freq == 0) )
4100  {
4101  /* take usefull constraints only - might improve success rate to take all */
4102  SCIP_CALL( checkSystemGF2(scip, conss, nusefulconss, NULL, result) );
4103  }
4104  }
4105 
4106  }
4107 
4108  return SCIP_OKAY;
4109 }
4110 
4111 
4112 /** presolving method of constraint handler */
4113 static
4114 SCIP_DECL_CONSPRESOL(consPresolXor)
4115 { /*lint --e{715}*/
4116  SCIP_CONSHDLRDATA* conshdlrdata;
4117  SCIP_CONS* cons;
4118  SCIP_CONSDATA* consdata;
4119  SCIP_Bool cutoff;
4120  SCIP_Bool delay;
4121  SCIP_Bool redundant;
4122  SCIP_Bool aggregated;
4123  int oldnfixedvars;
4124  int oldnchgbds;
4125  int oldnaggrvars;
4126  int oldndelconss;
4127  int oldnchgcoefs;
4128  int firstchange;
4129  int c;
4130 
4131  assert(result != NULL);
4132 
4133  oldnfixedvars = *nfixedvars;
4134  oldnchgbds = *nchgbds;
4135  oldnaggrvars = *naggrvars;
4136  oldndelconss = *ndelconss;
4137  oldnchgcoefs = *nchgcoefs;
4138 
4139  conshdlrdata = SCIPconshdlrGetData(conshdlr);
4140  assert(conshdlrdata != NULL);
4141 
4142  /* process constraints */
4143  cutoff = FALSE;
4144  delay = FALSE;
4145  firstchange = INT_MAX;
4146  for( c = 0; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
4147  {
4148  cons = conss[c];
4149  assert(cons != NULL);
4150  consdata = SCIPconsGetData(cons);
4151  assert(consdata != NULL);
4152 
4153  /* force presolving the constraint in the initial round */
4154  if( nrounds == 0 )
4155  consdata->propagated = FALSE;
4156 
4157  /* remember the first changed constraint to begin the next aggregation round with */
4158  if( firstchange == INT_MAX && consdata->changed )
4159  firstchange = c;
4160 
4161  /* remove all variables that are fixed to zero and all pairs of variables fixed to one;
4162  * merge multiple entries of the same or negated variables
4163  */
4164  SCIP_CALL( applyFixings(scip, cons, conshdlrdata->eventhdlr, nchgcoefs) );
4165 
4166  /* propagate constraint */
4167  SCIP_CALL( propagateCons(scip, cons, conshdlrdata->eventhdlr, &cutoff, nfixedvars, nchgbds) );
4168 
4169  if( !cutoff && !SCIPconsIsDeleted(cons) && !SCIPconsIsModifiable(cons) )
4170  {
4171  assert(consdata->nvars >= 2); /* otherwise, propagateCons() has deleted the constraint */
4172 
4173  /* if only two variables are left, both have to be equal or opposite, depending on the rhs */
4174  if( consdata->nvars == 2 )
4175  {
4176  SCIPdebugMessage("xor constraint <%s> has only two unfixed variables, rhs=%u\n",
4177  SCIPconsGetName(cons), consdata->rhs);
4178 
4179  assert(consdata->vars != NULL);
4180  assert(SCIPisEQ(scip, SCIPvarGetLbGlobal(consdata->vars[0]), 0.0));
4181  assert(SCIPisEQ(scip, SCIPvarGetUbGlobal(consdata->vars[0]), 1.0));
4182  assert(SCIPisEQ(scip, SCIPvarGetLbGlobal(consdata->vars[1]), 0.0));
4183  assert(SCIPisEQ(scip, SCIPvarGetUbGlobal(consdata->vars[1]), 1.0));
4184 
4185  if( !consdata->rhs )
4186  {
4187  /* aggregate variables: vars[0] - vars[1] == 0 */
4188  SCIPdebugMessage(" -> aggregate <%s> == <%s>\n", SCIPvarGetName(consdata->vars[0]),
4189  SCIPvarGetName(consdata->vars[1]));
4190  SCIP_CALL( SCIPaggregateVars(scip, consdata->vars[0], consdata->vars[1], 1.0, -1.0, 0.0,
4191  &cutoff, &redundant, &aggregated) );
4192  }
4193  else
4194  {
4195  /* aggregate variables: vars[0] + vars[1] == 1 */
4196  SCIPdebugMessage(" -> aggregate <%s> == 1 - <%s>\n", SCIPvarGetName(consdata->vars[0]),
4197  SCIPvarGetName(consdata->vars[1]));
4198  SCIP_CALL( SCIPaggregateVars(scip, consdata->vars[0], consdata->vars[1], 1.0, 1.0, 1.0,
4199  &cutoff, &redundant, &aggregated) );
4200  }
4201  assert(redundant || SCIPdoNotAggr(scip));
4202 
4203  if( aggregated )
4204  {
4205  assert(redundant);
4206  (*naggrvars)++;
4207  }
4208 
4209  if( redundant )
4210  {
4211  /* delete constraint */
4212  SCIP_CALL( SCIPdelCons(scip, cons) );
4213  (*ndelconss)++;
4214  }
4215  }
4216  else
4217  {
4218  /* try to use clique information to upgrade the constraint to a set-partitioning constraint or fix
4219  * variables
4220  */
4221  SCIP_CALL( cliquePresolve(scip, cons, nfixedvars, nchgcoefs, ndelconss, naddconss, &cutoff) );
4222  }
4223  }
4224  }
4225 
4226  /* process pairs of constraints: check them for equal operands;
4227  * only apply this expensive procedure, if the single constraint preprocessing did not find any reductions
4228  * (otherwise, we delay the presolving to be called again next time)
4229  */
4230  if( !cutoff )
4231  {
4232  if( *nfixedvars == oldnfixedvars && *nchgbds == oldnchgbds && *naggrvars == oldnaggrvars )
4233  {
4234  if( firstchange < nconss && conshdlrdata->presolusehashing )
4235  {
4236  /* detect redundant constraints; fast version with hash table instead of pairwise comparison */
4237  SCIP_CALL( detectRedundantConstraints(scip, SCIPblkmem(scip), conss, nconss, &firstchange, nchgcoefs, ndelconss, &cutoff) );
4238  }
4239  if( conshdlrdata->presolpairwise )
4240  {
4241  SCIP_Longint npaircomparisons;
4242  int lastndelconss;
4243  npaircomparisons = 0;
4244  lastndelconss = *ndelconss;
4245 
4246  for( c = firstchange; c < nconss && !cutoff && !SCIPisStopped(scip); ++c )
4247  {
4248  if( SCIPconsIsActive(conss[c]) && !SCIPconsIsModifiable(conss[c]) )
4249  {
4250  npaircomparisons += (SCIPconsGetData(conss[c])->changed) ? (SCIP_Longint) c : ((SCIP_Longint) c - (SCIP_Longint) firstchange);
4251 
4252  SCIP_CALL( preprocessConstraintPairs(scip, conss, firstchange, c,
4253  &cutoff, nfixedvars, naggrvars, ndelconss, nchgcoefs) );
4254 
4255  if( npaircomparisons > NMINCOMPARISONS )
4256  {
4257  if( ((SCIP_Real) (*ndelconss - lastndelconss)) / ((SCIP_Real) npaircomparisons) < MINGAINPERNMINCOMPARISONS )
4258  break;
4259  lastndelconss = *ndelconss;
4260  npaircomparisons = 0;
4261  }
4262  }
4263  }
4264  }
4265  }
4266  else
4267  delay = TRUE;
4268  }
4269 
4270  /* return the correct result code */
4271  if( cutoff )
4272  *result = SCIP_CUTOFF;
4273  else if( delay )
4274  *result = SCIP_DELAYED;
4275  else if( *nfixedvars > oldnfixedvars || *nchgbds > oldnchgbds || *naggrvars > oldnaggrvars
4276  || *ndelconss > oldndelconss || *nchgcoefs > oldnchgcoefs )
4277  *result = SCIP_SUCCESS;
4278  else
4279  *result = SCIP_DIDNOTFIND;
4280 
4281  /* add extended formulation at the end of presolving if required */
4282  if ( conshdlrdata->addextendedform && *result == SCIP_DIDNOTFIND && SCIPisPresolveFinished(scip) )
4283  {
4284  for (c = 0; c < nconss && ! SCIPisStopped(scip); ++c)
4285  {
4286  int naddedconss = 0;
4287 
4288  cons = conss[c];
4289  assert(cons != NULL);
4290  consdata = SCIPconsGetData(cons);
4291  assert(consdata != NULL);
4292 
4293  if ( consdata->extvars != NULL )
4294  break;
4295 
4296  if ( conshdlrdata->addflowextended )
4297  {
4298  SCIP_CALL( addExtendedFlowFormulation(scip, cons, &naddedconss) );
4299  }
4300  else
4301  {
4302  SCIP_CALL( addExtendedAsymmetricFormulation(scip, cons, &naddedconss) );
4303  }
4304  (*naddconss) += naddedconss;
4305  }
4306  }
4307 
4308  return SCIP_OKAY;
4309 }
4310 
4311 
4312 /** propagation conflict resolving method of constraint handler */
4313 static
4314 SCIP_DECL_CONSRESPROP(consRespropXor)
4315 { /*lint --e{715}*/
4316  SCIP_CALL( resolvePropagation(scip, cons, infervar, (PROPRULE)inferinfo, bdchgidx, result) );
4317 
4318  return SCIP_OKAY;
4319 }
4320 
4321 
4322 /** variable rounding lock method of constraint handler */
4323 static
4325 { /*lint --e{715}*/
4326  SCIP_CONSDATA* consdata;
4327  int i;
4328 
4329  consdata = SCIPconsGetData(cons);
4330  assert(consdata != NULL);
4331 
4332  /* external variables */
4333  for( i = 0; i < consdata->nvars; ++i )
4334  {
4335  SCIP_CALL( SCIPaddVarLocks(scip, consdata->vars[i], nlockspos + nlocksneg, nlockspos + nlocksneg) );
4336  }
4337 
4338  /* internal variable */
4339  if( consdata->intvar != NULL )
4340  {
4341  SCIP_CALL( SCIPaddVarLocks(scip, consdata->intvar, nlockspos + nlocksneg, nlockspos + nlocksneg) );
4342  }
4343 
4344  return SCIP_OKAY;
4345 }
4346 
4347 
4348 /** constraint display method of constraint handler */
4349 static
4350 SCIP_DECL_CONSPRINT(consPrintXor)
4351 { /*lint --e{715}*/
4352  assert( scip != NULL );
4353  assert( conshdlr != NULL );
4354  assert( cons != NULL );
4355 
4356  SCIP_CALL( consdataPrint(scip, SCIPconsGetData(cons), file, FALSE) );
4357 
4358  return SCIP_OKAY;
4359 }
4360 
4361 /** constraint copying method of constraint handler */
4362 static
4364 { /*lint --e{715}*/
4365  SCIP_CONSDATA* sourceconsdata;
4366  SCIP_VAR** sourcevars;
4367  SCIP_VAR** targetvars;
4368  SCIP_VAR* intvar;
4369  SCIP_VAR* targetintvar;
4370  const char* consname;
4371  int nvars;
4372  int v;
4373 
4374  assert(scip != NULL);
4375  assert(sourcescip != NULL);
4376  assert(sourcecons != NULL);
4377 
4378  (*valid) = TRUE;
4379 
4380  sourceconsdata = SCIPconsGetData(sourcecons);
4381  assert(sourceconsdata != NULL);
4382 
4383  /* get variables and coefficients of the source constraint */
4384  sourcevars = sourceconsdata->vars;
4385  nvars = sourceconsdata->nvars;
4386  intvar = sourceconsdata->intvar;
4387  targetintvar = NULL;
4388 
4389  if( name != NULL )
4390  consname = name;
4391  else
4392  consname = SCIPconsGetName(sourcecons);
4393 
4394  if( nvars == 0 )
4395  {
4396  if( intvar != NULL )
4397  {
4398  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, intvar, &targetintvar, varmap, consmap, global, valid) );
4399  assert(!(*valid) || targetintvar != NULL);
4400 
4401  SCIPdebugMessage("Copied integral variable <%s> (bounds: [%g,%g])\n", SCIPvarGetName(targetintvar),
4402  global ? SCIPvarGetLbGlobal(intvar) : SCIPvarGetLbLocal(intvar),
4403  global ? SCIPvarGetUbGlobal(intvar) : SCIPvarGetUbLocal(intvar));
4404  }
4405 
4406  if( *valid )
4407  {
4408  SCIP_CALL( createConsXorIntvar(scip, cons, consname, SCIPgetRhsXor(sourcescip, sourcecons), 0, NULL,
4409  targetintvar,
4410  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
4411  }
4412 
4413  return SCIP_OKAY;
4414  }
4415 
4416  /* duplicate variable array */
4417  SCIP_CALL( SCIPallocBufferArray(scip, &targetvars, nvars) );
4418 
4419  /* map variables of the source constraint to variables of the target SCIP */
4420  for( v = 0; v < nvars && *valid; ++v )
4421  {
4422  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &targetvars[v], varmap, consmap, global, valid) );
4423  assert(!(*valid) || targetvars[v] != NULL);
4424  }
4425 
4426  /* map artificial relaxation variable of the source constraint to variable of the target SCIP */
4427  if( *valid && intvar != NULL )
4428  {
4429  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, intvar, &targetintvar, varmap, consmap, global, valid) );
4430  assert(!(*valid) || targetintvar != NULL);
4431 
4432  SCIPdebugMessage("Copied integral variable <%s> (bounds: [%g,%g])\n", SCIPvarGetName(targetintvar),
4433  global ? SCIPvarGetLbGlobal(intvar) : SCIPvarGetLbLocal(intvar),
4434  global ? SCIPvarGetUbGlobal(intvar) : SCIPvarGetUbLocal(intvar));
4435  }
4436 
4437  /* only create the target constraints, if all variables could be copied */
4438  if( *valid )
4439  {
4440  SCIP_CALL( createConsXorIntvar(scip, cons, consname, SCIPgetRhsXor(sourcescip, sourcecons), nvars, targetvars,
4441  targetintvar,
4442  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
4443  }
4444 
4445  /* free buffer array */
4446  SCIPfreeBufferArray(scip, &targetvars);
4447 
4448  return SCIP_OKAY;
4449 }
4450 
4451 
4452 /** constraint parsing method of constraint handler */
4453 static
4454 SCIP_DECL_CONSPARSE(consParseXor)
4455 { /*lint --e{715}*/
4456  SCIP_VAR** vars;
4457  char* endptr;
4458  int requiredsize;
4459  int varssize;
4460  int nvars;
4461 
4462  SCIPdebugMessage("parse <%s> as xor constraint\n", str);
4463 
4464  varssize = 100;
4465  nvars = 0;
4466 
4467  /* allocate buffer array for variables */
4468  SCIP_CALL( SCIPallocBufferArray(scip, &vars, varssize) );
4469 
4470  /* parse string */
4471  SCIP_CALL( SCIPparseVarsList(scip, str, vars, &nvars, varssize, &requiredsize, &endptr, ',', success) );
4472 
4473  if( *success )
4474  {
4475  SCIP_Real rhs;
4476 
4477  /* check if the size of the variable array was big enough */
4478  if( varssize < requiredsize )
4479  {
4480  /* reallocate memory */
4481  varssize = requiredsize;
4482  SCIP_CALL( SCIPreallocBufferArray(scip, &vars, varssize) );
4483 
4484  /* parse string again with the correct size of the variable array */
4485  SCIP_CALL( SCIPparseVarsList(scip, str, vars, &nvars, varssize, &requiredsize, &endptr, ',', success) );
4486  }
4487 
4488  assert(*success);
4489  assert(varssize >= requiredsize);
4490 
4491  SCIPdebugMessage("successfully parsed %d variables\n", nvars);
4492 
4493  str = endptr;
4494 
4495  /* search for the equal symbol */
4496  while( *str != '=' && *str != '\0' )
4497  str++;
4498 
4499  /* if the string end has been reached without finding the '=' */
4500  if ( *str == '\0' )
4501  {
4502  SCIPerrorMessage("Could not find terminating '='.\n");
4503  *success = FALSE;
4504  }
4505  else
4506  {
4507  /* skip '=' character */
4508  ++str;
4509 
4510  if( SCIPstrToRealValue(str, &rhs, &endptr) )
4511  {
4512  assert(SCIPisZero(scip, rhs) || SCIPisEQ(scip, rhs, 1.0));
4513 
4514  /* create or constraint */
4515  SCIP_CALL( SCIPcreateConsXor(scip, cons, name, (rhs > 0.5 ? TRUE : FALSE), nvars, vars,
4516  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
4517 
4518  SCIPdebugPrintCons(scip, *cons, NULL);
4519  }
4520  else
4521  *success = FALSE;
4522  }
4523  }
4524 
4525  /* free variable buffer */
4526  SCIPfreeBufferArray(scip, &vars);
4527 
4528  return SCIP_OKAY;
4529 }
4530 
4531 /** constraint method of constraint handler which returns the variables (if possible) */
4532 static
4533 SCIP_DECL_CONSGETVARS(consGetVarsXor)
4534 { /*lint --e{715}*/
4535  SCIP_CONSDATA* consdata;
4536  int nintvar = 0;
4537  int cnt;
4538  int j;
4539 
4540  consdata = SCIPconsGetData(cons);
4541  assert(consdata != NULL);
4542 
4543  if ( consdata->intvar != NULL )
4544  nintvar = 1;
4545 
4546  if ( varssize < consdata->nvars + nintvar + consdata->nextvars )
4547  (*success) = FALSE;
4548  else
4549  {
4550  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
4551 
4552  if ( consdata->intvar != NULL )
4553  vars[consdata->nvars] = consdata->intvar;
4554 
4555  if ( consdata->nextvars > 0 )
4556  {
4557  assert( consdata->extvars != NULL );
4558  cnt = consdata->nvars + nintvar;
4559  for (j = 0; j < consdata->extvarssize; ++j)
4560  {
4561  if ( consdata->extvars[j] != NULL )
4562  vars[cnt++] = consdata->extvars[j];
4563  }
4564  assert( cnt == consdata->nvars + nintvar + consdata->nextvars );
4565  }
4566 
4567  (*success) = TRUE;
4568  }
4569 
4570  return SCIP_OKAY;
4571 }
4572 
4573 /** constraint method of constraint handler which returns the number of variable (if possible) */
4574 static
4575 SCIP_DECL_CONSGETNVARS(consGetNVarsXor)
4576 { /*lint --e{715}*/
4577  SCIP_CONSDATA* consdata;
4578 
4579  assert(cons != NULL);
4580 
4581  consdata = SCIPconsGetData(cons);
4582  assert(consdata != NULL);
4583 
4584  if( consdata->intvar == NULL )
4585  (*nvars) = consdata->nvars + consdata->nextvars;
4586  else
4587  (*nvars) = consdata->nvars + 1 + consdata->nextvars;
4588 
4589  (*success) = TRUE;
4590 
4591  return SCIP_OKAY;
4592 }
4593 
4594 /*
4595  * Callback methods of event handler
4596  */
4597 
4598 static
4599 SCIP_DECL_EVENTEXEC(eventExecXor)
4600 { /*lint --e{715}*/
4601  SCIP_CONSDATA* consdata;
4602 
4603  assert(eventhdlr != NULL);
4604  assert(eventdata != NULL);
4605  assert(event != NULL);
4606 
4607  consdata = (SCIP_CONSDATA*)eventdata;
4608  assert(consdata != NULL);
4609 
4610  consdata->propagated = FALSE;
4611 
4612  return SCIP_OKAY;
4613 }
4614 
4615 
4616 /*
4617  * constraint specific interface methods
4618  */
4619 
4620 /** creates the handler for xor constraints and includes it in SCIP */
4622  SCIP* scip /**< SCIP data structure */
4623  )
4624 {
4625  SCIP_CONSHDLRDATA* conshdlrdata;
4626  SCIP_CONSHDLR* conshdlr;
4627  SCIP_EVENTHDLR* eventhdlr;
4628 
4629  /* create event handler for events on variables */
4631  eventExecXor, NULL) );
4632 
4633  /* create constraint handler data */
4634  SCIP_CALL( conshdlrdataCreate(scip, &conshdlrdata, eventhdlr) );
4635 
4636  /* include constraint handler */
4639  consEnfolpXor, consEnfopsXor, consCheckXor, consLockXor,
4640  conshdlrdata) );
4641  assert(conshdlr != NULL);
4642 
4643  /* set non-fundamental callbacks via specific setter functions */
4644  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyXor, consCopyXor) );
4645  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteXor) );
4646  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolXor) );
4647  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeXor) );
4648  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsXor) );
4649  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsXor) );
4650  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpXor) );
4651  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseXor) );
4652  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolXor, CONSHDLR_MAXPREROUNDS, CONSHDLR_DELAYPRESOL) );
4653  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintXor) );
4654  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropXor, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
4656  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropXor) );
4657  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpXor, consSepasolXor, CONSHDLR_SEPAFREQ,
4659  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransXor) );
4660 
4661  /* add xor constraint handler parameters */
4663  "constraints/xor/presolpairwise",
4664  "should pairwise constraint comparison be performed in presolving?",
4665  &conshdlrdata->presolpairwise, TRUE, DEFAULT_PRESOLPAIRWISE, NULL, NULL) );
4666 
4668  "constraints/xor/presolusehashing",
4669  "should hash table be used for detecting redundant constraints in advance?",
4670  &conshdlrdata->presolusehashing, TRUE, DEFAULT_PRESOLUSEHASHING, NULL, NULL) );
4671 
4673  "constraints/xor/addextendedform",
4674  "should the extended formulation be added in presolving?",
4675  &conshdlrdata->addextendedform, TRUE, DEFAULT_ADDEXTENDEDFORM, NULL, NULL) );
4676 
4678  "constraints/xor/addflowextended",
4679  "should the extended flow formulation be added (nonsymmetric formulation otherwise)?",
4680  &conshdlrdata->addflowextended, TRUE, DEFAULT_ADDFLOWEXTENDED, NULL, NULL) );
4681 
4683  "constraints/xor/separateparity",
4684  "should parity inequalities be separated?",
4685  &conshdlrdata->separateparity, TRUE, DEFAULT_SEPARATEPARITY, NULL, NULL) );
4686 
4687  SCIP_CALL( SCIPaddIntParam(scip,
4688  "constraints/xor/gausspropfreq",
4689  "frequency for applying the Gauss propagator",
4690  &conshdlrdata->gausspropfreq, TRUE, DEFAULT_GAUSSPROPFREQ, -1, INT_MAX, NULL, NULL) );
4691 
4692  return SCIP_OKAY;
4693 }
4694 
4695 /** creates and captures a xor constraint x_0 xor ... xor x_{k-1} = rhs
4696  *
4697  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
4698  */
4700  SCIP* scip, /**< SCIP data structure */
4701  SCIP_CONS** cons, /**< pointer to hold the created constraint */
4702  const char* name, /**< name of constraint */
4703  SCIP_Bool rhs, /**< right hand side of the constraint */
4704  int nvars, /**< number of operator variables in the constraint */
4705  SCIP_VAR** vars, /**< array with operator variables of constraint */
4706  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
4707  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
4708  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
4709  * Usually set to TRUE. */
4710  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
4711  * TRUE for model constraints, FALSE for additional, redundant constraints. */
4712  SCIP_Bool check, /**< should the constraint be checked for feasibility?
4713  * TRUE for model constraints, FALSE for additional, redundant constraints. */
4714  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
4715  * Usually set to TRUE. */
4716  SCIP_Bool local, /**< is constraint only valid locally?
4717  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
4718  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
4719  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
4720  * adds coefficients to this constraint. */
4721  SCIP_Bool dynamic, /**< is constraint subject to aging?
4722  * Usually set to FALSE. Set to TRUE for own cuts which
4723  * are separated as constraints. */
4724  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
4725  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
4726  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
4727  * if it may be moved to a more global node?
4728  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
4729  )
4730 {
4731  SCIP_CONSHDLR* conshdlr;
4732  SCIP_CONSDATA* consdata;
4733 
4734  /* find the xor constraint handler */
4735  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
4736  if( conshdlr == NULL )
4737  {
4738  SCIPerrorMessage("xor constraint handler not found\n");
4739  return SCIP_PLUGINNOTFOUND;
4740  }
4741 
4742  /* create constraint data */
4743  SCIP_CALL( consdataCreate(scip, &consdata, rhs, nvars, vars, NULL) );
4744 
4745  /* create constraint */
4746  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
4747  local, modifiable, dynamic, removable, stickingatnode) );
4748 
4749  return SCIP_OKAY;
4750 }
4751 
4752 /** creates and captures a xor constraint x_0 xor ... xor x_{k-1} = rhs
4753  * with all constraint flags set to their default values
4754  *
4755  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
4756  */
4758  SCIP* scip, /**< SCIP data structure */
4759  SCIP_CONS** cons, /**< pointer to hold the created constraint */
4760  const char* name, /**< name of constraint */
4761  SCIP_Bool rhs, /**< right hand side of the constraint */
4762  int nvars, /**< number of operator variables in the constraint */
4763  SCIP_VAR** vars /**< array with operator variables of constraint */
4764  )
4765 {
4766  SCIP_CALL( SCIPcreateConsXor(scip,cons, name, rhs, nvars, vars,
4767  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
4768 
4769  return SCIP_OKAY;
4770 }
4771 
4772 /** gets number of variables in xor constraint */
4774  SCIP* scip, /**< SCIP data structure */
4775  SCIP_CONS* cons /**< constraint data */
4776  )
4777 {
4778  SCIP_CONSDATA* consdata;
4779 
4780  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
4781  {
4782  SCIPerrorMessage("constraint is not an xor constraint\n");
4783  SCIPABORT();
4784  return -1; /*lint !e527*/
4785  }
4786 
4787  consdata = SCIPconsGetData(cons);
4788  assert(consdata != NULL);
4789 
4790  return consdata->nvars;
4791 }
4792 
4793 /** gets array of variables in xor constraint */
4795  SCIP* scip, /**< SCIP data structure */
4796  SCIP_CONS* cons /**< constraint data */
4797  )
4798 {
4799  SCIP_CONSDATA* consdata;
4800 
4801  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
4802  {
4803  SCIPerrorMessage("constraint is not an xor constraint\n");
4804  SCIPABORT();
4805  return NULL; /*lint !e527*/
4806  }
4807 
4808  consdata = SCIPconsGetData(cons);
4809  assert(consdata != NULL);
4810 
4811  return consdata->vars;
4812 }
4813 
4814 /** gets the right hand side of the xor constraint */
4816  SCIP* scip, /**< SCIP data structure */
4817  SCIP_CONS* cons /**< constraint data */
4818  )
4819 {
4820  SCIP_CONSDATA* consdata;
4821 
4822  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
4823  {
4824  SCIPerrorMessage("constraint is not an xor constraint\n");
4825  SCIPABORT();
4826  }
4827 
4828  consdata = SCIPconsGetData(cons);
4829  assert(consdata != NULL);
4830 
4831  return consdata->rhs;
4832 }
4833