Scippy

SCIP

Solving Constraint Integer Programs

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