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