Scippy

SCIP

Solving Constraint Integer Programs

cons_superindicator.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2014 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not email to scip@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_superindicator.c
17  * @brief constraint handler for indicator constraints over arbitrary constraint types
18  * @author Ambros Gleixner
19  * @author Frederic Pythoud
20  */
21 
22 /**@todo allow more types for slack constraint */
23 /**@todo implement more upgrades, e.g., for nonlinear, quadratic, logicor slack constraints; upgrades could also help to
24  * handle difficult slack constraints such as pseudoboolean or indicator
25  */
26 /**@todo unify enfolp and enfops, sepalp and sepaps callbacks */
27 /**@todo enforce by branching on binary variable if slack constraint only returns SCIP_INFEASIBLE */
28 /**@todo consider enforcing by adding slack constraint (or copy of it) locally if binary variable is fixed to 1
29  * (some constraint handler cannot enforce constraints that are not active)
30  */
31 
32 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
33 
34 #include <assert.h>
35 #include <string.h>
36 
38 #include "scip/dialog_default.h"
39 #include "scip/cons_indicator.h"
40 #include "scip/cons_linear.h"
41 
42 
43 /* constraint handler properties */
44 #define CONSHDLR_NAME "superindicator"
45 #define CONSHDLR_DESC "constraint handler for indicator constraints over arbitrary constraint types"
46 #define CONSHDLR_SEPAPRIORITY 0 /**< priority of the constraint handler for separation */
47 #define CONSHDLR_ENFOPRIORITY -5000000 /**< priority of the constraint handler for constraint enforcing */
48 #define CONSHDLR_CHECKPRIORITY -5000000 /**< priority of the constraint handler for checking feasibility */
49 #define CONSHDLR_SEPAFREQ -1 /**< frequency for separating cuts; zero means to separate only in the root node */
50 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
51 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
52  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
53 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler
54  * participates in (-1: no limit) */
55 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
56 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
57 #define CONSHDLR_DELAYPRESOL FALSE /**< should presolving method be delayed, if other presolvers found reductions? */
58 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
59 
60 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler*/
61 
62 #define DEFAULT_CHECKSLACKTYPE TRUE /**< should type of slack constraint be checked when creating superindicator constraint? */
63 #define DEFAULT_UPGDPRIOINDICATOR 1 /**< priority for upgrading to an indicator constraint (-1: never) */
64 #define DEFAULT_UPGDPRIOLINEAR 2 /**< priority for upgrading to a linear constraint (-1: never) */
65 #define DEFAULT_MAXUPGDCOEFLINEAR 1e4 /**< maximum big-M coefficient of binary variable in upgrade to a linear constraint
66  * (relative to smallest coefficient) */
67 
68 
69 /*
70  * Data structures
71  */
72 
73 /** constraint data for superindicator constraints */
74 struct SCIP_ConsData
75 {
76  SCIP_CONS* slackcons; /**< constraint corresponding to the handled constraint */
77  SCIP_VAR* binvar; /**< binary variable for indicator constraint */
78 };
79 
80 /** constraint handler data */
81 struct SCIP_ConshdlrData
82 {
83  SCIP_Bool checkslacktype; /**< should type of slack constraint be checked when creating superindicator constraint? */
84  SCIP_Real maxupgdcoeflinear; /**< maximum big-M coefficient of binary variable in upgrade to a linear constraint
85  * (relative to smallest coefficient) */
86  int upgdprioindicator; /**< priority for upgrading to an indicator constraint (-1: never) */
87  int upgdpriolinear; /**< priority for upgrading to a linear constraint (-1: never) */
88  int nrejects; /**< number of rejected calls to create method */
89 };
90 
91 /*
92  * Local methods
93  */
94 
95 /** creates superindicator constraint data */
96 static
98  SCIP* scip, /**< SCIP data structure */
99  SCIP_CONSDATA** consdata, /**< pointer to constraint data */
100  SCIP_VAR* binvar, /**< binary variable */
101  SCIP_CONS* slackcons /**< slack constraint */
102  )
103 {
104  assert(scip != NULL);
105 
106  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
107 
108  (*consdata)->binvar = binvar;
109  (*consdata)->slackcons = slackcons;
110 
111  if( SCIPisTransformed(scip) )
112  {
113  SCIPdebugMessage("creating the transformed data\n");
114 
115  /* do not capture the slack constraint when scip is in transformed mode; this automatically happens in
116  * SCIPtransformCons() if necessary
117  */
118  SCIP_CALL( SCIPtransformCons(scip, (*consdata)->slackcons, &(*consdata)->slackcons) );
119 
120  /* get transformed binary variable */
121  SCIP_CALL( SCIPgetTransformedVar(scip, (*consdata)->binvar, &(*consdata)->binvar) );
122  }
123  else
124  {
125  /* we need to capture the constraint to avoid that SCIP deletes them since they are not (yet) added to the problem */
126  SCIP_CALL( SCIPcaptureCons(scip, slackcons) );
127  }
128 
129  assert((*consdata)->slackcons != NULL);
130 
131  return SCIP_OKAY;
132 }
133 
134 /** checks the feasibility of a superindicator constraint */
135 static
137  SCIP* scip, /**< SCIP data structure */
138  SCIP_CONSDATA* consdata, /**< pointer to superindicator constraint data */
139  SCIP_SOL* sol, /**< pointer to the solution to be checked */
140  SCIP_Bool checkintegrality, /**< has integrality to be checked? */
141  SCIP_Bool checklprows, /**< have current LP rows to be checked? */
142  SCIP_Bool printreason, /**< should the reason for the violation be printed? */
143  SCIP_RESULT* result /**< pointer to store the result of the test */
144  )
145 {
146  SCIP_Real binval;
147 
148  /* not to be called if infeasibility is already detected */
149  assert(*result == SCIP_FEASIBLE || *result == SCIP_DIDNOTRUN);
150 
151  binval = SCIPgetSolVal(scip, sol, consdata->binvar);
152 
153  /* check integrality of binary variable */
154  if( checkintegrality && !SCIPisIntegral(scip, binval) )
155  {
156  if( printreason )
157  {
158  SCIPinfoMessage(scip, NULL, "violation: binvar takes fractional value %.15g\n", binval);
159  }
160 
161  *result = SCIP_INFEASIBLE;
162  }
163  /* if binvar is one, call SCIPcheckCons() for the slack constraint */
164  else if( binval > 0.5 )
165  {
166  assert(SCIPisFeasEQ(scip, binval, 1.0));
167 
168  SCIP_CALL( SCIPcheckCons(scip, consdata->slackcons, sol, checkintegrality, checklprows, printreason, result) );
169 
170  if( printreason && *result != SCIP_FEASIBLE )
171  {
172  SCIPinfoMessage(scip, NULL, "violation: SCIPcheckCons() for slack constraint <%s> returns infeasible while binvar <%s> == 1\n",
173  SCIPconsGetName(consdata->slackcons), SCIPvarGetName(consdata->binvar));
174  }
175 
176 #ifdef SCIP_DEBUG
177  {
178  /* checking in debug mode that different flags don't give us different results */
179  SCIP_RESULT testresultnotintegrality;
180  SCIP_RESULT testresultnotlprows;
181 
182  SCIP_CALL( SCIPcheckCons(scip, consdata->slackcons, sol, checkintegrality, TRUE, TRUE, &testresultnotintegrality) );
183  SCIP_CALL( SCIPcheckCons(scip, consdata->slackcons, sol, TRUE, checklprows, TRUE, &testresultnotlprows) );
184 
185  assert(*result == testresultnotintegrality);
186  assert(*result == testresultnotlprows);
187  }
188 #endif
189 
190  SCIPdebugMessage("binvar <%s> == 1, sol=%p --> SCIPcheckCons() on constraint <%s> --> %s\n",
191  SCIPvarGetName(consdata->binvar), (void*)sol, SCIPconsGetName(consdata->slackcons),
192  *result == SCIP_FEASIBLE ? "satisfied" : "violated");
193  }
194  /* if binval is zero, the superindicator constraint is feasible */
195  else
196  {
197  *result = SCIP_FEASIBLE;
198  }
199 
200  return SCIP_OKAY;
201 }
202 
203 /** computes the minactivity, maxactivity, and minimal absolute value of nonzero coefficients of a linear constraint
204  * with respect to its global bounds
205  */
206 static
208  SCIP* scip, /**< SCIP data structure */
209  SCIP_CONS* cons, /**< pointer to linear constraint */
210  SCIP_Real* minactivity, /**< pointer to return the minimal activity */
211  SCIP_Real* maxactivity, /**< pointer to return the maximal activity */
212  SCIP_Real* minabscoef /**< pointer to return the minimal absolute value of the coefficients */
213  )
214 {
215  SCIP_VAR** vars;
216  SCIP_Real* vals;
217  SCIP_Bool ismininfinity;
218  SCIP_Bool ismaxinfinity;
219  int nvars;
220  int i;
221 
222  assert(scip != NULL);
223  assert(cons != NULL);
224  assert(minactivity != NULL);
225  assert(maxactivity != NULL);
226  assert(minabscoef != NULL);
227  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), "linear") == 0);
228 
229  /* get nonzero elements */
230  vars = SCIPgetVarsLinear(scip, cons);
231  vals = SCIPgetValsLinear(scip, cons);
232  nvars = SCIPgetNVarsLinear(scip, cons);
233 
234  /* initialize values */
235  *minactivity = 0.0;
236  *maxactivity = 0.0;
237  *minabscoef = SCIPinfinity(scip);
238  ismininfinity = FALSE;
239  ismaxinfinity = FALSE;
240 
241  /* we loop over all the coefficients of the constraint and we cannot end if the minactivity is infinite as we
242  * still need to compute the minimum absolute coefficient value
243  */
244  for( i = nvars-1; i >= 0; i-- )
245  {
246  SCIP_Real val;
247  SCIP_Real lb;
248  SCIP_Real ub;
249 
250  val = vals[i];
251  lb = SCIPvarGetLbGlobal(vars[i]);
252  ub = SCIPvarGetUbGlobal(vars[i]);
253 
254  /* update flags for infinite bounds */
255  ismininfinity = ismininfinity || (val > 0.0 && (SCIPisInfinity(scip, lb) || SCIPisInfinity(scip, -lb)))
256  || (val < 0.0 && (SCIPisInfinity(scip, ub) || SCIPisInfinity(scip, -ub)));
257 
258  ismaxinfinity = ismaxinfinity || (val > 0.0 && (SCIPisInfinity(scip, ub) || SCIPisInfinity(scip, -ub)))
259  || (val < 0.0 && (SCIPisInfinity(scip, lb) || SCIPisInfinity(scip, -lb)));
260 
261  /* update activities if not infinite */
262  if( !ismininfinity )
263  *minactivity += (val > 0.0) ? val * lb : val * ub;
264 
265  if( !ismaxinfinity )
266  *maxactivity += (val > 0.0) ? val * ub : val * lb;
267 
268  /* update minimal absolute coefficient value */
269  if( val > 0.0 && val < *minabscoef )
270  *minabscoef = val;
271  else if( val < 0.0 && -val < *minabscoef )
272  *minabscoef = -vals[i];
273  }
274 
275  if( ismininfinity )
276  *minactivity = -SCIPinfinity(scip);
277 
278  if( ismaxinfinity )
279  *maxactivity = SCIPinfinity(scip);
280 
281  return SCIP_OKAY;
282 }
283 
284 /** tries to upgrade superindicator constraint to an indicator constraint */
285 static
287  SCIP* scip, /**< SCIP data structure */
288  SCIP_CONS* cons, /**< superindicator constraint to be upgraded */
289  SCIP_Bool* success, /**< pointer to store if the upgrading was successful */
290  SCIP_Bool* deleted /**< pointer to store if the constraint was deleted */
291 )
292 {
293  SCIP_CONSHDLR* conshdlr;
294  SCIP_CONSDATA* consdata;
295  SCIP_CONS* indcons;
296 
297  SCIP_Real lhs;
298  SCIP_Real rhs;
299  char name[SCIP_MAXSTRLEN];
300  int i;
301 
302 #ifdef SCIP_DEBUG
303  int nnewconss;
304 #endif
305 
306  assert(scip != NULL);
307  assert(cons != NULL);
308  assert(success != NULL);
309  assert(deleted != NULL);
310 
311  *success = FALSE;
312  *deleted = FALSE;
313 
314  SCIPdebug( nnewconss = 0 );
315 
316  /* get data of superindicator constraint */
317  consdata = SCIPconsGetData(cons);
318  assert(consdata != NULL);
319 
320  /* upgrade only for linear slack constraint */
321  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(consdata->slackcons)), "linear") != 0 )
322  return SCIP_OKAY;
323 
324  /* upgrade only if indicator constraint handler found */
325  conshdlr = SCIPfindConshdlr(scip, "indicator");
326  if( conshdlr == NULL )
327  return SCIP_OKAY;
328 
329  /* if linear slack constraint is free we can delete the superindicator constraint */
330  lhs = SCIPgetLhsLinear(scip, consdata->slackcons);
331  rhs = SCIPgetRhsLinear(scip, consdata->slackcons);
332  if( SCIPisInfinity(scip, -lhs) && SCIPisInfinity(scip, rhs) )
333  {
334  SCIP_CALL( SCIPdelCons(scip, cons) );
335  *deleted = TRUE;
336 
337  SCIPdebugMessage("constraint <%s> deleted because of free slack constraint\n", SCIPconsGetName(cons));
338 
339  return SCIP_OKAY;
340  }
341 
342  /* upgrade rhs inequality */
343  if( !SCIPisInfinity(scip, rhs) )
344  {
345  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_upgd_indrhs", SCIPconsGetName(cons));
346 
347  SCIP_CALL( SCIPcreateConsIndicator(scip, &indcons, name, consdata->binvar, SCIPgetNVarsLinear(scip, consdata->slackcons),
348  SCIPgetVarsLinear(scip, consdata->slackcons), SCIPgetValsLinear(scip, consdata->slackcons), rhs,
351  SCIPconsIsStickingAtNode(cons)) );
352 
353  SCIP_CALL( SCIPaddCons(scip, indcons) );
354  SCIP_CALL( SCIPreleaseCons(scip, &indcons) );
355 
356  SCIPdebug( nnewconss++ );
357  }
358 
359  /* upgrade lhs inequality */
360  if( !SCIPisInfinity(scip, -lhs) )
361  {
362  SCIP_Real* negvals;
363  SCIP_Real* vals;
364  int nvars;
365 
366  vals = SCIPgetValsLinear(scip, consdata->slackcons);
367  nvars = SCIPgetNVarsLinear(scip, consdata->slackcons);
368 
369  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_upgd_indlhs", SCIPconsGetName(cons));
370 
371  /* create array of negated coefficient values */
372  SCIP_CALL( SCIPallocBufferArray(scip, &negvals, nvars) );
373  for( i = nvars-1; i >= 0; i-- )
374  negvals[i] = -vals[i];
375 
376  SCIP_CALL( SCIPcreateConsIndicator(scip, &indcons, name, consdata->binvar, nvars,
377  SCIPgetVarsLinear(scip, consdata->slackcons), negvals, -lhs,
380  SCIPconsIsStickingAtNode(cons)) );
381 
382  SCIP_CALL( SCIPaddCons(scip, indcons) );
383  SCIP_CALL( SCIPreleaseCons(scip, &indcons) );
384 
385  SCIPfreeBufferArray(scip, &negvals);
386 
387  SCIPdebug( nnewconss++ );
388  }
389 
390  SCIPdebug( SCIPdebugMessage("constraint <%s> upgraded to %d indicator constraint%s\n",
391  SCIPconsGetName(cons), nnewconss, nnewconss == 1 ? "" : "s") );
392 
393  /* delete the superindicator constraint */
394  SCIP_CALL( SCIPdelCons(scip, cons) );
395  *success = TRUE;
396 
397  return SCIP_OKAY;
398 }
399 
400 /** upgrades a superindicator constraint to a linear constraint if possible */
401 static
403  SCIP* scip, /**< SCIP data structure */
404  SCIP_CONS* cons, /**< superindicator constraint to be upgraded */
405  SCIP_Bool* success, /**< pointer to store if the upgrading was successful */
406  SCIP_Bool* deleted /**< pointer to store if the constraint was deleted */
407 )
408 {
409  SCIP_CONSHDLR* conshdlr;
410  SCIP_CONSDATA* consdata;
411  SCIP_CONS* slackcons;
412  SCIP_VAR** slackvars;
413  SCIP_VAR** newvars;
414  SCIP_Real* slackvals;
415  SCIP_Real* newvals;
416 
417  SCIP_Real maxcoef;
418  SCIP_Real minabscoef;
419  SCIP_Real minact;
420  SCIP_Real maxact;
421  SCIP_Real lhs;
422  SCIP_Real rhs;
423 
424  int nvars;
425  int i;
426 
427 #ifdef SCIP_DEBUG
428  int nnewconss;
429 #endif
430 
431  assert(scip != NULL);
432  assert(cons != NULL);
433  assert(success != NULL);
434  assert(deleted != NULL);
435 
436  *success = FALSE;
437  *deleted = FALSE;
438 
439  SCIPdebug( nnewconss = 0 );
440 
441  /* get data of superindicator constraint */
442  consdata = SCIPconsGetData(cons);
443  assert(consdata != NULL);
444 
445  slackcons = consdata->slackcons;
446  assert(slackcons != NULL);
447 
448  /* upgrade only for linear slack constraint */
449  if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(slackcons)), "linear") != 0 )
450  return SCIP_OKAY;
451 
452  /**@todo store in conshdlrdata */
453 
454  /* upgrade only if linear constraint handler found */
455  conshdlr = SCIPfindConshdlr(scip, "linear");
456  if( conshdlr == NULL )
457  return SCIP_OKAY;
458 
459  /* if linear slack constraint is free we can delete the superindicator constraint */
460  rhs = SCIPgetRhsLinear(scip, slackcons);
461  lhs = SCIPgetLhsLinear(scip, slackcons);
462 
463  if( SCIPisInfinity(scip, rhs) && SCIPisInfinity(scip, -lhs) )
464  {
465  SCIP_CALL( SCIPdelCons(scip, cons) );
466  *deleted = TRUE;
467 
468  SCIPdebugMessage("constraint <%s> deleted because of free slack constraint\n", SCIPconsGetName(cons));
469 
470  return SCIP_OKAY;
471  }
472 
473  /* if linear slack constraint is redundant due to bounded activities we can delete the superindicator constraint */
474  SCIP_CALL( extractLinearValues(scip, slackcons, &minact, &maxact, &minabscoef) );
475  assert(!SCIPisInfinity(scip, minact));
476  assert(!SCIPisInfinity(scip, -maxact));
477 
478  if( (SCIPisInfinity(scip, -lhs) || SCIPisLE(scip, lhs, minact)) && (SCIPisInfinity(scip, rhs) || SCIPisGE(scip, rhs, maxact)) )
479  {
480  SCIP_CALL( SCIPdelCons(scip, cons) );
481  *deleted = TRUE;
482 
483  SCIPdebugMessage("constraint <%s> deleted because of redundant slack constraint\n", SCIPconsGetName(cons));
484 
485  return SCIP_OKAY;
486  }
487 
488  /* if the big-M coefficient is too large compared to the coefficients of the slack constraint, we do not upgrade to
489  * avoid numerical problems
490  */
491  maxcoef = minabscoef * SCIPconshdlrGetData(SCIPconsGetHdlr(cons))->maxupgdcoeflinear;
492 
493  if( (!SCIPisInfinity(scip, rhs) && (SCIPisInfinity(scip, maxact) || SCIPisInfinity(scip, maxact - rhs) ||
494  maxact - rhs > maxcoef)) ||
495  (!SCIPisInfinity(scip, -lhs) && (SCIPisInfinity(scip, -minact) || SCIPisInfinity(scip, lhs - minact) ||
496  lhs - minact > maxcoef)) )
497  {
498  SCIPdebugMessage("constraint <%s> not upgraded to a linear constraint due to large big-M coefficient\n",
499  SCIPconsGetName(cons));
500  return SCIP_OKAY;
501  }
502 
503  /* allocating memory for new constraint */
504  nvars = SCIPgetNVarsLinear(scip, slackcons);
505  SCIP_CALL( SCIPallocBufferArray(scip, &newvars, nvars+1) );
506  SCIP_CALL( SCIPallocBufferArray(scip, &newvals, nvars+1) );
507 
508  /* copy the vars and the vals array */
509  slackvars = SCIPgetVarsLinear(scip, slackcons);
510  slackvals = SCIPgetValsLinear(scip, slackcons);
511 
512  assert(slackvars != NULL);
513  assert(slackvals != NULL);
514 
515  for( i = nvars-1; i >= 0; i-- )
516  {
517  newvars[i] = slackvars[i];
518  newvals[i] = slackvals[i];
519  }
520 
521  /* add binary variable */
522  newvars[nvars] = consdata->binvar;
523  assert(newvars[nvars] != NULL);
524 
525  assert(!SCIPisInfinity(scip, -lhs) || !SCIPisInfinity(scip, rhs));
526 
527  /* create the upgraded constraint for rhs inequality */
528  if( !SCIPisInfinity(scip, rhs) )
529  {
530  SCIP_CONS* newcons;
531  char name[SCIP_MAXSTRLEN];
532 
533  assert(!SCIPisInfinity(scip, -maxact) );
534  assert(!SCIPisInfinity(scip, maxact));
535 
536  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_upgd_linrhs", SCIPconsGetName(cons));
537 
538  /* compute big-M */
539  newvals[nvars] = maxact - rhs;
540  assert(!SCIPisInfinity(scip, newvals[nvars]));
541  assert(!SCIPisInfinity(scip, -newvals[nvars]));
542 
543  /* rhs inequality is redundant if maxact is less equal rhs */
544  if( SCIPisPositive(scip, newvals[nvars]) )
545  {
546  SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, nvars+1, newvars, newvals, -SCIPinfinity(scip), maxact,
550 
551  SCIP_CALL( SCIPaddCons(scip, newcons) );
552  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
553 
554  SCIPdebug( nnewconss++ );
555  }
556  }
557 
558  /* create the upgraded constraint for rhs inequality */
559  if( !SCIPisInfinity(scip, -lhs) )
560  {
561  SCIP_CONS* newcons;
562  char name[SCIP_MAXSTRLEN];
563 
564  assert(!SCIPisInfinity(scip, minact));
565  assert(!SCIPisInfinity(scip, -minact));
566 
567  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "%s_upgd_linlhs", SCIPconsGetName(cons));
568 
569  /* compute big-M */
570  newvals[nvars] = minact - lhs;
571  assert(!SCIPisInfinity(scip, newvals[nvars]));
572  assert(!SCIPisInfinity(scip, -newvals[nvars]));
573 
574  /* lhs inequality is redundant if minact is greater equal lhs */
575  if( SCIPisNegative(scip, newvals[nvars]) )
576  {
577  SCIP_CALL( SCIPcreateConsLinear(scip, &newcons, name, nvars+1, newvars, newvals, minact, SCIPinfinity(scip),
581 
582  SCIP_CALL( SCIPaddCons(scip, newcons) );
583  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
584 
585  SCIPdebug( nnewconss++ );
586  }
587  }
588 
589  /* free memory */
590  SCIPfreeBufferArray(scip, &newvals);
591  SCIPfreeBufferArray(scip, &newvars);
592 
593  SCIPdebug( SCIPdebugMessage("constraint <%s> upgraded to %d indicator constraint%s\n",
594  SCIPconsGetName(cons), nnewconss, nnewconss == 1 ? "" : "s") );
595 
596  /* delete the superindicator constraint */
597  SCIP_CALL( SCIPdelCons(scip, cons) );
598  *success = TRUE;
599 
600  return SCIP_OKAY;
601 }
602 
603 /** tries to upgrade a superindicator constraint in order of the upgrade priority parameters */
604 static
606  SCIP* scip, /**< SCIP data structure */
607  SCIP_CONS* cons, /**< superindicator constraint to be updated */
608  SCIP_Bool* success, /**< pointer to store if the constraint was upgraded */
609  SCIP_Bool* deleted /**< pointer to store if the constraint was deleted */
610  )
611 {
612  SCIP_CONSHDLRDATA* conshdlrdata;
613 
614  assert(scip != NULL);
615  assert(cons != NULL);
616  assert(success != NULL);
617  assert(deleted != NULL);
618 
619  *success = FALSE;
620  *deleted = FALSE;
621 
622  conshdlrdata = SCIPconshdlrGetData(SCIPconsGetHdlr(cons));
623 
624  /* indicator upgrade before linear upgrade */
625  if( conshdlrdata->upgdprioindicator > conshdlrdata->upgdpriolinear )
626  {
627  assert(conshdlrdata->upgdprioindicator >= 0);
628 
629  SCIP_CALL( upgradeIndicatorSuperindicator(scip, cons, success, deleted) );
630 
631  if( !*deleted && !*success && conshdlrdata->upgdpriolinear >= 0 )
632  {
633  SCIP_CALL( upgradeLinearSuperindicator(scip, cons, success, deleted) );
634  }
635  }
636  /* linear upgrade before indicator upgrade */
637  else if( conshdlrdata->upgdpriolinear >= 0 )
638  {
639  SCIP_CALL( upgradeLinearSuperindicator(scip, cons, success, deleted) );
640 
641  if( !*deleted && !*success && conshdlrdata->upgdprioindicator >= 0 )
642  {
643  SCIP_CALL( upgradeIndicatorSuperindicator(scip, cons, success, deleted) );
644  }
645  }
646 
647  return SCIP_OKAY;
648 }
649 
650 
651 /*
652  * Callback methods of constraint handler
653  */
654 
655 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
656 static
657 SCIP_DECL_CONSHDLRCOPY(conshdlrCopySuperindicator)
658 { /*lint --e{715}*/
659  assert(scip != NULL);
660  assert(conshdlr != NULL);
661  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
662 
663  /* call inclusion method of constraint handler */
665 
666  *valid = TRUE;
667 
668  return SCIP_OKAY;
669 }
670 
671 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
672 static
673 SCIP_DECL_CONSFREE(consFreeSuperindicator)
674 { /*lint --e{715}*/
675  SCIP_CONSHDLRDATA* conshdlrdata;
676 
677  assert(conshdlr != NULL);
678  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
679  assert(scip != NULL);
680 
681  SCIPdebugMessage("freeing superindicator constraint handler data\n");
682 
683  /* free constraint handler data */
684  conshdlrdata = SCIPconshdlrGetData(conshdlr);
685  assert(conshdlrdata != NULL);
686 
687  SCIPfreeMemory(scip, &conshdlrdata);
688 
689  SCIPconshdlrSetData(conshdlr, NULL);
690 
691  return SCIP_OKAY;
692 }
693 
694 /** presolving initialization method of constraint handler (called when presolving is about to begin) */
695 static
696 SCIP_DECL_CONSINITPRE(consInitpreSuperindicator)
697 { /*lint --e{715}*/
698  SCIP_CONSDATA* consdata;
699  int i;
700 
701  SCIPdebugMessage("initializing presolving\n");
702 
703  for( i = nconss-1; i >= 0; i-- )
704  {
705  consdata = SCIPconsGetData(conss[i]);
706  assert(consdata != NULL);
707 
708  /* make the constraint local to avoid wrong propagation */
709  SCIP_CALL( SCIPsetConsLocal(scip, consdata->slackcons, TRUE) );
710  }
711 
712  return SCIP_OKAY;
713 }
714 
715 /** frees specific constraint data */
716 static
717 SCIP_DECL_CONSDELETE(consDeleteSuperindicator)
718 { /*lint --e{715}*/
719  assert(conshdlr != NULL);
720  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
721  assert(consdata != NULL);
722  assert(*consdata != NULL);
723  assert((*consdata)->slackcons != NULL);
724 
725  SCIPdebugMessage("deleting constraint <%s>\n", SCIPconsGetName(cons));
726 
727  /* we have to release the slack constraint also in case we transformed it manually since it is captured automatically
728  * in SCIPtransformCons()
729  */
730  SCIP_CALL( SCIPreleaseCons(scip, &((*consdata)->slackcons)) );
731 
732  /* free memory */
733  SCIPfreeBlockMemory(scip, consdata);
734 
735  return SCIP_OKAY;
736 }
737 
738 /** transforms constraint data into data belonging to the transformed problem */
739 static
740 SCIP_DECL_CONSTRANS(consTransSuperindicator)
741 { /*lint --e{715}*/
742  SCIP_CONSDATA* sourcedata;
743  SCIP_CONSDATA* targetdata;
744  char newname[SCIP_MAXSTRLEN];
745 
746  SCIPdebugMessage("transforming superindicator constraint <%s>\n", SCIPconsGetName(sourcecons));
747 
748  /* get constraint data of source constraint */
749  sourcedata = SCIPconsGetData(sourcecons);
750  assert(sourcedata != NULL);
751 
752  (void) SCIPsnprintf(newname, SCIP_MAXSTRLEN, "t_%s", SCIPconsGetName(sourcecons) );
753  SCIP_CALL( consdataCreateSuperindicator(scip, &targetdata, sourcedata->binvar, sourcedata->slackcons) );
754 
755  /* create target constraint and capture it at the same time */
756  SCIP_CALL( SCIPcreateCons(scip, targetcons, newname, conshdlr, targetdata,
757  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
758  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
759  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons),
760  SCIPconsIsStickingAtNode(sourcecons)) );
761 
762  return SCIP_OKAY;
763 }
764 
765 /** LP initialization method of constraint handler */
766 static
767 SCIP_DECL_CONSINITLP(consInitlpSuperindicator)
768 {
769  int c;
770 
771  assert(scip != NULL);
772  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
773 
774  SCIPdebugMessage("executing initlp callback\n");
775 
776  for( c = nconss-1; c >= 0; c-- )
777  {
778  SCIP_CONSDATA* consdata;
779 
780  consdata = SCIPconsGetData(conss[c]);
781 
782  assert(consdata != NULL);
783  assert(SCIPconsIsInitial(conss[c]));
784 
785  if( SCIPvarGetLbLocal(consdata->binvar) > 0.5 )
786  {
787  assert(SCIPisFeasEQ(scip, SCIPvarGetLbLocal(consdata->binvar), 1.0));
788 
789  SCIPdebugMessage("binvar <%s> == 1 --> SCIPinitlpCons() on constraint <%s>\n",
790  SCIPvarGetName(consdata->binvar), SCIPconsGetName(consdata->slackcons));
791 
792  SCIP_CALL( SCIPinitlpCons(scip, consdata->slackcons) );
793  }
794  }
795 
796  return SCIP_OKAY;
797 }
798 
799 /** separation method of constraint handler for LP solutions */
800 static
801 SCIP_DECL_CONSSEPALP(consSepalpSuperindicator)
802 { /*lint --e{715}*/
803  int c;
804 
805  assert(conshdlr != NULL);
806  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
807  assert(conss != NULL);
808  assert(result != NULL);
809 
810  *result = SCIP_DELAYED;
811 
812  SCIPdebugMessage("executing sepalp callback\n");
813 
814 #ifdef SCIP_OUTPUT
815  SCIP_CALL( SCIPprintSol(scip, NULL, NULL, FALSE) );
816 #endif
817 
818  /* check all useful constraints */
819  for( c = nusefulconss-1; c >= 0 && *result != SCIP_CUTOFF; c-- )
820  {
821  SCIP_CONSDATA* consdata;
822  SCIP_RESULT locresult;
823 
824  consdata = SCIPconsGetData(conss[c]);
825  assert(consdata != NULL);
826 
827  locresult = SCIP_DELAYED;
828 
829  /* separate only if binvar is fixed to one */
830  if( SCIPvarGetLbLocal(consdata->binvar) > 0.5 )
831  {
832  assert(SCIPisFeasEQ(scip, SCIPvarGetLbLocal(consdata->binvar), 1.0));
833 
834  SCIPdebugMessage("binvar <%s> == 1 --> SCIPsepalpCons() on constraint <%s>\n",
835  SCIPvarGetName(consdata->binvar), SCIPconsGetName(consdata->slackcons));
836 
837  SCIP_CALL( SCIPsepalpCons(scip, consdata->slackcons, &locresult) );
838 
839  SCIPdebugPrintf(" --> locresult=%d\n", locresult);
840  }
841 
842  /* evaluate result value */
843  switch( locresult )
844  {
845  case SCIP_CUTOFF:
846  case SCIP_CONSADDED:
847  assert(*result != SCIP_CUTOFF);
848  *result = locresult;
849  break;
850  case SCIP_REDUCEDDOM:
851  assert(*result != SCIP_CUTOFF);
852  if( *result != SCIP_CONSADDED )
853  *result = locresult;
854  break;
855  case SCIP_SEPARATED:
856  assert(*result != SCIP_CUTOFF);
857  if( *result != SCIP_CONSADDED
858  && *result != SCIP_REDUCEDDOM )
859  *result = locresult;
860  break;
861  case SCIP_NEWROUND:
862  assert(*result != SCIP_CUTOFF);
863  if( *result != SCIP_CONSADDED
864  && *result != SCIP_REDUCEDDOM
865  && *result != SCIP_SEPARATED )
866  *result = locresult;
867  break;
868  case SCIP_DIDNOTFIND:
869  assert(*result != SCIP_CUTOFF);
870  if( *result != SCIP_CONSADDED
871  && *result != SCIP_REDUCEDDOM
872  && *result != SCIP_NEWROUND
873  && *result != SCIP_SEPARATED )
874  *result = locresult;
875  break;
876  case SCIP_DIDNOTRUN:
877  assert(*result != SCIP_CUTOFF);
878  if( *result != SCIP_CONSADDED
879  && *result != SCIP_REDUCEDDOM
880  && *result != SCIP_NEWROUND
881  && *result != SCIP_SEPARATED
882  && *result != SCIP_DIDNOTFIND )
883  *result = locresult;
884  break;
885  case SCIP_INFEASIBLE:
886  assert(*result != SCIP_CUTOFF);
887  if( *result != SCIP_CONSADDED
888  && *result != SCIP_REDUCEDDOM
889  && *result != SCIP_SEPARATED
890  && *result != SCIP_DIDNOTFIND
891  && *result != SCIP_DIDNOTRUN
892  && *result != SCIP_NEWROUND )
893  *result = locresult;
894  break;
895  case SCIP_DELAYED:
896  break;
897  default:
898  SCIPerrorMessage("invalid SCIP result %d\n", locresult);
899  return SCIP_INVALIDRESULT;
900  } /*lint !e788*/
901  }
902 
903  SCIPdebugMessage("sepalp result=%d\n", *result);
904 
905  return SCIP_OKAY;
906 }
907 
908 /** separation method of constraint handler for arbitrary primal solutions */
909 static
910 SCIP_DECL_CONSSEPASOL(consSepasolSuperindicator)
911 { /*lint --e{715}*/
912  int c;
913 
914  assert(conshdlr != NULL);
915  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
916  assert(conss != NULL);
917  assert(result != NULL);
918 
919  *result = SCIP_DELAYED;
920 
921  SCIPdebugMessage("executing sepasol callback\n");
922 
923 #ifdef SCIP_OUTPUT
924  SCIP_CALL( SCIPprintSol(scip, NULL, NULL, FALSE) );
925 #endif
926 
927 
928  /* check all the useful constraint */
929  for( c = 0; c < nusefulconss && *result != SCIP_CUTOFF; ++c )
930  {
931  SCIP_CONSDATA* consdata;
932  SCIP_RESULT locresult;
933 
934  consdata = SCIPconsGetData(conss[c]);
935  assert(consdata != NULL);
936 
937  locresult = SCIP_DELAYED;
938 
939  /* separate only if binvar is fixed to one */
940  if( SCIPvarGetLbLocal(consdata->binvar) > 0.5 )
941  {
942  assert(SCIPisFeasEQ(scip, SCIPvarGetLbLocal(consdata->binvar), 1.0));
943 
944  SCIPdebugMessage("binvar <%s> == 0 --> SCIPsepasolCons() on constraint <%s>\n",
945  SCIPvarGetName(consdata->binvar), SCIPconsGetName(consdata->slackcons));
946 
947  SCIP_CALL( SCIPsepasolCons(scip, consdata->slackcons, sol, &locresult) );
948 
949  SCIPdebugPrintf(" --> result=%d\n", locresult);
950  }
951 
952  /* evaluate result value */
953  switch( locresult )
954  {
955  case SCIP_CUTOFF:
956  case SCIP_CONSADDED:
957  assert(*result != SCIP_CUTOFF);
958  *result = locresult;
959  break;
960  case SCIP_REDUCEDDOM:
961  assert(*result != SCIP_CUTOFF);
962  if( *result != SCIP_CONSADDED )
963  *result = locresult;
964  break;
965  case SCIP_SEPARATED:
966  assert(*result != SCIP_CUTOFF);
967  if( *result != SCIP_CONSADDED
968  && *result != SCIP_REDUCEDDOM )
969  *result = locresult;
970  break;
971  case SCIP_NEWROUND:
972  assert(*result != SCIP_CUTOFF);
973  if( *result != SCIP_CONSADDED
974  && *result != SCIP_REDUCEDDOM
975  && *result != SCIP_SEPARATED )
976  *result = locresult;
977  break;
978  case SCIP_DIDNOTFIND:
979  assert(*result != SCIP_CUTOFF);
980  if( *result != SCIP_CONSADDED
981  && *result != SCIP_REDUCEDDOM
982  && *result != SCIP_NEWROUND
983  && *result != SCIP_SEPARATED )
984  *result = locresult;
985  break;
986  case SCIP_DIDNOTRUN:
987  assert(*result != SCIP_CUTOFF);
988  if( *result != SCIP_CONSADDED
989  && *result != SCIP_REDUCEDDOM
990  && *result != SCIP_NEWROUND
991  && *result != SCIP_SEPARATED
992  && *result != SCIP_DIDNOTFIND )
993  *result = locresult;
994  break;
995  case SCIP_INFEASIBLE:
996  assert(*result != SCIP_CUTOFF);
997  if( *result != SCIP_CONSADDED
998  && *result != SCIP_REDUCEDDOM
999  && *result != SCIP_SEPARATED
1000  && *result != SCIP_DIDNOTFIND
1001  && *result != SCIP_DIDNOTRUN
1002  && *result != SCIP_NEWROUND )
1003  *result = locresult;
1004  break;
1005  case SCIP_DELAYED:
1006  break;
1007  default:
1008  SCIPerrorMessage("invalid SCIP result %d\n", locresult);
1009  return SCIP_INVALIDRESULT;
1010  } /*lint !e788*/
1011  }
1012 
1013  SCIPdebugMessage("sepa sol result=%d\n", *result);
1014 
1015  return SCIP_OKAY;
1016 }
1017 
1018 /** constraint enforcing method of constraint handler for LP solutions */
1019 static
1020 SCIP_DECL_CONSENFOLP(consEnfolpSuperindicator)
1021 { /*lint --e{715}*/
1022  SCIP_Bool cont;
1023  int i;
1024 
1025  assert(scip != NULL);
1026  assert(conshdlr != NULL);
1027  assert(result != NULL);
1028 
1029  /* if the solution is infeasible anyway, skip the enforcement */
1030  if( solinfeasible )
1031  {
1032  *result = SCIP_FEASIBLE;
1033  return SCIP_OKAY;
1034  }
1035 
1036  SCIPdebugMessage("executing enfolp callback\n");
1037 
1038  cont = TRUE;
1039  *result = SCIP_FEASIBLE;
1040 
1041 #ifdef SCIP_OUTPUT
1042  SCIP_CALL( SCIPprintSol(scip, NULL, NULL, FALSE) );
1043 #endif
1044 
1045  /* check all constraints */
1046  for( i = nconss-1; i >= 0 && cont; i-- )
1047  {
1048  SCIP_CONSDATA* consdata;
1049  SCIP_RESULT locresult;
1050 
1051  consdata = SCIPconsGetData(conss[i]);
1052  assert(consdata != NULL);
1053 
1054  locresult = SCIP_FEASIBLE;
1055 
1056  /* enforce only if binvar is fixed to one */
1057  if( SCIPvarGetLbLocal(consdata->binvar) > 0.5 )
1058  {
1059  assert(SCIPisFeasEQ(scip, SCIPvarGetLbLocal(consdata->binvar), 1.0));
1060 
1061  SCIPdebugMessage("binvar <%s> == 1 locally --> SCIPenfolpCons() on constraint <%s>\n",
1062  SCIPvarGetName(consdata->binvar), SCIPconsGetName(consdata->slackcons));
1063 
1064  SCIP_CALL( SCIPenfolpCons(scip, consdata->slackcons, solinfeasible, &locresult) );
1065 
1066  SCIPdebugPrintf(" --> %slocresult=%d\n", locresult == SCIP_FEASIBLE ? "satisfied, " : "", locresult);
1067  }
1068  /* otherwise check if we have not yet detected infeasibility */
1069  else if( *result == SCIP_FEASIBLE )
1070  {
1071  SCIP_CALL( consdataCheckSuperindicator(scip, consdata, NULL, TRUE, FALSE, FALSE, &locresult) );
1072  }
1073 
1074  /* evaluate result */
1075  switch( locresult )
1076  {
1077  case SCIP_CUTOFF:
1078  case SCIP_BRANCHED:
1079  assert(*result != SCIP_CUTOFF);
1080  assert(*result != SCIP_BRANCHED);
1081  *result = locresult;
1082  cont = FALSE;
1083  break;
1084  case SCIP_CONSADDED:
1085  assert(*result != SCIP_CUTOFF);
1086  assert(*result != SCIP_BRANCHED);
1087  if( *result != SCIP_CUTOFF )
1088  *result = locresult;
1089  break;
1090  case SCIP_REDUCEDDOM:
1091  assert(*result != SCIP_CUTOFF);
1092  assert(*result != SCIP_BRANCHED);
1093  if( *result != SCIP_CUTOFF
1094  && *result != SCIP_CONSADDED )
1095  *result = locresult;
1096  break;
1097  case SCIP_SEPARATED:
1098  assert(*result != SCIP_CUTOFF);
1099  assert(*result != SCIP_BRANCHED);
1100  if( *result != SCIP_CUTOFF
1101  && *result != SCIP_CONSADDED
1102  && *result != SCIP_REDUCEDDOM )
1103  *result = locresult;
1104  break;
1105  case SCIP_INFEASIBLE:
1106  assert(*result != SCIP_CUTOFF);
1107  assert(*result != SCIP_BRANCHED);
1108  if( *result != SCIP_CUTOFF
1109  && *result != SCIP_CONSADDED
1110  && *result != SCIP_REDUCEDDOM
1111  && *result != SCIP_SEPARATED
1112  && *result != SCIP_BRANCHED )
1113  *result = locresult;
1114  break;
1115  case SCIP_FEASIBLE:
1116  break;
1117  default:
1118  SCIPerrorMessage("invalid SCIP result %d\n", locresult);
1119  return SCIP_INVALIDRESULT;
1120  } /*lint !e788*/
1121  }
1122 
1123  SCIPdebugMessage("enfolp result=%d\n", *result);
1124 
1125  return SCIP_OKAY;
1126 }
1127 
1128 /** constraint enforcing method of constraint handler for pseudo solutions */
1129 static
1130 SCIP_DECL_CONSENFOPS(consEnfopsSuperindicator)
1131 { /*lint --e{715}*/
1132  SCIP_Bool cont;
1133  int i;
1134 
1135  assert(scip != NULL);
1136  assert(conshdlr != NULL);
1137  assert(result != NULL);
1138 
1139  /* if the solution is infeasible anyway, skip the enforcement */
1140  if( solinfeasible )
1141  {
1142  *result = SCIP_FEASIBLE;
1143  return SCIP_OKAY;
1144  }
1145  else if( objinfeasible )
1146  {
1147  *result = SCIP_DIDNOTRUN;
1148  return SCIP_OKAY;
1149  }
1150 
1151  SCIPdebugMessage("executing enfops callback\n");
1152 
1153  *result = SCIP_FEASIBLE;
1154  cont = TRUE;
1155 
1156  /* check all contraints */
1157  for( i = nconss-1; i >= 0 && cont; i-- )
1158  {
1159  SCIP_CONSDATA* consdata;
1160  SCIP_RESULT locresult;
1161 
1162  consdata = SCIPconsGetData(conss[i]);
1163  assert(consdata != NULL);
1164 
1165  locresult = SCIP_DIDNOTRUN;
1166 
1167  /* enforce only if binvar is fixed to one */
1168  if( SCIPvarGetLbLocal(consdata->binvar) > 0.5 )
1169  {
1170  assert(SCIPisFeasEQ(scip, SCIPvarGetLbLocal(consdata->binvar), 1.0));
1171 
1172  SCIPdebugMessage("binvar <%s> == 1 locally --> SCIPenfopsCons() on constraint <%s>\n",
1173  SCIPvarGetName(consdata->binvar), SCIPconsGetName(consdata->slackcons));
1174 
1175  SCIP_CALL( SCIPenfopsCons(scip, consdata->slackcons, solinfeasible, objinfeasible, &locresult) );
1176 
1177  SCIPdebugPrintf(" --> %slocresult=%d\n", locresult == SCIP_FEASIBLE ? "satisfied, " : "", locresult);
1178  }
1179  /* otherwise check if we have not yet detected infeasibility */
1180  else if( *result == SCIP_FEASIBLE || *result == SCIP_DIDNOTRUN )
1181  {
1182  SCIP_CALL( consdataCheckSuperindicator(scip, consdata, NULL, TRUE, FALSE, FALSE, &locresult) );
1183 
1184  }
1185 
1186  /* evaluate result value */
1187  switch( locresult )
1188  {
1189  case SCIP_CUTOFF:
1190  case SCIP_BRANCHED:
1191  assert(*result != SCIP_CUTOFF);
1192  assert(*result != SCIP_BRANCHED);
1193  *result = locresult;
1194  cont = FALSE;
1195  break;
1196  case SCIP_CONSADDED:
1197  assert(*result != SCIP_CUTOFF);
1198  assert(*result != SCIP_BRANCHED);
1199  if( *result != SCIP_CUTOFF )
1200  *result = locresult;
1201  break;
1202  case SCIP_REDUCEDDOM:
1203  assert(*result != SCIP_CUTOFF);
1204  assert(*result != SCIP_BRANCHED);
1205  if( *result != SCIP_CUTOFF
1206  && *result != SCIP_CONSADDED )
1207  *result = locresult;
1208  break;
1209  case SCIP_SOLVELP:
1210  assert(*result != SCIP_CUTOFF);
1211  assert(*result != SCIP_BRANCHED);
1212  if( *result != SCIP_CUTOFF
1213  && *result != SCIP_CONSADDED
1214  && *result != SCIP_REDUCEDDOM
1215  && *result != SCIP_BRANCHED )
1216  *result = locresult;
1217  break;
1218  case SCIP_INFEASIBLE:
1219  assert(*result != SCIP_CUTOFF);
1220  assert(*result != SCIP_BRANCHED);
1221  if( *result != SCIP_CUTOFF
1222  && *result != SCIP_CONSADDED
1223  && *result != SCIP_REDUCEDDOM
1224  && *result != SCIP_BRANCHED
1225  && *result != SCIP_SOLVELP )
1226  *result = locresult;
1227  break;
1228  case SCIP_DIDNOTRUN:
1229  assert(*result != SCIP_CUTOFF);
1230  assert(*result != SCIP_BRANCHED);
1231  if( *result != SCIP_CUTOFF
1232  && *result != SCIP_CONSADDED
1233  && *result != SCIP_REDUCEDDOM
1234  && *result != SCIP_BRANCHED
1235  && *result != SCIP_SOLVELP
1236  && *result != SCIP_INFEASIBLE )
1237  *result = locresult;
1238  break;
1239  case SCIP_FEASIBLE:
1240  assert(*result != SCIP_CUTOFF);
1241  assert(*result != SCIP_BRANCHED);
1242  if( *result != SCIP_CUTOFF
1243  && *result != SCIP_CONSADDED
1244  && *result != SCIP_REDUCEDDOM
1245  && *result != SCIP_BRANCHED
1246  && *result != SCIP_SOLVELP
1247  && *result != SCIP_INFEASIBLE
1248  && *result != SCIP_DIDNOTRUN )
1249  *result = locresult;
1250  break;
1251  default:
1252  SCIPerrorMessage("invalid SCIP result %d\n", locresult);
1253  return SCIP_INVALIDRESULT;
1254  } /*lint !e788*/
1255  }
1256 
1257  SCIPdebugMessage("enfops result=%d\n", *result);
1258 
1259  return SCIP_OKAY;
1260 }
1261 
1262 /** feasibility check method of constraint handler for integral solutions */
1263 static
1264 SCIP_DECL_CONSCHECK(consCheckSuperindicator)
1265 { /*lint --e{715}*/
1266  int i;
1267 
1268  assert(scip != NULL);
1269  assert(conshdlr != NULL);
1270  assert(result != NULL);
1271  assert(sol != NULL);
1272 
1273  *result = SCIP_FEASIBLE;
1274 
1275  for( i = nconss-1; i >= 0 && *result == SCIP_FEASIBLE; i-- )
1276  {
1277  SCIP_CONSDATA* consdata;
1278 
1279  consdata = SCIPconsGetData(conss[i]);
1280  SCIP_CALL( consdataCheckSuperindicator(scip, consdata, sol, checkintegrality, checklprows, printreason, result) );
1281  }
1282 
1283  SCIPdebugMessage("checked solution from <%s> (checkintegrality=%u, checklprows=%u) --> result=%d (%sfeasible)\n",
1284  SCIPsolGetHeur(sol) == NULL ? "NULL" : SCIPheurGetName(SCIPsolGetHeur(sol)), checkintegrality, checklprows,
1285  *result, *result == SCIP_INFEASIBLE ? "in" : "");
1286 
1287  return SCIP_OKAY;
1288 }
1289 
1290 /** domain propagation method of constraint handler */
1291 static
1292 SCIP_DECL_CONSPROP(consPropSuperindicator)
1293 { /*lint --e{715}*/
1294  int i;
1295 
1296  assert(scip != NULL);
1297  assert(conshdlr != NULL);
1298  assert(result != NULL);
1299 
1300  *result = SCIP_DIDNOTRUN;
1301 
1302  SCIPdebugMessage("executing prop callback\n");
1303 
1304  /* loop over all useful contraints */
1305  for( i = nusefulconss-1; i >= 0 && *result != SCIP_CUTOFF; i-- )
1306  {
1307  SCIP_CONSDATA* consdata;
1308  SCIP_RESULT locresult;
1309 
1310  consdata = SCIPconsGetData(conss[i]);
1311  assert(consdata != NULL);
1312 
1313  locresult = SCIP_DIDNOTRUN;
1314 
1315  /* propagate only if binvar is fixed to one */
1316  if( SCIPvarGetLbGlobal(consdata->binvar) > 0.5 )
1317  {
1318  assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(consdata->binvar), 1.0));
1319 
1320  SCIPdebugMessage("binvar <%s> == 1 globally --> deleting superindicator and adding slack constraint <%s>\n",
1321  SCIPvarGetName(consdata->binvar), SCIPconsGetName(consdata->slackcons));
1322 
1323  SCIP_CALL( SCIPsetConsLocal(scip, consdata->slackcons, FALSE) );
1324  SCIP_CALL( SCIPaddCons(scip, consdata->slackcons) );
1325  SCIP_CALL( SCIPdelCons(scip, conss[i]) );
1326 
1327  locresult = SCIP_DIDNOTFIND;
1328  }
1329  else if( SCIPvarGetLbLocal(consdata->binvar) > 0.5 )
1330  {
1331  assert(SCIPisFeasEQ(scip, SCIPvarGetLbLocal(consdata->binvar), 1.0));
1332 
1333  SCIPdebugMessage("binvar <%s> == 1 locally --> propagating slack constraint <%s>\n",
1334  SCIPvarGetName(consdata->binvar), SCIPconsGetName(consdata->slackcons));
1335 
1336  SCIP_CALL( SCIPpropCons(scip, consdata->slackcons, proptiming, &locresult) );
1337 
1338  SCIPdebugPrintf(" --> locresult=%d\n", locresult);
1339  }
1340  /**@todo else propagate the domain of the binvar as well: start probing mode, fix binvar to one, propagate
1341  * constraint, and see whether we become infeasible; if this is implemented, the resprop callback must be
1342  * updated
1343  */
1344 
1345  /* evaluate result value */
1346  switch( locresult )
1347  {
1348  case SCIP_CUTOFF:
1349  case SCIP_DELAYED:
1350  /* if propagation of one constraint is delayed, we want to propagate again unless the node is cut off */
1351  assert(*result != SCIP_CUTOFF);
1352  *result = locresult;
1353  break;
1354  case SCIP_REDUCEDDOM:
1355  assert(*result != SCIP_CUTOFF);
1356  if( *result != SCIP_DELAYED )
1357  *result = locresult;
1358  break;
1359  case SCIP_DIDNOTFIND:
1360  assert(*result != SCIP_CUTOFF);
1361  if( *result != SCIP_REDUCEDDOM
1362  && *result != SCIP_DELAYED )
1363  *result = locresult;
1364  break;
1365  case SCIP_DIDNOTRUN:
1366  assert(*result != SCIP_CUTOFF);
1367  if( *result != SCIP_REDUCEDDOM
1368  && *result != SCIP_DIDNOTFIND
1369  && *result != SCIP_DELAYED )
1370  *result = locresult;
1371  break;
1372  default:
1373  SCIPerrorMessage("invalid SCIP result %d\n", locresult);
1374  return SCIP_INVALIDRESULT;
1375  } /*lint !e788*/
1376  }
1377 
1378  SCIPdebugMessage("prop result=%d\n", *result);
1379 
1380  return SCIP_OKAY;
1381 }
1382 
1383 /** presolving method of constraint handler */
1384 static
1385 SCIP_DECL_CONSPRESOL(consPresolSuperindicator)
1386 { /*lint --e{715}*/
1387  int i;
1388 
1389  assert(scip != NULL);
1390  assert(conss != NULL);
1391  assert(conshdlr != NULL);
1392 
1393  *result = SCIP_DIDNOTRUN;
1394 
1395  SCIPdebugMessage("executing presol callback\n");
1396 
1397  for( i = nconss-1; i >= 0 && *result != SCIP_CUTOFF; i-- )
1398  {
1399  SCIP_CONSDATA* consdata;
1400  SCIP_RESULT locresult;
1401 
1402  consdata = SCIPconsGetData(conss[i]);
1403  assert(consdata != NULL);
1404 
1405  locresult = SCIP_DIDNOTFIND;
1406 
1407  /**@todo check whether the slack constraint is added to SCIP; in this case the superindicator can be deleted */
1408 
1409  /**@todo check whether the slack constraint is a superindicator constraint and presolve */
1410 
1411  /* if binvar is globally fixed to 1, we add the slack constraint and remove the superindicator */
1412  if( SCIPvarGetLbGlobal(consdata->binvar) > 0.5 )
1413  {
1414  assert(SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(consdata->binvar), 1.0));
1415 
1416  SCIPdebugMessage("binvar <%s> == 1 globally --> deleting superindicator and adding slack constraint <%s>\n",
1417  SCIPvarGetName(consdata->binvar), SCIPconsGetName(consdata->slackcons));
1418 
1419  SCIP_CALL( SCIPsetConsLocal(scip, consdata->slackcons, FALSE) );
1420  SCIP_CALL( SCIPaddCons(scip, consdata->slackcons) );
1421  SCIP_CALL( SCIPdelCons(scip, conss[i]) );
1422 
1423  locresult = SCIP_SUCCESS;
1424  }
1425  /* otherwise try upgrading */
1426  else
1427  {
1428  SCIP_Bool success;
1429  SCIP_Bool deleted;
1430 
1431  SCIP_CALL( upgradeSuperindicator(scip, conss[i], &success, &deleted) );
1432 
1433  /* update statistics */
1434  if( deleted )
1435  (*ndelconss)++;
1436  else if( success )
1437  (*nupgdconss)++;
1438 
1439  /**@todo mark if upgrading failed to avoid trying too often; however, since upgrading might fail only due to
1440  * large domains, we may want to try again later, e.g., if SCIPisPresolveFinished() is TRUE
1441  */
1442 
1443  if( deleted || success )
1444  locresult = SCIP_SUCCESS;
1445  }
1446  /**@todo else propagate the domain of the binvar as well: start probing mode, fix binvar to one, propagate
1447  * constraint, and see whether we become infeasible
1448  */
1449 
1450  /* evaluate result value */
1451  switch( locresult )
1452  {
1453  case SCIP_CUTOFF:
1454  case SCIP_DELAYED:
1455  /* if presolving of one constraint is delayed, we want to run again unless the result is cutoff */
1456  assert(*result != SCIP_CUTOFF);
1457  *result = locresult;
1458  break;
1459  case SCIP_SUCCESS:
1460  assert(*result != SCIP_CUTOFF);
1461  if( *result != SCIP_DELAYED )
1462  *result = locresult;
1463  break;
1464  case SCIP_UNBOUNDED:
1465  assert(*result != SCIP_CUTOFF);
1466  if( *result != SCIP_DELAYED
1467  && *result != SCIP_SUCCESS )
1468  *result = locresult;
1469  break;
1470  case SCIP_DIDNOTFIND:
1471  assert(*result != SCIP_CUTOFF);
1472  if( *result != SCIP_UNBOUNDED
1473  && *result != SCIP_DELAYED
1474  && *result != SCIP_SUCCESS )
1475  *result = locresult;
1476  break;
1477  case SCIP_DIDNOTRUN:
1478  assert(*result != SCIP_CUTOFF);
1479  if( *result != SCIP_UNBOUNDED
1480  && *result != SCIP_DIDNOTFIND
1481  && *result != SCIP_DELAYED
1482  && *result != SCIP_SUCCESS )
1483  *result = locresult;
1484  break;
1485  default:
1486  SCIPerrorMessage("invalid SCIP result %d\n", locresult);
1487  return SCIP_INVALIDRESULT;
1488  } /*lint !e788*/
1489  }
1490 
1491  SCIPdebugMessage("presol result=%d\n", *result);
1492 
1493  return SCIP_OKAY;
1494 }
1495 
1496 /** propagation conflict resolving method of constraint handler */
1497 static
1498 SCIP_DECL_CONSRESPROP(consRespropSuperindicator)
1499 { /*lint --e{715}*/
1500  SCIP_CONSDATA* consdata;
1501 
1502  assert(scip != NULL);
1503  assert(cons != NULL);
1504  assert(infervar != NULL);
1505  assert(bdchgidx != NULL);
1506  assert(result != NULL);
1507 
1508  SCIPdebugMessage("executing resprop callback for constraint <%s>\n", SCIPconsGetName(cons));
1509 
1510  consdata = SCIPconsGetData(cons);
1511  assert(consdata != NULL);
1512 
1513  *result = SCIP_DIDNOTFIND;
1514 
1515  /* check that we only propagated if the binvar is fixed to one */
1516  assert(SCIPisFeasEQ(scip, SCIPvarGetUbAtIndex(consdata->binvar, bdchgidx, TRUE), 1.0));
1517 
1518  /* add tightened lower bound on binvar to conflict set */
1519  SCIP_CALL( SCIPaddConflictLb(scip, consdata->binvar, bdchgidx) );
1520 
1521  /* call propagation conflict resolving method for the slack constraint */
1522  SCIP_CALL( SCIPrespropCons(scip, consdata->slackcons, infervar, inferinfo, boundtype, bdchgidx, relaxedbd, result) );
1523 
1524  SCIPdebugPrintf(" --> result=%d\n", *result);
1525 
1526  return SCIP_OKAY;
1527 }
1528 
1529 /** variable rounding lock method of constraint handler */
1530 static
1531 SCIP_DECL_CONSLOCK(consLockSuperindicator)
1532 { /*lint --e{715}*/
1533  SCIP_CONSDATA* consdata;
1534 
1535  assert(scip != NULL);
1536 
1537  SCIPdebugMessage("locking variables for constraint <%s>\n", SCIPconsGetName(cons));
1538 
1539  consdata = SCIPconsGetData(cons);
1540  assert(consdata != NULL);
1541 
1542  /* lock binvar up */
1543  SCIP_CALL( SCIPaddVarLocks(scip, consdata->binvar, nlocksneg, nlockspos) );
1544 
1545  /* call lock method for the slack constraint */
1546  SCIP_CALL( SCIPaddConsLocks(scip, consdata->slackcons, nlockspos, nlocksneg) );
1547 
1548  return SCIP_OKAY;
1549 }
1550 
1551 
1552 /** constraint display method of constraint handler */
1553 static
1554 SCIP_DECL_CONSPRINT(consPrintSuperindicator)
1555 { /*lint --e{715}*/
1556  SCIP_CONSDATA* consdata;
1557  SCIP_VAR* binvar;
1558  int zeroone;
1559 
1560  assert(scip != NULL);
1561  assert(conshdlr != NULL);
1562  assert(cons != NULL);
1563  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
1564 
1565  consdata = SCIPconsGetData(cons);
1566  assert(consdata != NULL);
1567 
1568  /* get binary variable */
1569  binvar = consdata->binvar;
1570  assert(binvar != NULL);
1571 
1572  /* resolve negation if necessary */
1573  zeroone = 1;
1574  if ( SCIPvarGetStatus(binvar) == SCIP_VARSTATUS_NEGATED )
1575  {
1576  zeroone = 0;
1577  binvar = SCIPvarGetNegatedVar(binvar);
1578  assert(binvar != NULL);
1579  }
1580 
1581  /* print name of the binary variable */
1582  SCIP_CALL( SCIPwriteVarName(scip, file, binvar, TRUE) );
1583 
1584  /* print implication */
1585  SCIPinfoMessage(scip, file, " = %d ->", zeroone);
1586 
1587  /* print slack constraint */
1588  assert(consdata->slackcons != NULL);
1589  SCIP_CALL( SCIPprintCons(scip, consdata->slackcons, file) );
1590 
1591  return SCIP_OKAY;
1592 }
1593 
1594 /** constraint copying method of constraint handler */
1595 static
1596 SCIP_DECL_CONSCOPY(consCopySuperindicator)
1597 { /*lint --e{715}*/
1598  SCIP_CONSHDLR* conshdlrslack;
1599  SCIP_CONSDATA* sourceconsdata;
1600  SCIP_CONS* sourceslackcons;
1601  SCIP_CONS* targetslackcons;
1602  SCIP_VAR* targetbinvar;
1603  const char* consname;
1604 
1605  assert(scip != NULL);
1606  assert(sourcescip != NULL);
1607  assert(sourcecons != NULL);
1608  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(sourcecons)), CONSHDLR_NAME) == 0);
1609 
1610  *valid = TRUE;
1611 
1612  if( name != NULL )
1613  consname = name;
1614  else
1615  consname = SCIPconsGetName(sourcecons);
1616 
1617  SCIPdebugMessage("copying superindicator constraint <%s> to <%s>\n", SCIPconsGetName(sourcecons), consname);
1618 
1619  if( modifiable )
1620  {
1621  SCIPwarningMessage(scip, "cannot create modifiable superindicator constraint when trying to copy constraint <%s>\n",
1622  SCIPconsGetName(sourcecons));
1623  *valid = FALSE;
1624  return SCIP_OKAY;
1625  }
1626 
1627  sourceconsdata = SCIPconsGetData(sourcecons);
1628  assert(sourceconsdata != NULL);
1629 
1630  /* get slack constraint */
1631  sourceslackcons = sourceconsdata->slackcons;
1632  assert(sourceslackcons != NULL);
1633 
1634  /* if the slack constraint has been deleted, create an empty linear constraint */
1635  if( SCIPconsIsDeleted(sourceslackcons) )
1636  {
1637  SCIPdebugMessage("slack constraint <%s> deleted; creating empty linear constraint\n",
1638  SCIPconsGetName(sourceslackcons));
1639 
1640  SCIP_CALL( SCIPcreateConsLinear(scip, &targetslackcons, "dummy", 0, NULL, NULL, 0.0, SCIPinfinity(scip),
1642 
1643  SCIP_CALL( SCIPaddCons(scip, targetslackcons) );
1644  }
1645  else
1646  {
1647  /* get copied version of slack constraint */
1648  conshdlrslack = SCIPconsGetHdlr(sourceslackcons);
1649  assert(conshdlrslack != NULL);
1650 
1651  /* if copying scip after transforming the original instance before presolving, we need to correct the slack
1652  * constraint pointer
1653  */
1654  assert(!SCIPisTransformed(sourcescip) || SCIPconsIsTransformed(sourceslackcons));
1655  if( SCIPisTransformed(sourcescip) && !SCIPconsIsTransformed(sourceslackcons) )
1656  {
1657  SCIP_CONS* transslackcons;
1658 
1659  SCIP_CALL( SCIPgetTransformedCons(sourcescip, sourceslackcons, &transslackcons) );
1660  assert(transslackcons != NULL);
1661  SCIP_CALL( SCIPreleaseCons(sourcescip, &sourceconsdata->slackcons) );
1662  SCIP_CALL( SCIPcaptureCons(sourcescip, transslackcons) );
1663 
1664  sourceconsdata->slackcons = transslackcons;
1665  sourceslackcons = transslackcons;
1666  }
1667 
1668  SCIP_CALL( SCIPgetConsCopy(sourcescip, scip, sourceslackcons, &targetslackcons, conshdlrslack, varmap, consmap,
1669  SCIPconsGetName(sourceslackcons), SCIPconsIsInitial(sourceslackcons), SCIPconsIsSeparated(sourceslackcons),
1670  SCIPconsIsEnforced(sourceslackcons), SCIPconsIsChecked(sourceslackcons), SCIPconsIsPropagated(sourceslackcons),
1671  SCIPconsIsLocal(sourceslackcons), SCIPconsIsModifiable(sourceslackcons), SCIPconsIsDynamic(sourceslackcons),
1672  SCIPconsIsRemovable(sourceslackcons), SCIPconsIsStickingAtNode(sourceslackcons), global, valid) );
1673  }
1674 
1675  /* find copied variable corresponding to binvar */
1676  if( *valid )
1677  {
1678  SCIP_VAR* sourcebinvar;
1679 
1680  sourcebinvar = sourceconsdata->binvar;
1681  assert(sourcebinvar != NULL);
1682 
1683  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcebinvar, &targetbinvar, varmap, consmap, global, valid) );
1684  }
1685  else
1686  targetbinvar = NULL;
1687 
1688  /* create superindicator constraint */
1689  if( *valid )
1690  {
1691  assert(targetslackcons != NULL);
1692  assert(targetbinvar != NULL);
1693  assert(!modifiable);
1694 
1695  SCIP_CALL( SCIPcreateConsSuperindicator(scip, cons, consname, targetbinvar, targetslackcons,
1696  initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
1697  }
1698 
1699  /* relase slack constraint */
1700  if( targetslackcons != NULL )
1701  {
1702  SCIP_CALL( SCIPreleaseCons(scip, &targetslackcons) );
1703  }
1704 
1705  if( !(*valid) )
1706  {
1707  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "could not copy superindicator constraint <%s>\n", SCIPconsGetName(sourcecons));
1708  }
1709 
1710  return SCIP_OKAY;
1711 }
1712 
1713 /** constraint parsing method of constraint handler */
1714 static
1715 SCIP_DECL_CONSPARSE(consParseSuperindicator)
1716 { /*lint --e{715}*/
1717  SCIP_VAR* binvar;
1718  SCIP_CONS* slackcons;
1719  char binvarname[1024];
1720  const char* slackstr;
1721  int zeroone;
1722  int nargs;
1723 
1724  assert(cons != NULL);
1725  assert(scip != NULL);
1726  assert(success != NULL);
1727  assert(str != NULL);
1728  assert(name != NULL);
1729 
1730  *success = FALSE;
1731 
1732  /* extract binary variable name and value which triggers slack constraint */
1733  nargs = sscanf(str, " <%1023[^>]>[B] = %d", binvarname, &zeroone);
1734 
1735  if( nargs != 2 || (zeroone != 0 && zeroone != 1) )
1736  {
1737  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "Syntax error: expected the following form: <var> = [0|1] -> <cons>\n");
1738  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "got: %s\n", str);
1739  return SCIP_OKAY;
1740  }
1741 
1742  /* extract string describing slack constraint */
1743  slackstr = strstr(str, "->");
1744 
1745  if( slackstr == NULL )
1746  {
1747  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "Syntax error: expected the following form: <var> = [0|1] -> <cons>\n");
1748  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "got: %s\n", str);
1749  return SCIP_OKAY;
1750  }
1751 
1752  slackstr = strstr(slackstr, "[");
1753 
1754  if( slackstr == NULL )
1755  {
1756  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "Syntax error: expected the following form: <var> = [0|1] -> <cons>\n");
1757  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "got: %s\n", str);
1758  return SCIP_OKAY;
1759  }
1760 
1761  SCIPdebugMessage("binvarname=%s, zeroone=%d, slackstr=%s\n", binvarname, zeroone, slackstr);
1762 
1763  /* get binary variable */
1764  binvar = SCIPfindVar(scip, binvarname);
1765  if( binvar == NULL )
1766  {
1767  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable <%s>\n", binvarname);
1768  return SCIP_OKAY;
1769  }
1770 
1771  /* resolve negation if necessary */
1772  if( zeroone == 0 )
1773  {
1774  SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &binvar) );
1775  }
1776 
1777  /**@todo get slack constraint name and check whether constraint already exists; however, using only SCIPfindCons() is
1778  * not sufficient since slack constraints are not added to the problem; do we need something like
1779  * SCIPfindConsInConshdlr()?; currently, if there are two superindicator constraints with same slack constraint
1780  * (binvars may be different), then after writing and reading, the slack constraint will be created twice with
1781  * identical constraint name; this is not incorrect, but might consume more memory or time
1782  */
1783 
1784  /* parse slack constraint string */
1785  SCIP_CALL( SCIPparseCons(scip, &slackcons, slackstr, initial, separate, enforce, check, propagate, local, modifiable,
1786  dynamic, removable, stickingatnode, success) );
1787 
1788  if( *success )
1789  {
1790  assert(binvar != NULL);
1791  assert(slackcons != NULL);
1792 
1793  /* create the superindicator constraint */
1794  SCIP_CALL( SCIPcreateConsSuperindicator(scip, cons, name, binvar, slackcons,
1795  initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
1796 
1797  /* the new superindicator constraint captured the slack constraint, so we can release it now */
1798  SCIP_CALL( SCIPreleaseCons(scip, &slackcons) );
1799  }
1800 
1801  return SCIP_OKAY;
1802 }
1803 
1804 /** constraint method of constraint handler which returns the variables (if possible) */
1805 static
1806 SCIP_DECL_CONSGETVARS(consGetVarsSuperindicator)
1807 { /*lint --e{715}*/
1808  SCIP_CONSDATA* consdata;
1809 
1810  consdata = SCIPconsGetData(cons);
1811  assert(consdata != NULL);
1812 
1813  /* must be ready to hold at least the binary variable */
1814  if( varssize <= 0 )
1815  *success = FALSE;
1816  else
1817  {
1818  /* add binary variable */
1819  vars[0] = consdata->binvar;
1820 
1821  /* add variables of slack constraint */
1822  SCIP_CALL( SCIPgetConsVars(scip, consdata->slackcons, &(vars[1]), varssize-1, success) );
1823  }
1824 
1825  return SCIP_OKAY;
1826 }
1827 
1828 /** constraint method of constraint handler which returns the number of variables (if possible) */
1829 static
1830 SCIP_DECL_CONSGETNVARS(consGetNVarsSuperindicator)
1831 { /*lint --e{715}*/
1832  SCIP_CONSDATA* consdata;
1833 
1834  consdata = SCIPconsGetData(cons);
1835  assert(consdata != NULL);
1836 
1837  /* get number of variables in slack constraint */
1838  SCIP_CALL( SCIPgetConsNVars(scip, consdata->slackcons, nvars, success) );
1839 
1840  /* add binary variable */
1841  if( *success )
1842  (*nvars)++;
1843 
1844  return SCIP_OKAY;
1845 }
1846 
1847 
1848 /*
1849  * constraint specific interface methods
1850  */
1851 
1852 /** creates the handler for superindicator constraints and includes it in SCIP */
1854  SCIP* scip /**< SCIP data structure */
1855  )
1856 {
1857  SCIP_CONSHDLRDATA* conshdlrdata;
1858  SCIP_CONSHDLR* conshdlr;
1859  SCIP_DIALOG* root;
1860  SCIP_DIALOG* changemenu;
1861  SCIP_DIALOG* dialog;
1862 
1863  /* create superindicator constraint handler data */
1864  SCIP_CALL( SCIPallocMemory(scip, &conshdlrdata) );
1865 
1866  conshdlrdata->nrejects = 0;
1867 
1868  /* include constraint handler */
1871  consEnfolpSuperindicator, consEnfopsSuperindicator, consCheckSuperindicator, consLockSuperindicator,
1872  conshdlrdata) );
1873 
1874  assert(conshdlr != NULL);
1875 
1876  /* set non-fundamental callbacks via specific setter functions */
1877  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopySuperindicator, consCopySuperindicator) );
1878  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteSuperindicator) );
1879  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeSuperindicator) );
1880  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsSuperindicator) );
1881  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsSuperindicator) );
1882  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpSuperindicator) );
1883  SCIP_CALL( SCIPsetConshdlrInitpre(scip, conshdlr, consInitpreSuperindicator) );
1884  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseSuperindicator) );
1885  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolSuperindicator, CONSHDLR_MAXPREROUNDS, CONSHDLR_DELAYPRESOL) );
1886  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintSuperindicator) );
1887  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropSuperindicator, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP, CONSHDLR_PROP_TIMING) );
1888  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropSuperindicator) );
1889  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpSuperindicator, consSepasolSuperindicator, CONSHDLR_SEPAFREQ, CONSHDLR_SEPAPRIORITY, CONSHDLR_DELAYSEPA) );
1890  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransSuperindicator) );
1891 
1892  /* includes or updates the default dialog menus in SCIP */
1894 
1895  root = SCIPgetRootDialog(scip);
1896  assert(root != NULL);
1897 
1898  /* find change menu */
1899  if( !SCIPdialogHasEntry(root, "change") )
1900  {
1901  SCIP_CALL( SCIPincludeDialog(scip, &changemenu,
1902  NULL,
1903  SCIPdialogExecMenu, NULL, NULL,
1904  "change", "change the problem", TRUE, NULL) );
1905  SCIP_CALL( SCIPaddDialogEntry(scip, root, changemenu) );
1906  SCIP_CALL( SCIPreleaseDialog(scip, &changemenu) );
1907  }
1908 
1909  if( SCIPdialogFindEntry(root, "change", &changemenu) != 1 )
1910  {
1911  SCIPerrorMessage("change sub menu not found\n");
1912  return SCIP_PLUGINNOTFOUND;
1913  }
1914 
1915  /* add minuc dialog */
1916  if( !SCIPdialogHasEntry(changemenu, "minuc") )
1917  {
1918  SCIP_CALL( SCIPincludeDialog(scip, &dialog,
1919  NULL,
1920  SCIPdialogExecChangeMinUC, NULL, NULL,
1921  "minuc", "transforms the current problem into a MinUC problem minimizing the number of unsatisfied constraints",
1922  FALSE, NULL) );
1923  SCIP_CALL( SCIPaddDialogEntry(scip, changemenu, dialog) );
1924  SCIP_CALL( SCIPreleaseDialog(scip, &dialog) );
1925  }
1926 
1927  /* add constraint handler parameters */
1929  "constraints/"CONSHDLR_NAME"/checkslacktype",
1930  "should type of slack constraint be checked when creating superindicator constraint?",
1931  &conshdlrdata->checkslacktype, TRUE, DEFAULT_CHECKSLACKTYPE, NULL, NULL) );
1932 
1934  "constraints/"CONSHDLR_NAME"/maxupgdcoeflinear",
1935  "maximum big-M coefficient of binary variable in upgrade to a linear constraint (relative to smallest coefficient)",
1936  &conshdlrdata->maxupgdcoeflinear, TRUE, DEFAULT_MAXUPGDCOEFLINEAR, 0.0, 1e15, NULL, NULL) );
1937 
1938  SCIP_CALL( SCIPaddIntParam(scip,
1939  "constraints/"CONSHDLR_NAME"/upgdprioindicator",
1940  "priority for upgrading to an indicator constraint (-1: never)",
1941  &conshdlrdata->upgdprioindicator, TRUE, DEFAULT_UPGDPRIOINDICATOR, -1, INT_MAX, NULL, NULL) );
1942 
1943  SCIP_CALL( SCIPaddIntParam(scip,
1944  "constraints/"CONSHDLR_NAME"/upgdpriolinear",
1945  "priority for upgrading to an indicator constraint (-1: never)",
1946  &conshdlrdata->upgdpriolinear, TRUE, DEFAULT_UPGDPRIOLINEAR, -1, INT_MAX, NULL, NULL) );
1947 
1948  return SCIP_OKAY;
1949 }
1950 
1951 /** creates and captures a superindicator constraint
1952  *
1953  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
1954  */
1956  SCIP* scip, /**< SCIP data structure */
1957  SCIP_CONS** cons, /**< pointer to hold the created constraint */
1958  const char* name, /**< name of constraint */
1959  SCIP_VAR* binvar, /**< pointer to the indicator constraint */
1960  SCIP_CONS* slackcons, /**< constraint corresponding to the handled constraint */
1961  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
1962  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1963  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
1964  * Usually set to TRUE. */
1965  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
1966  * TRUE for model constraints, FALSE for additional, redundant constraints. */
1967  SCIP_Bool check, /**< should the constraint be checked for feasibility?
1968  * TRUE for model constraints, FALSE for additional, redundant constraints. */
1969  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
1970  * Usually set to TRUE. */
1971  SCIP_Bool local, /**< is constraint only valid locally?
1972  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1973  SCIP_Bool dynamic, /**< is constraint subject to aging?
1974  * Usually set to FALSE. Set to TRUE for own cuts which
1975  * are separated as constraints. */
1976  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
1977  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
1978  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
1979  * if it may be moved to a more global node?
1980  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
1981  )
1982 {
1983  SCIP_CONSHDLRDATA* conshdlrdata;
1984  SCIP_CONSHDLR* conshdlr;
1985  SCIP_CONSDATA* consdata;
1986  SCIP_Bool modifiable;
1987 
1988  assert(scip != NULL);
1989  assert(cons != NULL);
1990  assert(name != NULL);
1991  assert(binvar != NULL);
1992  assert(slackcons != NULL);
1993 
1994  modifiable = FALSE;
1995 
1996  /* find the superindicator constraint handler */
1997  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
1998  if( conshdlr == NULL )
1999  {
2000  SCIPerrorMessage("superindicator constraint handler not found\n");
2001  return SCIP_PLUGINNOTFOUND;
2002  }
2003 
2004  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2005  assert(conshdlrdata != NULL);
2006 
2007  /* only allow types of slack constraints that can be handled */
2008  if( conshdlrdata->checkslacktype &&
2009  strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(slackcons)), "abspower") != 0 &&
2010  strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(slackcons)), "and") != 0 &&
2011  strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(slackcons)), "bivariate") != 0 &&
2012  strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(slackcons)), "bounddisjunction") != 0 &&
2013  strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(slackcons)), "conjunction") != 0 &&
2014  strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(slackcons)), "disjunction") != 0 &&
2015  strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(slackcons)), "knapsack") != 0 &&
2016  strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(slackcons)), "linear") != 0 &&
2017  strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(slackcons)), "linking") != 0 &&
2018  strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(slackcons)), "logicor") != 0 &&
2019  strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(slackcons)), "nonlinear") != 0 &&
2020  strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(slackcons)), "or") != 0 &&
2021  strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(slackcons)), "quadratic") != 0 &&
2022  strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(slackcons)), "soc") != 0 &&
2023  strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(slackcons)), "SOS1") != 0 &&
2024  strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(slackcons)), "SOS2") != 0 &&
2025  strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(slackcons)), "cumulative") != 0 &&
2026  strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(slackcons)), "varbound") != 0 &&
2027  strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(slackcons)), "superindicator") != 0
2028  )
2029  {
2030  if( conshdlrdata->nrejects < 5 )
2031  {
2032  SCIPwarningMessage(scip, "rejected creation of superindicator with slack constraint <%s> of type <%s> "
2033  "(use parameter <checkslacktype> to disable check)\n",
2034  SCIPconsGetName(slackcons), SCIPconshdlrGetName(SCIPconsGetHdlr(slackcons)));
2035  conshdlrdata->nrejects++;
2036  }
2037 
2038  if( conshdlrdata->nrejects == 5 )
2039  {
2040  SCIPwarningMessage(scip, "suppressing further warning messages of this type\n");
2041  conshdlrdata->nrejects++;
2042  }
2043 
2044  return SCIP_INVALIDCALL;
2045  }
2046 
2047  /* create constraint data */
2048  SCIP_CALL( consdataCreateSuperindicator(scip, &consdata, binvar, slackcons) );
2049  assert(consdata != NULL);
2050 
2051  /* create constraint */
2052  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
2053  local, modifiable, dynamic, removable, stickingatnode) );
2054 
2055  return SCIP_OKAY;
2056 }
2057 
2058 /** creates and captures a superindicator constraint
2059  * in its most basic version, i. e., all constraint flags are set to their basic value as explained for the
2060  * method SCIPcreateConsSuperindicator(); all flags can be set via SCIPsetConsFLAGNAME-methods in scip.h
2061  *
2062  * @see SCIPcreateConsSuperindicator() for information about the basic constraint flag configuration
2063  *
2064  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
2065  */
2067  SCIP* scip, /**< SCIP data structure */
2068  SCIP_CONS** cons, /**< pointer to hold the created constraint */
2069  const char* name, /**< name of constraint */
2070  SCIP_VAR* binvar, /**< pointer to the indicator constraint */
2071  SCIP_CONS* slackcons /**< constraint corresponding to the handled constraint */
2072  )
2073 {
2074  assert(scip != NULL);
2075  assert(cons != NULL);
2076  assert(name != NULL);
2077  assert(binvar != NULL);
2078  assert(slackcons != NULL);
2079 
2080  SCIP_CALL( SCIPcreateConsSuperindicator(scip, cons, name, binvar, slackcons,
2081  TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
2082 
2083  return SCIP_OKAY;
2084 }
2085 
2086 
2087 /** gets binary variable corresponding to the general indicator constraint */
2089  SCIP_CONS* cons /**< superindicator constraint */
2090  )
2091 {
2092  assert(cons != NULL);
2093  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
2094  assert(SCIPconsGetData(cons) != NULL);
2095 
2096  return SCIPconsGetData(cons)->binvar;
2097 }
2098 
2099 /** gets the slack constraint corresponding to the general indicator constraint */
2101  SCIP_CONS* cons /**< superindicator constraint */
2102  )
2103 {
2104  assert(cons != NULL);
2105  assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) == 0);
2106  assert(SCIPconsGetData(cons) != NULL);
2107 
2108  return SCIPconsGetData(cons)->slackcons;
2109 }
2110 
2111 
2112 /*
2113  * constraint-dependent SCIP methods
2114  */
2115 
2116 /** transforms the current problem into a MinUC problem (minimizing the number of unsatisfied constraints),
2117  * a CIP generalization of the MinULR (min. unsatisfied linear relations) problem
2118  */
2120  SCIP* scip, /**< SCIP data structure */
2121  SCIP_Bool* success /**< pointer to store whether all constraints could be transformed */
2122  )
2123 {
2124  SCIP_CONS** conss;
2125  SCIP_VAR** vars;
2126  char consname[SCIP_MAXSTRLEN];
2127  char varname[SCIP_MAXSTRLEN];
2128  int maxbranchprio;
2129  int ntransconss;
2130  int nconss;
2131  int nvars;
2132  int i;
2133 
2134  assert(scip != NULL);
2135  assert(success != NULL);
2136 
2137  *success = FALSE;
2138 
2139  if( SCIPgetStage(scip) != SCIP_STAGE_PROBLEM )
2140  {
2141  SCIPerrorMessage("method <SCIPtransformMinUC> can only be called in problem stage\n");
2142  return SCIP_INVALIDCALL;
2143  }
2144 
2145  /* get variable data */
2146  SCIP_CALL( SCIPgetVarsData(scip, &vars, &nvars, NULL, NULL, NULL, NULL) );
2147 
2148  /* copy the conss array because it changes when adding and deleting constraints */
2149  nconss = SCIPgetNConss(scip);
2150  SCIP_ALLOC( BMSduplicateMemoryArray(&conss, SCIPgetConss(scip), nconss) );
2151 
2152  /* clear objective function and compute maximal branching priority */
2153  maxbranchprio = 0;
2154  for( i = nvars-1; i >= 0; i-- )
2155  {
2156  SCIP_CALL( SCIPchgVarObj(scip, vars[i], 0.0) );
2157 
2158  if( SCIPvarGetBranchPriority(vars[i]) > maxbranchprio )
2159  maxbranchprio = SCIPvarGetBranchPriority(vars[i]);
2160  }
2161 
2162  maxbranchprio++;
2163 
2164  /* transform each constraint to slack constraint in a newly created superindicator constraint; note that we also need
2165  * to transform superindicator constraints, since their binary variable might have down-locks
2166  */
2167  ntransconss = 0;
2168  for( i = 0; i < nconss; ++i )
2169  {
2170  SCIP_CONS* cons;
2171  SCIP_CONS* supindcons;
2172  SCIP_VAR* binvar;
2173  SCIP_VAR* negbinvar;
2174  SCIP_RETCODE retcode;
2175 
2176  cons = conss[i];
2177  assert(cons != NULL);
2178 
2179  /* create a new binary variable with objective coefficient one */
2180  (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "%s_master", SCIPconsGetName(cons));
2181 
2182  SCIP_CALL( SCIPcreateVar(scip, &binvar, varname, 0.0, 1.0, 1.0, SCIP_VARTYPE_BINARY,
2183  TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
2184 
2185  /* get negated variable, since we want to minimize the number of violated constraints */
2186  SCIP_CALL( SCIPgetNegatedVar(scip, binvar, &negbinvar) );
2187 
2188  /* create superindicator constraint */
2189  (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "%s_super", SCIPconsGetName(cons));
2190 
2191  retcode = SCIPcreateConsSuperindicator(scip, &supindcons, consname, negbinvar, cons,
2194  SCIPconsIsStickingAtNode(cons));
2195 
2196  if( retcode == SCIP_OKAY )
2197  {
2198  /* add binary variable and increase its branching priority */
2199  SCIP_CALL( SCIPaddVar(scip, binvar) );
2200  SCIP_CALL( SCIPchgVarBranchPriority(scip, binvar, maxbranchprio) );
2201 
2202  /* add superindicator constraint */
2203  SCIP_CALL( SCIPaddCons(scip, supindcons) );
2204 
2205  /* release binary variable and superindicator constraint */
2206  SCIP_CALL( SCIPreleaseVar(scip, &binvar) );
2207  SCIP_CALL( SCIPreleaseCons(scip, &supindcons) );
2208 
2209  /* delete slack constraint; it is still captured by the superindicator constraint */
2210  SCIP_CALL( SCIPdelCons(scip, cons) );
2211 
2212  ntransconss++;
2213  }
2214  else if( retcode == SCIP_INVALIDCALL )
2215  {
2216  SCIPdebugMessage("constraint <%s> of type <%s> could not be transformed to superindicator and was removed\n",
2218 
2219  /* release binary variable */
2220  SCIP_CALL( SCIPreleaseVar(scip, &binvar) );
2221 
2222  /* delete slack constraint; this is necessary, because, e.g., the indicator expects its linear slack constraint
2223  * present in the problem, but this has just be transformed; hence, it cannot function any more and we have to
2224  * remove it
2225  */
2226  SCIP_CALL( SCIPdelCons(scip, cons) );
2227  }
2228  else
2229  {
2230  /* return all other error codes */
2231  SCIP_CALL( retcode );
2232  }
2233  }
2234 
2235  if( ntransconss == nconss )
2236  *success = TRUE;
2237 
2238  /* minimize the number of violated constraints */
2240 
2241  /* free the allocated memory for the copied constraint array */
2242  BMSfreeMemoryArray(&conss);
2243 
2244  return SCIP_OKAY;
2245 }
2246 
2247 
2248 /*
2249  * constraint-dependent dialog entries
2250  */
2251 
2252 /** dialog execution method for the SCIPtransformMinUC() method */
2253 SCIP_DECL_DIALOGEXEC(SCIPdialogExecChangeMinUC)
2254 { /*lint --e{715}*/
2255  SCIP_Bool success;
2256 
2257  SCIP_CALL( SCIPdialoghdlrAddHistory(dialoghdlr, dialog, NULL, FALSE) );
2258  SCIPdialogMessage(scip, NULL, "\n");
2259 
2260  switch( SCIPgetStage(scip) )
2261  {
2262  case SCIP_STAGE_INIT:
2263  SCIPdialogMessage(scip, NULL, "no problem exists\n");
2264  break;
2265  case SCIP_STAGE_PROBLEM:
2266  SCIPdialogMessage(scip, NULL, "change problem to MinUC\n");
2267  SCIPdialogMessage(scip, NULL, "==============\n");
2268 
2269  SCIP_CALL( SCIPtransformMinUC(scip, &success) );
2270 
2271  if( !success )
2272  {
2273  SCIPdialogMessage(scip, NULL, "some constraints could not be transformed to superindicator constraints and were removed\n");
2274  }
2275 
2276  SCIPdialogMessage(scip, NULL, "\n");
2277  SCIPdialogMessage(scip, NULL, "changed problem has %d variables (%d bin, %d int, %d impl, %d cont) and %d constraints\n",
2279  SCIPgetNConss(scip));
2280 
2281  SCIPdialogMessage(scip, NULL, "increased branching priority of new binary variables");
2282 
2283  break;
2286  case SCIP_STAGE_PRESOLVING:
2288  case SCIP_STAGE_PRESOLVED:
2289  case SCIP_STAGE_SOLVING:
2290  case SCIP_STAGE_SOLVED:
2292  case SCIP_STAGE_INITSOLVE:
2293  case SCIP_STAGE_EXITSOLVE:
2294  case SCIP_STAGE_FREETRANS:
2295  case SCIP_STAGE_FREE:
2296  SCIPdialogMessage(scip, NULL, "problem has to be in problem stage to create MinUC problem\n");
2297  break;
2298  default:
2299  SCIPerrorMessage("invalid SCIP stage\n");
2300  return SCIP_INVALIDCALL;
2301  } /*lint --e{616}*/
2302 
2303  SCIPdialogMessage(scip, NULL, "\n");
2304  *nextdialog = SCIPdialoghdlrGetRoot(dialoghdlr);
2305 
2306  return SCIP_OKAY;
2307 }
2308