Scippy

SCIP

Solving Constraint Integer Programs

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