Scippy

SCIP

Solving Constraint Integer Programs

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