Scippy

SCIP

Solving Constraint Integer Programs

cons_sos1.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-2015 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_sos1.c
17  * @brief constraint handler for SOS type 1 constraints
18  * @author Tobias Fischer
19  * @author Marc Pfetsch
20  *
21  * A specially ordered set of type 1 (SOS1) is a sequence of variables such that at most one
22  * variable is nonzero. The special case of two variables arises, for instance, from equilibrium or
23  * complementary conditions like \f$x \cdot y = 0\f$. Note that it is in principle allowed that a
24  * variables appears twice, but it then can be fixed to 0.
25  *
26  * This implementation of this constraint handler is based on classical ideas, see e.g.@n
27  * "Special Facilities in General Mathematical Programming System for
28  * Non-Convex Problems Using Ordered Sets of Variables"@n
29  * E. Beale and J. Tomlin, Proc. 5th IFORS Conference, 447-454 (1970)
30  *
31  *
32  * The order of the variables is determined as follows:
33  *
34  * - If the constraint is created with SCIPcreateConsSOS1() and weights are given, the weights
35  * determine the order (decreasing weights). Additional variables can be added with
36  * SCIPaddVarSOS1(), which adds a variable with given weight.
37  *
38  * - If an empty constraint is created and then variables are added with SCIPaddVarSOS1(), weights
39  * are needed and stored.
40  *
41  * - All other calls ignore the weights, i.e., if a nonempty constraint is created or variables are
42  * added with SCIPappendVarSOS1().
43  *
44  * The validity of the SOS1 constraints can be enforced by different branching rules:
45  *
46  * - If classical SOS branching is used, branching is performed on only one SOS1 constraint.
47  * Depending on the parameters, there are two ways to choose this branching constraint. Either
48  * the constraint with the most number of nonzeros or the one with the largest nonzero-variable
49  * weight. The later version allows the user to specify an order for the branching importance of
50  * the constraints. Constraint branching can also be turned off.
51  *
52  * - Another way is to branch on the neighborhood of a single variable @p i, i.e., in one branch
53  * \f$x_i\f$ is fixed to zero and in the other its neighbors from the conflict graph.
54  *
55  * - If bipartite branching is used, then we branch using complete bipartite subgraphs of the
56  * conflict graph, i.e., in one branch fix the variables from the first bipartite partition and
57  * the variables from the second bipartite partition in the other.
58  *
59  * - In addition to variable domain fixings, it is sometimes also possible to add new SOS1
60  * constraints to the branching nodes. This results in a nonstatic conflict graph, which may
61  * change dynamically with every branching node.
62  *
63  *
64  * @todo Possibly allow to generate local cuts via strengthened local cuts (would need to modified coefficients of rows).
65  *
66  * @todo Check whether we can avoid turning off multi-aggregation (it is sometimes possible to fix a multi-aggregated
67  * variable to 0 by fixing the aggregating variables to 0).
68  */
69 
70 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
71 
72 #include <assert.h>
73 
74 #include "scip/cons_sos1.h"
75 #include "scip/cons_linear.h"
76 #include "scip/cons_setppc.h"
77 #include "scip/pub_misc.h"
78 #include "scip/misc.h"
79 #include "scip/struct_misc.h"
80 #include "tclique/tclique.h"
81 #include <string.h>
82 #include <ctype.h>
83 
84 
85 /* constraint handler properties */
86 #define CONSHDLR_NAME "SOS1"
87 #define CONSHDLR_DESC "SOS1 constraint handler"
88 #define CONSHDLR_SEPAPRIORITY 100 /**< priority of the constraint handler for separation */
89 #define CONSHDLR_ENFOPRIORITY 100 /**< priority of the constraint handler for constraint enforcing */
90 #define CONSHDLR_CHECKPRIORITY -10 /**< priority of the constraint handler for checking feasibility */
91 #define CONSHDLR_SEPAFREQ 10 /**< frequency for separating cuts; zero means to separate only in the root node */
92 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
93 #define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
94  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
95 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
96 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
97 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
98 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
99 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
100 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_MEDIUM
102 /* adjacency matrix */
103 #define DEFAULT_MAXSOSADJACENCY 10000 /**< do not create an adjacency matrix if number of SOS1 variables is larger than predefined value
104  * (-1: no limit) */
105 
106 /* presolving */
107 #define DEFAULT_MAXEXTENSIONS 1 /**< maximal number of extensions that will be computed for each SOS1 constraint */
108 #define DEFAULT_MAXTIGHTENBDS 5 /**< maximal number of bound tightening rounds per presolving round (-1: no limit) */
109 #define DEFAULT_UPDATECONFLPRESOL FALSE /**< if TRUE then update conflict graph during presolving procedure */
111 /* propagation */
112 #define DEFAULT_CONFLICTPROP TRUE /**< whether to use conflict graph propagation */
113 #define DEFAULT_IMPLPROP TRUE /**< whether to use implication graph propagation */
114 #define DEFAULT_SOSCONSPROP FALSE /**< whether to use SOS1 constraint propagation */
116 /* branching rules */
117 #define DEFAULT_NEIGHBRANCH TRUE /**< if TRUE turn neighborhood branching method on (note: an automatic switching to SOS1 branching is possible) */
118 #define DEFAULT_BIPBRANCH FALSE /**< if TRUE turn bipartite branching method on (note: an automatic switching to SOS1 branching is possible) */
119 #define DEFAULT_SOS1BRANCH FALSE /**< if TRUE turn SOS1 branching method on */
120 #define DEFAULT_AUTOSOS1BRANCH TRUE /**< if TRUE then automatically switch to SOS1 branching if the SOS1 constraints do not overlap */
121 #define DEFAULT_FIXNONZERO FALSE /**< if neighborhood branching is used, then fix the branching variable (if positive in sign) to the value of the
122  * feasibility tolerance */
123 #define DEFAULT_ADDCOMPS FALSE /**< if TRUE then add complementarity constraints to the branching nodes (can be used in combination with
124  * neighborhood or bipartite branching) */
125 #define DEFAULT_MAXADDCOMPS -1 /**< maximal number of complementarity constraints added per branching node (-1: no limit) */
126 #define DEFAULT_ADDCOMPSDEPTH 30 /**< only add complementarity constraints to branching nodes for predefined depth (-1: no limit) */
127 #define DEFAULT_ADDCOMPSFEAS -0.6 /**< minimal feasibility value for complementarity constraints in order to be added to the branching node */
128 #define DEFAULT_ADDBDSFEAS 1.0 /**< minimal feasibility value for bound inequalities in order to be added to the branching node */
129 #define DEFAULT_ADDEXTENDEDBDS TRUE /**< should added complementarity constraints be extended to SOS1 constraints to get tighter bound inequalities */
131 /* selection rules */
132 #define DEFAULT_NSTRONGROUNDS 0 /**< maximal number of strong branching rounds to perform for each node (-1: auto)
133  * (only available for neighborhood and bipartite branching) */
134 #define DEFAULT_NSTRONGITER 10000 /**< maximal number LP iterations to perform for each strong branching round (-2: auto, -1: no limit) */
135 
136 /* separation */
137 #define DEFAULT_BOUNDCUTSFROMSOS1 FALSE /**< if TRUE separate bound inequalities from SOS1 constraints */
138 #define DEFAULT_BOUNDCUTSFROMGRAPH TRUE /**< if TRUE separate bound inequalities from the conflict graph */
139 #define DEFAULT_AUTOCUTSFROMSOS1 TRUE /**< if TRUE then automatically switch to separating from SOS1 constraints if the SOS1 constraints do not overlap */
140 #define DEFAULT_BOUNDCUTSFREQ 10 /**< frequency for separating bound cuts; zero means to separate only in the root node */
141 #define DEFAULT_BOUNDCUTSDEPTH 40 /**< node depth of separating bound cuts (-1: no limit) */
142 #define DEFAULT_MAXBOUNDCUTS 50 /**< maximal number of bound cuts separated per branching node */
143 #define DEFAULT_MAXBOUNDCUTSROOT 150 /**< maximal number of bound cuts separated per iteration in the root node */
144 #define DEFAULT_STRTHENBOUNDCUTS TRUE /**< if TRUE then bound cuts are strengthened in case bound variables are available */
145 #define DEFAULT_IMPLCUTSFREQ 0 /**< frequency for separating implied bound cuts; zero means to separate only in the root node */
146 #define DEFAULT_IMPLCUTSDEPTH 40 /**< node depth of separating implied bound cuts (-1: no limit) */
147 #define DEFAULT_MAXIMPLCUTS 50 /**< maximal number of implied bound cuts separated per branching node */
148 #define DEFAULT_MAXIMPLCUTSROOT 150 /**< maximal number of implied bound cuts separated per iteration in the root node */
150 /* event handler properties */
151 #define EVENTHDLR_NAME "SOS1"
152 #define EVENTHDLR_DESC "bound change event handler for SOS1 constraints"
154 /* defines */
155 #define DIVINGCUTOFFVALUE 1e6
158 /** constraint data for SOS1 constraints */
159 struct SCIP_ConsData
160 {
161  int nvars; /**< number of variables in the constraint */
162  int maxvars; /**< maximal number of variables (= size of storage) */
163  int nfixednonzeros; /**< number of variables fixed to be nonzero */
164  SCIP_Bool local; /**< TRUE if constraint is only valid locally */
165  SCIP_VAR** vars; /**< variables in constraint */
166  SCIP_ROW* rowlb; /**< row corresponding to lower bounds, or NULL if not yet created */
167  SCIP_ROW* rowub; /**< row corresponding to upper bounds, or NULL if not yet created */
168  SCIP_Real* weights; /**< weights determining the order (ascending), or NULL if not used */
169 };
170 
171 
172 /** node data of a given node in the conflict graph */
173 struct SCIP_NodeData
174 {
175  SCIP_VAR* var; /**< variable belonging to node */
176  SCIP_VAR* lbboundvar; /**< bound variable @p z from constraint \f$x \geq \mu \cdot z\f$ (or NULL if not existent) */
177  SCIP_VAR* ubboundvar; /**< bound variable @p z from constraint \f$x \leq \mu \cdot z\f$ (or NULL if not existent) */
178  SCIP_Real lbboundcoef; /**< value \f$\mu\f$ from constraint \f$x \geq \mu z \f$ (0.0 if not existent) */
179  SCIP_Real ubboundcoef; /**< value \f$\mu\f$ from constraint \f$x \leq \mu z \f$ (0.0 if not existent) */
180  SCIP_Bool lbboundcomp; /**< TRUE if the nodes from the connected component of the conflict graph the given node belongs to
181  * all have the same lower bound variable */
182  SCIP_Bool ubboundcomp; /**< TRUE if the nodes from the connected component of the conflict graph the given node belongs to
183  * all have the same lower bound variable */
184 };
185 typedef struct SCIP_NodeData SCIP_NODEDATA;
186 
187 
188 /** successor data of a given nodes successor in the implication graph */
189 struct SCIP_SuccData
190 {
191  SCIP_Real lbimpl; /**< lower bound implication */
192  SCIP_Real ubimpl; /**< upper bound implication */
193 };
194 typedef struct SCIP_SuccData SCIP_SUCCDATA;
195 
196 
197 /** tclique data for bound cut generation */
198 struct TCLIQUE_Data
199 {
200  SCIP* scip; /**< SCIP data structure */
201  SCIP_CONSHDLR* conshdlr; /**< SOS1 constraint handler */
202  SCIP_DIGRAPH* conflictgraph; /**< conflict graph */
203  SCIP_SOL* sol; /**< LP solution to be separated (or NULL) */
204  SCIP_Real scaleval; /**< factor for scaling weights */
205  SCIP_Bool cutoff; /**< whether a cutoff occurred */
206  int ncuts; /**< number of bound cuts found in this iteration */
207  int nboundcuts; /**< number of bound cuts found so far */
208  int maxboundcuts; /**< maximal number of clique cuts separated per separation round (-1: no limit) */
209  SCIP_Bool strthenboundcuts; /**< if TRUE then bound cuts are strengthened in case bound variables are available */
210 };
213 /** SOS1 constraint handler data */
214 struct SCIP_ConshdlrData
215 {
216  /* conflict graph */
217  SCIP_DIGRAPH* conflictgraph; /**< conflict graph */
218  SCIP_DIGRAPH* localconflicts; /**< local conflicts */
219  SCIP_Bool isconflocal; /**< if TRUE then local conflicts are present and conflict graph has to be updated for each node */
220  SCIP_HASHMAP* varhash; /**< hash map from variable to node in the conflict graph */
221  int nsos1vars; /**< number of problem variables that are part of the SOS1 conflict graph */
222  /* adjacency matrix */
223  int maxsosadjacency; /**< do not create an adjacency matrix in if number of SOS1 variables is larger than predefined
224  * value (-1: no limit) */
225  /* implication graph */
226  SCIP_DIGRAPH* implgraph; /**< implication graph (@p j is successor of @p i if and only if \f$ x_i\not = 0 \Rightarrow x_j\not = 0\f$) */
227  int nimplnodes; /**< number of nodes in the implication graph */
228  /* tclique graph */
229  TCLIQUE_GRAPH* tcliquegraph; /**< tclique graph data structure */
230  TCLIQUE_DATA* tcliquedata; /**< tclique data */
231  /* event handler */
232  SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
233  SCIP_VAR** fixnonzerovars; /**< stack of variables fixed to nonzero marked by event handler */
234  int maxnfixnonzerovars; /**< size of stack fixnonzerovars */
235  int nfixnonzerovars; /**< number of variables fixed to nonzero marked by event handler */
236  /* presolving */
237  int cntextsos1; /**< counts number of extended SOS1 constraints */
238  int maxextensions; /**< maximal number of extensions that will be computed for each SOS1 constraint */
239  int maxtightenbds; /**< maximal number of bound tightening rounds per presolving round (-1: no limit) */
240  SCIP_Bool updateconflpresol; /**< if TRUE then update conflict graph during presolving procedure */
241  /* propagation */
242  SCIP_Bool conflictprop; /**< whether to use conflict graph propagation */
243  SCIP_Bool implprop; /**< whether to use implication graph propagation */
244  SCIP_Bool sosconsprop; /**< whether to use SOS1 constraint propagation */
245  /* branching */
246  SCIP_Bool neighbranch; /**< if TRUE turn neighborhood branching method on (note: an automatic switching to SOS1 branching is possible) */
247  SCIP_Bool bipbranch; /**< if TRUE turn bipartite branching method on (note: an automatic switching to SOS1 branching is possible) */
248  SCIP_Bool sos1branch; /**< if TRUE turn SOS1 branching method on */
249  SCIP_Bool autosos1branch; /**< if TRUE then automatically switch to SOS1 branching if the SOS1 constraints do not overlap */
250  SCIP_Bool fixnonzero; /**< if neighborhood branching is used, then fix the branching variable (if positive in sign) to the value of the
251  * feasibility tolerance */
252  SCIP_Bool addcomps; /**< if TRUE then add complementarity constraints to the branching nodes additionally to domain fixings
253  * (can be used in combination with neighborhood or bipartite branching) */
254  int maxaddcomps; /**< maximal number of complementarity cons. and cor. bound ineq. added per branching node (-1: no limit) */
255  int addcompsdepth; /**< only add complementarity constraints to branching nodes for predefined depth (-1: no limit) */
256  SCIP_Real addcompsfeas; /**< minimal feasibility value for complementarity constraints in order to be added to the branching node */
257  SCIP_Real addbdsfeas; /**< minimal feasibility value for bound inequalities in order to be added to the branching node */
258  SCIP_Bool addextendedbds; /**< should added complementarity constraints be extended to SOS1 constraints to get tighter bound inequalities */
259  SCIP_Bool branchsos; /**< Branch on SOS condition in enforcing? */
260  SCIP_Bool branchnonzeros; /**< Branch on SOS cons. with most number of nonzeros? */
261  SCIP_Bool branchweight; /**< Branch on SOS cons. with highest nonzero-variable weight for branching - needs branchnonzeros to be false */
262  SCIP_Bool switchsos1branch; /**< whether to switch to SOS1 branching */
263  /* selection rules */
264  int nstrongrounds; /**< maximal number of strong branching rounds to perform for each node (-1: auto)
265  * (only available for neighborhood and bipartite branching) */
266  int nstrongiter; /**< maximal number LP iterations to perform for each strong branching round (-2: auto, -1: no limit) */
267  /* separation */
268  SCIP_Bool boundcutsfromsos1; /**< if TRUE separate bound inequalities from SOS1 constraints */
269  SCIP_Bool boundcutsfromgraph; /**< if TRUE separate bound inequalities from the conflict graph */
270  SCIP_Bool autocutsfromsos1; /**< if TRUE then automatically switch to separating SOS1 constraints if the SOS1 constraints do not overlap */
271  SCIP_Bool switchcutsfromsos1; /**< whether to switch to separate bound inequalities from SOS1 constraints */
272  int boundcutsfreq; /**< frequency for separating bound cuts; zero means to separate only in the root node */
273  int boundcutsdepth; /**< node depth of separating bound cuts (-1: no limit) */
274  int maxboundcuts; /**< maximal number of bound cuts separated per branching node */
275  int maxboundcutsroot; /**< maximal number of bound cuts separated per iteration in the root node */
276  int nboundcuts; /**< number of bound cuts found so far */
277  SCIP_Bool strthenboundcuts; /**< if TRUE then bound cuts are strengthened in case bound variables are available */
278  int implcutsfreq; /**< frequency for separating implied bound cuts; zero means to separate only in the root node */
279  int implcutsdepth; /**< node depth of separating implied bound cuts (-1: no limit) */
280  int maximplcuts; /**< maximal number of implied bound cuts separated per branching node */
281  int maximplcutsroot; /**< maximal number of implied bound cuts separated per iteration in the root node */
282 };
283 
284 
285 
286 /*
287  * local methods
288  */
289 
290 /** returns whether two vertices are adjacent in the conflict graph */
291 static
293  SCIP_Bool** adjacencymatrix, /**< adjacency matrix of conflict graph (lower half) (or NULL if an adjacencymatrix is not at hand) */
294  SCIP_DIGRAPH* conflictgraph, /**< conflict graph (or NULL if an adjacencymatrix is at hand) */
295  int vertex1, /**< first vertex */
296  int vertex2 /**< second vertex */
297  )
298 {
299  assert( adjacencymatrix != NULL || conflictgraph != NULL );
300 
301  /* we do not allow self-loops */
302  if ( vertex1 == vertex2 )
303  return FALSE;
304 
305  /* for debugging */
306  if ( adjacencymatrix == NULL )
307  {
308  int succvertex;
309  int* succ;
310  int nsucc1;
311  int nsucc2;
312  int j;
313 
314  nsucc1 = SCIPdigraphGetNSuccessors(conflictgraph, vertex1);
315  nsucc2 = SCIPdigraphGetNSuccessors(conflictgraph, vertex2);
316 
317  if ( nsucc1 < 1 || nsucc2 < 1 )
318  return FALSE;
319 
320  if ( nsucc1 > nsucc2 )
321  {
322  SCIPswapInts(&vertex1, &vertex2);
323  SCIPswapInts(&nsucc1, &nsucc2);
324  }
325 
326  succ = SCIPdigraphGetSuccessors(conflictgraph, vertex1);
327  SCIPsortInt(succ, nsucc1);
328 
329  for (j = 0; j < nsucc1; ++j)
330  {
331  succvertex = succ[j];
332  if ( succvertex == vertex2 )
333  return TRUE;
334  else if ( succvertex > vertex2 )
335  return FALSE;
336  }
337  }
338  else
339  {
340  if ( vertex1 < vertex2 )
341  return adjacencymatrix[vertex2][vertex1];
342  else
343  return adjacencymatrix[vertex1][vertex2];
344  }
345 
346  return FALSE;
347 }
348 
349 
350 /** checks whether a variable violates an SOS1 constraint w.r.t. sol together with at least one other variable */
351 static
353  SCIP* scip, /**< SCIP data structure */
354  SCIP_DIGRAPH* conflictgraph, /**< conflict graph (or NULL if an adjacencymatrix is at hand) */
355  int node, /**< node of variable in the conflict graph */
356  SCIP_SOL* sol /**< solution, or NULL to use current node's solution */
357  )
358 {
359  SCIP_Real solval;
360  SCIP_VAR* var;
361 
362  assert( scip != NULL );
363  assert( conflictgraph != NULL );
364  assert( node >= 0 );
365 
366  var = SCIPnodeGetVarSOS1(conflictgraph, node);
367  assert( var != NULL );
368  solval = SCIPgetSolVal(scip, sol, var);
369 
370  /* check whether variable is nonzero w.r.t. sol and the bounds have not been fixed to zero by propagation */
371  if ( ! SCIPisFeasZero(scip, solval) && ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) || ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) ) )
372  {
373  int* succ;
374  int nsucc;
375  int s;
376 
377  nsucc = SCIPdigraphGetNSuccessors(conflictgraph, node);
378  succ = SCIPdigraphGetSuccessors(conflictgraph, node);
379 
380  /* check whether a neighbor variable is nonzero w.r.t. sol */
381  for (s = 0; s < nsucc; ++s)
382  {
383  var = SCIPnodeGetVarSOS1(conflictgraph, succ[s]);
384  assert( var != NULL );
385  solval = SCIPgetSolVal(scip, sol, var);
386  if ( ! SCIPisFeasZero(scip, solval) && ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) || ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) ) )
387  return TRUE;
388  }
389  }
390 
391  return FALSE;
392 }
393 
394 
395 /** returns solution value of imaginary binary big-M variable of a given node from the conflict graph */
396 static
398  SCIP* scip, /**< SCIP pointer */
399  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
400  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
401  int node /**< node of the conflict graph */
402  )
403 {
404  SCIP_Real bound;
405  SCIP_VAR* var;
406  SCIP_Real val;
407 
408  assert( scip != NULL );
409  assert( conflictgraph != NULL );
410  assert( node >= 0 && node < SCIPdigraphGetNNodes(conflictgraph) );
411 
412  var = SCIPnodeGetVarSOS1(conflictgraph, node);
413  val = SCIPgetSolVal(scip, sol, var);
414 
415  if ( SCIPisFeasNegative(scip, val) )
416  {
417  bound = SCIPvarGetLbLocal(var);
418  assert( SCIPisFeasNegative(scip, bound) );
419 
420  if ( SCIPisInfinity(scip, -val) )
421  return 1.0;
422  else if ( SCIPisInfinity(scip, -bound) )
423  return 0.0;
424  else
425  return (val/bound);
426  }
427  else if ( SCIPisFeasPositive(scip, val) )
428  {
429  bound = SCIPvarGetUbLocal(var);
430  assert( SCIPisFeasPositive(scip, bound) );
431  assert( SCIPisFeasPositive(scip, val) );
432 
433  if ( SCIPisInfinity(scip, val) )
434  return 1.0;
435  else if ( SCIPisInfinity(scip, bound) )
436  return 0.0;
437  else
438  return (val/bound);
439  }
440  else
441  return 0.0;
442 }
443 
444 
445 /** gets (variable) lower bound value of current LP relaxation solution for a given node from the conflict graph */
446 static
448  SCIP* scip, /**< SCIP pointer */
449  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
450  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
451  int node /**< node of the conflict graph */
452  )
453 {
454  SCIP_NODEDATA* nodedata;
455 
456  assert( scip != NULL );
457  assert( conflictgraph != NULL );
458  assert( node >= 0 && node < SCIPdigraphGetNNodes(conflictgraph) );
459 
460  /* get node data */
461  nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, node);
462  assert( nodedata != NULL );
463 
464  /* if variable is not involved in a variable upper bound constraint */
465  if ( nodedata->lbboundvar == NULL || ! nodedata->lbboundcomp )
466  return SCIPvarGetLbLocal(nodedata->var);
467 
468  return nodedata->lbboundcoef * SCIPgetSolVal(scip, sol, nodedata->lbboundvar);
469 }
470 
471 
472 /** gets (variable) upper bound value of current LP relaxation solution for a given node from the conflict graph */
473 static
475  SCIP* scip, /**< SCIP pointer */
476  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
477  SCIP_SOL* sol, /**< primal solution, or NULL for current LP/pseudo solution */
478  int node /**< node of the conflict graph */
479  )
480 {
481  SCIP_NODEDATA* nodedata;
482 
483  assert( scip != NULL );
484  assert( conflictgraph != NULL );
485  assert( node >= 0 && node < SCIPdigraphGetNNodes(conflictgraph) );
486 
487  /* get node data */
488  nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, node);
489  assert( nodedata != NULL );
490 
491  /* if variable is not involved in a variable upper bound constraint */
492  if ( nodedata->ubboundvar == NULL || ! nodedata->ubboundcomp )
493  return SCIPvarGetUbLocal(nodedata->var);
494 
495  return nodedata->ubboundcoef * SCIPgetSolVal(scip, sol, nodedata->ubboundvar);
496 }
497 
498 
499 /** returns whether variable is part of the SOS1 conflict graph */
500 static
502  SCIP_CONSHDLRDATA* conshdlrdata, /**< SOS1 constraint handler */
503  SCIP_VAR* var /**< variable */
504  )
505 {
506  assert( conshdlrdata != NULL );
507  assert( var != NULL );
508 
509  if ( conshdlrdata->varhash == NULL || ! SCIPhashmapExists(conshdlrdata->varhash, var) )
510  return FALSE;
511 
512  return TRUE;
513 }
514 
515 
516 /** returns SOS1 index of variable or -1 if variable is not part of the SOS1 conflict graph */
517 static
518 int varGetNodeSOS1(
519  SCIP_CONSHDLRDATA* conshdlrdata, /**< SOS1 constraint handler */
520  SCIP_VAR* var /**< variable */
521  )
522 {
523  assert( conshdlrdata != NULL );
524  assert( var != NULL );
525  assert( conshdlrdata->varhash != NULL );
526 
527  if ( ! SCIPhashmapExists(conshdlrdata->varhash, var) )
528  return -1;
529 
530  return (int) (size_t) SCIPhashmapGetImage(conshdlrdata->varhash, var);
531 }
532 
533 
534 /** fix variable in given node to 0 or add constraint if variable is multi-aggregated
535  *
536  * @todo Try to handle multi-aggregated variables as in fixVariableZero() below.
537  */
538 static
540  SCIP* scip, /**< SCIP pointer */
541  SCIP_VAR* var, /**< variable to be fixed to 0*/
542  SCIP_NODE* node, /**< node */
543  SCIP_Bool* infeasible /**< if fixing is infeasible */
544  )
545 {
546  /* if variable cannot be nonzero */
547  *infeasible = FALSE;
549  {
550  *infeasible = TRUE;
551  return SCIP_OKAY;
552  }
553 
554  /* if variable is multi-aggregated */
556  {
557  SCIP_CONS* cons;
558  SCIP_Real val;
559 
560  val = 1.0;
561 
562  if ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) || ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) )
563  {
564  SCIPdebugMessage("creating constraint to force multi-aggregated variable <%s> to 0.\n", SCIPvarGetName(var));
565  /* we have to insert a local constraint var = 0 */
566  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, "branch", 1, &var, &val, 0.0, 0.0, TRUE, TRUE, TRUE, TRUE, TRUE,
567  TRUE, FALSE, FALSE, FALSE, FALSE) );
568  SCIP_CALL( SCIPaddConsNode(scip, node, cons, NULL) );
569  SCIP_CALL( SCIPreleaseCons(scip, &cons) );
570  }
571  }
572  else
573  {
574  if ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) )
575  SCIP_CALL( SCIPchgVarLbNode(scip, node, var, 0.0) );
576  if ( ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) )
577  SCIP_CALL( SCIPchgVarUbNode(scip, node, var, 0.0) );
578  }
579 
580  return SCIP_OKAY;
581 }
582 
583 
584 /** try to fix variable to 0
585  *
586  * Try to treat fixing by special consideration of multiaggregated variables. For a multi-aggregation
587  * \f[
588  * x = \sum_{i=1}^n \alpha_i x_i + c,
589  * \f]
590  * we can express the fixing \f$x = 0\f$ by fixing all \f$x_i\f$ to 0 if \f$c = 0\f$ and the lower bounds of \f$x_i\f$
591  * are nonnegative if \f$\alpha_i > 0\f$ or the upper bounds are nonpositive if \f$\alpha_i < 0\f$.
592  */
593 static
595  SCIP* scip, /**< SCIP pointer */
596  SCIP_VAR* var, /**< variable to be fixed to 0*/
597  SCIP_Bool* infeasible, /**< if fixing is infeasible */
598  SCIP_Bool* tightened /**< if fixing was performed */
599  )
600 {
601  assert( scip != NULL );
602  assert( var != NULL );
603  assert( infeasible != NULL );
604  assert( tightened != NULL );
605 
606  *infeasible = FALSE;
607  *tightened = FALSE;
608 
610  {
611  SCIP_Real aggrconst;
612 
613  /* if constant is 0 */
614  aggrconst = SCIPvarGetMultaggrConstant(var);
615  if ( SCIPisZero(scip, aggrconst) )
616  {
617  SCIP_VAR** aggrvars;
618  SCIP_Real* aggrvals;
619  SCIP_Bool allnonnegative = TRUE;
620  int naggrvars;
621  int i;
622 
624 
625  /* check whether all variables are "nonnegative" */
626  naggrvars = SCIPvarGetMultaggrNVars(var);
627  aggrvars = SCIPvarGetMultaggrVars(var);
628  aggrvals = SCIPvarGetMultaggrScalars(var);
629  for (i = 0; i < naggrvars; ++i)
630  {
631  if ( (SCIPisPositive(scip, aggrvals[i]) && SCIPisNegative(scip, SCIPvarGetLbLocal(aggrvars[i]))) ||
632  (SCIPisNegative(scip, aggrvals[i]) && SCIPisPositive(scip, SCIPvarGetUbLocal(aggrvars[i]))) )
633  {
634  allnonnegative = FALSE;
635  break;
636  }
637  }
638 
639  if ( allnonnegative )
640  {
641  /* all variables are nonnegative -> fix variables */
642  for (i = 0; i < naggrvars; ++i)
643  {
644  SCIP_Bool fixed;
645  SCIP_CALL( SCIPfixVar(scip, aggrvars[i], 0.0, infeasible, &fixed) );
646  if ( *infeasible )
647  return SCIP_OKAY;
648  *tightened = *tightened || fixed;
649  }
650  }
651  }
652  }
653  else
654  {
655  SCIP_CALL( SCIPfixVar(scip, var, 0.0, infeasible, tightened) );
656  }
657 
658  return SCIP_OKAY;
659 }
660 
661 
662 /** fix variable in local node to 0, and return whether the operation was feasible
663  *
664  * @note We do not add a linear constraint if the variable is multi-aggregated as in
665  * fixVariableZeroNode(), since this would be too time consuming.
666  */
667 static
669  SCIP* scip, /**< SCIP pointer */
670  SCIP_VAR* var, /**< variable to be fixed to 0*/
671  SCIP_CONS* cons, /**< constraint */
672  int inferinfo, /**< info for reverse prop. */
673  SCIP_Bool* infeasible, /**< if fixing is infeasible */
674  SCIP_Bool* tightened, /**< if fixing was performed */
675  SCIP_Bool* success /**< whether fixing was successful, i.e., variable is not multi-aggregated */
676  )
677 {
678  *infeasible = FALSE;
679  *tightened = FALSE;
680  *success = FALSE;
681 
682  /* if variable cannot be nonzero */
684  {
685  *infeasible = TRUE;
686  return SCIP_OKAY;
687  }
688 
689  /* directly fix variable if it is not multi-aggregated */
691  {
692  SCIP_Bool tighten;
693 
694  /* fix lower bound */
695  SCIP_CALL( SCIPinferVarLbCons(scip, var, 0.0, cons, inferinfo, FALSE, infeasible, &tighten) );
696  *tightened = *tightened || tighten;
697 
698  /* fix upper bound */
699  SCIP_CALL( SCIPinferVarUbCons(scip, var, 0.0, cons, inferinfo, FALSE, infeasible, &tighten) );
700  *tightened = *tightened || tighten;
701 
702  *success = TRUE;
703  }
704 
705  return SCIP_OKAY;
706 }
707 
708 
709 /** add lock on variable */
710 static
712  SCIP* scip, /**< SCIP data structure */
713  SCIP_CONS* cons, /**< constraint */
714  SCIP_VAR* var /**< variable */
715  )
716 {
717  assert( scip != NULL );
718  assert( cons != NULL );
719  assert( var != NULL );
720 
721  /* rounding down == bad if lb < 0, rounding up == bad if ub > 0 */
723 
724  return SCIP_OKAY;
725 }
726 
727 
728 /** remove lock on variable */
729 static
731  SCIP* scip, /**< SCIP data structure */
732  SCIP_CONS* cons, /**< constraint */
733  SCIP_VAR* var /**< variable */
734  )
735 {
736  assert( scip != NULL );
737  assert( cons != NULL );
738  assert( var != NULL );
739 
740  /* rounding down == bad if lb < 0, rounding up == bad if ub > 0 */
742 
743  return SCIP_OKAY;
744 }
745 
746 
747 /** ensures that the vars and weights array can store at least num entries */
748 static
750  SCIP* scip, /**< SCIP data structure */
751  SCIP_CONSDATA* consdata, /**< constraint data */
752  int num, /**< minimum number of entries to store */
753  SCIP_Bool reserveWeights /**< whether the weights array is handled */
754  )
755 {
756  assert( consdata != NULL );
757  assert( consdata->nvars <= consdata->maxvars );
758 
759  if ( num > consdata->maxvars )
760  {
761  int newsize;
762 
763  newsize = SCIPcalcMemGrowSize(scip, num);
764  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->maxvars, newsize) );
765  if ( reserveWeights )
766  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->maxvars, newsize) );
767  consdata->maxvars = newsize;
768  }
769  assert( num <= consdata->maxvars );
770 
771  return SCIP_OKAY;
772 }
773 
774 
775 /** handle new variable */
776 static
778  SCIP* scip, /**< SCIP data structure */
779  SCIP_CONS* cons, /**< constraint */
780  SCIP_CONSDATA* consdata, /**< constraint data */
781  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
782  SCIP_VAR* var, /**< variable */
783  SCIP_Bool transformed /**< whether original variable was transformed */
784  )
785 {
786  SCIP_DIGRAPH* conflictgraph;
787  int node;
788 
789  assert( scip != NULL );
790  assert( cons != NULL );
791  assert( consdata != NULL );
792  assert( conshdlrdata != NULL );
793  assert( var != NULL );
794 
795  /* if we are in transformed problem, catch the variable's events */
796  if ( transformed )
797  {
798  assert( conshdlrdata->eventhdlr != NULL );
799 
800  /* catch bound change events of variable */
801  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlr,
802  (SCIP_EVENTDATA*)cons, NULL) ); /*lint !e740*/
803 
804  /* if the variable if fixed to nonzero */
805  assert( consdata->nfixednonzeros >= 0 );
807  ++consdata->nfixednonzeros;
808  }
809 
810  /* install the rounding locks for the new variable */
811  SCIP_CALL( lockVariableSOS1(scip, cons, var) );
812 
813  /* branching on multiaggregated variables does not seem to work well, so avoid it */
814  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, var) );
815 
816  /* add the new coefficient to the upper bound LP row, if necessary */
817  if ( consdata->rowub != NULL && ! SCIPisInfinity(scip, SCIPvarGetUbGlobal(var)) && ! SCIPisZero(scip, SCIPvarGetUbGlobal(var)) )
818  {
819  SCIP_CALL( SCIPaddVarToRow(scip, consdata->rowub, var, 1.0/SCIPvarGetUbGlobal(var)) );
820  }
821 
822  /* add the new coefficient to the lower bound LP row, if necessary */
823  if ( consdata->rowlb != NULL && ! SCIPisInfinity(scip, SCIPvarGetLbGlobal(var)) && ! SCIPisZero(scip, SCIPvarGetLbGlobal(var)) )
824  {
825  SCIP_CALL( SCIPaddVarToRow(scip, consdata->rowlb, var, 1.0/SCIPvarGetLbGlobal(var)) );
826  }
827 
828  /* return if the conflict graph has not been created yet */
829  conflictgraph = conshdlrdata->conflictgraph;
830  if ( conflictgraph == NULL )
831  return SCIP_OKAY;
832 
833  /* get node of variable in the conflict graph (or -1) */
834  node = varGetNodeSOS1(conshdlrdata, var);
835  assert( node < conshdlrdata->nsos1vars );
836 
837  /* if the variable is not already a node of the conflict graph */
838  if ( node < 0 )
839  {
840  /* variable does not appear in the conflict graph: switch to SOS1 branching rule, which does not make use of a conflict graph
841  * @todo: maybe recompute the conflict graph, implication graph and varhash instead */
842  SCIPdebugMessage("Switched to SOS1 branching rule, since conflict graph could be infeasible.\n");
843  conshdlrdata->switchsos1branch = TRUE;
844  return SCIP_OKAY;
845  }
846 
847  /* if the constraint is local, then there is no need to act, since local constraints are handled by the local conflict graph in the
848  * function enforceConflictgraph() */
849  if ( ! consdata->local )
850  {
851  SCIP_VAR** vars;
852  int nvars;
853  int v;
854 
855  vars = consdata->vars;
856  nvars = consdata->nvars;
857 
858  for (v = 0; v < nvars; ++v)
859  {
860  int nodev;
861 
862  if ( var == vars[v] )
863  continue;
864 
865  /* get node of variable in the conflict graph (or -1) */
866  nodev = varGetNodeSOS1(conshdlrdata, vars[v]);
867  assert( nodev < conshdlrdata->nsos1vars );
868 
869  /* if the variable is already a node of the conflict graph */
870  if ( nodev >= 0 )
871  {
872  int nsucc;
873  int nsuccv;
874 
875  nsucc = SCIPdigraphGetNSuccessors(conflictgraph, node);
876  nsuccv = SCIPdigraphGetNSuccessors(conflictgraph, nodev);
877 
878  /* add arcs if not existent */
879  SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraph, nodev, node, NULL) );
880  SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraph, node, nodev, NULL) );
881 
882  /* in case of new arcs: sort successors in ascending order */
883  if ( nsucc < SCIPdigraphGetNSuccessors(conflictgraph, node) )
884  {
885  SCIPdebugMessage("Added new conflict graph arc from variable %s to variable %s.\n", SCIPvarGetName(var), SCIPvarGetName(vars[v]));
886  SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, node), SCIPdigraphGetNSuccessors(conflictgraph, node));
887  }
888 
889  if ( nsuccv < SCIPdigraphGetNSuccessors(conflictgraph, nodev) )
890  {
891  SCIPdebugMessage("Added new conflict graph arc from variable %s to variable %s.\n", SCIPvarGetName(vars[v]), SCIPvarGetName(var));
892  SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, nodev), SCIPdigraphGetNSuccessors(conflictgraph, nodev));
893  }
894  }
895  else
896  {
897  /* variable does not appear in the conflict graph: switch to SOS1 branching rule, which does not make use of a conflict graph
898  * @todo: maybe recompute the conflict graph, implication graph and varhash instead */
899  SCIPdebugMessage("Switched to SOS1 branching rule, since conflict graph could be infeasible.\n");
900  conshdlrdata->switchsos1branch = TRUE;
901  return SCIP_OKAY;
902  }
903  }
904  }
905 
906  return SCIP_OKAY;
907 }
908 
909 
910 /** adds a variable to an SOS1 constraint, at position given by weight - ascending order */
911 static
913  SCIP* scip, /**< SCIP data structure */
914  SCIP_CONS* cons, /**< constraint */
915  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
916  SCIP_VAR* var, /**< variable to add to the constraint */
917  SCIP_Real weight /**< weight to determine position */
918  )
919 {
920  SCIP_CONSDATA* consdata;
921  SCIP_Bool transformed;
922  int pos;
923  int j;
924 
925  assert( var != NULL );
926  assert( cons != NULL );
927  assert( conshdlrdata != NULL );
928 
929  consdata = SCIPconsGetData(cons);
930  assert( consdata != NULL );
931 
932  if ( consdata->weights == NULL && consdata->maxvars > 0 )
933  {
934  SCIPerrorMessage("cannot add variable to SOS1 constraint <%s> that does not contain weights.\n", SCIPconsGetName(cons));
935  return SCIP_INVALIDCALL;
936  }
937 
938  /* are we in the transformed problem? */
939  transformed = SCIPconsIsTransformed(cons);
940 
941  /* always use transformed variables in transformed constraints */
942  if ( transformed )
943  {
944  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
945  }
946  assert( var != NULL );
947  assert( transformed == SCIPvarIsTransformed(var) );
948 
949  SCIP_CALL( consdataEnsurevarsSizeSOS1(scip, consdata, consdata->nvars + 1, TRUE) );
950  assert( consdata->weights != NULL );
951  assert( consdata->maxvars >= consdata->nvars+1 );
952 
953  /* find variable position */
954  for (pos = 0; pos < consdata->nvars; ++pos)
955  {
956  if ( consdata->weights[pos] > weight )
957  break;
958  }
959  assert( 0 <= pos && pos <= consdata->nvars );
960 
961  /* move other variables, if necessary */
962  for (j = consdata->nvars; j > pos; --j)
963  {
964  consdata->vars[j] = consdata->vars[j-1];
965  consdata->weights[j] = consdata->weights[j-1];
966  }
967 
968  /* insert variable */
969  consdata->vars[pos] = var;
970  consdata->weights[pos] = weight;
971  ++consdata->nvars;
972 
973  /* handle the new variable */
974  SCIP_CALL( handleNewVariableSOS1(scip, cons, consdata, conshdlrdata, var, transformed) );
975 
976  return SCIP_OKAY;
977 }
978 
979 
980 /** appends a variable to an SOS1 constraint */
981 static
983  SCIP* scip, /**< SCIP data structure */
984  SCIP_CONS* cons, /**< constraint */
985  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
986  SCIP_VAR* var /**< variable to add to the constraint */
987  )
988 {
989  SCIP_CONSDATA* consdata;
990  SCIP_Bool transformed;
991 
992  assert( var != NULL );
993  assert( cons != NULL );
994  assert( conshdlrdata != NULL );
995 
996  consdata = SCIPconsGetData(cons);
997  assert( consdata != NULL );
998 
999  /* are we in the transformed problem? */
1000  transformed = SCIPconsIsTransformed(cons);
1001 
1002  /* always use transformed variables in transformed constraints */
1003  if ( transformed )
1004  {
1005  SCIP_CALL( SCIPgetTransformedVar(scip, var, &var) );
1006  }
1007  assert( var != NULL );
1008  assert( transformed == SCIPvarIsTransformed(var) );
1009 
1010  SCIP_CALL( consdataEnsurevarsSizeSOS1(scip, consdata, consdata->nvars + 1, FALSE) );
1011 
1012  /* insert variable */
1013  consdata->vars[consdata->nvars] = var;
1014  assert( consdata->weights != NULL || consdata->nvars > 0 );
1015  if ( consdata->weights != NULL && consdata->nvars > 0 )
1016  consdata->weights[consdata->nvars] = consdata->weights[consdata->nvars-1] + 1.0;
1017  ++consdata->nvars;
1018 
1019  /* handle the new variable */
1020  SCIP_CALL( handleNewVariableSOS1(scip, cons, consdata, conshdlrdata, var, transformed) );
1021 
1022  return SCIP_OKAY;
1023 }
1024 
1025 
1026 /** deletes a variable of an SOS1 constraint */
1027 static
1029  SCIP* scip, /**< SCIP data structure */
1030  SCIP_CONS* cons, /**< constraint */
1031  SCIP_CONSDATA* consdata, /**< constraint data */
1032  SCIP_EVENTHDLR* eventhdlr, /**< corresponding event handler */
1033  int pos /**< position of variable in array */
1034  )
1035 {
1036  int j;
1037 
1038  assert( 0 <= pos && pos < consdata->nvars );
1039 
1040  /* remove lock of variable */
1041  SCIP_CALL( unlockVariableSOS1(scip, cons, consdata->vars[pos]) );
1042 
1043  /* drop events on variable */
1044  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos], SCIP_EVENTTYPE_BOUNDCHANGED, eventhdlr, (SCIP_EVENTDATA*)cons, -1) ); /*lint !e740*/
1045 
1046  /* delete variable - need to copy since order is important */
1047  for (j = pos; j < consdata->nvars-1; ++j)
1048  {
1049  consdata->vars[j] = consdata->vars[j+1]; /*lint !e679*/
1050  if ( consdata->weights != NULL )
1051  consdata->weights[j] = consdata->weights[j+1]; /*lint !e679*/
1052  }
1053  --consdata->nvars;
1054 
1055  return SCIP_OKAY;
1056 }
1057 
1058 
1059 /* ----------------------------- presolving --------------------------------------*/
1060 
1061 /** extends a given clique of the conflict graph
1062  *
1063  * Implementation of the Bron-Kerbosch Algorithm from the paper:
1064  * Algorithm 457: Finding all Cliques of an Undirected Graph, Bron & Kerbosch, Commun. ACM, 1973
1065  */
1066 static
1068  SCIP* scip, /**< SCIP pointer */
1069  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
1070  SCIP_Bool** adjacencymatrix, /**< adjacencymatrix of the conflict graph (only lower half filled) */
1071  SCIP_DIGRAPH* vertexcliquegraph, /**< graph that contains the information which cliques contain a given vertex
1072  * vertices of variables = 0, ..., nsos1vars-1; vertices of cliques = nsos1vars, ..., nsos1vars+ncliques-1*/
1073  int nsos1vars, /**< number of SOS1 variables */
1074  int nconss, /**< number of SOS1 constraints */
1075  SCIP_CONS* cons, /**< constraint to be extended */
1076  SCIP_VAR** vars, /**< variables of extended clique */
1077  SCIP_Real* weights, /**< weights of extended clique */
1078  SCIP_Bool firstcall, /**< whether this is the first call of extension operator */
1079  SCIP_Bool usebacktrack, /**< whether backtracking is needed for the computation */
1080  int** cliques, /**< all cliques found so far */
1081  int* ncliques, /**< number of clique found so far */
1082  int* cliquesizes, /**< number of variables of current clique */
1083  int* newclique, /**< clique we want to extended*/
1084  int* workingset, /**< set of vertices that already served as extension and set of candidates that probably will lead to an extension */
1085  int nworkingset, /**< length of array workingset */
1086  int nexts, /**< number of vertices that already served as extension */
1087  int pos, /**< position of potential candidate */
1088  int* maxextensions, /**< maximal number of extensions */
1089  int* naddconss, /**< number of added constraints */
1090  SCIP_Bool* success /**< pointer to store if at least one new clique was found */
1091  )
1092 {
1093  int* workingsetnew = NULL;
1094  int nextsnew;
1095  int nworkingsetnew;
1096  int mincands;
1097  int btriter = 0; /* backtrack iterator */
1098  int selvertex;
1099  int selpos = -1;
1100  int fixvertex = -1;
1101  int i;
1102  int j;
1103 
1104  assert( scip != NULL );
1105  assert( conshdlrdata != NULL );
1106  assert( adjacencymatrix != NULL );
1107  assert( vertexcliquegraph != NULL );
1108  assert( cons != NULL );
1109  assert( cliques != NULL );
1110  assert( cliquesizes != NULL );
1111  assert( newclique != NULL );
1112  assert( workingset != NULL );
1113  assert( maxextensions != NULL );
1114  assert( naddconss != NULL );
1115  assert( success != NULL );
1116 
1117  if ( firstcall )
1118  *success = FALSE;
1119 
1120  mincands = nworkingset;
1121  if ( mincands < 1 )
1122  return SCIP_OKAY;
1123 
1124  /* allocate buffer array */
1125  SCIP_CALL( SCIPallocBufferArray(scip, &workingsetnew, nworkingset) );
1126 
1127 #ifdef SCIP_DEBUG
1128  for (i = 0; i < nexts; ++i)
1129  {
1130  int vertex = workingset[i];
1131  for (j = nexts; j < nworkingset; ++j)
1132  {
1133  assert( isConnectedSOS1(adjacencymatrix, NULL, vertex, workingset[j]) );
1134  }
1135  }
1136 #endif
1137 
1138  /* determine candidate with minimum number of disconnections */
1139  for (i = 0; i < nworkingset; ++i)
1140  {
1141  int vertex;
1142  int cnt = 0;
1143 
1144  vertex = workingset[i];
1145 
1146  /* count disconnections */
1147  for (j = nexts; j < nworkingset && cnt < mincands; ++j)
1148  {
1149  if ( vertex != workingset[j] && ! isConnectedSOS1(adjacencymatrix, NULL, vertex, workingset[j]) )
1150  {
1151  cnt++;
1152 
1153  /* save position of potential candidate */
1154  pos = j;
1155  }
1156  }
1157 
1158  /* check whether a new minimum was found */
1159  if ( cnt < mincands )
1160  {
1161  fixvertex = vertex;
1162  mincands = cnt;
1163  if ( i < nexts )
1164  {
1165  assert( pos >= 0 );
1166  selpos = pos;
1167  }
1168  else
1169  {
1170  selpos = i;
1171 
1172  /* preincrement */
1173  btriter = 1;
1174  }
1175  }
1176  }
1177 
1178  /* If fixed point is initially chosen from candidates then number of disconnections will be preincreased by one. */
1179 
1180  /* backtrackcycle */
1181  for (btriter = mincands + btriter; btriter >= 1; --btriter)
1182  {
1183  assert( selpos >= 0);
1184  assert( fixvertex >= 0);
1185 
1186  /* interchange */
1187  selvertex = workingset[selpos];
1188  workingset[selpos] = workingset[nexts];
1189  workingset[nexts] = selvertex;
1190 
1191  /* create new workingset */
1192  nextsnew = 0;
1193  for (j = 0 ; j < nexts; ++j)
1194  {
1195  if ( isConnectedSOS1(adjacencymatrix, NULL, selvertex, workingset[j]) )
1196  workingsetnew[nextsnew++] = workingset[j];
1197  }
1198  nworkingsetnew = nextsnew;
1199  for (j = nexts + 1; j < nworkingset; ++j)
1200  {
1201  if ( isConnectedSOS1(adjacencymatrix, NULL, selvertex, workingset[j]) )
1202  workingsetnew[nworkingsetnew++] = workingset[j];
1203  }
1204 
1205  newclique[cliquesizes[*ncliques]++] = selvertex;
1206 
1207  /* if we found a new clique */
1208  if ( nworkingsetnew == 0 )
1209  {
1210  char consname[SCIP_MAXSTRLEN];
1211  SCIP_CONSDATA* consdata;
1212  SCIP_CONS* newcons;
1213  int cliqueind;
1214 
1215  cliqueind = nsos1vars + *ncliques; /* index of clique in the vertex-clique graph */
1216 
1217  /* save new clique */
1218  assert( cliquesizes[*ncliques] >= 0 && cliquesizes[*ncliques] <= nsos1vars );
1219  assert( *ncliques < MAX(1, conshdlrdata->maxextensions) * nconss );
1220  SCIP_CALL( SCIPallocBufferArray(scip, &(cliques[*ncliques]), cliquesizes[*ncliques]) );/*lint !e866*/
1221  for (j = 0 ; j < cliquesizes[*ncliques]; ++j)
1222  {
1223  vars[j] = SCIPnodeGetVarSOS1(conshdlrdata->conflictgraph, newclique[j]);
1224  weights[j] = j+1;
1225  cliques[*ncliques][j] = newclique[j];
1226  }
1227 
1228  SCIPsortInt(cliques[*ncliques], cliquesizes[*ncliques]);
1229 
1230  /* create new constraint */
1231  (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "extsos1_%"SCIP_LONGINT_FORMAT, conshdlrdata->cntextsos1, conshdlrdata->cntextsos1);
1232 
1233  SCIP_CALL( SCIPcreateConsSOS1(scip, &newcons, consname, cliquesizes[*ncliques], vars, weights,
1237  SCIPconsIsDynamic(cons),
1239 
1240  consdata = SCIPconsGetData(newcons);
1241 
1242  /* add directed edges to the vertex-clique graph */
1243  for (j = 0; j < consdata->nvars; ++j)
1244  {
1245  /* add arc from clique vertex to clique (needed in presolRoundConssSOS1() to delete redundand cliques) */
1246  SCIP_CALL( SCIPdigraphAddArcSafe(vertexcliquegraph, cliques[*ncliques][j], cliqueind, NULL) );
1247  }
1248 
1249  SCIP_CALL( SCIPaddCons(scip, newcons) );
1250  SCIP_CALL( SCIPreleaseCons(scip, &newcons) );
1251 
1252  ++(*naddconss);
1253  ++(conshdlrdata->cntextsos1);
1254  ++(*ncliques);
1255  cliquesizes[*ncliques] = cliquesizes[*ncliques-1]; /* cliquesizes[*ncliques] = size of newclique */
1256 
1257  *success = TRUE;
1258 
1259  --(*maxextensions);
1260 
1261  if ( *maxextensions <= 0 )
1262  {
1263  SCIPfreeBufferArray(scip, &workingsetnew);
1264  return SCIP_OKAY;
1265  }
1266  }
1267  else if ( nextsnew < nworkingsetnew ) /* else if the number of of candidates equals zero */
1268  {
1269  /* if backtracking is used, it is necessary to keep the memory for 'workingsetnew' */
1270  if ( usebacktrack )
1271  {
1272  SCIP_CALL( extensionOperatorSOS1(scip, conshdlrdata, adjacencymatrix, vertexcliquegraph, nsos1vars, nconss, cons, vars, weights, FALSE, usebacktrack,
1273  cliques, ncliques, cliquesizes, newclique, workingsetnew, nworkingsetnew, nextsnew, pos, maxextensions, naddconss, success) );
1274  if ( *maxextensions <= 0 )
1275  {
1276  SCIPfreeBufferArrayNull(scip, &workingsetnew);
1277  return SCIP_OKAY;
1278  }
1279  }
1280  else
1281  {
1282  int w;
1283 
1284  assert( nworkingset >= nworkingsetnew );
1285  for (w = 0; w < nworkingsetnew; ++w)
1286  workingset[w] = workingsetnew[w];
1287  nworkingset = nworkingsetnew;
1288 
1289  SCIPfreeBufferArrayNull(scip, &workingsetnew);
1290 
1291  SCIP_CALL( extensionOperatorSOS1(scip, conshdlrdata, adjacencymatrix, vertexcliquegraph, nsos1vars, nconss, cons, vars, weights, FALSE, usebacktrack,
1292  cliques, ncliques, cliquesizes, newclique, workingset, nworkingset, nextsnew, pos, maxextensions, naddconss, success) );
1293  assert( *maxextensions <= 0 );
1294  return SCIP_OKAY;
1295  }
1296  }
1297  assert( workingsetnew != NULL );
1298  assert( workingset != NULL );
1299 
1300  /* remove selvertex from clique */
1301  --cliquesizes[*ncliques];
1302 
1303  /* add selvertex to the set of vertices that already served as extension */
1304  ++nexts;
1305 
1306  if ( btriter > 1 )
1307  {
1308  /* select a candidate that is not connected to the fixed vertex */
1309  for (j = nexts; j < nworkingset; ++j)
1310  {
1311  assert( fixvertex != workingset[j] );
1312  if ( ! isConnectedSOS1(adjacencymatrix, NULL, fixvertex, workingset[j]) )
1313  {
1314  selpos = j;
1315  break;
1316  }
1317  }
1318  }
1319  }
1320 
1321  SCIPfreeBufferArrayNull(scip, &workingsetnew);
1322 
1323  return SCIP_OKAY;
1324 }
1325 
1326 
1327 /** generates conflict graph that is induced by the variables of a linear constraint */
1328 static
1330  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
1331  SCIP_DIGRAPH* conflictgraphlin, /**< conflict graph of linear constraint (nodes: 1, ..., nlinvars) */
1332  SCIP_DIGRAPH* conflictgraphorig, /**< original conflict graph (nodes: 1, ..., nsos1vars) */
1333  SCIP_VAR** linvars, /**< linear variables in linear constraint */
1334  int nlinvars, /**< number of linear variables in linear constraint */
1335  int* posinlinvars /**< posinlinvars[i] = position (index) of SOS1 variable i in linear constraint,
1336  * posinlinvars[i]= -1 if @p i is not a SOS1 variable or not a variable of the linear constraint */
1337  )
1338 {
1339  int indexinsosvars;
1340  int indexinlinvars;
1341  int* succ;
1342  int nsucc;
1343  int v;
1344  int s;
1345 
1346  assert( conflictgraphlin != NULL );
1347  assert( conflictgraphorig != NULL );
1348  assert( linvars != NULL );
1349  assert( posinlinvars != NULL );
1350 
1351  for (v = 1; v < nlinvars; ++v) /* we start with v = 1, since "indexinlinvars < v" (see below) is never fulfilled for v = 0 */
1352  {
1353  indexinsosvars = varGetNodeSOS1(conshdlrdata, linvars[v]);
1354 
1355  /* if linvars[v] is contained in at least one SOS1 constraint */
1356  if ( indexinsosvars >= 0 )
1357  {
1358  succ = SCIPdigraphGetSuccessors(conflictgraphorig, indexinsosvars);
1359  nsucc = SCIPdigraphGetNSuccessors(conflictgraphorig, indexinsosvars);
1360 
1361  for (s = 0; s < nsucc; ++s)
1362  {
1363  assert( succ[s] >= 0 );
1364  indexinlinvars = posinlinvars[succ[s]];
1365  assert( indexinlinvars < nlinvars );
1366 
1367  if ( indexinlinvars >= 0 && indexinlinvars < v )
1368  {
1369  SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraphlin, v, indexinlinvars, NULL) );
1370  SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraphlin, indexinlinvars, v, NULL) );
1371  }
1372  }
1373  }
1374  }
1375 
1376  return SCIP_OKAY;
1377 }
1378 
1379 
1380 /** determine the common successors of the vertices from the considered clique */
1381 static
1383  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
1384  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
1385  int* clique, /**< current clique */
1386  SCIP_VAR** vars, /**< clique variables */
1387  int nvars, /**< number of clique variables */
1388  int* comsucc, /**< pointer to store common successors of clique vertices (size = nvars) */
1389  int* ncomsucc /**< pointer to store number common successors of clique vertices */
1390  )
1391 {
1392  int nsucc;
1393  int* succ;
1394  int ind;
1395  int k = 0;
1396  int v;
1397  int i;
1398  int j;
1399 
1400  assert( conflictgraph != NULL );
1401  assert( clique != NULL );
1402  assert( vars != NULL );
1403  assert( comsucc != NULL );
1404  assert( ncomsucc != NULL );
1405 
1406  *ncomsucc = 0;
1407 
1408  /* determine the common successors of the vertices from the considered clique */
1409 
1410  /* determine successors of variable var[0] that are not in the clique */
1411  assert(vars[0] != NULL );
1412  ind = varGetNodeSOS1(conshdlrdata, vars[0]);
1413  assert( ind >= 0 && ind < SCIPdigraphGetNNodes(conflictgraph) );
1414  nsucc = SCIPdigraphGetNSuccessors(conflictgraph, ind);
1415  succ = SCIPdigraphGetSuccessors(conflictgraph, ind);
1416 
1417  for (j = 0; j < nvars; ++j)
1418  {
1419  for (i = k; i < nsucc; ++i)
1420  {
1421  if ( succ[i] > clique[j] )
1422  {
1423  k = i;
1424  break;
1425  }
1426  else if ( succ[i] == clique[j] )
1427  {
1428  k = i + 1;
1429  break;
1430  }
1431  else
1432  comsucc[(*ncomsucc)++] = succ[i];
1433  }
1434  }
1435 
1436  /* for all variables except the first one */
1437  for (v = 1; v < nvars; ++v)
1438  {
1439  int ncomsuccsave = 0;
1440  k = 0;
1441 
1442  assert(vars[v] != NULL );
1443  ind = varGetNodeSOS1(conshdlrdata, vars[v]);
1444  assert( ind >= 0 && ind < SCIPdigraphGetNNodes(conflictgraph) );
1445 
1446  if ( ind >= 0 )
1447  {
1448  nsucc = SCIPdigraphGetNSuccessors(conflictgraph, ind);
1449  succ = SCIPdigraphGetSuccessors(conflictgraph, ind);
1450 
1451  /* determine successors that are in comsucc */
1452  for (j = 0; j < *ncomsucc; ++j)
1453  {
1454  for (i = k; i < nsucc; ++i)
1455  {
1456  if ( succ[i] > comsucc[j] )
1457  {
1458  k = i;
1459  break;
1460  }
1461  else if ( succ[i] == comsucc[j] )
1462  {
1463  comsucc[ncomsuccsave++] = succ[i];
1464  k = i + 1;
1465  break;
1466  }
1467  }
1468  }
1469  *ncomsucc = ncomsuccsave;
1470  }
1471  }
1472 
1473  return SCIP_OKAY;
1474 }
1475 
1476 
1477 /** get nodes whose corresponding SOS1 variables are nonzero if an SOS1 variable of a given node is nonzero */
1478 static
1480  SCIP* scip, /**< SCIP pointer */
1481  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
1482  SCIP_VAR** vars, /**< problem and SOS1 variables */
1483  SCIP_DIGRAPH* implgraph, /**< implication graph (@p j is successor of @p i if and only if \f$ x_i\not = 0 \Rightarrow x_j\not = 0\f$) */
1484  SCIP_HASHMAP* implhash, /**< hash map from variable to node in implication graph */
1485  SCIP_Bool* implnodes, /**< implnodes[i] = TRUE if the SOS1 variable corresponding to node i in the implication graph is implied to be nonzero */
1486  int node /**< node of the implication graph */
1487  )
1488 {
1489  SCIP_SUCCDATA** succdatas;
1490  int sos1node;
1491  int* succ;
1492  int nsucc;
1493  int s;
1494 
1495  assert( scip != NULL );
1496  assert( implgraph != NULL );
1497  assert( implnodes != NULL );
1498  assert( node >= 0 );
1499  assert( vars[node] != NULL );
1500  assert( (int) (size_t) SCIPhashmapGetImage(implhash, vars[node]) == node );
1501 
1502  /* get node of variable in the conflict graph (-1 if variable is no SOS1 variable) */
1503  sos1node = varGetNodeSOS1(conshdlrdata, vars[node]);
1504  if ( sos1node < 0 )
1505  return SCIP_OKAY;
1506 
1507  succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(implgraph, node);
1508  nsucc = SCIPdigraphGetNSuccessors(implgraph, node);
1509  succ = SCIPdigraphGetSuccessors(implgraph, node);
1510 
1511  for (s = 0; s < nsucc; ++s)
1512  {
1513  SCIP_SUCCDATA* data;
1514  int succnode;
1515  succnode = succ[s];
1516  data = succdatas[s];
1517  sos1node = varGetNodeSOS1(conshdlrdata, vars[succnode]);
1518 
1519  /* if node is SOS1 and the corresponding variable is implied to be nonzero */
1520  assert( succdatas[s] != NULL );
1521  if ( sos1node >= 0 && ! implnodes[sos1node] && ( SCIPisFeasPositive(scip, data->lbimpl) || SCIPisFeasNegative(scip, data->ubimpl) ) )
1522  {
1523  assert( sos1node == succnode );
1524  implnodes[sos1node] = TRUE;
1525  SCIP_CALL( getSOS1Implications(scip, conshdlrdata, vars, implgraph, implhash, implnodes, succnode) );
1526  }
1527  }
1528 
1529  return SCIP_OKAY;
1530 }
1531 
1532 
1533 /** perform one presolving round for a single SOS1 constraint
1534  *
1535  * We perform the following presolving steps.
1536  *
1537  * - If the bounds of some variable force it to be nonzero, we can
1538  * fix all other variables to zero and remove the SOS1 constraints
1539  * that contain it.
1540  * - If a variable is fixed to zero, we can remove the variable.
1541  * - If a variable appears twice, it can be fixed to 0.
1542  * - We substitute appregated variables.
1543  */
1544 static
1546  SCIP* scip, /**< SCIP pointer */
1547  SCIP_CONS* cons, /**< constraint */
1548  SCIP_CONSDATA* consdata, /**< constraint data */
1549  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1550  SCIP_Bool* substituted, /**< whether a variable was substituted */
1551  SCIP_Bool* cutoff, /**< whether a cutoff happened */
1552  SCIP_Bool* success, /**< whether we performed a successful reduction */
1553  int* ndelconss, /**< number of deleted constraints */
1554  int* nupgdconss, /**< number of upgraded constraints */
1555  int* nfixedvars, /**< number of fixed variables */
1556  int* nremovedvars /**< number of variables removed */
1557  )
1558 {
1559  SCIP_VAR** vars;
1560  SCIP_Bool allvarsbinary;
1561  SCIP_Bool infeasible;
1562  SCIP_Bool fixed;
1563  int nfixednonzeros;
1564  int lastFixedNonzero;
1565  int j;
1566 
1567  assert( scip != NULL );
1568  assert( cons != NULL );
1569  assert( consdata != NULL );
1570  assert( eventhdlr != NULL );
1571  assert( cutoff != NULL );
1572  assert( success != NULL );
1573  assert( ndelconss != NULL );
1574  assert( nfixedvars != NULL );
1575  assert( nremovedvars != NULL );
1576 
1577  *substituted = FALSE;
1578  *cutoff = FALSE;
1579  *success = FALSE;
1580 
1581  SCIPdebugMessage("Presolving SOS1 constraint <%s>.\n", SCIPconsGetName(cons) );
1582 
1583  j = 0;
1584  nfixednonzeros = 0;
1585  lastFixedNonzero = -1;
1586  allvarsbinary = TRUE;
1587  vars = consdata->vars;
1588 
1589  /* check for variables fixed to 0 and bounds that fix a variable to be nonzero */
1590  while ( j < consdata->nvars )
1591  {
1592  int l;
1593  SCIP_VAR* var;
1594  SCIP_Real lb;
1595  SCIP_Real ub;
1596  SCIP_Real scalar;
1597  SCIP_Real constant;
1598 
1599  scalar = 1.0;
1600  constant = 0.0;
1601 
1602  /* check for aggregation: if the constant is zero the variable is zero iff the aggregated
1603  * variable is 0 */
1604  var = vars[j];
1605  SCIP_CALL( SCIPgetProbvarSum(scip, &var, &scalar, &constant) );
1606 
1607  /* if constant is zero and we get a different variable, substitute variable */
1608  if ( SCIPisZero(scip, constant) && ! SCIPisZero(scip, scalar) && var != vars[j] )
1609  {
1610  SCIPdebugMessage("substituted variable <%s> by <%s>.\n", SCIPvarGetName(vars[j]), SCIPvarGetName(var));
1611  SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[j], SCIP_EVENTTYPE_BOUNDCHANGED, eventhdlr, (SCIP_EVENTDATA*)cons, -1) ); /*lint !e740*/
1612  SCIP_CALL( SCIPcatchVarEvent(scip, var, SCIP_EVENTTYPE_BOUNDCHANGED, eventhdlr, (SCIP_EVENTDATA*)cons, NULL) ); /*lint !e740*/
1613 
1614  /* change the rounding locks */
1615  SCIP_CALL( unlockVariableSOS1(scip, cons, consdata->vars[j]) );
1616  SCIP_CALL( lockVariableSOS1(scip, cons, var) );
1617 
1618  vars[j] = var;
1619  *substituted = TRUE;
1620  }
1621 
1622  /* check whether the variable appears again later */
1623  for (l = j+1; l < consdata->nvars; ++l)
1624  {
1625  /* if variable appeared before, we can fix it to 0 and remove it */
1626  if ( vars[j] == vars[l] )
1627  {
1628  SCIPdebugMessage("variable <%s> appears twice in constraint, fixing it to 0.\n", SCIPvarGetName(vars[j]));
1629  SCIP_CALL( SCIPfixVar(scip, vars[j], 0.0, &infeasible, &fixed) );
1630 
1631  if ( infeasible )
1632  {
1633  *cutoff = TRUE;
1634  return SCIP_OKAY;
1635  }
1636  if ( fixed )
1637  ++(*nfixedvars);
1638  }
1639  }
1640 
1641  /* get bounds */
1642  lb = SCIPvarGetLbLocal(vars[j]);
1643  ub = SCIPvarGetUbLocal(vars[j]);
1644 
1645  /* if the variable if fixed to nonzero */
1646  if ( SCIPisFeasPositive(scip, lb) || SCIPisFeasNegative(scip, ub) )
1647  {
1648  ++nfixednonzeros;
1649  lastFixedNonzero = j;
1650  }
1651 
1652  /* if the variable is fixed to 0 */
1653  if ( SCIPisFeasZero(scip, lb) && SCIPisFeasZero(scip, ub) )
1654  {
1655  SCIPdebugMessage("deleting variable <%s> fixed to 0.\n", SCIPvarGetName(vars[j]));
1656  SCIP_CALL( deleteVarSOS1(scip, cons, consdata, eventhdlr, j) );
1657  ++(*nremovedvars);
1658  }
1659  else
1660  {
1661  /* check whether all variables are binary */
1662  if ( ! SCIPvarIsBinary(vars[j]) )
1663  allvarsbinary = FALSE;
1664 
1665  ++j;
1666  }
1667  }
1668 
1669  /* if the number of variables is less than 2 */
1670  if ( consdata->nvars < 2 )
1671  {
1672  SCIPdebugMessage("Deleting SOS1 constraint <%s> with < 2 variables.\n", SCIPconsGetName(cons));
1673 
1674  /* delete constraint */
1675  assert( ! SCIPconsIsModifiable(cons) );
1676  SCIP_CALL( SCIPdelCons(scip, cons) );
1677  ++(*ndelconss);
1678  *success = TRUE;
1679  return SCIP_OKAY;
1680  }
1681 
1682  /* if more than one variable are fixed to be nonzero, we are infeasible */
1683  if ( nfixednonzeros > 1 )
1684  {
1685  SCIPdebugMessage("The problem is infeasible: more than one variable has bounds that keep it from being 0.\n");
1686  assert( lastFixedNonzero >= 0 );
1687  *cutoff = TRUE;
1688  return SCIP_OKAY;
1689  }
1690 
1691  /* if there is exactly one fixed nonzero variable */
1692  if ( nfixednonzeros == 1 )
1693  {
1694  assert( lastFixedNonzero >= 0 );
1695 
1696  /* fix all other variables to zero */
1697  for (j = 0; j < consdata->nvars; ++j)
1698  {
1699  if ( j != lastFixedNonzero )
1700  {
1701  SCIP_CALL( fixVariableZero(scip, vars[j], &infeasible, &fixed) );
1702  if ( infeasible )
1703  {
1704  *cutoff = TRUE;
1705  return SCIP_OKAY;
1706  }
1707  if ( fixed )
1708  ++(*nfixedvars);
1709  }
1710  }
1711 
1712  SCIPdebugMessage("Deleting redundant SOS1 constraint <%s> with one variable.\n", SCIPconsGetName(cons));
1713 
1714  /* delete original constraint */
1715  assert( ! SCIPconsIsModifiable(cons) );
1716  SCIP_CALL( SCIPdelCons(scip, cons) );
1717  ++(*ndelconss);
1718  *success = TRUE;
1719  }
1720  /* note: there is no need to update consdata->nfixednonzeros, since the constraint is deleted as soon nfixednonzeros > 0. */
1721  else
1722  {
1723  /* if all variables are binary create a set packing constraint */
1724  if ( allvarsbinary )
1725  {
1726  SCIP_CONS* setpackcons;
1727 
1728  /* create, add, and release the logicor constraint */
1729  SCIP_CALL( SCIPcreateConsSetpack(scip, &setpackcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
1733  SCIP_CALL( SCIPaddCons(scip, setpackcons) );
1734  SCIP_CALL( SCIPreleaseCons(scip, &setpackcons) );
1735 
1736  SCIPdebugMessage("Upgrading SOS1 constraint <%s> to set packing constraint.\n", SCIPconsGetName(cons));
1737 
1738  /* remove the SOS1 constraint globally */
1739  assert( ! SCIPconsIsModifiable(cons) );
1740  SCIP_CALL( SCIPdelCons(scip, cons) );
1741  ++(*nupgdconss);
1742  *success = TRUE;
1743  }
1744  }
1745 
1746  return SCIP_OKAY;
1747 }
1748 
1749 
1750 
1751 /** perform one presolving round for all SOS1 constraints
1752  *
1753  * We perform the following presolving steps.
1754  *
1755  * - If the bounds of some variable force it to be nonzero, we can
1756  * fix all other variables to zero and remove the SOS1 constraints
1757  * that contain it.
1758  * - If a variable is fixed to zero, we can remove the variable.
1759  * - If a variable appears twice, it can be fixed to 0.
1760  * - We substitute appregated variables.
1761  * - Remove redundant SOS1 constraints
1762  *
1763  * If the adjacency matrix of the conflict graph is present, then
1764  * we perform the following additional presolving steps
1765  *
1766  * - Search for larger SOS1 constraints in the conflict graph
1767  */
1768 static
1770  SCIP* scip, /**< SCIP pointer */
1771  SCIP_EVENTHDLR* eventhdlr, /**< event handler */
1772  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
1773  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
1774  SCIP_Bool** adjacencymatrix, /**< adjacency matrix of conflict graph (or NULL) */
1775  SCIP_CONS** conss, /**< SOS1 constraints */
1776  int nconss, /**< number of SOS1 constraints */
1777  int nsos1vars, /**< number of SOS1 variables */
1778  int* naddconss, /**< number of added constraints */
1779  int* ndelconss, /**< number of deleted constraints */
1780  int* nupgdconss, /**< number of upgraded constraints */
1781  int* nfixedvars, /**< number of fixed variables */
1782  int* nremovedvars, /**< number of variables removed */
1783  SCIP_RESULT* result /**< result */
1784  )
1785 {
1786  SCIP_DIGRAPH* vertexcliquegraph;
1787  SCIP_VAR** consvars;
1788  SCIP_Real* consweights;
1789  int** cliques = NULL;
1790  int ncliques = 0;
1791  int* cliquesizes = NULL;
1792  int* newclique = NULL;
1793  int* indconss = NULL;
1794  int* lengthconss = NULL;
1795  int* comsucc = NULL;
1796  int csize;
1797  int iter;
1798  int c;
1799 
1800  assert( scip != NULL );
1801  assert( eventhdlr != NULL );
1802  assert( conshdlrdata != NULL );
1803  assert( conflictgraph != NULL );
1804  assert( conss != NULL );
1805  assert( naddconss != NULL );
1806  assert( ndelconss != NULL );
1807  assert( nupgdconss != NULL );
1808  assert( nfixedvars != NULL );
1809  assert( nremovedvars != NULL );
1810  assert( result != NULL );
1811 
1812  /* create digraph whose nodes represent variables and cliques in the conflict graph */
1813  csize = MAX(1, conshdlrdata->maxextensions) * nconss;
1814  SCIP_CALL( SCIPdigraphCreate(&vertexcliquegraph, nsos1vars + csize) );
1815 
1816  /* allocate buffer arrays */
1817  SCIP_CALL( SCIPallocBufferArray(scip, &consvars, nsos1vars) );
1818  SCIP_CALL( SCIPallocBufferArray(scip, &consweights, nsos1vars) );
1819  SCIP_CALL( SCIPallocBufferArray(scip, &cliquesizes, csize) );
1820  SCIP_CALL( SCIPallocBufferArray(scip, &newclique, nsos1vars) );
1821  SCIP_CALL( SCIPallocBufferArray(scip, &indconss, csize) );
1822  SCIP_CALL( SCIPallocBufferArray(scip, &lengthconss, csize) );
1823  SCIP_CALL( SCIPallocBufferArray(scip, &comsucc, MAX(nsos1vars, csize)) );
1824  SCIP_CALL( SCIPallocBufferArray(scip, &cliques, csize) );
1825 
1826  /* get constraint indices and sort them in descending order of their lengths */
1827  for (c = 0; c < nconss; ++c)
1828  {
1829  SCIP_CONSDATA* consdata;
1830 
1831  consdata = SCIPconsGetData(conss[c]);
1832  assert( consdata != NULL );
1833 
1834  indconss[c] = c;
1835  lengthconss[c] = consdata->nvars;
1836  }
1837  SCIPsortDownIntInt(lengthconss, indconss, nconss);
1838 
1839  /* check each constraint */
1840  for (iter = 0; iter < nconss; ++iter)
1841  {
1842  SCIP_CONSDATA* consdata;
1843  SCIP_CONS* cons;
1844  SCIP_Bool substituted;
1845  SCIP_Bool success;
1846  SCIP_Bool cutoff;
1847  int savennupgdconss;
1848  int savendelconss;
1849 
1850  SCIP_VAR** vars;
1851  int nvars;
1852 
1853  c = indconss[iter];
1854 
1855  assert( conss != NULL );
1856  assert( conss[c] != NULL );
1857  cons = conss[c];
1858  consdata = SCIPconsGetData(cons);
1859 
1860  assert( consdata != NULL );
1861  assert( consdata->nvars >= 0 );
1862  assert( consdata->nvars <= consdata->maxvars );
1863  assert( ! SCIPconsIsModifiable(cons) );
1864  assert( ncliques < csize );
1865 
1866  savendelconss = *ndelconss;
1867  savennupgdconss = *nupgdconss;
1868 
1869  /* perform one presolving round for SOS1 constraint */
1870  SCIP_CALL( presolRoundConsSOS1(scip, cons, consdata, eventhdlr, &substituted, &cutoff, &success, ndelconss, nupgdconss, nfixedvars, nremovedvars) );
1871 
1872  if ( cutoff )
1873  {
1874  *result = SCIP_CUTOFF;
1875  break;
1876  }
1877 
1878  if ( *ndelconss > savendelconss || *nupgdconss > savennupgdconss || substituted )
1879  {
1880  *result = SCIP_SUCCESS;
1881  continue;
1882  }
1883 
1884  if ( success )
1885  *result = SCIP_SUCCESS;
1886 
1887  /* get number of variables of constraint */
1888  nvars = consdata->nvars;
1889 
1890  /* get variables of constraint */
1891  vars = consdata->vars;
1892 
1893  if ( nvars > 1 && conshdlrdata->maxextensions != 0 )
1894  {
1895  SCIP_Bool extended = FALSE;
1896  int cliquesize = 0;
1897  int ncomsucc = 0;
1898  int varprobind;
1899  int j;
1900 
1901  /* get clique and size of clique */
1902  for (j = 0; j < nvars; ++j)
1903  {
1904  varprobind = varGetNodeSOS1(conshdlrdata, vars[j]);
1905 
1906  if ( varprobind >= 0 )
1907  newclique[cliquesize++] = varprobind;
1908  }
1909 
1910  if ( cliquesize > 1 )
1911  {
1912  cliquesizes[ncliques] = cliquesize;
1913 
1914  /* sort clique vertices */
1915  SCIPsortInt(newclique, cliquesizes[ncliques]);
1916 
1917  /* check if clique is contained in an already known clique */
1918  if ( ncliques > 0 )
1919  {
1920  int* succ;
1921  int nsucc;
1922  int v;
1923 
1924  varprobind = newclique[0];
1925  ncomsucc = SCIPdigraphGetNSuccessors(vertexcliquegraph, varprobind);
1926  succ = SCIPdigraphGetSuccessors(vertexcliquegraph, varprobind);
1927 
1928  /* get all (already processed) cliques that contain 'varpropind' */
1929  for (j = 0; j < ncomsucc; ++j)
1930  {
1931  /* successors should have been sorted in a former step of the algorithm */
1932  assert( j == 0 || succ[j] > succ[j-1] );
1933  comsucc[j] = succ[j];
1934  }
1935 
1936  /* loop through remaining nodes of clique (case v = 0 already processed) */
1937  for (v = 1; v < cliquesize && ncomsucc > 0; ++v)
1938  {
1939  varprobind = newclique[v];
1940 
1941  /* get all (already processed) cliques that contain 'varpropind' */
1942  nsucc = SCIPdigraphGetNSuccessors(vertexcliquegraph, varprobind);
1943  succ = SCIPdigraphGetSuccessors(vertexcliquegraph, varprobind);
1944  assert( succ != NULL || nsucc == 0 );
1945 
1946  if ( nsucc < 1 )
1947  {
1948  ncomsucc = 0;
1949  break;
1950  }
1951 
1952  /* get intersection with comsucc */
1953  SCIP_CALL( SCIPcomputeArraysIntersection(comsucc, ncomsucc, succ, nsucc, comsucc, &ncomsucc) );
1954  }
1955  }
1956 
1957  /* if constraint is redundand then delete it */
1958  if ( ncomsucc > 0 )
1959  {
1960  assert( ! SCIPconsIsModifiable(cons) );
1961  SCIP_CALL( SCIPdelCons(scip, cons) );
1962  ++(*ndelconss);
1963  *result = SCIP_SUCCESS;
1964  continue;
1965  }
1966 
1967  if ( conshdlrdata->maxextensions != 0 && adjacencymatrix != NULL )
1968  {
1969  int maxextensions;
1970  ncomsucc = 0;
1971 
1972  /* determine the common successors of the vertices from the considered clique */
1973  SCIP_CALL( cliqueGetCommonSuccessorsSOS1(conshdlrdata, conflictgraph, newclique, vars, nvars, comsucc, &ncomsucc) );
1974 
1975  /* find extensions for the clique */
1976  maxextensions = conshdlrdata->maxextensions;
1977  extended = FALSE;
1978  SCIP_CALL( extensionOperatorSOS1(scip, conshdlrdata, adjacencymatrix, vertexcliquegraph, nsos1vars, nconss, cons, consvars, consweights,
1979  TRUE, (maxextensions <= 1) ? FALSE : TRUE, cliques, &ncliques, cliquesizes, newclique, comsucc, ncomsucc, 0, -1, &maxextensions,
1980  naddconss, &extended) );
1981  }
1982 
1983  /* if an extension was found for the current clique then free the old SOS1 constraint */
1984  if ( extended )
1985  {
1986  assert( ! SCIPconsIsModifiable(cons) );
1987  SCIP_CALL( SCIPdelCons(scip, cons) );
1988  ++(*ndelconss);
1989  *result = SCIP_SUCCESS;
1990  }
1991  else /* if we keep the constraint */
1992  {
1993  int cliqueind;
1994 
1995  cliqueind = nsos1vars + ncliques; /* index of clique in vertex-clique graph */
1996 
1997  /* add directed edges to the vertex-clique graph */
1998  assert( cliquesize >= 0 && cliquesize <= nsos1vars );
1999  assert( ncliques < csize );
2000  SCIP_CALL( SCIPallocBufferArray(scip, &cliques[ncliques], cliquesize) );/*lint !e866*/
2001  for (j = 0; j < cliquesize; ++j)
2002  {
2003  cliques[ncliques][j] = newclique[j];
2004  SCIP_CALL( SCIPdigraphAddArcSafe(vertexcliquegraph, cliques[ncliques][j], cliqueind, NULL) );
2005  }
2006 
2007  /* update number of maximal cliques */
2008  ++ncliques;
2009  }
2010  }
2011  }
2012  }
2013 
2014  /* free buffer arrays */
2015  for (c = ncliques-1; c >= 0; --c)
2016  SCIPfreeBufferArrayNull(scip, &cliques[c]);
2017  SCIPfreeBufferArrayNull(scip, &cliques);
2018  SCIPfreeBufferArrayNull(scip, &comsucc);
2019  SCIPfreeBufferArrayNull(scip, &lengthconss);
2020  SCIPfreeBufferArrayNull(scip, &indconss);
2021  SCIPfreeBufferArrayNull(scip, &newclique);
2022  SCIPfreeBufferArrayNull(scip, &cliquesizes);
2023  SCIPfreeBufferArrayNull(scip, &consweights);
2024  SCIPfreeBufferArrayNull(scip, &consvars);
2025  SCIPdigraphFree(&vertexcliquegraph);
2026 
2027  return SCIP_OKAY;
2028 }
2029 
2030 
2031 /** updates conflict graph based on the information of an implication graph */
2032 static
2034  SCIP* scip, /**< SCIP pointer */
2035  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
2036  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
2037  SCIP_VAR** totalvars, /**< problem and SOS1 variables */
2038  SCIP_DIGRAPH* implgraph, /**< implication graph (@p j is successor of @p i if and only if \f$ x_i\not = 0 \Rightarrow x_j\not = 0\f$) */
2039  SCIP_HASHMAP* implhash, /**< hash map from variable to node in implication graph */
2040  SCIP_Bool* implnodes, /**< implnodes[i] = TRUE if the SOS1 variable corresponding to a given node i in the implication graph is implied to be nonzero */
2041  SCIP_Bool** adjacencymatrix, /**< adjacencymatrix of the conflict graph (only lower half filled) */
2042  int givennode, /**< node of the conflict graph */
2043  int nonznode, /**< node of the conflict graph that is implied to be nonzero if given node is nonzero */
2044  int* naddconss /**< number of added SOS1 constraints */
2045  )
2046 {
2047  SCIP_SUCCDATA** succdatas;
2048  int succnode;
2049  int* succ;
2050  int nsucc;
2051  int s;
2052 
2053  assert( nonznode >= 0 && nonznode < SCIPdigraphGetNNodes(conflictgraph) );
2054 
2055  nsucc = SCIPdigraphGetNSuccessors(conflictgraph, nonznode);
2056  succ = SCIPdigraphGetSuccessors(conflictgraph, nonznode);
2057 
2058  /* update conflict graph */
2059  for (s = 0; s < nsucc; ++s)
2060  {
2061  succnode = succ[s];
2062 
2063  if ( givennode != succnode )
2064  {
2065  if ( ! isConnectedSOS1(adjacencymatrix, NULL, givennode, succnode) )
2066  {
2067  char namesos[SCIP_MAXSTRLEN];
2068  SCIP_CONS* soscons = NULL;
2069  SCIP_VAR* var1;
2070  SCIP_VAR* var2;
2071 
2072  /* add arcs to the conflict graph */
2073  SCIP_CALL( SCIPdigraphAddArc(conflictgraph, givennode, succnode, NULL) );
2074  SCIP_CALL( SCIPdigraphAddArc(conflictgraph, succnode, givennode, NULL) );
2075 
2076  /* update adjacencymatrix */
2077  if ( givennode > succnode )
2078  adjacencymatrix[givennode][succnode] = 1;
2079  else
2080  adjacencymatrix[succnode][givennode] = 1;
2081 
2082  var1 = SCIPnodeGetVarSOS1(conflictgraph, givennode);
2083  var2 = SCIPnodeGetVarSOS1(conflictgraph, succnode);
2084 
2085  /* create SOS1 constraint */
2086  (void) SCIPsnprintf(namesos, SCIP_MAXSTRLEN, "presolved_sos1_%s_%s", SCIPvarGetName(var1), SCIPvarGetName(var2) );
2087  SCIP_CALL( SCIPcreateConsSOS1(scip, &soscons, namesos, 0, NULL, NULL, TRUE, TRUE, TRUE, FALSE, TRUE,
2088  TRUE, FALSE, FALSE, FALSE) );
2089 
2090  /* add variables to SOS1 constraint */
2091  SCIP_CALL( addVarSOS1(scip, soscons, conshdlrdata, var1, 1.0) );
2092  SCIP_CALL( addVarSOS1(scip, soscons, conshdlrdata, var2, 2.0) );
2093 
2094  /* add constraint */
2095  SCIP_CALL( SCIPaddCons(scip, soscons) );
2096 
2097  /* release constraint */
2098  SCIP_CALL( SCIPreleaseCons(scip, &soscons) );
2099 
2100  ++(*naddconss);
2101  }
2102  }
2103  }
2104 
2105  /* by constr.: nodes of SOS1 variables are equal for conflict graph and implication graph */
2106  assert( nonznode == (int) (size_t) SCIPhashmapGetImage(implhash, SCIPnodeGetVarSOS1(conflictgraph, nonznode)) );
2107  succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(implgraph, nonznode);
2108  nsucc = SCIPdigraphGetNSuccessors(implgraph, nonznode);
2109  succ = SCIPdigraphGetSuccessors(implgraph, nonznode);
2110 
2111  /* go further in implication graph */
2112  for (s = 0; s < nsucc; ++s)
2113  {
2114  SCIP_SUCCDATA* data;
2115 
2116  succnode = succ[s];
2117  data = succdatas[s];
2118 
2119  /* if node is SOS1 and not already known to be an implication node */
2120  if ( varGetNodeSOS1(conshdlrdata, totalvars[succnode]) >= 0 && ! implnodes[succnode] && ( SCIPisFeasPositive(scip, data->lbimpl) || SCIPisFeasNegative(scip, data->ubimpl) ) )
2121  {
2122  /* by construction: nodes of SOS1 variables are equal for conflict graph and implication graph */
2123  assert( succnode == (int) (size_t) SCIPhashmapGetImage(implhash, SCIPnodeGetVarSOS1(conflictgraph, succnode)) );
2124  implnodes[succnode] = TRUE; /* in order to avoid cycling */
2125  SCIP_CALL( updateConflictGraphSOS1(scip, conshdlrdata, conflictgraph, totalvars, implgraph, implhash, implnodes, adjacencymatrix, givennode, succnode, naddconss) );
2126  }
2127  }
2128 
2129  return SCIP_OKAY;
2130 }
2131 
2132 
2133 /** returns whether node is implied to be zero; this information is taken from the input array 'implnodes' */
2134 static
2136  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
2137  SCIP_Bool* implnodes, /**< implnodes[i] = TRUE if the SOS1 variable corresponding to node i in the implication graph is implied to be nonzero */
2138  int node /**< node of the conflict graph (or -1) */
2139  )
2141  int* succ;
2142  int nsucc;
2143  int s;
2144 
2145  if ( node < 0 )
2146  return FALSE;
2147 
2148  nsucc = SCIPdigraphGetNSuccessors(conflictgraph, node);
2149  succ = SCIPdigraphGetSuccessors(conflictgraph, node);
2150 
2151  /* check whether any successor is implied to be nonzero */
2152  for (s = 0; s < nsucc; ++s)
2153  {
2154  if ( implnodes[succ[s]] )
2155  return TRUE;
2156  }
2157 
2158  return FALSE;
2159 }
2160 
2161 
2162 /** updates arc data of implication graph */
2163 static
2165  SCIP* scip, /**< SCIP pointer */
2166  SCIP_DIGRAPH* implgraph, /**< implication graph */
2167  SCIP_HASHMAP* implhash, /**< hash map from variable to node in implication graph */
2168  SCIP_VAR** totalvars, /**< problem and SOS1 variables */
2169  SCIP_VAR* varv, /**< variable that is assumed to be nonzero */
2170  SCIP_VAR* varw, /**< implication variable */
2171  SCIP_Real lb, /**< old lower bound of \f$x_w\f$ */
2172  SCIP_Real ub, /**< old upper bound of \f$x_w\f$ */
2173  SCIP_Real newbound, /**< new bound of \f$x_w\f$ */
2174  SCIP_Bool lower, /**< whether to consider lower bound implication (otherwise upper bound) */
2175  int* nchgbds, /**< pointer to store number of changed bounds */
2176  SCIP_Bool* update /**< pointer to store whether implication graph has been updated */
2177  )
2178 {
2179  SCIP_SUCCDATA** succdatas;
2180  SCIP_SUCCDATA* data = NULL;
2181  int nsucc;
2182  int* succ;
2183  int indv;
2184  int indw;
2185  int s;
2186 
2187  assert( scip != NULL );
2188  assert( implgraph != NULL );
2189  assert( implhash != NULL );
2190  assert( totalvars != NULL );
2191  assert( varv != NULL );
2192  assert( varw != NULL );
2193 
2194  /* if x_v != 0 turns out to be infeasible then fix x_v = 0 */
2195  if ( ( lower && SCIPisFeasLT(scip, ub, newbound) ) || ( ! lower && SCIPisFeasGT(scip, lb, newbound) ) )
2196  {
2197  SCIP_Bool infeasible;
2198  SCIP_Bool tightened1;
2199  SCIP_Bool tightened2;
2200 
2201  SCIP_CALL( SCIPtightenVarLb(scip, varv, 0.0, FALSE, &infeasible, &tightened1) );
2202  assert( !infeasible );
2203  SCIP_CALL( SCIPtightenVarUb(scip, varv, 0.0, FALSE, &infeasible, &tightened2) );
2204  assert( !infeasible );
2205 
2206  if ( tightened1 || tightened2 )
2207  {
2208  SCIPdebugMessage("fixed variable %s from lb = %f and ub = %f to 0.0 \n", SCIPvarGetName(varv), lb, ub);
2209  ++(*nchgbds);
2210  }
2211  }
2212 
2213  /* get successor information */
2214  indv = (int) (size_t) SCIPhashmapGetImage(implhash, varv); /* get index of x_v in implication graph */
2215  assert( (int) (size_t) SCIPhashmapGetImage(implhash, totalvars[indv]) == indv );
2216  succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(implgraph, indv);
2217  nsucc = SCIPdigraphGetNSuccessors(implgraph, indv);
2218  succ = SCIPdigraphGetSuccessors(implgraph, indv);
2219 
2220  /* search for nodew in existing successors. If this is the case then check whether the lower implication bound may be updated ... */
2221  indw = (int) (size_t) SCIPhashmapGetImage(implhash, varw);
2222  assert( (int) (size_t) SCIPhashmapGetImage(implhash, totalvars[indw]) == indw );
2223  for (s = 0; s < nsucc; ++s)
2224  {
2225  if ( succ[s] == indw )
2226  {
2227  data = succdatas[s];
2228  assert( data != NULL );
2229  if ( lower && SCIPisFeasLT(scip, data->lbimpl, newbound) )
2230  {
2231  data->lbimpl = newbound;
2232  *update = TRUE;
2233  SCIPdebugMessage("updated to implication %s != 0 -> %s >= %f\n", SCIPvarGetName(varv), SCIPvarGetName(varw), newbound);
2234  }
2235  else if ( ! lower && SCIPisFeasGT(scip, data->ubimpl, newbound) )
2236  {
2237  data->ubimpl = newbound;
2238  *update = TRUE;
2239  SCIPdebugMessage("updated to implication %s != 0 -> %s >= %f\n", SCIPvarGetName(varv), SCIPvarGetName(varw), newbound);
2240  }
2241  break;
2242  }
2243  }
2244 
2245  /* ..., otherwise if there does not exist an arc between indv and indw already, then create one and add implication */
2246  if ( s == nsucc )
2247  {
2248  assert( data == NULL );
2249  SCIP_CALL( SCIPallocMemory(scip, &data) );
2250  if ( lower )
2251  {
2252  data->lbimpl = newbound;
2253  data->ubimpl = ub;
2254  SCIPdebugMessage("add implication %s != 0 -> %s >= %f\n", SCIPvarGetName(varv), SCIPvarGetName(varw), newbound);
2255  }
2256  else
2257  {
2258  data->lbimpl = lb;
2259  data->ubimpl = newbound;
2260  SCIPdebugMessage("add implication %s != 0 -> %s <= %f\n", SCIPvarGetName(varv), SCIPvarGetName(varw), newbound);
2261  }
2262  SCIP_CALL( SCIPdigraphAddArc(implgraph, indv, indw, (void*)data) );
2263  *update = TRUE;
2264  }
2265 
2266  return SCIP_OKAY;
2267 }
2268 
2269 
2270 /** updates implication graph
2271  *
2272  * Assume the variable from the input is nonzero. If this implies that some other variable is also nonzero, then
2273  * store this information in an implication graph
2274  */
2275 static
2277  SCIP* scip, /**< SCIP pointer */
2278  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
2279  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
2280  SCIP_Bool** adjacencymatrix, /**< adjacency matrix of conflict graph (lower half) */
2281  SCIP_DIGRAPH* implgraph, /**< implication graph (@p j is successor of @p i if and only if \f$ x_i\not = 0 \Rightarrow x_j\not = 0\f$) */
2282  SCIP_HASHMAP* implhash, /**< hash map from variable to node in implication graph */
2283  SCIP_Bool* implnodes, /**< implnodes[i] = TRUE if the SOS1 variable corresponding to node i in the implication graph is implied to be nonzero */
2284  SCIP_VAR** totalvars, /**< problem and SOS1 variables */
2285  int** cliquecovers, /**< clique covers of linear constraint */
2286  int* cliquecoversizes, /**< size of clique covers */
2287  int* varincover, /**< array with varincover[i] = cover of SOS1 index @p i */
2288  SCIP_VAR** vars, /**< variables to be checked */
2289  SCIP_Real* coefs, /**< coefficients of variables in linear constraint */
2290  int nvars, /**< number of variables to be checked */
2291  SCIP_Real* bounds, /**< bounds of variables */
2292  SCIP_VAR* var, /**< variable that is assumed to be nonzero */
2293  SCIP_Real bound, /**< bound of variable */
2294  SCIP_Real boundnonzero, /**< bound of variable if it is known to be nonzero if infinity values are not summarized */
2295  int ninftynonzero, /**< number of times infinity/-infinity has to be summarized to boundnonzero */
2296  SCIP_Bool lower, /**< TRUE if lower bounds are consideres; FALSE for upper bounds */
2297  int* nchgbds, /**< pointer to store number of changed bounds */
2298  SCIP_Bool* update /**< pointer to store whether implication graph has been updated */
2299  )
2300 {
2301  int nodev;
2302  int w;
2303 
2304  assert( update != NULL );
2305 
2306  /* update implication graph if possible */
2307  *update = FALSE;
2308  nodev = varGetNodeSOS1(conshdlrdata, var); /* possibly -1 if var is not involved in an SOS1 constraint */
2309 
2310  /* if nodev is an index of an SOS1 variable and at least one lower bound of a variable that is not x_v is infinity */
2311  if ( nodev < 0 || SCIPisInfinity(scip, REALABS(bound)) || ninftynonzero > 1 )
2312  return SCIP_OKAY;
2313 
2314  /* for every variable x_w: compute upper bound of a_w * x_w if x_v is known to be nonzero */
2315  for (w = 0; w < nvars; ++w)
2316  {
2317  int newninftynonzero;
2318  SCIP_Bool implinfty = FALSE;
2319  int nodew;
2320 
2321  /* get node of x_w in conflict graph: nodew = -1 if it is no SOS1 variable */
2322  nodew = varGetNodeSOS1(conshdlrdata, vars[w]);
2323 
2324  newninftynonzero = ninftynonzero;
2325 
2326  /* variable should not be fixed to be already zero (note x_v is fixed to be nonzero by assumption) */
2327  if ( nodew < 0 || ( nodev != nodew && ! isConnectedSOS1(adjacencymatrix, NULL, nodev, nodew) && ! isImpliedZero(conflictgraph, implnodes, nodew) ) )
2328  {
2329  SCIP_Real implbound;
2330  SCIP_Bool implcoverw;
2331  int nodecliq;
2332  int indcliq;
2333  int ind;
2334  int j;
2335 
2336  /* boundnonzero is the bound of x_v if x_v is nonzero we use this information to get a bound of x_w if x_v is
2337  * nonzero; therefore, we have to perform some recomputations */
2338  implbound = boundnonzero - bound;
2339  ind = varincover[w];
2340  assert( cliquecoversizes[ind] > 0 );
2341 
2342  implcoverw = FALSE;
2343  for (j = 0; j < cliquecoversizes[ind]; ++j)
2344  {
2345  indcliq = cliquecovers[ind][j];
2346  assert( 0 <= indcliq && indcliq < nvars );
2347 
2348  nodecliq = varGetNodeSOS1(conshdlrdata, vars[indcliq]); /* possibly -1 if variable is not involved in an SOS1 constraint */
2349 
2350  /* if nodecliq is not a member of an SOS1 constraint or the variable corresponding to nodecliq is not implied to be zero if x_v != 0 */
2351  if ( nodecliq < 0 || (! isConnectedSOS1(adjacencymatrix, NULL, nodev, nodecliq) && ! isImpliedZero(conflictgraph, implnodes, nodecliq) ) )
2352  {
2353  if ( indcliq == w )
2354  {
2355  if ( ! SCIPisInfinity(scip, REALABS(bounds[w])) )
2356  implbound += bounds[w];
2357  else
2358  --newninftynonzero;
2359  implcoverw = TRUE;
2360  }
2361  else if ( implcoverw )
2362  {
2363  if ( SCIPisInfinity(scip, REALABS( bounds[indcliq] )) )
2364  implinfty = TRUE;
2365  else
2366  implbound -= bounds[indcliq];
2367  break;
2368  }
2369  else
2370  {
2371  if ( SCIPisInfinity(scip, REALABS( bounds[indcliq] ) ) )
2372  implinfty = TRUE;
2373  break;
2374  }
2375  }
2376  }
2377 
2378  /* check whether x_v != 0 implies a bound change of x_w */
2379  if ( ! implinfty && newninftynonzero == 0 )
2380  {
2381  SCIP_Real newbound;
2382  SCIP_Real coef;
2383  SCIP_Real lb;
2384  SCIP_Real ub;
2385 
2386  lb = SCIPvarGetLbLocal(vars[w]);
2387  ub = SCIPvarGetUbLocal(vars[w]);
2388  coef = coefs[w];
2389  assert( ! SCIPisFeasZero(scip, coef) );
2390  newbound = implbound / coef;
2391 
2392  /* check if an implication can be added/updated or assumption x_v != 0 is infeasible */
2393  if ( lower )
2394  {
2395  if ( SCIPisFeasPositive(scip, coef) && SCIPisFeasLT(scip, lb, newbound) )
2396  {
2397  SCIP_CALL( updateArcData(scip, implgraph, implhash, totalvars, var, vars[w], lb, ub, newbound, TRUE, nchgbds, update) );
2398  }
2399  else if ( SCIPisFeasNegative(scip, coef) && SCIPisFeasGT(scip, ub, newbound) )
2400  {
2401  SCIP_CALL( updateArcData(scip, implgraph, implhash, totalvars, var, vars[w], lb, ub, newbound, FALSE, nchgbds, update) );
2402  }
2403  }
2404  else
2405  {
2406  if ( SCIPisFeasPositive(scip, coef) && SCIPisFeasGT(scip, ub, newbound) )
2407  {
2408  SCIP_CALL( updateArcData(scip, implgraph, implhash, totalvars, var, vars[w], lb, ub, newbound, FALSE, nchgbds, update) );
2409  }
2410  else if ( SCIPisFeasNegative(scip, coef) && SCIPisFeasLT(scip, lb, newbound) )
2411  {
2412  SCIP_CALL( updateArcData(scip, implgraph, implhash, totalvars, var, vars[w], lb, ub, newbound, TRUE, nchgbds, update) );
2413  }
2414  }
2415  }
2416  }
2417  }
2418 
2419  return SCIP_OKAY;
2420 }
2421 
2422 
2423 /** search new disjoint clique that covers given node
2424  *
2425  * For a given vertex @p v search for a clique of the conflict graph induced by the variables of a linear constraint that
2426  * - covers @p v and
2427  * - has an an empty intersection with already computed clique cover.
2428  */
2429 static
2431  SCIP* scip, /**< SCIP pointer */
2432  SCIP_DIGRAPH* conflictgraphroot, /**< conflict graph of the root node (nodes: 1, ..., @p nsos1vars) */
2433  SCIP_DIGRAPH* conflictgraphlin, /**< conflict graph of linear constraint (nodes: 1, ..., @p nlinvars) */
2434  SCIP_VAR** linvars, /**< variables in linear constraint */
2435  SCIP_Bool* coveredvars, /**< states which variables of the linear constraint are currently covered by a clique */
2436  int* clique, /**< array to store new clique in cover */
2437  int* cliquesize, /**< pointer to store the size of @p clique */
2438  int v, /**< position of variable in linear constraint that should be covered */
2439  SCIP_Bool considersolvals /**< TRUE if largest auxiliary bigM values of variables should be prefered */
2440  )
2441 {
2442  int nsucc;
2443  int s;
2444 
2445  assert( conflictgraphlin != NULL );
2446  assert( linvars != NULL );
2447  assert( coveredvars != NULL );
2448  assert( clique != NULL );
2449  assert( cliquesize != NULL );
2450 
2451  assert( ! coveredvars[v] ); /* we should produce a new clique */
2452 
2453  /* add index 'v' to the clique cover */
2454  clique[0] = v;
2455  *cliquesize = 1;
2456 
2457  nsucc = SCIPdigraphGetNSuccessors(conflictgraphlin, v);
2458  if ( nsucc > 0 )
2459  {
2460  int* extensions;
2461  int nextensions = 0;
2462  int nextensionsnew;
2463  int succnode;
2464  int* succ;
2465 
2466  /* allocate buffer array */
2467  SCIP_CALL( SCIPallocBufferArray(scip, &extensions, nsucc) );
2468 
2469  succ = SCIPdigraphGetSuccessors(conflictgraphlin, v);
2470 
2471  /* compute possible extensions for the clique cover */
2472  for (s = 0; s < nsucc; ++s)
2473  {
2474  succnode = succ[s];
2475  if ( ! coveredvars[succnode] )
2476  extensions[nextensions++] = succ[s];
2477  }
2478 
2479  /* while there exist possible extensions for the clique cover */
2480  while ( nextensions > 0 )
2481  {
2482  int bestindex = -1;
2483 
2484  if ( considersolvals )
2485  {
2486  SCIP_Real bestbigMval;
2487  SCIP_Real bigMval;
2488 
2489  bestbigMval = -SCIPinfinity(scip);
2490 
2491  /* search for the extension with the largest absolute value of its LP relaxation solution value */
2492  for (s = 0; s < nextensions; ++s)
2493  {
2494  bigMval = nodeGetSolvalBinaryBigMSOS1(scip, conflictgraphroot, NULL, extensions[s]);
2495  if ( SCIPisFeasLT(scip, bestbigMval, bigMval) )
2496  {
2497  bestbigMval = bigMval;
2498  bestindex = extensions[s];
2499  }
2500  }
2501  }
2502  else
2503  bestindex = extensions[0];
2504 
2505  assert( bestindex != -1 );
2506 
2507  /* add bestindex to the clique cover */
2508  clique[(*cliquesize)++] = bestindex;
2509 
2510  /* compute new 'extensions' array */
2511  nextensionsnew = 0;
2512  for (s = 0; s < nextensions; ++s)
2513  {
2514  if ( s != bestindex && isConnectedSOS1(NULL, conflictgraphlin, bestindex, extensions[s]) )
2515  extensions[nextensionsnew++] = extensions[s];
2516  }
2517  nextensions = nextensionsnew;
2518  }
2519 
2520  /* free buffer array */
2521  SCIPfreeBufferArray(scip, &extensions);
2522  }
2523 
2524  /* mark covered indices */
2525  for (s = 0; s < *cliquesize; ++s)
2526  {
2527  int ind;
2528 
2529  ind = clique[s];
2530  assert( 0 <= ind );
2531  assert( ! coveredvars[ind] );
2532  coveredvars[ind] = TRUE;
2533  }
2534 
2535  return SCIP_OKAY;
2536 }
2537 
2538 
2539 /** try to tighten upper and lower bounds for variables */
2540 static
2542  SCIP* scip, /**< SCIP pointer */
2543  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
2544  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
2545  SCIP_DIGRAPH* implgraph, /**< implication graph (@p j is successor of @p i if and only if \f$ x_i\not = 0 \f$ implies a new lower/upper bound for \f$ x_j\f$) */
2546  SCIP_HASHMAP* implhash, /**< hash map from variable to node in implication graph */
2547  SCIP_Bool** adjacencymatrix, /**< adjacencymatrix of conflict graph */
2548  SCIP_VAR** totalvars, /**< problem and SOS1 vars */
2549  int ntotalvars, /**< number of problem and SOS1 variables*/
2550  int nsos1vars, /**< number of SOS1 variables */
2551  int* nchgbds, /**< pointer to store number of changed bounds */
2552  SCIP_Bool* implupdate, /**< pointer to store whether the implication graph has been updated in this function call */
2553  SCIP_Bool* cutoff /**< pointer to store if current nodes LP is infeasible */
2554  )
2555 {
2556  SCIP_CONSHDLR* conshdlrlinear;
2557  SCIP_CONS** linearconss;
2558  int nlinearconss;
2559 
2560  SCIP_Bool* implnodes = NULL; /* implnodes[i] = TRUE if the SOS1 variable corresponding to node i in the implication graph is implied to be nonzero */
2561  SCIP_Bool* coveredvars = NULL; /* coveredvars[i] = TRUE if variable with index i is covered by the clique cover */
2562  int* varindincons = NULL; /* varindincons[i] = position of SOS1 index i in linear constraint (-1 if x_i is not involved in linear constraint) */
2563 
2564  SCIP_VAR** trafolinvars = NULL; /* variables of transformed linear constraints without (multi)aggregated variables */
2565  int ntrafolinvars = 0;
2566  SCIP_Real* trafolinvals = NULL;
2567  SCIP_Real* trafoubs = NULL;
2568  SCIP_Real* trafolbs = NULL;
2569  SCIP_Real traforhs;
2570  SCIP_Real trafolhs;
2571 
2572  SCIP_VAR** sos1linvars = NULL; /* variables that are not contained in linear constraint, but are in conflict with a variable from the linear constraint */
2573  int nsos1linvars;
2574  int c;
2575 
2576  assert( scip != NULL );
2577  assert( conflictgraph != NULL );
2578  assert( adjacencymatrix != NULL );
2579  assert( nchgbds != NULL );
2580  assert( cutoff != NULL );
2581 
2582  *cutoff = FALSE;
2583  *implupdate = FALSE;
2584 
2585  /* get constraint handler data of linear constraints */
2586  conshdlrlinear = SCIPfindConshdlr(scip, "linear");
2587  if ( conshdlrlinear == NULL )
2588  return SCIP_OKAY;
2589 
2590  /* get linear constraints and number of linear constraints */
2591  nlinearconss = SCIPconshdlrGetNConss(conshdlrlinear);
2592  linearconss = SCIPconshdlrGetConss(conshdlrlinear);
2593 
2594  /* allocate buffer arrays */
2595  SCIP_CALL( SCIPallocBufferArray(scip, &sos1linvars, nsos1vars) );
2596  SCIP_CALL( SCIPallocBufferArray(scip, &implnodes, nsos1vars) );
2597  SCIP_CALL( SCIPallocBufferArray(scip, &varindincons, nsos1vars) );
2598  SCIP_CALL( SCIPallocBufferArray(scip, &coveredvars, ntotalvars) );
2599  SCIP_CALL( SCIPallocBufferArray(scip, &trafoubs, ntotalvars) );
2600  SCIP_CALL( SCIPallocBufferArray(scip, &trafolbs, ntotalvars) );
2601 
2602  /* for every linear constraint and every SOS1 variable */
2603  for (c = 0; c < nlinearconss + nsos1vars && ! (*cutoff); ++c)
2604  {
2605  SCIP_DIGRAPH* conflictgraphlin;
2606  int** cliquecovers = NULL; /* clique covers of indices of variables in linear constraint */
2607  int* cliquecoversizes = NULL; /* size of each cover */
2608  int ncliquecovers;
2609  SCIP_Real* cliquecovervals = NULL;
2610  int* varincover = NULL; /* varincover[i] = cover of SOS1 index i */
2611 
2612  int v;
2613  int i;
2614  int j;
2615 
2616  /* get transformed linear constraints (without aggregated variables) */
2617  if ( c < nlinearconss )
2618  {
2619  SCIP_VAR** origlinvars;
2620  int noriglinvars;
2621  SCIP_Real* origlinvals;
2622  SCIP_Real origrhs;
2623  SCIP_Real origlhs;
2624  SCIP_Real constant;
2625  int requiredsize;
2626 
2627  /* get data of linear constraint */
2628  noriglinvars = SCIPgetNVarsLinear(scip, linearconss[c]);
2629  origlinvars = SCIPgetVarsLinear(scip, linearconss[c]);
2630  origlinvals = SCIPgetValsLinear(scip, linearconss[c]);
2631  origrhs = SCIPgetRhsLinear(scip, linearconss[c]);
2632  origlhs = SCIPgetLhsLinear(scip, linearconss[c]);
2633 
2634  /* copy variables and coefficients of linear constraint */
2635  SCIP_CALL( SCIPduplicateBufferArray(scip, &trafolinvars, origlinvars, noriglinvars) );
2636  SCIP_CALL( SCIPduplicateBufferArray(scip, &trafolinvals, origlinvals, noriglinvars) );
2637  ntrafolinvars = noriglinvars;
2638 
2639  /* transform linear constraint */
2640  constant = 0.0;
2641  SCIP_CALL( SCIPgetProbvarLinearSum(scip, trafolinvars, trafolinvals, &ntrafolinvars, noriglinvars, &constant, &requiredsize, TRUE) );
2642  if( requiredsize > ntrafolinvars )
2643  {
2644  SCIP_CALL( SCIPreallocBufferArray(scip, &trafolinvars, requiredsize) );
2645  SCIP_CALL( SCIPreallocBufferArray(scip, &trafolinvals, requiredsize) );
2646 
2647  SCIP_CALL( SCIPgetProbvarLinearSum(scip, trafolinvars, trafolinvals, &ntrafolinvars, requiredsize, &constant, &requiredsize, TRUE) );
2648  assert( requiredsize <= ntrafolinvars );
2649  }
2650  trafolhs = origlhs - constant;
2651  traforhs = origrhs - constant;
2652  }
2653  else
2654  {
2655  SCIP_VAR* var;
2656 
2657  var = SCIPnodeGetVarSOS1(conflictgraph, c-nlinearconss);
2658 
2660  {
2661  SCIP_Real constant;
2662 
2663  SCIP_CALL( SCIPallocBufferArray(scip, &trafolinvars, 2) );
2664  SCIP_CALL( SCIPallocBufferArray(scip, &trafolinvals, 2) );
2665 
2666  constant = SCIPvarGetAggrConstant(var);
2667  trafolinvars[0] = SCIPvarGetAggrVar(var);
2668  trafolinvals[0] = SCIPvarGetAggrScalar(var);
2669  trafolinvars[1] = var;
2670  trafolinvals[1] = -1.0;
2671  trafolhs = -constant;
2672  traforhs = -constant;
2673  ntrafolinvars = 2;
2674  }
2675  else if ( SCIPvarGetStatus(var) == SCIP_VARSTATUS_MULTAGGR )
2676  {
2677  SCIP_Real* scalars;
2678  SCIP_VAR** agrvars;
2679  SCIP_Real constant;
2680  int nagrvars;
2681 
2682  nagrvars = SCIPvarGetMultaggrNVars(var);
2683 
2684  SCIP_CALL( SCIPallocBufferArray(scip, &trafolinvars, nagrvars+1) );
2685  SCIP_CALL( SCIPallocBufferArray(scip, &trafolinvals, nagrvars+1) );
2686 
2687  agrvars = SCIPvarGetMultaggrVars(var);
2688  scalars = SCIPvarGetMultaggrScalars(var);
2689  constant = SCIPvarGetMultaggrConstant(var);
2690 
2691  for (v = 0; v < nagrvars; ++v)
2692  {
2693  trafolinvars[v] = agrvars[v];
2694  trafolinvals[v] = scalars[v];
2695  }
2696  trafolinvars[nagrvars] = var;
2697  trafolinvals[nagrvars] = -1.0;
2698  trafolhs = -constant;
2699  traforhs = -constant;
2700  ntrafolinvars = nagrvars + 1;
2701  }
2702  else if ( SCIPvarGetStatus(var) == SCIP_VARSTATUS_NEGATED )
2703  {
2704  SCIP_VAR* negvar;
2705  SCIP_Real negcons;
2706 
2707  /* get negation variable and negation offset */
2708  negvar = SCIPvarGetNegationVar(var);
2709  negcons = SCIPvarGetNegationConstant(var);
2710 
2711  SCIP_CALL( SCIPallocBufferArray(scip, &trafolinvars, 2) );
2712  SCIP_CALL( SCIPallocBufferArray(scip, &trafolinvals, 2) );
2713 
2714  trafolinvars[0] = negvar;
2715  trafolinvars[1] = var;
2716  trafolinvals[0] = 1.0;
2717  trafolinvals[1] = 1.0;
2718  trafolhs = -negcons;
2719  traforhs = -negcons;
2720  }
2721  else
2722  continue;
2723  }
2724 
2725  if ( ntrafolinvars == 0 )
2726  {
2727  SCIPfreeBufferArray(scip, &trafolinvars);
2728  SCIPfreeBufferArray(scip, &trafolinvals);
2729  continue;
2730  }
2731 
2732  /* compute lower and upper bounds of each term a_i * x_i of transformed constraint */
2733  for (v = 0; v < ntrafolinvars; ++v)
2734  {
2735  SCIP_Real lb = SCIPvarGetLbLocal(trafolinvars[v]);
2736  SCIP_Real ub = SCIPvarGetUbLocal(trafolinvars[v]);
2737 
2738  if ( trafolinvals[v] < 0.0 )
2739  {
2740  SCIPswapPointers((void**)&lb, (void**)&ub);
2741  }
2742 
2743  if ( SCIPisInfinity(scip, REALABS(lb)) )
2744  trafolbs[v] = -SCIPinfinity(scip);
2745  else
2746  trafolbs[v] = lb * trafolinvals[v];
2747 
2748  if ( SCIPisInfinity(scip, REALABS(ub)) )
2749  trafoubs[v] = SCIPinfinity(scip);
2750  else
2751  trafoubs[v] = ub * trafolinvals[v];
2752  }
2753 
2754  /* initialization: mark all the SOS1 variables as 'not a member of the linear constraint' */
2755  for (v = 0; v < nsos1vars; ++v)
2756  varindincons[v] = -1;
2757 
2758  /* save position of SOS1 variables in linear constraint */
2759  for (v = 0; v < ntrafolinvars; ++v)
2760  {
2761  int node;
2762 
2763  node = varGetNodeSOS1(conshdlrdata, trafolinvars[v]);
2764 
2765  if ( node >= 0 )
2766  varindincons[node] = v;
2767  }
2768 
2769  /* create conflict graph of linear constraint */
2770  SCIP_CALL( SCIPdigraphCreate(&conflictgraphlin, ntrafolinvars) );
2771  SCIP_CALL( genConflictgraphLinearCons(conshdlrdata, conflictgraphlin, conflictgraph, trafolinvars, ntrafolinvars, varindincons) );
2772 
2773  /* mark all the variables as 'not covered by some clique cover' */
2774  for (i = 0; i < ntrafolinvars; ++i)
2775  coveredvars[i] = FALSE;
2776 
2777  /* allocate buffer array */
2778  SCIP_CALL( SCIPallocBufferArray(scip, &cliquecovervals, ntrafolinvars) );
2779  SCIP_CALL( SCIPallocBufferArray(scip, &cliquecoversizes, ntrafolinvars) );
2780  SCIP_CALL( SCIPallocBufferArray(scip, &cliquecovers, ntrafolinvars) );
2781 
2782  /* compute distinct cliques that cover all the variables of the linear constraint */
2783  ncliquecovers = 0;
2784  for (v = 0; v < ntrafolinvars; ++v)
2785  {
2786  /* if variable is not already covered by an already known clique cover */
2787  if ( ! coveredvars[v] )
2788  {
2789  SCIP_CALL( SCIPallocBufferArray(scip, &(cliquecovers[ncliquecovers]), ntrafolinvars) ); /*lint !e866*/
2790  SCIP_CALL( computeVarsCoverSOS1(scip, conflictgraph, conflictgraphlin, trafolinvars, coveredvars, cliquecovers[ncliquecovers], &(cliquecoversizes[ncliquecovers]), v, FALSE) );
2791  ++ncliquecovers;
2792  }
2793  }
2794 
2795  /* free conflictgraph */
2796  SCIPdigraphFree(&conflictgraphlin);
2797 
2798  /* compute variables that are not contained in transformed linear constraint, but are in conflict with a variable from the transformed linear constraint */
2799  nsos1linvars = 0;
2800  for (v = 0; v < ntrafolinvars; ++v)
2801  {
2802  int nodev;
2803 
2804  nodev = varGetNodeSOS1(conshdlrdata, trafolinvars[v]);
2805 
2806  /* if variable is an SOS1 variable */
2807  if ( nodev >= 0 )
2808  {
2809  int succnode;
2810  int nsucc;
2811  int* succ;
2812  int s;
2813 
2814  succ = SCIPdigraphGetSuccessors(conflictgraph, nodev);
2815  nsucc = SCIPdigraphGetNSuccessors(conflictgraph, nodev);
2816 
2817  for (s = 0; s < nsucc; ++s)
2818  {
2819  succnode = succ[s];
2820 
2821  /* if variable is not a member of linear constraint and not already listed in the array sos1linvars */
2822  if ( varindincons[succnode] == -1 )
2823  {
2824  sos1linvars[nsos1linvars] = SCIPnodeGetVarSOS1(conflictgraph, succnode);
2825  varindincons[succnode] = -2; /* mark variable as listed in array sos1linvars */
2826  ++nsos1linvars;
2827  }
2828  }
2829  }
2830  }
2831 
2832 
2833  /* try to tighten lower bounds */
2834 
2835  /* sort each cliquecover array in ascending order of the lower bounds of a_i * x_i; fill vector varincover */
2836  SCIP_CALL( SCIPallocBufferArray(scip, &varincover, ntrafolinvars) );
2837  for (i = 0; i < ncliquecovers; ++i)
2838  {
2839  for (j = 0; j < cliquecoversizes[i]; ++j)
2840  {
2841  int ind = cliquecovers[i][j];
2842 
2843  varincover[ind] = i;
2844  cliquecovervals[j] = trafoubs[ind];
2845  }
2846  SCIPsortDownRealInt(cliquecovervals, cliquecovers[i], cliquecoversizes[i]);
2847  }
2848 
2849  /* for every variable in transformed constraint: try lower bound tightening */
2850  for (v = 0; v < ntrafolinvars + nsos1linvars; ++v)
2851  {
2852  SCIP_Real newboundnonzero; /* new bound of a_v*x_v if we assume that x_v != 0 */
2853  SCIP_Real newboundnores; /* new bound of a_v*x_v if we assume that x_v = 0 is possible */
2854  SCIP_Real newbound; /* resulting new bound of x_v */
2855  SCIP_VAR* var;
2856  SCIP_Real trafoubv;
2857  SCIP_Real linval;
2858  SCIP_Real ub;
2859  SCIP_Real lb;
2860  SCIP_Bool tightened;
2861  SCIP_Bool infeasible;
2862  SCIP_Bool inftynores = FALSE;
2863  SCIP_Bool update;
2864  int ninftynonzero = 0;
2865  int nodev;
2866  int w;
2867 
2868  if ( v < ntrafolinvars )
2869  {
2870  var = trafolinvars[v];
2871  trafoubv = trafoubs[v];
2872  }
2873  else
2874  {
2875  assert( v >= ntrafolinvars );
2876  var = sos1linvars[v-ntrafolinvars];/*lint !e679*/
2877  trafoubv = 0.0;
2878  }
2879 
2880  ub = SCIPvarGetUbLocal(var);
2881  lb = SCIPvarGetLbLocal(var);
2882 
2883  if ( SCIPisInfinity(scip, -trafolhs) || SCIPisZero(scip, ub - lb) )
2884  continue;
2885 
2886  newboundnonzero = trafolhs;
2887  newboundnores = trafolhs;
2888  nodev = varGetNodeSOS1(conshdlrdata, var); /* possibly -1 if var is not involved in an SOS1 constraint */
2889  assert( nodev < nsos1vars );
2890 
2891  /* determine incidence vector of implication variables */
2892  for (w = 0; w < nsos1vars; ++w)
2893  implnodes[w] = FALSE;
2894  SCIP_CALL( getSOS1Implications(scip, conshdlrdata, totalvars, implgraph, implhash, implnodes, (int) (size_t) SCIPhashmapGetImage(implhash, var)) );
2895 
2896  /* compute new bound */
2897  for (i = 0; i < ncliquecovers; ++i)
2898  {
2899  int indcliq;
2900  int nodecliq;
2901 
2902  assert( cliquecoversizes[i] > 0 );
2903 
2904  indcliq = cliquecovers[i][0];
2905  assert( 0 <= indcliq && indcliq < ntrafolinvars );
2906 
2907  /* determine maximum without index v (note that trafoub is sorted non-increasingly) */
2908  if ( v != indcliq )
2909  {
2910  if ( SCIPisInfinity(scip, trafoubs[indcliq]) )
2911  inftynores = TRUE;
2912  else
2913  newboundnores -= trafoubs[indcliq];
2914  }
2915  else if ( cliquecoversizes[i] > 1 )
2916  {
2917  assert( 0 <= cliquecovers[i][1] && cliquecovers[i][1] < ntrafolinvars );
2918  if ( SCIPisInfinity(scip, trafoubs[cliquecovers[i][1]]) )
2919  inftynores = TRUE;
2920  else
2921  newboundnores -= trafoubs[cliquecovers[i][1]];/*lint --e{679}*/
2922  }
2923 
2924  for (j = 0; j < cliquecoversizes[i]; ++j)
2925  {
2926  indcliq = cliquecovers[i][j];
2927  assert( 0 <= indcliq && indcliq < ntrafolinvars );
2928 
2929  nodecliq = varGetNodeSOS1(conshdlrdata, trafolinvars[indcliq]); /* possibly -1 if variable is not involved in an SOS1 constraint */
2930  assert( nodecliq < nsos1vars );
2931 
2932  if ( v != indcliq )
2933  {
2934  /* if nodev or nodecliq are not a member of an SOS1 constraint or the variable corresponding to nodecliq is not implied to be zero if x_v != 0 */
2935  if ( nodev < 0 || nodecliq < 0 || (! isConnectedSOS1(adjacencymatrix, NULL, nodev, nodecliq) && ! isImpliedZero(conflictgraph, implnodes, nodecliq) ) )
2936  {
2937  if ( SCIPisInfinity(scip, trafoubs[indcliq]) )
2938  ++ninftynonzero;
2939  else
2940  newboundnonzero -= trafoubs[indcliq];
2941  break;
2942  }
2943  }
2944  }
2945  }
2946  assert( ninftynonzero == 0 || inftynores );
2947 
2948  /* if computed upper bound is not infinity and variable is contained in linear constraint */
2949  if ( ninftynonzero == 0 && v < ntrafolinvars )
2950  {
2951  linval = trafolinvals[v];
2952  /* compute new bound */
2953  assert( ! SCIPisFeasZero(scip, linval) );
2954  if ( SCIPisFeasPositive(scip, newboundnores) && ! inftynores )
2955  newbound = newboundnonzero;
2956  else
2957  newbound = MIN(0, newboundnonzero);
2958  newbound /= linval;
2959 
2960  /* check if new bound is tighter than the old one or problem is infeasible */
2961  if ( SCIPisFeasPositive(scip, linval) && SCIPisFeasLT(scip, lb, newbound) )
2962  {
2963  if ( SCIPisFeasLT(scip, ub, newbound) )
2964  {
2965  *cutoff = TRUE;
2966  break;
2967  }
2968 
2969  if ( SCIPvarIsIntegral(var) )
2970  newbound = SCIPceil(scip, newbound);
2971 
2972  SCIP_CALL( SCIPtightenVarLb(scip, var, newbound, FALSE, &infeasible, &tightened) );
2973  assert( ! infeasible );
2974 
2975  if ( tightened )
2976  {
2977  SCIPdebugMessage("changed lower bound of variable %s from %f to %f \n", SCIPvarGetName(var), lb, newbound);
2978  ++(*nchgbds);
2979  }
2980  }
2981  else if ( SCIPisFeasNegative(scip, linval) && SCIPisFeasGT(scip, ub, newbound) )
2982  {
2983  /* if assumption a_i * x_i != 0 was not correct */
2984  if ( SCIPisFeasGT(scip, SCIPvarGetLbLocal(var), newbound) )
2985  {
2986  *cutoff = TRUE;
2987  break;
2988  }
2989 
2990  if ( SCIPvarIsIntegral(var) )
2991  newbound = SCIPfloor(scip, newbound);
2992 
2993  SCIP_CALL( SCIPtightenVarUb(scip, var, newbound, FALSE, &infeasible, &tightened) );
2994  assert( ! infeasible );
2995 
2996  if ( tightened )
2997  {
2998  SCIPdebugMessage("changed upper bound of variable %s from %f to %f \n", SCIPvarGetName(var), ub, newbound);
2999  ++(*nchgbds);
3000  }
3001  }
3002  }
3003 
3004  /* update implication graph if possible */
3005  SCIP_CALL( updateImplicationGraphSOS1(scip, conshdlrdata, conflictgraph, adjacencymatrix, implgraph, implhash, implnodes, totalvars, cliquecovers, cliquecoversizes, varincover,
3006  trafolinvars, trafolinvals, ntrafolinvars, trafoubs, var, trafoubv, newboundnonzero, ninftynonzero, TRUE, nchgbds, &update) );
3007  if ( update )
3008  *implupdate = TRUE;
3009  }
3010 
3011  if ( *cutoff == TRUE )
3012  {
3013  /* free memory */
3014  SCIPfreeBufferArrayNull(scip, &varincover);
3015  for (j = ncliquecovers-1; j >= 0; --j)
3016  SCIPfreeBufferArrayNull(scip, &cliquecovers[j]);
3017  SCIPfreeBufferArrayNull(scip, &cliquecovers);
3018  SCIPfreeBufferArrayNull(scip, &cliquecoversizes);
3019  SCIPfreeBufferArrayNull(scip, &cliquecovervals);
3020  SCIPfreeBufferArrayNull(scip, &trafolinvals);
3021  SCIPfreeBufferArrayNull(scip, &trafolinvars);
3022  break;
3023  }
3024 
3025 
3026  /* try to tighten upper bounds */
3027 
3028  /* sort each cliquecover array in ascending order of the lower bounds of a_i * x_i; fill vector varincover */
3029  for (i = 0; i < ncliquecovers; ++i)
3030  {
3031  for (j = 0; j < cliquecoversizes[i]; ++j)
3032  {
3033  int ind = cliquecovers[i][j];
3034 
3035  varincover[ind] = i;
3036  cliquecovervals[j] = trafolbs[ind];
3037  }
3038  SCIPsortRealInt(cliquecovervals, cliquecovers[i], cliquecoversizes[i]);
3039  }
3040 
3041  /* for every variable that is in transformed constraint or every variable that is in conflict with some variable from trans. cons.:
3042  try upper bound tightening */
3043  for (v = 0; v < ntrafolinvars + nsos1linvars; ++v)
3044  {
3045  SCIP_Real newboundnonzero; /* new bound of a_v*x_v if we assume that x_v != 0 */
3046  SCIP_Real newboundnores; /* new bound of a_v*x_v if there are no restrictions */
3047  SCIP_Real newbound; /* resulting new bound of x_v */
3048  SCIP_VAR* var;
3049  SCIP_Real linval;
3050  SCIP_Real trafolbv;
3051  SCIP_Real lb;
3052  SCIP_Real ub;
3053  SCIP_Bool tightened;
3054  SCIP_Bool infeasible;
3055  SCIP_Bool inftynores = FALSE;
3056  SCIP_Bool update;
3057  int ninftynonzero = 0;
3058  int nodev;
3059  int w;
3060 
3061  if ( v < ntrafolinvars )
3062  {
3063  var = trafolinvars[v];
3064  trafolbv = trafolbs[v];
3065  }
3066  else
3067  {
3068  assert( v-ntrafolinvars >= 0 );
3069  var = sos1linvars[v-ntrafolinvars];/*lint !e679*/
3070  trafolbv = 0.0; /* since variable is not a member of linear constraint */
3071  }
3072  lb = SCIPvarGetLbLocal(var);
3073  ub = SCIPvarGetUbLocal(var);
3074  if ( SCIPisInfinity(scip, traforhs) || SCIPisEQ(scip, lb, ub) )
3075  continue;
3076 
3077  newboundnonzero = traforhs;
3078  newboundnores = traforhs;
3079  nodev = varGetNodeSOS1(conshdlrdata, var); /* possibly -1 if var is not involved in an SOS1 constraint */
3080  assert( nodev < nsos1vars );
3081 
3082  /* determine incidence vector of implication variables (i.e., which SOS1 variables are nonzero if x_v is nonzero) */
3083  for (w = 0; w < nsos1vars; ++w)
3084  implnodes[w] = FALSE;
3085  SCIP_CALL( getSOS1Implications(scip, conshdlrdata, totalvars, implgraph, implhash, implnodes, (int) (size_t) SCIPhashmapGetImage(implhash, var)) );
3086 
3087  /* compute new bound */
3088  for (i = 0; i < ncliquecovers; ++i)
3089  {
3090  int indcliq;
3091  int nodecliq;
3092 
3093  assert( cliquecoversizes[i] > 0 );
3094 
3095  indcliq = cliquecovers[i][0];
3096  assert( 0 <= indcliq && indcliq < ntrafolinvars );
3097 
3098  /* determine maximum without index v (note that trafolbs is sorted non-increasingly) */
3099  if ( v != indcliq )
3100  {
3101  /* if bound would be infinity */
3102  if ( SCIPisInfinity(scip, -trafolbs[indcliq]) )
3103  inftynores = TRUE;
3104  else
3105  newboundnores -= trafolbs[indcliq];
3106  }
3107  else if ( cliquecoversizes[i] > 1 )
3108  {
3109  assert( 0 <= cliquecovers[i][1] && cliquecovers[i][1] < ntrafolinvars );
3110  if ( SCIPisInfinity(scip, -trafolbs[cliquecovers[i][1]]) )
3111  inftynores = TRUE;
3112  else
3113  newboundnores -= trafolbs[cliquecovers[i][1]]; /*lint --e{679}*/
3114  }
3115 
3116  /* determine maximum without index v and if x_v is nonzero (note that trafolbs is sorted non-increasingly) */
3117  for (j = 0; j < cliquecoversizes[i]; ++j)
3118  {
3119  indcliq = cliquecovers[i][j];
3120  assert( 0 <= indcliq && indcliq < ntrafolinvars );
3121 
3122  nodecliq = varGetNodeSOS1(conshdlrdata, trafolinvars[indcliq]); /* possibly -1 if variable is not involved in an SOS1 constraint */
3123  assert( nodecliq < nsos1vars );
3124 
3125  if ( v != indcliq )
3126  {
3127  /* if nodev or nodecliq are not a member of an SOS1 constraint or the variable corresponding to nodecliq is not implied to be zero if x_v != 0 */
3128  if ( nodev < 0 || nodecliq < 0 || (! isConnectedSOS1(adjacencymatrix, NULL, nodev, nodecliq) && ! isImpliedZero(conflictgraph, implnodes, nodecliq) ) )
3129  {
3130  /* if bound would be infinity */
3131  if ( SCIPisInfinity(scip, -trafolbs[indcliq]) )
3132  ++ninftynonzero;
3133  else
3134  newboundnonzero -= trafolbs[indcliq];
3135  break;
3136  }
3137  }
3138  }
3139  }
3140  assert( ninftynonzero == 0 || inftynores );
3141 
3142 
3143  /* if computed upper bound is not infinity and variable is contained in linear constraint */
3144  if ( ninftynonzero == 0 && v < ntrafolinvars )
3145  {
3146  linval = trafolinvals[v];
3147 
3148  /* compute new bound */
3149  assert( ! SCIPisFeasZero(scip, linval) );
3150  if ( SCIPisFeasNegative(scip, newboundnores) && ! inftynores )
3151  newbound = newboundnonzero;
3152  else
3153  newbound = MAX(0, newboundnonzero);
3154  newbound /= linval;
3155 
3156  /* check if new bound is tighter than the old one or problem is infeasible */
3157  if ( SCIPisFeasPositive(scip, linval) && SCIPisFeasGT(scip, ub, newbound) )
3158  {
3159  /* if new upper bound is smaller than the lower bound, we are infeasible */
3160  if ( SCIPisFeasGT(scip, lb, newbound) )
3161  {
3162  *cutoff = TRUE;
3163  break;
3164  }
3165 
3166  if ( SCIPvarIsIntegral(var) )
3167  newbound = SCIPfloor(scip, newbound);
3168 
3169  SCIP_CALL( SCIPtightenVarUb(scip, var, newbound, FALSE, &infeasible, &tightened) );
3170  assert( ! infeasible );
3171 
3172  if ( tightened )
3173  {
3174  SCIPdebugMessage("changed upper bound of variable %s from %f to %f \n", SCIPvarGetName(var), ub, newbound);
3175  ++(*nchgbds);
3176  }
3177  }
3178  else if ( SCIPisFeasNegative(scip, linval) && SCIPisFeasLT(scip, lb, newbound) )
3179  {
3180  /* if assumption a_i * x_i != 0 was not correct */
3181  if ( SCIPisFeasLT(scip, ub, newbound) )
3182  {
3183  *cutoff = TRUE;
3184  break;
3185  }
3186 
3187  if ( SCIPvarIsIntegral(var) )
3188  newbound = SCIPceil(scip, newbound);
3189 
3190  SCIP_CALL( SCIPtightenVarLb(scip, var, newbound, FALSE, &infeasible, &tightened) );
3191  assert( ! infeasible );
3192 
3193  if ( tightened )
3194  {
3195  SCIPdebugMessage("changed lower bound of variable %s from %f to %f \n", SCIPvarGetName(var), lb, newbound);
3196  ++(*nchgbds);
3197  }
3198  }
3199  }
3200 
3201  /* update implication graph if possible */
3202  SCIP_CALL( updateImplicationGraphSOS1(scip, conshdlrdata, conflictgraph, adjacencymatrix, implgraph, implhash, implnodes, totalvars, cliquecovers, cliquecoversizes, varincover,
3203  trafolinvars, trafolinvals, ntrafolinvars, trafolbs, var, trafolbv, newboundnonzero, ninftynonzero, FALSE, nchgbds, &update) );
3204  if ( update )
3205  *implupdate = TRUE;
3206  }
3207 
3208  /* free memory */
3209  SCIPfreeBufferArrayNull(scip, &varincover);
3210  for (j = ncliquecovers-1; j >= 0; --j)
3211  SCIPfreeBufferArrayNull(scip, &cliquecovers[j]);
3212  SCIPfreeBufferArrayNull(scip, &cliquecovers);
3213  SCIPfreeBufferArrayNull(scip, &cliquecoversizes);
3214  SCIPfreeBufferArrayNull(scip, &cliquecovervals);
3215  SCIPfreeBufferArrayNull(scip, &trafolinvals);
3216  SCIPfreeBufferArrayNull(scip, &trafolinvars);
3217 
3218  if ( *cutoff == TRUE )
3219  break;
3220  } /* end for every linear constraint */
3221 
3222  /* free buffer arrays */
3223  SCIPfreeBufferArrayNull(scip, &sos1linvars);
3224  SCIPfreeBufferArrayNull(scip, &trafolbs);
3225  SCIPfreeBufferArrayNull(scip, &trafoubs);
3226  SCIPfreeBufferArrayNull(scip, &coveredvars);
3227  SCIPfreeBufferArrayNull(scip, &varindincons);
3228  SCIPfreeBufferArrayNull(scip, &implnodes);
3229 
3230  return SCIP_OKAY;
3231 }
3232 
3233 
3234 /** perform one presolving round for variables
3235  *
3236  * We perform the following presolving steps:
3237  * - Tighten the bounds of the variables
3238  * - Update conflict graph based on bound implications of the variables
3239  */
3240 static
3242  SCIP* scip, /**< SCIP pointer */
3243  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
3244  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
3245  SCIP_Bool** adjacencymatrix, /**< adjacencymatrix of conflict graph */
3246  int nsos1vars, /**< number of SOS1 variables */
3247  int* nchgbds, /**< pointer to store number of changed bounds */
3248  int* naddconss, /**< pointer to store number of addded constraints */
3249  SCIP_RESULT* result /**< result */
3250  )
3251 {
3252  SCIP_DIGRAPH* implgraph;
3253  SCIP_HASHMAP* implhash;
3254  SCIP_Bool* implnodes;
3255 
3256  SCIP_Bool cutoff = FALSE;
3257  SCIP_Bool updateconfl;
3258 
3259  SCIP_VAR** totalvars;
3260  SCIP_VAR** probvars;
3261  int ntotalvars = 0;
3262  int nprobvars;
3263  int i;
3264  int j;
3265 
3266  /* determine totalvars (union of SOS1 and problem variables) */
3267  probvars = SCIPgetVars(scip);
3268  nprobvars = SCIPgetNVars(scip);
3269  SCIP_CALL( SCIPhashmapCreate(&implhash, SCIPblkmem(scip), nsos1vars + nprobvars) );
3270  SCIP_CALL( SCIPallocBufferArray(scip, &totalvars, nsos1vars + nprobvars) );
3271 
3272  for (i = 0; i < nsos1vars; ++i)
3273  {
3274  SCIP_VAR* var;
3275  var = SCIPnodeGetVarSOS1(conflictgraph, i);
3276 
3277  /* insert node number to hash map */
3278  assert( ! SCIPhashmapExists(implhash, var) );
3279  SCIP_CALL( SCIPhashmapInsert(implhash, var, (void*) (size_t) ntotalvars) );/*lint !e571*/
3280  assert( ntotalvars == (int) (size_t) SCIPhashmapGetImage(implhash, var) );
3281  totalvars[ntotalvars++] = var;
3282  }
3283 
3284  for (i = 0; i < nprobvars; ++i)
3285  {
3286  SCIP_VAR* var;
3287  var = probvars[i];
3288 
3289  /* insert node number to hash map if not existent */
3290  if ( ! SCIPhashmapExists(implhash, var) )
3291  {
3292  SCIP_CALL( SCIPhashmapInsert(implhash, var, (void*) (size_t) ntotalvars) );/*lint !e571*/
3293  assert( ntotalvars == (int) (size_t) SCIPhashmapGetImage(implhash, var) );
3294  totalvars[ntotalvars++] = var;
3295  }
3296  }
3297 
3298  /* create implication graph */
3299  SCIP_CALL( SCIPdigraphCreate(&implgraph, ntotalvars) );
3300  SCIP_CALL( SCIPallocBufferArray(scip, &implnodes, nsos1vars) );
3301 
3302  /* try to tighten the lower and upper bounds of the variables */
3303  updateconfl = FALSE;
3304  for (j = 0; (j < conshdlrdata->maxtightenbds || conshdlrdata->maxtightenbds == -1 ) && ! cutoff; ++j)
3305  {
3306  SCIP_Bool implupdate;
3307  int nchgbdssave;
3308 
3309  nchgbdssave = *nchgbds;
3310 
3311  assert( ntotalvars > 0 );
3312  SCIP_CALL( tightenVarsBoundsSOS1(scip, conshdlrdata, conflictgraph, implgraph, implhash, adjacencymatrix, totalvars, ntotalvars, nsos1vars, nchgbds, &implupdate, &cutoff) );
3313  if ( *nchgbds > nchgbdssave )
3314  {
3315  *result = SCIP_SUCCESS;
3316  if ( implupdate )
3317  updateconfl = TRUE;
3318  }
3319  else if ( implupdate )
3320  updateconfl = TRUE;
3321  else
3322  break;
3323  }
3324 
3325  /* if an infeasibility has been detected */
3326  if ( cutoff )
3327  {
3328  SCIPdebugMessage("cutoff \n");
3329  *result = SCIP_CUTOFF;
3330  }
3331 
3332  /* try to update the conflict graph based on the information of the implication graph */
3333  if ( updateconfl && conshdlrdata->updateconflpresol && ! cutoff )
3334  {
3335  int naddconsssave;
3336 
3337  naddconsssave = *naddconss;
3338  for (i = 0; i < nsos1vars; ++i)
3339  {
3340  for (j = 0; j < nsos1vars; ++j)
3341  implnodes[j] = FALSE;
3342  SCIP_CALL( updateConflictGraphSOS1(scip, conshdlrdata, conflictgraph, totalvars, implgraph, implhash, implnodes, adjacencymatrix, i, i, naddconss) );
3343  }
3344 
3345  if ( *naddconss > naddconsssave )
3346  *result = SCIP_SUCCESS;
3347  }
3348 
3349  /* free memory */;
3350  for (j = ntotalvars-1; j >= 0; --j)
3351  {
3352  SCIP_SUCCDATA** succdatas;
3353  int nsucc;
3354  int s;
3355 
3356  succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(implgraph, j);
3357  nsucc = SCIPdigraphGetNSuccessors(implgraph, j);
3358 
3359  for (s = nsucc-1; s >= 0; --s)
3360  SCIPfreeMemory(scip, &succdatas[s]);
3361  }
3362  SCIPfreeBufferArrayNull(scip, &implnodes);
3363  SCIPdigraphFree(&implgraph);
3364  SCIPfreeBufferArrayNull(scip, &totalvars);
3365  SCIPhashmapFree(&implhash);
3366 
3367  return SCIP_OKAY;
3368 }
3369 
3370 
3371 /* ----------------------------- propagation -------------------------------------*/
3372 
3373 /** propagate variables of SOS1 constraint */
3374 static
3376  SCIP* scip, /**< SCIP pointer */
3377  SCIP_CONS* cons, /**< constraint */
3378  SCIP_CONSDATA* consdata, /**< constraint data */
3379  SCIP_Bool* cutoff, /**< whether a cutoff happened */
3380  int* ngen /**< number of domain changes */
3381  )
3382 {
3383  assert( scip != NULL );
3384  assert( cons != NULL );
3385  assert( consdata != NULL );
3386  assert( cutoff != NULL );
3387  assert( ngen != NULL );
3388 
3389  *cutoff = FALSE;
3390 
3391  /* if more than one variable is fixed to be nonzero */
3392  if ( consdata->nfixednonzeros > 1 )
3393  {
3394  SCIPdebugMessage("the node is infeasible, more than 1 variable is fixed to be nonzero.\n");
3395  SCIP_CALL( SCIPresetConsAge(scip, cons) );
3396  *cutoff = TRUE;
3397  return SCIP_OKAY;
3398  }
3399 
3400  /* if exactly one variable is fixed to be nonzero */
3401  if ( consdata->nfixednonzeros == 1 )
3402  {
3403  SCIP_VAR** vars;
3404  SCIP_Bool infeasible;
3405  SCIP_Bool tightened;
3406  SCIP_Bool success;
3407  SCIP_Bool allVarFixed;
3408  int firstFixedNonzero;
3409  int nvars;
3410  int j;
3411 
3412  firstFixedNonzero = -1;
3413  nvars = consdata->nvars;
3414  vars = consdata->vars;
3415  assert( vars != NULL );
3416 
3417  /* search nonzero variable - is needed for propinfo */
3418  for (j = 0; j < nvars; ++j)
3419  {
3420  if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(vars[j])) || SCIPisFeasNegative(scip, SCIPvarGetUbLocal(vars[j])) )
3421  {
3422  firstFixedNonzero = j;
3423  break;
3424  }
3425  }
3426  assert( firstFixedNonzero >= 0 );
3427 
3428  SCIPdebugMessage("variable <%s> is fixed nonzero, fixing other variables to 0.\n", SCIPvarGetName(vars[firstFixedNonzero]));
3429 
3430  /* fix variables before firstFixedNonzero to 0 */
3431  allVarFixed = TRUE;
3432  for (j = 0; j < firstFixedNonzero; ++j)
3433  {
3434  /* fix variable */
3435  SCIP_CALL( inferVariableZero(scip, vars[j], cons, firstFixedNonzero, &infeasible, &tightened, &success) );
3436  assert( ! infeasible );
3437  allVarFixed = allVarFixed && success;
3438  if ( tightened )
3439  ++(*ngen);
3440  }
3441 
3442  /* fix variables after firstFixedNonzero to 0 */
3443  for (j = firstFixedNonzero+1; j < nvars; ++j)
3444  {
3445  /* fix variable */
3446  SCIP_CALL( inferVariableZero(scip, vars[j], cons, firstFixedNonzero, &infeasible, &tightened, &success) );
3447  assert( ! infeasible ); /* there should be no variables after firstFixedNonzero that are fixed to be nonzero */
3448  allVarFixed = allVarFixed && success;
3449  if ( tightened )
3450  ++(*ngen);
3451  }
3452 
3453  /* reset constraint age counter */
3454  if ( *ngen > 0 )
3455  {
3456  SCIP_CALL( SCIPresetConsAge(scip, cons) );
3457  }
3458 
3459  /* delete constraint locally */
3460  if ( allVarFixed )
3461  {
3462  assert( !SCIPconsIsModifiable(cons) );
3463  SCIP_CALL( SCIPdelConsLocal(scip, cons) );
3464  }
3465  }
3466 
3467  return SCIP_OKAY;
3468 }
3469 
3470 
3471 /** propagate a variable that is known to be nonzero */
3472 static
3474  SCIP* scip, /**< SCIP pointer */
3475  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
3476  SCIP_DIGRAPH* implgraph, /**< implication graph */
3477  SCIP_CONS* cons, /**< some arbitrary SOS1 constraint */
3478  int node, /**< conflict graph node of variable that is known to be nonzero */
3479  SCIP_Bool implprop, /**< whether implication graph propagation shall be applied */
3480  SCIP_Bool* cutoff, /**< whether a cutoff happened */
3481  int* ngen /**< number of domain changes */
3482  )
3483 {
3484  int inferinfo;
3485  int* succ;
3486  int nsucc;
3487  int s;
3488 
3489  assert( scip != NULL );
3490  assert( conflictgraph != NULL );
3491  assert( cutoff != NULL );
3492  assert( ngen != NULL );
3493  assert( node >= 0 );
3494 
3495  *cutoff = FALSE;
3496  inferinfo = -node - 1;
3497 
3498  /* by assumption zero is outside the domain of variable */
3499  assert( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(SCIPnodeGetVarSOS1(conflictgraph, node))) || SCIPisFeasNegative(scip, SCIPvarGetUbLocal(SCIPnodeGetVarSOS1(conflictgraph, node))) );
3500 
3501  /* apply conflict graph propagation (fix all neighbors in the conflict graph to zero) */
3502  succ = SCIPdigraphGetSuccessors(conflictgraph, node);
3503  nsucc = SCIPdigraphGetNSuccessors(conflictgraph, node);
3504  for (s = 0; s < nsucc; ++s)
3505  {
3506  SCIP_VAR* succvar;
3507  SCIP_Real lb;
3508  SCIP_Real ub;
3509 
3510  succvar = SCIPnodeGetVarSOS1(conflictgraph, succ[s]);
3511  lb = SCIPvarGetLbLocal(succvar);
3512  ub = SCIPvarGetUbLocal(succvar);
3513 
3514  if ( ! SCIPisFeasZero(scip, lb) || ! SCIPisFeasZero(scip, ub) )
3515  {
3516  SCIP_Bool infeasible;
3517  SCIP_Bool tightened;
3518  SCIP_Bool success;
3519 
3520  /* fix variable if it is not multi-aggregated */
3521  SCIP_CALL( inferVariableZero(scip, succvar, cons, inferinfo, &infeasible, &tightened, &success) );
3522 
3523  if ( infeasible )
3524  {
3525  /* variable cannot be nonzero */
3526  *cutoff = TRUE;
3527  return SCIP_OKAY;
3528  }
3529  if ( tightened )
3530  ++(*ngen);
3531  assert( success || SCIPvarGetStatus(succvar) == SCIP_VARSTATUS_MULTAGGR );
3532  }
3533  }
3534 
3535 
3536  /* apply implication graph propagation */
3537  if ( implprop && implgraph != NULL )
3538  {
3539  SCIP_SUCCDATA** succdatas;
3540 
3541 #ifndef NDEBUG
3542  SCIP_NODEDATA* nodedbgdata;
3543  nodedbgdata = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(implgraph, node);
3544  assert( SCIPvarCompare(nodedbgdata->var, SCIPnodeGetVarSOS1(conflictgraph, node)) == 0 );
3545 #endif
3546 
3547  /* get successor datas */
3548  succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(implgraph, node);
3549 
3550  if ( succdatas != NULL )
3551  {
3552  succ = SCIPdigraphGetSuccessors(implgraph, node);
3553  nsucc = SCIPdigraphGetNSuccessors(implgraph, node);
3554  for (s = 0; s < nsucc; ++s)
3555  {
3556  SCIP_SUCCDATA* succdata;
3557  SCIP_NODEDATA* nodedata;
3558  SCIP_VAR* var;
3559 
3560  nodedata = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(implgraph, succ[s]);
3561  succdata = succdatas[s];
3562  var = nodedata->var;
3563  assert( nodedata != NULL && succdata != NULL && var != NULL );
3564 
3565  /* tighten variable if it is not multi-aggregated */
3567  {
3568  /* check for lower bound implication */
3569  if ( SCIPisFeasLT(scip, SCIPvarGetLbLocal(var), succdata->lbimpl) )
3570  {
3571  SCIP_Bool infeasible;
3572  SCIP_Bool tightened;
3573 
3574  SCIP_CALL( SCIPinferVarLbCons(scip, var, succdata->lbimpl, cons, inferinfo, FALSE, &infeasible, &tightened) );
3575  if ( infeasible )
3576  {
3577  *cutoff = TRUE;
3578  return SCIP_OKAY;
3579  }
3580  if ( tightened )
3581  ++(*ngen);
3582  }
3583 
3584  /* check for upper bound implication */
3585  if ( SCIPisFeasGT(scip, SCIPvarGetUbLocal(var), succdata->ubimpl) )
3586  {
3587  SCIP_Bool infeasible;
3588  SCIP_Bool tightened;
3589 
3590  SCIP_CALL( SCIPinferVarUbCons(scip, var, succdata->ubimpl, cons, inferinfo, FALSE, &infeasible, &tightened) );
3591  if ( infeasible )
3592  {
3593  *cutoff = TRUE;
3594  return SCIP_OKAY;
3595  }
3596  if ( tightened )
3597  ++(*ngen);
3598  }
3599  }
3600  }
3601  }
3602  }
3603 
3604  return SCIP_OKAY;
3605 }
3606 
3607 
3608 /** initialize implication graph
3609  *
3610  * @p j is successor of @p i if and only if \f$ x_i\not = 0 \Rightarrow x_j\not = 0\f$
3611  *
3612  * @note By construction the implication graph is globally valid.
3613  */
3614 static
3616  SCIP* scip, /**< SCIP pointer */
3617  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
3618  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
3619  int nsos1vars, /**< number of SOS1 variables */
3620  int maxrounds, /**< maximal number of propagation rounds for generating implications */
3621  int* nchgbds, /**< pointer to store number of bound changes */
3622  SCIP_Bool* cutoff, /**< pointer to store whether a cutoff occurred */
3623  SCIP_Bool* success /**< whether initialization was successful */
3624  )
3625 {
3626  SCIP_HASHMAP* implhash = NULL;
3627  SCIP_Bool** adjacencymatrix = NULL;
3628  SCIP_Bool* implnodes = NULL;
3629  SCIP_VAR** implvars = NULL;
3630  SCIP_VAR** probvars;
3631  int nimplnodes;
3632  int nprobvars;
3633  int i;
3634  int j;
3635 
3636  assert( scip != NULL );
3637  assert( conshdlrdata != NULL );
3638  assert( conflictgraph != NULL );
3639  assert( conshdlrdata->nimplnodes == 0 );
3640  assert( cutoff != NULL );
3641  assert( nchgbds != NULL );
3642 
3643  *nchgbds = 0;
3644  *cutoff = FALSE;
3645 
3646  /* we do not create the adjacency matrix of the conflict graph if the number of SOS1 variables is larger than a predefined value */
3647  if ( conshdlrdata->maxsosadjacency != -1 && nsos1vars > conshdlrdata->maxsosadjacency )
3648  {
3649  *success = FALSE;
3650  SCIPdebugMessage("Implication graph was not created since number of SOS1 variables (%d) is larger than %d.\n", nsos1vars, conshdlrdata->maxsosadjacency);
3651 
3652  return SCIP_OKAY;
3653  }
3654  *success = TRUE;
3655 
3656  /* only add globally valid implications to implication graph */
3657  assert ( SCIPgetDepth(scip) == 0 );
3658 
3659  probvars = SCIPgetVars(scip);
3660  nprobvars = SCIPgetNVars(scip);
3661  nimplnodes = 0;
3662 
3663  /* create implication graph */
3664  SCIP_CALL( SCIPdigraphCreate(&conshdlrdata->implgraph, nsos1vars + nprobvars) );
3665 
3666  /* create hashmap */
3667  SCIP_CALL( SCIPhashmapCreate(&implhash, SCIPblkmem(scip), nsos1vars + nprobvars) );
3668 
3669  /* determine implvars (union of SOS1 and problem variables)
3670  * Note: For separation of implied bound cuts it is important that SOS1 variables are enumerated first
3671  */
3672  SCIP_CALL( SCIPallocBufferArray(scip, &implvars, nsos1vars + nprobvars) );
3673  for (i = 0; i < nsos1vars; ++i)
3674  {
3675  SCIP_VAR* var;
3676  var = SCIPnodeGetVarSOS1(conflictgraph, i);
3677 
3678  /* insert node number to hash map */
3679  assert( ! SCIPhashmapExists(implhash, var) );
3680  SCIP_CALL( SCIPhashmapInsert(implhash, var, (void*) (size_t) nimplnodes) );/*lint !e571*/
3681  assert( nimplnodes == (int) (size_t) SCIPhashmapGetImage(implhash, var) );
3682  implvars[nimplnodes++] = var;
3683  }
3684 
3685  for (i = 0; i < nprobvars; ++i)
3686  {
3687  SCIP_VAR* var;
3688  var = probvars[i];
3689 
3690  /* insert node number to hash map if not existent */
3691  if ( ! SCIPhashmapExists(implhash, var) )
3692  {
3693  SCIP_CALL( SCIPhashmapInsert(implhash, var, (void*) (size_t) nimplnodes) );/*lint !e571*/
3694  assert( nimplnodes == (int) (size_t) SCIPhashmapGetImage(implhash, var) );
3695  implvars[nimplnodes++] = var;
3696  }
3697  }
3698  conshdlrdata->nimplnodes = nimplnodes;
3699 
3700  /* add variables to nodes of implication graph */
3701  for (i = 0; i < nimplnodes; ++i)
3702  {
3703  SCIP_NODEDATA* nodedata = NULL;
3704 
3705  /* create node data */
3706  SCIP_CALL( SCIPallocMemory(scip, &nodedata) );
3707  nodedata->var = implvars[i];
3708 
3709  /* set node data */
3710  SCIPdigraphSetNodeData(conshdlrdata->implgraph, (void*) nodedata, i);
3711  }
3712 
3713  /* allocate buffer arrays */
3714  SCIP_CALL( SCIPallocBufferArray(scip, &implnodes, nsos1vars) );
3715  SCIP_CALL( SCIPallocBufferArray(scip, &adjacencymatrix, nsos1vars) );
3716 
3717  for (i = 0; i < nsos1vars; ++i)
3718  SCIP_CALL( SCIPallocBufferArray(scip, &adjacencymatrix[i], i+1) ); /*lint !e866*/
3719 
3720  /* create adjacency matrix */
3721  for (i = 0; i < nsos1vars; ++i)
3722  {
3723  for (j = 0; j < i+1; ++j)
3724  adjacencymatrix[i][j] = 0;
3725  }
3726 
3727  for (i = 0; i < nsos1vars; ++i)
3728  {
3729  int* succ;
3730  int nsucc;
3731  succ = SCIPdigraphGetSuccessors(conflictgraph, i);
3732  nsucc = SCIPdigraphGetNSuccessors(conflictgraph, i);
3733 
3734  for (j = 0; j < nsucc; ++j)
3735  {
3736  if ( i > succ[j] )
3737  adjacencymatrix[i][succ[j]] = 1;
3738  }
3739  }
3740 
3741  assert( SCIPgetDepth(scip) == 0 );
3742 
3743  /* compute SOS1 implications from linear constraints and tighten bounds of variables */
3744  for (j = 0; (j < maxrounds || maxrounds == -1 ); ++j)
3745  {
3746  SCIP_Bool implupdate;
3747  int nchgbdssave;
3748 
3749  nchgbdssave = *nchgbds;
3750 
3751  assert( nimplnodes > 0 );
3752  SCIP_CALL( tightenVarsBoundsSOS1(scip, conshdlrdata, conflictgraph, conshdlrdata->implgraph, implhash, adjacencymatrix, implvars, nimplnodes, nsos1vars, nchgbds, &implupdate, cutoff) );
3753  if ( *cutoff || ( ! implupdate && ! ( *nchgbds > nchgbdssave ) ) )
3754  break;
3755  }
3756 
3757  /* free memory */
3758  for (i = nsos1vars-1; i >= 0; --i)
3759  SCIPfreeBufferArrayNull(scip, &adjacencymatrix[i]);
3760  SCIPfreeBufferArrayNull(scip, &adjacencymatrix);
3761  SCIPfreeBufferArrayNull(scip, &implnodes);
3762  SCIPfreeBufferArrayNull(scip, &implvars);
3763  SCIPhashmapFree(&implhash);
3764 
3765 #ifdef SCIP_DEBUG
3766  /* evaluate results */
3767  if ( cutoff )
3768  SCIPdebugMessage("cutoff \n");
3769  else if ( *nchgbds > 0 )
3770  SCIPdebugMessage("found %d bound changes\n", *nchgbds);
3771 #endif
3772 
3773  return SCIP_OKAY;
3774 }
3775 
3776 
3777 /** deinitialize implication graph */
3778 static
3780  SCIP* scip, /**< SCIP pointer */
3781  SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
3782  )
3783 {
3784  int j;
3785 
3786  assert( scip != NULL );
3787  assert( conshdlrdata != NULL );
3788 
3789  /* free whole memory of implication graph */
3790  if ( conshdlrdata->implgraph == NULL )
3791  return SCIP_OKAY;
3792 
3793  /* free arc data */
3794  for (j = conshdlrdata->nimplnodes-1; j >= 0; --j)
3795  {
3796  SCIP_SUCCDATA** succdatas;
3797  int nsucc;
3798  int s;
3799 
3800  succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(conshdlrdata->implgraph, j);
3801  nsucc = SCIPdigraphGetNSuccessors(conshdlrdata->implgraph, j);
3802 
3803  for (s = nsucc-1; s >= 0; --s)
3804  {
3805  assert( succdatas[s] != NULL );
3806  SCIPfreeMemory(scip, &succdatas[s]);
3807  }
3808  }
3809 
3810  /* free node data */
3811  for (j = conshdlrdata->nimplnodes-1; j >= 0; --j)
3812  {
3813  SCIP_NODEDATA* nodedata;
3814  nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conshdlrdata->implgraph, j);
3815  assert( nodedata != NULL );
3816  SCIPfreeMemory(scip, &nodedata);
3817  SCIPdigraphSetNodeData(conshdlrdata->implgraph, NULL, j);
3818  }
3819 
3820  /* free implication graph */
3821  SCIPdigraphFree(&conshdlrdata->implgraph);
3822 
3823  return SCIP_OKAY;
3824 }
3825 
3826 
3827 /* ----------------------------- branching -------------------------------------*/
3828 
3829 /** get the vertices whose neighbor set covers a subset of the neighbor set of a given other vertex.
3830  *
3831  * This function can be used to compute sets of variables to branch on.
3832  */
3833 static
3835  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
3836  SCIP_Bool* verticesarefixed, /**< array that indicates which variables are currently fixed to zero */
3837  int vertex, /**< vertex (-1 if not needed) */
3838  int* neightocover, /**< neighbors of given vertex to be covered (or NULL if all neighbors shall be covered) */
3839  int nneightocover, /**< number of entries of neightocover (or 0 if all neighbors shall be covered )*/
3840  int* coververtices, /**< array to store the vertices whose neighbor set covers the neighbor set of the given vertex */
3841  int* ncoververtices /**< pointer to store size of coververtices */
3842  )
3843 {
3844  int* succ1;
3845  int nsucc1;
3846  int s;
3847 
3848  assert( conflictgraph != NULL );
3849  assert( verticesarefixed != NULL );
3850  assert( coververtices != NULL );
3851  assert( ncoververtices != NULL );
3852 
3853  *ncoververtices = 0;
3854 
3855  /* if all the neighbors shall be covered */
3856  if ( neightocover == NULL )
3857  {
3858  assert( nneightocover == 0 );
3859  nsucc1 = SCIPdigraphGetNSuccessors(conflictgraph, vertex);
3860  succ1 = SCIPdigraphGetSuccessors(conflictgraph, vertex);
3861  }
3862  else
3863  {
3864  nsucc1 = nneightocover;
3865  succ1 = neightocover;
3866  }
3867 
3868  /* determine all the successors of the first unfixed successor */
3869  for (s = 0; s < nsucc1; ++s)
3870  {
3871  int succvertex1 = succ1[s];
3872 
3873  if ( ! verticesarefixed[succvertex1] )
3874  {
3875  int succvertex2;
3876  int* succ2;
3877  int nsucc2;
3878  int j;
3879 
3880  nsucc2 = SCIPdigraphGetNSuccessors(conflictgraph, succvertex1);
3881  succ2 = SCIPdigraphGetSuccessors(conflictgraph, succvertex1);
3882 
3883  /* for the first unfixed vertex */
3884  if ( *ncoververtices == 0 )
3885  {
3886  for (j = 0; j < nsucc2; ++j)
3887  {
3888  succvertex2 = succ2[j];
3889  if ( ! verticesarefixed[succvertex2] )
3890  coververtices[(*ncoververtices)++] = succvertex2;
3891  }
3892  }
3893  else
3894  {
3895  int vv = 0;
3896  int k = 0;
3897  int v;
3898 
3899  /* determine all the successors that are in the set "coververtices" */
3900  for (v = 0; v < *ncoververtices; ++v)
3901  {
3902  assert( vv <= v );
3903  for (j = k; j < nsucc2; ++j)
3904  {
3905  succvertex2 = succ2[j];
3906  if ( succvertex2 > coververtices[v] )
3907  {
3908  /* coververtices[v] does not appear in succ2 list, go to next vertex in coververtices */
3909  k = j;
3910  break;
3911  }
3912  else if ( succvertex2 == coververtices[v] )
3913  {
3914  /* vertices are equal, copy to free position vv */
3915  coververtices[vv++] = succvertex2;
3916  k = j + 1;
3917  break;
3918  }
3919  }
3920  }
3921  /* store new size of coververtices */
3922  *ncoververtices = vv;
3923  }
3924  }
3925  }
3926 
3927 #ifdef SCIP_DEBUG
3928  /* check sorting */
3929  for (s = 0; s < *ncoververtices; ++s)
3930  {
3931  assert( *ncoververtices <= 1 || coververtices[*ncoververtices - 1] > coververtices[*ncoververtices - 2] );
3932  }
3933 #endif
3934 
3935  return SCIP_OKAY;
3936 }
3937 
3938 
3939 /** get vertices of variables that will be fixed to zero for each node */
3940 static
3942  SCIP* scip, /**< SCIP pointer */
3943  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
3944  SCIP_Bool* verticesarefixed, /**< vector that indicates which variables are currently fixed to zero */
3945  SCIP_Bool bipbranch, /**< TRUE if bipartite branching method should be used */
3946  int branchvertex, /**< branching vertex */
3947  int* fixingsnode1, /**< vertices of variables that will be fixed to zero for the first node */
3948  int* nfixingsnode1, /**< pointer to store number of fixed variables for the first node */
3949  int* fixingsnode2, /**< vertices of variables that will be fixed to zero for the second node */
3950  int* nfixingsnode2 /**< pointer to store number of fixed variables for the second node */
3951  )
3952 {
3953  SCIP_Bool takeallsucc; /* whether to set fixingsnode1 = neighbors of 'branchvertex' in the conflict graph */
3954  int* succ;
3955  int nsucc;
3956  int j;
3957 
3958  assert( scip != NULL );
3959  assert( conflictgraph != NULL );
3960  assert( verticesarefixed != NULL );
3961  assert( ! verticesarefixed[branchvertex] );
3962  assert( fixingsnode1 != NULL );
3963  assert( fixingsnode2 != NULL );
3964  assert( nfixingsnode1 != NULL );
3965  assert( nfixingsnode2 != NULL );
3966 
3967  *nfixingsnode1 = 0;
3968  *nfixingsnode2 = 0;
3969  takeallsucc = TRUE;
3970 
3971  /* get successors and number of successors of branching vertex */
3972  nsucc = SCIPdigraphGetNSuccessors(conflictgraph, branchvertex);
3973  succ = SCIPdigraphGetSuccessors(conflictgraph, branchvertex);
3974 
3975  /* if bipartite branching method is turned on */
3976  if ( bipbranch )
3977  {
3978  SCIP_Real solval;
3979  int cnt = 0;
3980 
3981  /* get all the neighbors of the variable with index 'branchvertex' whose solution value is nonzero */
3982  for (j = 0; j < nsucc; ++j)
3983  {
3984  if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, NULL, SCIPnodeGetVarSOS1(conflictgraph, succ[j]))) )
3985  {
3986  assert( ! verticesarefixed[succ[j]] );
3987  fixingsnode1[(*nfixingsnode1)++] = succ[j];
3988  }
3989  }
3990 
3991  /* if one of the sets fixingsnode1 or fixingsnode2 contains only one variable with a nonzero LP value we perform standard neighborhood branching */
3992  if ( *nfixingsnode1 > 0 )
3993  {
3994  /* get the vertices whose neighbor set cover the selected subset of the neighbors of the given branching vertex */
3995  SCIP_CALL( getCoverVertices(conflictgraph, verticesarefixed, branchvertex, fixingsnode1, *nfixingsnode1, fixingsnode2, nfixingsnode2) );
3996 
3997  /* determine the intersection of the neighbors of branchvertex with the intersection of all the neighbors of fixingsnode2 */
3998  SCIP_CALL( getCoverVertices(conflictgraph, verticesarefixed, branchvertex, fixingsnode2, *nfixingsnode2, fixingsnode1, nfixingsnode1) );
3999 
4000  for (j = 0; j < *nfixingsnode2; ++j)
4001  {
4002  solval = SCIPgetSolVal(scip, NULL, SCIPnodeGetVarSOS1(conflictgraph, fixingsnode2[j]));
4003  if( ! SCIPisFeasZero(scip, solval) )
4004  ++cnt;
4005  }
4006 
4007  /* we decide whether to use all successors if one partition of complete bipartite subgraph has only one node */
4008  if ( cnt >= 2 )
4009  {
4010  cnt = 0;
4011  for (j = 0; j < *nfixingsnode1; ++j)
4012  {
4013  solval = SCIPgetSolVal(scip, NULL, SCIPnodeGetVarSOS1(conflictgraph, fixingsnode1[j]));
4014  if( ! SCIPisFeasZero(scip, solval) )
4015  ++cnt;
4016  }
4017 
4018  if ( cnt >= 2 )
4019  takeallsucc = FALSE;
4020  }
4021  }
4022  }
4023 
4024  if ( takeallsucc )
4025  {
4026  /* get all the unfixed neighbors of the branching vertex */
4027  *nfixingsnode1 = 0;
4028  for (j = 0; j < nsucc; ++j)
4029  {
4030  if ( ! verticesarefixed[succ[j]] )
4031  fixingsnode1[(*nfixingsnode1)++] = succ[j];
4032  }
4033 
4034  if ( bipbranch )
4035  {
4036  /* get the vertices whose neighbor set covers the neighbor set of a given branching vertex */
4037  SCIP_CALL( getCoverVertices(conflictgraph, verticesarefixed, branchvertex, fixingsnode1, *nfixingsnode1, fixingsnode2, nfixingsnode2) );
4038  }
4039  else
4040  {
4041  /* use neighborhood branching, i.e, for the second node only the branching vertex can be fixed */
4042  fixingsnode2[0] = branchvertex;
4043  *nfixingsnode2 = 1;
4044  }
4045  }
4046 
4047  return SCIP_OKAY;
4048 }
4049 
4050 
4051 /** gets branching priorities for SOS1 variables and applies 'most infeasible selection' rule to determine a vertex for the next branching decision */
4052 static
4054  SCIP* scip, /**< SCIP pointer */
4055  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4056  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
4057  int nsos1vars, /**< number of SOS1 variables */
4058  SCIP_Bool* verticesarefixed, /**< vector that indicates which variables are currently fixed to zero */
4059  SCIP_Bool bipbranch, /**< TRUE if bipartite branching method should be used */
4060  int* fixingsnode1, /**< vertices of variables that will be fixed to zero for the first node (size = nsos1vars) */
4061  int* fixingsnode2, /**< vertices of variables that will be fixed to zero for the second node (size = nsos1vars) */
4062  SCIP_Real* branchpriors, /**< pointer to store branching priorities (size = nsos1vars) or NULL if not needed */
4063  int* vertexbestprior, /**< pointer to store vertex with the best branching priority or NULL if not needed */
4064  SCIP_Bool* relsolfeas /**< pointer to store if LP relaxation solution is feasible */
4065  )
4066 {
4067  SCIP_Real bestprior;
4068  int i;
4069 
4070  assert( scip != NULL );
4071  assert( conshdlrdata != NULL );
4072  assert( conflictgraph != NULL );
4073  assert( verticesarefixed != NULL );
4074  assert( fixingsnode1 != NULL );
4075  assert( fixingsnode2 != NULL );
4076  assert( relsolfeas != NULL );
4077 
4078  bestprior = -SCIPinfinity(scip);
4079 
4080  for (i = 0; i < nsos1vars; ++i)
4081  {
4082  SCIP_Real prior;
4083  SCIP_Real solval;
4084  SCIP_Real sum1;
4085  SCIP_Real sum2;
4086  int nfixingsnode1;
4087  int nfixingsnode2;
4088  int nsucc;
4089  int j;
4090 
4091  nsucc = SCIPdigraphGetNSuccessors(conflictgraph, i);
4092 
4093  if ( nsucc == 0 || SCIPisFeasZero(scip, SCIPgetSolVal(scip, NULL, SCIPnodeGetVarSOS1(conflictgraph, i))) || verticesarefixed[i] )
4094  prior = -SCIPinfinity(scip);
4095  else
4096  {
4097  SCIP_Bool iszero1 = TRUE;
4098  SCIP_Bool iszero2 = TRUE;
4099 
4100  /* get vertices of variables that will be fixed to zero for each strong branching execution */
4101  assert( ! verticesarefixed[i] );
4102  SCIP_CALL( getBranchingVerticesSOS1(scip, conflictgraph, verticesarefixed, bipbranch, i, fixingsnode1, &nfixingsnode1, fixingsnode2, &nfixingsnode2) );
4103 
4104  sum1 = 0.0;
4105  for (j = 0; j < nfixingsnode1; ++j)
4106  {
4107  solval = SCIPgetSolVal(scip, NULL, SCIPnodeGetVarSOS1(conflictgraph, fixingsnode1[j]));
4108  if ( ! SCIPisFeasZero(scip, solval) )
4109  {
4110  sum1 += REALABS( solval );
4111  iszero1 = FALSE;
4112  }
4113  }
4114 
4115  sum2 = 0.0;
4116  for (j = 0; j < nfixingsnode2; ++j)
4117  {
4118  solval = SCIPgetSolVal(scip, NULL, SCIPnodeGetVarSOS1(conflictgraph, fixingsnode2[j]));
4119  if ( ! SCIPisFeasZero(scip, solval) )
4120  {
4121  sum2 += REALABS( solval );
4122  iszero2 = FALSE;
4123  }
4124  }
4125 
4126  if ( iszero1 || iszero2 )
4127  prior = -SCIPinfinity(scip);
4128  else
4129  prior = sum1 * sum2;
4130  }
4131 
4132  if ( branchpriors != NULL )
4133  branchpriors[i] = prior;
4134  if ( bestprior < prior )
4135  {
4136  bestprior = prior;
4137 
4138  if ( vertexbestprior != NULL )
4139  *vertexbestprior = i;
4140  }
4141  }
4142 
4143  if ( SCIPisInfinity(scip, -bestprior) )
4144  *relsolfeas = TRUE;
4145  else
4146  *relsolfeas = FALSE;
4147 
4148  return SCIP_OKAY;
4149 }
4150 
4151 
4152 /** performs strong branching with given domain fixings */
4153 static
4155  SCIP* scip, /**< SCIP pointer */
4156  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
4157  int* fixingsexec, /**< vertices of variables to be fixed to zero for this strong branching execution */
4158  int nfixingsexec, /**< number of vertices of variables to be fixed to zero for this strong branching execution */
4159  int* fixingsop, /**< vertices of variables to be fixed to zero for the opposite strong branching execution */
4160  int nfixingsop, /**< number of vertices of variables to be fixed to zero for the opposite strong branching execution */
4161  int inititer, /**< maximal number of LP iterations to perform */
4162  SCIP_Bool fixnonzero, /**< shall opposite variable (if positive in sign) fixed to the feasibility tolerance
4163  * (only possible if nfixingsop = 1) */
4164  int* domainfixings, /**< vertices that can be used to reduce the domain (should have size equal to number of variables) */
4165  int* ndomainfixings, /**< pointer to store number of vertices that can be used to reduce the domain, could be filled by earlier calls */
4166  SCIP_Bool* infeasible, /**< pointer to store whether branch is infeasible */
4167  SCIP_Real* objval, /**< pointer to store objective value of LP with fixed variables (SCIP_INVALID if reddomain = TRUE or lperror = TRUE) */
4168  SCIP_Bool* lperror /**< pointer to store whether an unresolved LP error or a strange solution status occurred */
4169  )
4170 {
4171  SCIP_LPSOLSTAT solstat;
4172  int i;
4173 
4174  assert( scip != NULL );
4175  assert( conflictgraph != NULL );
4176  assert( fixingsexec != NULL );
4177  assert( nfixingsop > 0 );
4178  assert( fixingsop != NULL );
4179  assert( nfixingsop > 0 );
4180  assert( inititer >= -1 );
4181  assert( domainfixings != NULL );
4182  assert( ndomainfixings != NULL );
4183  assert( *ndomainfixings >= 0 );
4184  assert( infeasible != NULL );
4185  assert( objval != NULL );
4186  assert( lperror != NULL );
4187 
4188  *objval = SCIP_INVALID; /* for debugging */
4189  *lperror = FALSE;
4190  *infeasible = FALSE;
4191 
4192  /* start probing */
4193  SCIP_CALL( SCIPstartProbing(scip) );
4194 
4195  /* perform domain fixings */
4196  if ( fixnonzero && nfixingsop == 1 )
4197  {
4198  SCIP_VAR* var;
4199  SCIP_Real lb;
4200  SCIP_Real ub;
4201 
4202  var = SCIPnodeGetVarSOS1(conflictgraph, fixingsop[0]);
4203  lb = SCIPvarGetLbLocal(var);
4204  ub = SCIPvarGetUbLocal(var);
4205 
4207  {
4208  if ( SCIPisZero(scip, lb) )
4209  {
4210  /* fix variable to some small positive number */
4211  SCIP_CALL( SCIPchgVarLbProbing(scip, var, 1.5 * SCIPfeastol(scip)) );
4212  }
4213  else if ( SCIPisZero(scip, ub) )
4214  {
4215  /* fix variable to some negative number with small absolute value */
4216  SCIP_CALL( SCIPchgVarUbProbing(scip, var, -1.5 * SCIPfeastol(scip)) );
4217  }
4218  }
4219  }
4220 
4221  /* injects variable fixings into current probing node */
4222  for (i = 0; i < nfixingsexec && ! *infeasible; ++i)
4223  {
4224  SCIP_VAR* var;
4225 
4226  var = SCIPnodeGetVarSOS1(conflictgraph, fixingsexec[i]);
4227  if ( SCIPisFeasGT(scip, SCIPvarGetLbLocal(var), 0.0) || SCIPisFeasLT(scip, SCIPvarGetUbLocal(var), 0.0) )
4228  *infeasible = TRUE;
4229  else
4230  {
4231  SCIP_CALL( SCIPfixVarProbing(scip, var, 0.0) );
4232  }
4233  }
4234 
4235  /* apply domain propagation */
4236  if ( ! *infeasible )
4237  {
4238  SCIP_CALL( SCIPpropagateProbing(scip, 0, infeasible, NULL) );
4239  }
4240 
4241  if ( *infeasible )
4242  solstat = SCIP_LPSOLSTAT_INFEASIBLE;
4243  else
4244  {
4245  /* solve the probing LP */
4246  SCIP_CALL( SCIPsolveProbingLP(scip, inititer, lperror, NULL) );
4247  if ( *lperror )
4248  {
4249  SCIP_CALL( SCIPendProbing(scip) );
4250  return SCIP_OKAY;
4251  }
4252 
4253  /* get solution status */
4254  solstat = SCIPgetLPSolstat(scip);
4255  }
4256 
4257  /* if objective limit was reached, then the domain can be reduced */
4258  if ( solstat == SCIP_LPSOLSTAT_OBJLIMIT || solstat == SCIP_LPSOLSTAT_INFEASIBLE )
4259  {
4260  *infeasible = TRUE;
4261 
4262  for (i = 0; i < nfixingsop; ++i)
4263  domainfixings[(*ndomainfixings)++] = fixingsop[i];
4264  }
4265  else if ( solstat == SCIP_LPSOLSTAT_OPTIMAL || solstat == SCIP_LPSOLSTAT_TIMELIMIT || solstat == SCIP_LPSOLSTAT_ITERLIMIT )
4266  {
4267  /* get objective value of probing LP */
4268  *objval = SCIPgetLPObjval(scip);
4269  }
4270  else
4271  *lperror = TRUE;
4272 
4273  /* end probing */
4274  SCIP_CALL( SCIPendProbing(scip) );
4275 
4276  return SCIP_OKAY;
4277 }
4278 
4279 
4280 /** apply strong branching to determine the vertex for the next branching decision */
4281 static
4283  SCIP* scip, /**< SCIP pointer */
4284  SCIP_CONSHDLRDATA* conshdlrdata, /**< SOS1 constraint handler data */
4285  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
4286  int nsos1vars, /**< number of SOS1 variables */
4287  SCIP_Real lpobjval, /**< current LP relaxation solution */
4288  SCIP_Bool bipbranch, /**< TRUE if bipartite branching method should be used */
4289  int nstrongrounds, /**< number of strong branching rounds */
4290  SCIP_Bool* verticesarefixed, /**< vector that indicates which variables are currently fixed to zero */
4291  int* fixingsnode1, /**< pointer to store vertices of variables that will be fixed to zero for the first node (size = nsos1vars) */
4292  int* fixingsnode2, /**< pointer to store vertices of variables that will be fixed to zero for the second node (size = nsos1vars) */
4293  int* vertexbestprior, /**< pointer to store vertex with the best strong branching priority */
4294  SCIP_Real* bestobjval1, /**< pointer to store LP objective for left child node of branching decision with best priority */
4295  SCIP_Real* bestobjval2, /**< pointer to store LP objective for right child node of branching decision with best priority */
4296  SCIP_RESULT* result /**< pointer to store result of strong branching */
4297  )
4298 {
4299  SCIP_Real* branchpriors = NULL;
4300  int* indsos1vars = NULL;
4301  int* domainfixings = NULL;
4302  int ndomainfixings;
4303  int nfixingsnode1;
4304  int nfixingsnode2;
4305 
4306  SCIP_Bool relsolfeas;
4307  SCIP_Real bestscore;
4308  int lastscorechange;
4309  int maxfailures;
4310 
4311  SCIP_Longint nlpiterations;
4312  SCIP_Longint nlps;
4313  int inititer;
4314  int j;
4315  int i;
4316 
4317  assert( scip != NULL );
4318  assert( conshdlrdata != NULL );
4319  assert( conflictgraph != NULL );
4320  assert( verticesarefixed != NULL );
4321  assert( fixingsnode1 != NULL );
4322  assert( fixingsnode2 != NULL );
4323  assert( vertexbestprior != NULL );
4324  assert( result != NULL );
4325 
4326  /* allocate buffer arrays */
4327  SCIP_CALL( SCIPallocBufferArray(scip, &branchpriors, nsos1vars) );
4328 
4329  /* get branching priorities */
4330  SCIP_CALL( getBranchingPrioritiesSOS1(scip, conshdlrdata, conflictgraph, nsos1vars, verticesarefixed,
4331  bipbranch, fixingsnode1, fixingsnode2, branchpriors, NULL, &relsolfeas) );
4332 
4333  /* if LP relaxation solution is feasible */
4334  if ( relsolfeas )
4335  {
4336  SCIPdebugMessage("all the SOS1 constraints are feasible.\n");
4337  *result = SCIP_FEASIBLE;
4338 
4339  /* free memory */
4340  SCIPfreeBufferArrayNull(scip, &branchpriors);
4341 
4342  return SCIP_OKAY;
4343  }
4344 
4345  /* allocate buffer arrays */
4346  SCIP_CALL( SCIPallocBufferArray(scip, &indsos1vars, nsos1vars) );
4347  SCIP_CALL( SCIPallocBufferArray(scip, &domainfixings, nsos1vars) );
4348 
4349  /* sort branching priorities (descending order) */
4350  for (j = 0; j < nsos1vars; ++j)
4351  indsos1vars[j] = j;
4352  SCIPsortDownRealInt(branchpriors, indsos1vars, nsos1vars);
4353 
4354  /* determine the number of LP iterations to perform in each strong branch */
4355  nlpiterations = SCIPgetNDualResolveLPIterations(scip);
4356  nlps = SCIPgetNDualResolveLPs(scip);
4357  if ( nlps == 0 )
4358  {
4359  nlpiterations = SCIPgetNNodeInitLPIterations(scip);
4360  nlps = SCIPgetNNodeInitLPs(scip);
4361  if ( nlps == 0 )
4362  {
4363  nlpiterations = 1000;
4364  nlps = 1;
4365  }
4366  }
4367  assert(nlps >= 1);
4368 
4369  /* compute number of LP iterations performed per strong branching iteration */
4370  if ( conshdlrdata->nstrongiter == -2 )
4371  {
4372  inititer = (int)(2*nlpiterations / nlps);
4373  inititer = (int)((SCIP_Real)inititer * (1.0 + 20.0/SCIPgetNNodes(scip)));
4374  inititer = MAX(inititer, 10);
4375  inititer = MIN(inititer, 500);
4376  }
4377  else
4378  inititer = conshdlrdata->nstrongiter;
4379 
4380  /* get current LP relaxation solution */
4381  lpobjval = SCIPgetLPObjval(scip);
4382 
4383  /* determine branching variable by strong branching or reduce domain */
4384  ndomainfixings = 0;
4385  lastscorechange = -1;
4386  *vertexbestprior = indsos1vars[0]; /* for the case that nstrongrounds = 0 */
4387  bestscore = -SCIPinfinity(scip);
4388  *bestobjval1 = -SCIPinfinity(scip);
4389  *bestobjval2 = -SCIPinfinity(scip);
4390  maxfailures = nstrongrounds;
4391 
4392  /* for each strong branching round */
4393  for (j = 0; j < nstrongrounds; ++j)
4394  {
4395  int testvertex;
4396 
4397  /* get branching vertex for the current strong branching iteration */
4398  testvertex = indsos1vars[j];
4399 
4400  /* if variable with index 'vertex' does not violate any complementarity in its neighborhood for the current LP relaxation solution */
4401  if ( SCIPisPositive(scip, branchpriors[j]) )
4402  {
4403  SCIP_Bool infeasible1;
4404  SCIP_Bool infeasible2;
4405  SCIP_Bool lperror;
4406  SCIP_Real objval1;
4407  SCIP_Real objval2;
4408  SCIP_Real score;
4409 
4410  /* get vertices of variables that will be fixed to zero for each strong branching execution */
4411  assert( ! verticesarefixed[testvertex] );
4412  SCIP_CALL( getBranchingVerticesSOS1(scip, conflictgraph, verticesarefixed, bipbranch, testvertex, fixingsnode1, &nfixingsnode1, fixingsnode2, &nfixingsnode2) );
4413 
4414  /* get information for first strong branching execution */
4415  SCIP_CALL( performStrongbranchSOS1(scip, conflictgraph, fixingsnode1, nfixingsnode1, fixingsnode2, nfixingsnode2,
4416  inititer, conshdlrdata->fixnonzero, domainfixings, &ndomainfixings, &infeasible1, &objval1, &lperror) );
4417  if ( lperror )
4418  continue;
4419 
4420  /* get information for second strong branching execution */
4421  SCIP_CALL( performStrongbranchSOS1(scip, conflictgraph, fixingsnode2, nfixingsnode2, fixingsnode1, nfixingsnode1,
4422  inititer, FALSE, domainfixings, &ndomainfixings, &infeasible2, &objval2, &lperror) );
4423  if ( lperror )
4424  continue;
4425 
4426  /* if both subproblems are infeasible */
4427  if ( infeasible1 && infeasible2 )
4428  {
4429  SCIPdebugMessage("detected cutoff.\n");
4430 
4431  /* update result */
4432  *result = SCIP_CUTOFF;
4433 
4434  /* free memory */
4435  SCIPfreeBufferArrayNull(scip, &domainfixings);
4436  SCIPfreeBufferArrayNull(scip, &indsos1vars);
4437  SCIPfreeBufferArrayNull(scip, &branchpriors);
4438 
4439  return SCIP_OKAY;
4440  }
4441  else if ( ! infeasible1 && ! infeasible2 ) /* both subproblems are feasible */
4442  {
4443  /* if domain has not been reduced in this for-loop */
4444  if ( ndomainfixings == 0 )
4445  {
4446  score = MAX( REALABS( objval1 - lpobjval ), SCIPfeastol(scip) ) * MAX( REALABS( objval2 - lpobjval ), SCIPfeastol(scip) );/*lint !e666*/
4447 
4448  if ( SCIPisPositive(scip, score - bestscore) )
4449  {
4450  bestscore = score;
4451  *vertexbestprior = testvertex;
4452  *bestobjval1 = objval1;
4453  *bestobjval2 = objval2;
4454 
4455  lastscorechange = j;
4456  }
4457  else if ( j - lastscorechange > maxfailures )
4458  break;
4459  }
4460  }
4461  }
4462  }
4463 
4464  /* if variable fixings have been detected by probing, then reduce domain */
4465  if ( ndomainfixings > 0 )
4466  {
4467  SCIP_NODE* node = SCIPgetCurrentNode(scip);
4468  SCIP_Bool infeasible;
4469 
4470  for (i = 0; i < ndomainfixings; ++i)
4471  {
4472  SCIP_CALL( fixVariableZeroNode(scip, SCIPnodeGetVarSOS1(conflictgraph, domainfixings[i]), node, &infeasible) );
4473  assert( ! infeasible );
4474  }
4475 
4476  SCIPdebugMessage("found %d domain fixings.\n", ndomainfixings);
4477 
4478  /* update result */
4479  *result = SCIP_REDUCEDDOM;
4480  }
4481 
4482  /* free buffer arrays */
4483  SCIPfreeBufferArrayNull(scip, &domainfixings);
4484  SCIPfreeBufferArrayNull(scip, &indsos1vars);
4485  SCIPfreeBufferArrayNull(scip, &branchpriors);
4486 
4487  return SCIP_OKAY;
4488 }
4489 
4490 
4491 /** for two given vertices @p v1 and @p v2 search for a clique in the conflict graph that contains these vertices. From
4492  * this clique, we create a bound constraint.
4493  */
4494 static
4496  SCIP* scip, /**< SCIP pointer */
4497  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
4498  int v1, /**< first vertex that shall be contained in bound constraint */
4499  int v2, /**< second vertex that shall be contained in bound constraint */
4500  SCIP_VAR* boundvar, /**< bound variable of @p v1 and @p v2 (or NULL if not existent) */
4501  SCIP_Bool extend, /**< should @p v1 and @p v2 be greedily extended to a clique of larger size */
4502  SCIP_CONS* cons, /**< bound constraint */
4503  SCIP_Real* feas /**< feasibility value of bound constraint */
4504  )
4505 {
4506  SCIP_NODEDATA* nodedata;
4507  SCIP_Bool addv2 = TRUE;
4508  SCIP_Real solval;
4509  SCIP_VAR* var;
4510  SCIP_Real coef = 0.0;
4511  int nsucc;
4512  int s;
4513 
4514  int* extensions = NULL;
4515  int nextensions = 0;
4516  int nextensionsnew;
4517  int* succ;
4518 
4519  assert( scip != NULL );
4520  assert( conflictgraph != NULL );
4521  assert( cons != NULL );
4522  assert( feas != NULL );
4523 
4524  *feas = 0.0;
4525 
4526  /* add index 'v1' to the clique */
4527  nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, v1);
4528  var = nodedata->var;
4529  assert( boundvar == NULL || SCIPvarCompare(boundvar, nodedata->ubboundvar) == 0 );
4530  solval = SCIPgetSolVal(scip, NULL, var);
4531 
4532  /* if 'v1' and 'v2' have the same bound variable then the bound cut can be strengthened */
4533  if ( boundvar == NULL )
4534  {
4535  if ( SCIPisFeasPositive(scip, solval) )
4536  {
4537  SCIP_Real ub;
4538  ub = SCIPvarGetUbLocal(var);
4539  assert( SCIPisFeasPositive(scip, ub));
4540 
4541  if ( ! SCIPisInfinity(scip, ub) )
4542  coef = 1.0/ub;
4543  }
4544  else if ( SCIPisFeasNegative(scip, solval) )
4545  {
4546  SCIP_Real lb;
4547  lb = SCIPvarGetLbLocal(var);
4548  assert( SCIPisFeasNegative(scip, lb) );
4549  if ( ! SCIPisInfinity(scip, -lb) )
4550  coef = 1.0/lb;
4551  }
4552  }
4553  else if ( boundvar == nodedata->ubboundvar )
4554  {
4555  if ( SCIPisFeasPositive(scip, solval) )
4556  {
4557  SCIP_Real ub;
4558 
4559  ub = nodedata->ubboundcoef;
4560  assert( SCIPisFeasPositive(scip, ub) );
4561  if ( ! SCIPisInfinity(scip, ub) )
4562  coef = 1.0/ub;
4563  }
4564  else if ( SCIPisFeasNegative(scip, solval) )
4565  {
4566  SCIP_Real lb;
4567 
4568  lb = nodedata->lbboundcoef;
4569  assert( SCIPisFeasPositive(scip, lb) );
4570  if ( ! SCIPisInfinity(scip, lb) )
4571  coef = 1.0/lb;
4572  }
4573  }
4574 
4575  if ( ! SCIPisZero(scip, coef) )
4576  {
4577  *feas += coef * solval;
4578  SCIP_CALL( SCIPaddCoefLinear(scip, cons, var, coef) );
4579  }
4580 
4581  /* if clique shall be greedily extended to a clique of larger size */
4582  if ( extend )
4583  {
4584  /* get successors */
4585  nsucc = SCIPdigraphGetNSuccessors(conflictgraph, v1);
4586  succ = SCIPdigraphGetSuccessors(conflictgraph, v1);
4587  assert( nsucc > 0 );
4588 
4589  /* allocate buffer array */
4590  SCIP_CALL( SCIPallocBufferArray(scip, &extensions, nsucc) );
4591 
4592  /* get possible extensions for the clique cover */
4593  for (s = 0; s < nsucc; ++s)
4594  extensions[s] = succ[s];
4595  nextensions = nsucc;
4596  }
4597  else
4598  nextensions = 1;
4599 
4600  /* while there exist possible extensions for the clique cover */
4601  while ( nextensions > 0 )
4602  {
4603  SCIP_Real bestbigMval;
4604  SCIP_Real bigMval;
4605  int bestindex = -1;
4606  int ext;
4607 
4608  bestbigMval = -SCIPinfinity(scip);
4609 
4610  /* if v2 has not been added to clique already */
4611  if ( addv2 )
4612  {
4613  bestindex = v2;
4614  addv2 = FALSE;
4615  }
4616  else /* search for the extension with the largest absolute value of its LP relaxation solution value */
4617  {
4618  assert( extensions != NULL );
4619  for (s = 0; s < nextensions; ++s)
4620  {
4621  ext = extensions[s];
4622  bigMval = nodeGetSolvalBinaryBigMSOS1(scip, conflictgraph, NULL, ext);
4623  if ( SCIPisFeasLT(scip, bestbigMval, bigMval) )
4624  {
4625  bestbigMval = bigMval;
4626  bestindex = ext;
4627  }
4628  }
4629  }
4630  assert( bestindex != -1 );
4631 
4632  /* add bestindex variable to the constraint */
4633  nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, bestindex);
4634  var = nodedata->var;
4635  solval = SCIPgetSolVal(scip, NULL, var);
4636  coef = 0.0;
4637  if ( boundvar == NULL )
4638  {
4639  if ( SCIPisFeasPositive(scip, solval) )
4640  {
4641  SCIP_Real ub;
4642  ub = SCIPvarGetUbLocal(var);
4643  assert( SCIPisFeasPositive(scip, ub));
4644 
4645  if ( ! SCIPisInfinity(scip, ub) )
4646  coef = 1.0/ub;
4647  }
4648  else if ( SCIPisFeasNegative(scip, solval) )
4649  {
4650  SCIP_Real lb;
4651  lb = SCIPvarGetLbLocal(var);
4652  assert( SCIPisFeasNegative(scip, lb) );
4653  if ( ! SCIPisInfinity(scip, -lb) )
4654  coef = 1.0/lb;
4655  }
4656  }
4657  else if ( boundvar == nodedata->ubboundvar )
4658  {
4659  if ( SCIPisFeasPositive(scip, solval) )
4660  {
4661  SCIP_Real ub;
4662 
4663  ub = nodedata->ubboundcoef;
4664  assert( SCIPisFeasPositive(scip, ub) );
4665  if ( ! SCIPisInfinity(scip, ub) )
4666  coef = 1.0/ub;
4667  }
4668  else if ( SCIPisFeasNegative(scip, solval) )
4669  {
4670  SCIP_Real lb;
4671 
4672  lb = nodedata->lbboundcoef;
4673  assert( SCIPisFeasPositive(scip, lb) );
4674  if ( ! SCIPisInfinity(scip, -lb) )
4675  coef = 1.0/lb;
4676  }
4677  }
4678  if ( ! SCIPisZero(scip, coef) )
4679  {
4680  *feas += coef * solval;
4681  SCIP_CALL( SCIPaddCoefLinear(scip, cons, var, coef) );
4682  }
4683 
4684  if ( extend )
4685  {
4686  assert( extensions != NULL );
4687  /* compute new 'extensions' array */
4688  nextensionsnew = 0;
4689  for (s = 0; s < nextensions; ++s)
4690  {
4691  if ( s != bestindex && isConnectedSOS1(NULL, conflictgraph, bestindex, extensions[s]) )
4692  extensions[nextensionsnew++] = extensions[s];
4693  }
4694  nextensions = nextensionsnew;
4695  }
4696  else
4697  nextensions = 0;
4698  }
4699 
4700  /* free buffer array */
4701  if ( extend )
4702  SCIPfreeBufferArray(scip, &extensions);
4703 
4704  /* subtract rhs of constraint from feasibility value or add bound variable if existent */
4705  if ( boundvar == NULL )
4706  *feas -= 1.0;
4707  else
4708  {
4709  SCIP_CALL( SCIPaddCoefLinear(scip, cons, boundvar, -1.0) );
4710  *feas -= SCIPgetSolVal(scip, NULL, boundvar);
4711  }
4712 
4713  return SCIP_OKAY;
4714 }
4715 
4716 
4717 /** tries to add feasible complementarity constraints to a given child branching node.
4718  *
4719  * @note In this function the conflict graph is updated to the conflict graph of the considered child branching node.
4720  */
4721 static
4723  SCIP* scip, /**< SCIP pointer */
4724  SCIP_NODE* node, /**< branching node */
4725  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
4726  SCIP_DIGRAPH* conflictgraph, /**< conflict graph of the current node */
4727  SCIP_DIGRAPH* localconflicts, /**< local conflicts (updates to local conflicts of child node) */
4728  int nsos1vars, /**< number of SOS1 variables */
4729  SCIP_Bool* verticesarefixed, /**< vector that indicates which variables are currently fixed to zerox */
4730  int* fixingsnode1, /**< vertices of variables that will be fixed to zero for the branching node in the input of this function */
4731  int nfixingsnode1, /**< number of entries of array nfixingsnode1 */
4732  int* fixingsnode2, /**< vertices of variables that will be fixed to zero for the other branching node */
4733  int nfixingsnode2, /**< number of entries of array nfixingsnode2 */
4734  int* naddedconss, /**< pointer to store the number of added SOS1 constraints */
4735  SCIP_Bool onlyviolsos1 /**< should only SOS1 constraints be added that are violated by the LP solution */
4736  )
4737 {
4738  assert( scip != NULL );
4739  assert( node != NULL );
4740  assert( conshdlrdata != NULL );
4741  assert( conflictgraph != NULL );
4742  assert( verticesarefixed != NULL );
4743  assert( fixingsnode1 != NULL );
4744  assert( fixingsnode2 != NULL );
4745  assert( naddedconss != NULL );
4746 
4747  *naddedconss = 0;
4748 
4749  if ( nfixingsnode2 > 1 )
4750  {
4751  int* fixingsnode21; /* first partition of fixingsnode2 */
4752  int* fixingsnode22; /* second partition of fixingsnode2 */
4753  int nfixingsnode21;
4754  int nfixingsnode22;
4755 
4756  int* coverarray; /* vertices, not in fixingsnode1 that cover all the vertices in array fixingsnode22 */
4757  int ncoverarray;
4758 
4759  SCIP_Bool* mark;
4760  int* succarray;
4761  int nsuccarray;
4762  int* succ;
4763  int nsucc;
4764 
4765  int i;
4766  int s;
4767 
4768  /* allocate buffer arrays */
4769  SCIP_CALL( SCIPallocBufferArray(scip, &succarray, nsos1vars) );
4770  SCIP_CALL( SCIPallocBufferArray(scip, &mark, nsos1vars) );
4771  SCIP_CALL( SCIPallocBufferArray(scip, &fixingsnode21, nfixingsnode2) );
4772  SCIP_CALL( SCIPallocBufferArray(scip, &fixingsnode22, nfixingsnode2) );
4773 
4774  /* mark all the unfixed vertices with FALSE */
4775  for (i = 0; i < nsos1vars; ++i)
4776  mark[i] = (verticesarefixed[i]);
4777 
4778  /* mark all the vertices that are in the set fixingsnode1 */
4779  for (i = 0; i < nfixingsnode1; ++i)
4780  {
4781  assert( nfixingsnode1 <= 1 || (fixingsnode1[nfixingsnode1 - 1] > fixingsnode1[nfixingsnode1 - 2]) ); /* test: vertices are sorted */
4782  mark[fixingsnode1[i]] = TRUE;
4783  }
4784 
4785  /* mark all the vertices that are in the set fixingsnode2 */
4786  for (i = 0; i < nfixingsnode2; ++i)
4787  {
4788  assert( nfixingsnode2 <= 1 || (fixingsnode2[nfixingsnode2 - 1] > fixingsnode2[nfixingsnode2 - 2]) ); /* test: vertices are sorted */
4789  mark[fixingsnode2[i]] = TRUE;
4790  }
4791 
4792  /* compute the set of vertices that have a neighbor in the set fixingsnode2, but are not in the set fixingsnode1 or fixingsnode2 and are not already fixed */
4793  nsuccarray = 0;
4794  for (i = 0; i < nfixingsnode2; ++i)
4795  {
4796  nsucc = SCIPdigraphGetNSuccessors(conflictgraph, fixingsnode2[i]);
4797  succ = SCIPdigraphGetSuccessors(conflictgraph, fixingsnode2[i]);
4798 
4799  for (s = 0; s < nsucc; ++s)
4800  {
4801  int succnode = succ[s];
4802 
4803  if ( ! mark[succnode] )
4804  {
4805  mark[succnode] = TRUE;
4806  succarray[nsuccarray++] = succnode;
4807  }
4808  }
4809  }
4810 
4811  /* allocate buffer array */
4812  SCIP_CALL( SCIPallocBufferArray(scip, &coverarray, nsuccarray) );
4813 
4814  /* mark all the vertices with FALSE */
4815  for (i = 0; i < nsos1vars; ++i)
4816  mark[i] = FALSE;
4817 
4818  /* mark all the vertices that are in the set fixingsnode2 */
4819  for (i = 0; i < nfixingsnode2; ++i)
4820  mark[fixingsnode2[i]] = TRUE;
4821 
4822  /* for every node in succarray */
4823  for (i = 0; i < nsuccarray; ++i)
4824  {
4825  SCIP_Real solval1;
4826  SCIP_VAR* var1;
4827  int vertex1;
4828  int j;
4829 
4830  vertex1 = succarray[i];
4831  var1 = SCIPnodeGetVarSOS1(conflictgraph, vertex1);
4832  solval1 = SCIPgetSolVal(scip, NULL, var1);
4833 
4834  /* we only add complementarity constraints if they are violated by the current LP solution */
4835  if ( ! onlyviolsos1 || ! SCIPisFeasZero(scip, solval1) )
4836  {
4837  /* compute first partition of fixingsnode2 that is the intersection of the neighbors of 'vertex1' with the set fixingsnode2 */
4838  nsucc = SCIPdigraphGetNSuccessors(conflictgraph, vertex1);
4839  succ = SCIPdigraphGetSuccessors(conflictgraph, vertex1);
4840  nfixingsnode21 = 0;
4841 
4842  for (s = 0; s < nsucc; ++s)
4843  {
4844  if ( mark[succ[s]] )
4845  {
4846  fixingsnode21[nfixingsnode21++] = succ[s];
4847  assert( nfixingsnode21 == 1 || (fixingsnode21[nfixingsnode21 - 1] > fixingsnode21[nfixingsnode21 - 2]) ); /* test: successor vertices are sorted */
4848  }
4849  }
4850 
4851  /* if variable can be fixed to zero */
4852  if ( nfixingsnode21 == nfixingsnode2 )
4853  {
4854  SCIP_Bool infeasible;
4855 
4856  SCIP_CALL( fixVariableZeroNode(scip, var1, node, &infeasible) );
4857  assert( ! infeasible );
4858  continue;
4859  }
4860 
4861  /* compute second partition of fixingsnode2 (that is fixingsnode2 \setminus fixingsnode21 ) */
4862  SCIP_CALL( SCIPcomputeArraysSetminus(fixingsnode2, nfixingsnode2, fixingsnode21, nfixingsnode21, fixingsnode22, &nfixingsnode22) );
4863  assert ( nfixingsnode22 + nfixingsnode21 == nfixingsnode2 );
4864 
4865  /* compute cover set (that are all the vertices not in fixingsnode1 and fixingsnode21, whose neighborhood covers all the vertices of fixingsnode22) */
4866  SCIP_CALL( getCoverVertices(conflictgraph, verticesarefixed, -1, fixingsnode22, nfixingsnode22, coverarray, &ncoverarray) );
4867  SCIP_CALL( SCIPcomputeArraysSetminus(coverarray, ncoverarray, fixingsnode1, nfixingsnode1, coverarray, &ncoverarray) );
4868  SCIP_CALL( SCIPcomputeArraysSetminus(coverarray, ncoverarray, fixingsnode21, nfixingsnode21, coverarray, &ncoverarray) );
4869 
4870  for (j = 0; j < ncoverarray; ++j)
4871  {
4872  int vertex2;
4873 
4874  vertex2 = coverarray[j];
4875  assert( vertex2 != vertex1 );
4876 
4877  /* prevent double enumeration */
4878  if ( vertex2 < vertex1 )
4879  {
4880  SCIP_VAR* var2;
4881  SCIP_Real solval2;
4882 
4883  var2 = SCIPnodeGetVarSOS1(conflictgraph, vertex2);
4884  solval2 = SCIPgetSolVal(scip, NULL, var2);
4885 
4886  if ( onlyviolsos1 && ( SCIPisFeasZero(scip, solval1) || SCIPisFeasZero(scip, solval2) ) )
4887  continue;
4888 
4889  if ( ! isConnectedSOS1(NULL, conflictgraph, vertex1, vertex2) )
4890  {
4891  char name[SCIP_MAXSTRLEN];
4892  SCIP_CONS* conssos1 = NULL;
4893  SCIP_Bool takebound = FALSE;
4894  SCIP_Real feas;
4895 
4896  SCIP_NODEDATA* nodedata;
4897  SCIP_Real lbboundcoef1;
4898  SCIP_Real lbboundcoef2;
4899  SCIP_Real ubboundcoef1;
4900  SCIP_Real ubboundcoef2;
4901  SCIP_VAR* boundvar1;
4902  SCIP_VAR* boundvar2;
4903 
4904  /* get bound variables if available */
4905  nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, vertex1);
4906  assert( nodedata != NULL );
4907  boundvar1 = nodedata->ubboundvar;
4908  lbboundcoef1 = nodedata->lbboundcoef;
4909  ubboundcoef1 = nodedata->ubboundcoef;
4910  nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, vertex2);
4911  assert( nodedata != NULL );
4912  boundvar2 = nodedata->ubboundvar;
4913  lbboundcoef2 = nodedata->lbboundcoef;
4914  ubboundcoef2 = nodedata->ubboundcoef;
4915 
4916  if ( boundvar1 != NULL && boundvar2 != NULL && SCIPvarCompare(boundvar1, boundvar2) == 0 )
4917  takebound = TRUE;
4918 
4919  /* add new arc to local conflicts in order to generate tighter bound inequalities */
4920  if ( conshdlrdata->addextendedbds )
4921  {
4922  if ( localconflicts == NULL )
4923  {
4924  SCIP_CALL( SCIPdigraphCreate(&conshdlrdata->localconflicts, nsos1vars) );
4925  localconflicts = conshdlrdata->localconflicts;
4926  }
4927  SCIP_CALL( SCIPdigraphAddArc(localconflicts, vertex1, vertex2, NULL) );
4928  SCIP_CALL( SCIPdigraphAddArc(localconflicts, vertex2, vertex1, NULL) );
4929  SCIP_CALL( SCIPdigraphAddArc(conflictgraph, vertex1, vertex2, NULL) );
4930  SCIP_CALL( SCIPdigraphAddArc(conflictgraph, vertex2, vertex1, NULL) );
4931 
4932  /* can sort successors in place - do not use arcdata */
4933  SCIPsortInt(SCIPdigraphGetSuccessors(localconflicts, vertex1), SCIPdigraphGetNSuccessors(localconflicts, vertex1));
4934  SCIPsortInt(SCIPdigraphGetSuccessors(localconflicts, vertex2), SCIPdigraphGetNSuccessors(localconflicts, vertex2));
4935  SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, vertex1), SCIPdigraphGetNSuccessors(conflictgraph, vertex1));
4936  SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, vertex2), SCIPdigraphGetNSuccessors(conflictgraph, vertex2));
4937 
4938  /* mark conflictgraph as not local such that the new arcs are deleted after currents node processing */
4939  conshdlrdata->isconflocal = TRUE;
4940  }
4941 
4942  /* measure feasibility of complementarity between var1 and var2 */
4943  if ( ! takebound )
4944  {
4945  feas = -1.0;
4946  if ( SCIPisFeasPositive(scip, solval1) )
4947  {
4948  assert( SCIPisFeasPositive(scip, SCIPvarGetUbLocal(var1)));
4949  if ( ! SCIPisInfinity(scip, SCIPvarGetUbLocal(var1)) )
4950  feas += solval1/SCIPvarGetUbLocal(var1);
4951  }
4952  else if ( SCIPisFeasNegative(scip, solval1) )
4953  {
4954  assert( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(var1)));
4955  if ( ! SCIPisInfinity(scip, -SCIPvarGetLbLocal(var1)) )
4956  feas += solval1/SCIPvarGetLbLocal(var1);
4957  }
4958 
4959  if ( SCIPisFeasPositive(scip, solval2) )
4960  {
4961  assert( SCIPisFeasPositive(scip, SCIPvarGetUbLocal(var2)));
4962  if ( ! SCIPisInfinity(scip, SCIPvarGetUbLocal(var2)) )
4963  feas += solval2/SCIPvarGetUbLocal(var2);
4964  }
4965  else if ( SCIPisFeasNegative(scip, solval2) )
4966  {
4967  assert( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(var2)));
4968  if ( ! SCIPisInfinity(scip, -SCIPvarGetLbLocal(var2)) )
4969  feas += solval2/SCIPvarGetLbLocal(var2);
4970  }
4971  }
4972  else
4973  {
4974  feas = -SCIPgetSolVal(scip, NULL, boundvar1);
4975  if ( SCIPisFeasPositive(scip, solval1) )
4976  {
4977  assert( SCIPisFeasPositive(scip, ubboundcoef1));
4978  if ( ! SCIPisInfinity(scip, ubboundcoef1) )
4979  feas += solval1/ubboundcoef1;
4980  }
4981  else if ( SCIPisFeasNegative(scip, solval1) )
4982  {
4983  assert( SCIPisFeasPositive(scip, lbboundcoef1));
4984  if ( ! SCIPisInfinity(scip, -lbboundcoef1) )
4985  feas += solval1/lbboundcoef1;
4986  }
4987 
4988  if ( SCIPisFeasPositive(scip, solval2) )
4989  {
4990  assert( SCIPisFeasPositive(scip, ubboundcoef2));
4991  if ( ! SCIPisInfinity(scip, ubboundcoef2) )
4992  feas += solval2/ubboundcoef2;
4993  }
4994  else if ( SCIPisFeasNegative(scip, solval2) )
4995  {
4996  assert( SCIPisFeasPositive(scip, lbboundcoef2));
4997  if ( ! SCIPisInfinity(scip, -lbboundcoef2) )
4998  feas += solval2/lbboundcoef2;
4999  }
5000  assert( ! SCIPisFeasNegative(scip, solval2) );
5001  }
5002 
5003  if ( SCIPisGT(scip, feas, conshdlrdata->addcompsfeas) )
5004  {
5005  /* create SOS1 constraint */
5006  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "sos1_branchnode_%i_no_%i", SCIPnodeGetNumber(node), *naddedconss);
5007  SCIP_CALL( SCIPcreateConsSOS1(scip, &conssos1, name, 0, NULL, NULL, TRUE, TRUE, TRUE, FALSE, TRUE,
5008  TRUE, FALSE, FALSE, FALSE) );
5009 
5010  /* add variables to SOS1 constraint */
5011  SCIP_CALL( addVarSOS1(scip, conssos1, conshdlrdata, var1, 1.0) );
5012  SCIP_CALL( addVarSOS1(scip, conssos1, conshdlrdata, var2, 2.0) );
5013 
5014  /* add SOS1 constraint to the branching node */
5015  SCIP_CALL( SCIPaddConsNode(scip, node, conssos1, NULL) );
5016  ++(*naddedconss);
5017 
5018  /* release constraint */
5019  SCIP_CALL( SCIPreleaseCons(scip, &conssos1) );
5020  }
5021 
5022 
5023  /* add bound inequality*/
5024  if ( ! SCIPisFeasZero(scip, solval1) && ! SCIPisFeasZero(scip, solval2) )
5025  {
5026  /* possibly create linear constraint of the form x_i/u_i + x_j/u_j <= t if a bound variable t with x_i <= u_i * t and x_j <= u_j * t exists.
5027  * Otherwise try to create a constraint of the form x_i/u_i + x_j/u_j <= 1. Try the same for the lower bounds. */
5028  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "boundcons_branchnode_%i_no_%i", SCIPnodeGetNumber(node), *naddedconss);
5029  if ( takebound )
5030  {
5031  /* create constraint with right hand side = 0.0 */
5032  SCIP_CALL( SCIPcreateConsLinear(scip, &conssos1, name, 0, NULL, NULL, -SCIPinfinity(scip), 0.0, TRUE, FALSE, TRUE, FALSE, FALSE,
5033  TRUE, FALSE, FALSE, FALSE, FALSE) );
5034 
5035  /* add variables */
5036  SCIP_CALL( getBoundConsFromVertices(scip, conflictgraph, vertex1, vertex2, boundvar1, conshdlrdata->addextendedbds, conssos1, &feas) );
5037  }
5038  else
5039  {
5040  /* create constraint with right hand side = 1.0 */
5041  SCIP_CALL( SCIPcreateConsLinear(scip, &conssos1, name, 0, NULL, NULL, -SCIPinfinity(scip), 1.0, TRUE, FALSE, TRUE, FALSE, FALSE,
5042  TRUE, FALSE, FALSE, FALSE, FALSE) );
5043 
5044  /* add variables */
5045  SCIP_CALL( getBoundConsFromVertices(scip, conflictgraph, vertex1, vertex2, NULL, conshdlrdata->addextendedbds, conssos1, &feas) );
5046  }
5047 
5048  /* add linear constraint to the branching node if usefull */
5049  if ( SCIPisGT(scip, feas, conshdlrdata->addbdsfeas ) )
5050  {
5051  SCIP_CALL( SCIPaddConsNode(scip, node, conssos1, NULL) );
5052  ++(*naddedconss);
5053  }
5054 
5055  /* release constraint */
5056  SCIP_CALL( SCIPreleaseCons(scip, &conssos1) );
5057  }
5058 
5059  /* break if number of added constraints exceeds a predefined value */
5060  if ( conshdlrdata->maxaddcomps >= 0 && *naddedconss > conshdlrdata->maxaddcomps )
5061  break;
5062  }
5063  }
5064  }
5065  }
5066 
5067  /* break if number of added constraints exceeds a predefined value */
5068  if ( conshdlrdata->maxaddcomps >= 0 && *naddedconss > conshdlrdata->maxaddcomps )
5069  break;
5070  }
5071 
5072  /* free buffer array */
5073  SCIPfreeBufferArray(scip, &coverarray);
5074  SCIPfreeBufferArray(scip, &fixingsnode22);
5075  SCIPfreeBufferArray(scip, &fixingsnode21);
5076  SCIPfreeBufferArray(scip, &mark);
5077  SCIPfreeBufferArray(scip, &succarray);
5078  }
5079 
5080  return SCIP_OKAY;
5081 }
5082 
5083 
5084 /** resets local conflict graph to the conflict graph of the root node */
5085 static
5087  SCIP_DIGRAPH* conflictgraph, /**< conflict graph of root node */
5088  SCIP_DIGRAPH* localconflicts, /**< local conflicts that should be removed from conflict graph */
5089  int nsos1vars /**< number of SOS1 variables */
5090  )
5092  int j;
5093 
5094  for (j = 0; j < nsos1vars; ++j)
5095  {
5096  int nsuccloc;
5097 
5098  nsuccloc = SCIPdigraphGetNSuccessors(localconflicts, j);
5099  if ( nsuccloc > 0 )
5100  {
5101  int* succloc;
5102  int* succ;
5103  int nsucc;
5104  int k = 0;
5105 
5106  succloc = SCIPdigraphGetSuccessors(localconflicts, j);
5107  succ = SCIPdigraphGetSuccessors(conflictgraph, j);
5108  nsucc = SCIPdigraphGetNSuccessors(conflictgraph, j);
5109 
5110  /* reset number of successors */
5111  SCIP_CALL( SCIPcomputeArraysSetminus(succ, nsucc, succloc, nsuccloc, succ, &k) );
5112  SCIP_CALL( SCIPdigraphSetNSuccessors(conflictgraph, j, k) );
5113  SCIP_CALL( SCIPdigraphSetNSuccessors(localconflicts, j, 0) );
5114  }
5115  }
5116 
5117  return SCIP_OKAY;
5118 }
5119 
5120 
5121 /** Conflict graph enforcement method
5122  *
5123  * The conflict graph can be enforced by different branching rules:
5124  *
5125  * - Branch on the neighborhood of a single variable @p i, i.e., in one branch \f$x_i\f$ is fixed to zero and in the
5126  * other its neighbors from the conflict graph.
5127  *
5128  * - Branch on complete bipartite subgraphs of the conflict graph, i.e., in one branch fix the variables from the first
5129  * bipartite partition and the variables from the second bipartite partition in the other.
5130  *
5131  * - In addition to variable domain fixings, it is sometimes also possible to add new SOS1 constraints to the branching
5132  * nodes. This results in a nonstatic conflict graph, which may change dynamically with every branching node.
5133  *
5134  * We make use of different selection rules that define on which system of SOS1 variables to branch next:
5135  *
5136  * - Most infeasible branching: Branch on the system of SOS1 variables with largest violation.
5137  *
5138  * - Strong branching: Here, the LP-relaxation is partially solved for each branching decision among a candidate list.
5139  * Then the decision with best progress is chosen.
5140  */
5141 static
5143  SCIP* scip, /**< SCIP pointer */
5144  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5145  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5146  int nconss, /**< number of constraints */
5147  SCIP_CONS** conss, /**< SOS1 constraints */
5148  SCIP_RESULT* result /**< result */
5149  )
5150 {
5151  SCIP_DIGRAPH* conflictgraph;
5152  int nsos1vars;
5153 
5154  SCIP_Bool* verticesarefixed = NULL;
5155  int* fixingsnode1 = NULL;
5156  int* fixingsnode2 = NULL;
5157  int nfixingsnode1;
5158  int nfixingsnode2;
5159 
5160  SCIP_Real bestobjval1 = -SCIPinfinity(scip);
5161  SCIP_Real bestobjval2 = -SCIPinfinity(scip);
5162  SCIP_Real lpobjval = -SCIPinfinity(scip);
5163 
5164  SCIP_Bool infeasible;
5165  SCIP_Bool bipbranch = FALSE;
5166  int nstrongrounds;
5167 
5168  int branchvertex;
5169  SCIP_NODE* node1;
5170  SCIP_NODE* node2;
5171  SCIP_Real nodeselest;
5172  SCIP_Real objest;
5173 
5174  int i;
5175  int j;
5176  int c;
5177 
5178  assert( scip != NULL );
5179  assert( conshdlrdata != NULL );
5180  assert( conshdlr != NULL );
5181  assert( conss != NULL );
5182  assert( result != NULL );
5183 
5184  SCIPdebugMessage("Enforcing SOS1 conflict graph <%s>.\n", SCIPconshdlrGetName(conshdlr) );
5185  *result = SCIP_DIDNOTRUN;
5186 
5187  /* get number of SOS1 variables */
5188  nsos1vars = conshdlrdata->nsos1vars;
5189 
5190  /* get conflict graph */
5191  conflictgraph = conshdlrdata->conflictgraph;
5192  assert( ! conshdlrdata->isconflocal ); /* conflictgraph should be the one of the root node */
5193 
5194  /* check each constraint and update conflict graph if necessary */
5195  for (c = 0; c < nconss; ++c)
5196  {
5197  SCIP_CONSDATA* consdata;
5198  SCIP_CONS* cons;
5199  SCIP_Bool cutoff;
5200  int ngen;
5201 
5202  cons = conss[c];
5203  assert( cons != NULL );
5204  consdata = SCIPconsGetData(cons);
5205  assert( consdata != NULL );
5206 
5207  /* do nothing if there are not enough variables - this is usually eliminated by preprocessing */
5208  if ( consdata->nvars < 2 )
5209  continue;
5210 
5211  /* first perform propagation (it might happen that standard propagation is turned off) */
5212  ngen = 0;
5213  SCIP_CALL( propConsSOS1(scip, cons, consdata, &cutoff, &ngen) );
5214  SCIPdebugMessage("propagating <%s> in enforcing (cutoff: %u, domain reductions: %d).\n", SCIPconsGetName(cons), cutoff, ngen);
5215  if ( cutoff )
5216  {
5217  *result = SCIP_CUTOFF;
5218 
5219  /* remove local conflicts from conflict graph */
5220  if ( conshdlrdata->isconflocal )
5221  {
5222  SCIP_CALL( resetConflictgraphSOS1(conflictgraph, conshdlrdata->localconflicts, nsos1vars) );
5223  conshdlrdata->isconflocal = FALSE;
5224  }
5225  return SCIP_OKAY;
5226  }
5227  if ( ngen > 0 )
5228  {
5229  *result = SCIP_REDUCEDDOM;
5230 
5231  /* remove local conflicts from conflict graph */
5232  if ( conshdlrdata->isconflocal )
5233  {
5234  SCIP_CALL( resetConflictgraphSOS1(conflictgraph, conshdlrdata->localconflicts, nsos1vars) );
5235  conshdlrdata->isconflocal = FALSE;
5236  }
5237  return SCIP_OKAY;
5238  }
5239  assert( ngen == 0 );
5240 
5241  /* add local conflicts to conflict graph and save them in 'localconflicts' */
5242  if ( consdata->local )
5243  {
5244  SCIP_VAR** vars;
5245  int nvars;
5246  int indi;
5247  int indj;
5248 
5249  if ( conshdlrdata->localconflicts == NULL )
5250  {
5251  SCIP_CALL( SCIPdigraphCreate(&conshdlrdata->localconflicts, nsos1vars ) );
5252  }
5253 
5254  vars = consdata->vars;
5255  nvars = consdata->nvars;
5256  for (i = 0; i < nvars-1; ++i)
5257  {
5258  SCIP_VAR* var;
5259 
5260  var = vars[i];
5261  indi = varGetNodeSOS1(conshdlrdata, var);
5262  assert( indi >= 0 );
5263 
5264  if ( ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) || ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) )
5265  {
5266  for (j = i+1; j < nvars; ++j)
5267  {
5268  var = vars[j];
5269  indj = varGetNodeSOS1(conshdlrdata, var);
5270  assert( indj >= 0 );
5271 
5272  if ( indj >= 0 )
5273  {
5274  if ( ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) || ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) )
5275  {
5276  SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraph, indi, indj, NULL) );
5277  SCIP_CALL( SCIPdigraphAddArcSafe(conflictgraph, indj, indi, NULL) );
5278 
5279  SCIP_CALL( SCIPdigraphAddArcSafe(conshdlrdata->localconflicts, indi, indj, NULL) );
5280  SCIP_CALL( SCIPdigraphAddArcSafe(conshdlrdata->localconflicts, indj, indi, NULL) );
5281 
5282  conshdlrdata->isconflocal = TRUE;
5283  }
5284  }
5285  }
5286  }
5287  }
5288  }
5289  }
5290 
5291  /* sort successor list of conflict graph if necessary */
5292  if ( conshdlrdata->isconflocal )
5293  {
5294  for (j = 0; j < nsos1vars; ++j)
5295  {
5296  int nsuccloc;
5297 
5298  nsuccloc = SCIPdigraphGetNSuccessors(conshdlrdata->localconflicts, j);
5299  if ( nsuccloc > 0 )
5300  {
5301  SCIPsortInt(SCIPdigraphGetSuccessors(conflictgraph, j), SCIPdigraphGetNSuccessors(conflictgraph, j));
5302  SCIPsortInt(SCIPdigraphGetSuccessors(conshdlrdata->localconflicts, j), nsuccloc);
5303  }
5304  }
5305  }
5306 
5307  /* detect fixed variables */
5308  SCIP_CALL( SCIPallocBufferArray(scip, &verticesarefixed, nsos1vars) );
5309  for (j = 0; j < nsos1vars; ++j)
5310  {
5311  SCIP_VAR* var;
5312  SCIP_Real ub;
5313  SCIP_Real lb;
5314 
5315  var = SCIPnodeGetVarSOS1(conflictgraph, j);
5316  ub = SCIPvarGetUbLocal(var);
5317  lb = SCIPvarGetLbLocal(var);
5318  if ( SCIPisFeasZero(scip, ub) && SCIPisFeasZero(scip, lb) )
5319  verticesarefixed[j] = TRUE;
5320  else
5321  verticesarefixed[j] = FALSE;
5322  }
5323 
5324  /* should bipartite branching be used? */
5325  if ( conshdlrdata->bipbranch )
5326  bipbranch = TRUE;
5327 
5328  /* determine number of strong branching iterations */
5329  if ( conshdlrdata->nstrongrounds >= 0 )
5330  nstrongrounds = MIN(conshdlrdata->nstrongrounds, nsos1vars);
5331  else
5332  {
5333  /* determine number depending on depth, based on heuristical considerations */
5334  if ( SCIPgetDepth(scip) <= 10 )
5335  nstrongrounds = MAX(10, (int)SCIPfloor(scip, pow(log((SCIP_Real)nsos1vars), 1.0)));/*lint !e666*/
5336  else if ( SCIPgetDepth(scip) <= 20 )
5337  nstrongrounds = MAX(5, (int)SCIPfloor(scip, pow(log((SCIP_Real)nsos1vars), 0.7)));/*lint !e666*/
5338  else
5339  nstrongrounds = 0;
5340  nstrongrounds = MIN(nsos1vars, nstrongrounds);
5341  }
5342 
5343 
5344  /* allocate buffer arrays */
5345  SCIP_CALL( SCIPallocBufferArray(scip, &fixingsnode1, nsos1vars) );
5346  if ( bipbranch )
5347  SCIP_CALL( SCIPallocBufferArray(scip, &fixingsnode2, nsos1vars) );
5348  else
5349  SCIP_CALL( SCIPallocBufferArray(scip, &fixingsnode2, 1) );
5350 
5351 
5352  /* if strongbranching is turned off: use most infeasible branching */
5353  if ( nstrongrounds == 0 )
5354  {
5355  SCIP_Bool relsolfeas;
5356 
5357  /* get branching vertex using most infeasible branching */
5358  SCIP_CALL( getBranchingPrioritiesSOS1(scip, conshdlrdata, conflictgraph, nsos1vars, verticesarefixed, bipbranch, fixingsnode1, fixingsnode2, NULL, &branchvertex, &relsolfeas) );
5359 
5360  /* if LP relaxation solution is feasible */
5361  if ( relsolfeas )
5362  {
5363  SCIPdebugMessage("all the SOS1 constraints are feasible.\n");
5364 
5365  /* update result */
5366  *result = SCIP_FEASIBLE;
5367 
5368  /* remove local conflicts from conflict graph */
5369  if ( conshdlrdata->isconflocal )
5370  {
5371  SCIP_CALL( resetConflictgraphSOS1(conflictgraph, conshdlrdata->localconflicts, nsos1vars) );
5372  conshdlrdata->isconflocal = FALSE;
5373  }
5374 
5375  /* free memory */
5376  SCIPfreeBufferArrayNull(scip, &fixingsnode2);
5377  SCIPfreeBufferArrayNull(scip, &fixingsnode1);
5378  SCIPfreeBufferArrayNull(scip, &verticesarefixed);
5379 
5380  return SCIP_OKAY;
5381  }
5382  }
5383  else
5384  {
5385  /* get branching vertex using strong branching */
5386  SCIP_CALL( getBranchingDecisionStrongbranchSOS1(scip, conshdlrdata, conflictgraph, nsos1vars, lpobjval, bipbranch, nstrongrounds, verticesarefixed,
5387  fixingsnode1, fixingsnode2, &branchvertex, &bestobjval1, &bestobjval2, result) );
5388 
5389  if ( *result == SCIP_CUTOFF || *result == SCIP_FEASIBLE || *result == SCIP_REDUCEDDOM )
5390  {
5391  /* remove local conflicts from conflict graph */
5392  if ( conshdlrdata->isconflocal )
5393  {
5394  SCIP_CALL( resetConflictgraphSOS1(conflictgraph, conshdlrdata->localconflicts, nsos1vars) );
5395  conshdlrdata->isconflocal = FALSE;
5396  }
5397 
5398  /* free memory */
5399  SCIPfreeBufferArrayNull(scip, &fixingsnode2);
5400  SCIPfreeBufferArrayNull(scip, &fixingsnode1);
5401  SCIPfreeBufferArrayNull(scip, &verticesarefixed);
5402 
5403  return SCIP_OKAY;
5404  }
5405  }
5406 
5407  /* create branching nodes */
5408 
5409  /* get vertices of variables that will be fixed to zero for each node */
5410  assert( branchvertex >= 0 && branchvertex < nsos1vars );
5411  assert( ! verticesarefixed[branchvertex] );
5412  SCIP_CALL( getBranchingVerticesSOS1(scip, conflictgraph, verticesarefixed, bipbranch, branchvertex, fixingsnode1, &nfixingsnode1, fixingsnode2, &nfixingsnode2) );
5413 
5414  /* calculate node selection and objective estimate for node 1 */
5415  nodeselest = 0.0;
5416  objest = 0.0;
5417  for (j = 0; j < nfixingsnode1; ++j)
5418  {
5419  SCIP_VAR* var;
5420 
5421  var = SCIPnodeGetVarSOS1(conflictgraph, fixingsnode1[j]);
5422  nodeselest += SCIPcalcNodeselPriority(scip, var, SCIP_BRANCHDIR_DOWNWARDS, 0.0);
5423  objest += SCIPcalcChildEstimate(scip, var, 0.0);
5424  }
5425  /* take the average of the individual estimates */
5426  objest = objest/((SCIP_Real) nfixingsnode1);
5427 
5428  /* create node 1 */
5429  SCIP_CALL( SCIPcreateChild(scip, &node1, nodeselest, objest) );
5430 
5431  /* fix variables for the first node */
5432  if ( conshdlrdata->fixnonzero && nfixingsnode2 == 1 )
5433  {
5434  SCIP_VAR* var;
5435  SCIP_Real lb;
5436  SCIP_Real ub;
5437 
5438  var = SCIPnodeGetVarSOS1(conflictgraph, fixingsnode2[0]);
5439  lb = SCIPvarGetLbLocal(var);
5440  ub = SCIPvarGetUbLocal(var);
5441 
5443  {
5444  if ( SCIPisZero(scip, lb) )
5445  {
5446  /* fix variable to some very small, but positive number */
5447  SCIP_CALL( SCIPchgVarLbNode(scip, node1, var, 1.5 * SCIPfeastol(scip)) );
5448  }
5449  else if ( SCIPisZero(scip, ub) )
5450  {
5451  /* fix variable to some negative number with small absolute value */
5452  SCIP_CALL( SCIPchgVarUbNode(scip, node1, var, -1.5 * SCIPfeastol(scip)) );
5453  }
5454  }
5455  }
5456  for (j = 0; j < nfixingsnode1; ++j)
5457  {
5458  /* fix variable to zero */
5459  SCIP_CALL( fixVariableZeroNode(scip, SCIPnodeGetVarSOS1(conflictgraph, fixingsnode1[j]), node1, &infeasible) );
5460  assert( ! infeasible );
5461  }
5462 
5463  /* calculate node selection and objective estimate for node 2 */
5464  nodeselest = 0.0;
5465  objest = 0.0;
5466  for (j = 0; j < nfixingsnode2; ++j)
5467  {
5468  SCIP_VAR* var;
5469 
5470  var = SCIPnodeGetVarSOS1(conflictgraph, fixingsnode2[j]);
5471  nodeselest += SCIPcalcNodeselPriority(scip, var, SCIP_BRANCHDIR_DOWNWARDS, 0.0);
5472  objest += SCIPcalcChildEstimate(scip, var, 0.0);
5473  }
5474 
5475  /* take the average of the individual estimates */
5476  objest = objest/((SCIP_Real) nfixingsnode2);
5477 
5478  /* create node 2 */
5479  SCIP_CALL( SCIPcreateChild(scip, &node2, nodeselest, objest) );
5480 
5481  /* fix variables to zero */
5482  for (j = 0; j < nfixingsnode2; ++j)
5483  {
5484  SCIP_CALL( fixVariableZeroNode(scip, SCIPnodeGetVarSOS1(conflictgraph, fixingsnode2[j]), node2, &infeasible) );
5485  assert( ! infeasible );
5486  }
5487 
5488 
5489  /* add complementarity constraints to the branching nodes */
5490  if ( conshdlrdata->addcomps && ( conshdlrdata->addcompsdepth == -1 || conshdlrdata->addcompsdepth >= SCIPgetDepth(scip) ) )
5491  {
5492  int naddedconss;
5493 
5494  assert( ! conshdlrdata->fixnonzero );
5495 
5496  /* add complementarity constraints to the left branching node */
5497  SCIP_CALL( addBranchingComplementaritiesSOS1(scip, node1, conshdlrdata, conflictgraph, conshdlrdata->localconflicts,
5498  nsos1vars, verticesarefixed, fixingsnode1, nfixingsnode1, fixingsnode2, nfixingsnode2, &naddedconss, TRUE) );
5499 
5500  if ( naddedconss == 0 )
5501  {
5502  /* add complementarity constraints to the right branching node */
5503  SCIP_CALL( addBranchingComplementaritiesSOS1(scip, node2, conshdlrdata, conflictgraph, conshdlrdata->localconflicts,
5504  nsos1vars, verticesarefixed, fixingsnode2, nfixingsnode2, fixingsnode1, nfixingsnode1, &naddedconss, TRUE) );
5505  }
5506  }
5507 
5508  /* sets node's lower bound to the best known value */
5509  if ( nstrongrounds > 0 )
5510  {
5511  SCIP_CALL( SCIPupdateNodeLowerbound(scip, node1, MAX(lpobjval, bestobjval1) ) );
5512  SCIP_CALL( SCIPupdateNodeLowerbound(scip, node2, MAX(lpobjval, bestobjval2) ) );
5513  }
5514 
5515  /* remove local conflicts from conflict graph */
5516  if ( conshdlrdata->isconflocal )
5517  {
5518  SCIP_CALL( resetConflictgraphSOS1(conflictgraph, conshdlrdata->localconflicts, nsos1vars) );
5519  conshdlrdata->isconflocal = FALSE;
5520  }
5521 
5522  /* free buffer arrays */
5523  SCIPfreeBufferArrayNull(scip, &fixingsnode2);
5524  SCIPfreeBufferArrayNull(scip, &fixingsnode1);
5525  SCIPfreeBufferArrayNull(scip, &verticesarefixed );
5526  *result = SCIP_BRANCHED;
5527 
5528  return SCIP_OKAY;
5529 }
5530 
5531 
5532 /** SOS1 branching enforcement method
5533  *
5534  * We check whether the current solution is feasible, i.e., contains at most one nonzero
5535  * variable. If not, we branch along the lines indicated by Beale and Tomlin:
5536  *
5537  * We first compute \f$W = \sum_{j=1}^n |x_i|\f$ and \f$w = \sum_{j=1}^n j\, |x_i|\f$. Then we
5538  * search for the index \f$k\f$ that satisfies
5539  * \f[
5540  * k \leq \frac{w}{W} < k+1.
5541  * \f]
5542  * The branches are then
5543  * \f[
5544  * x_1 = 0, \ldots, x_k = 0 \qquad \mbox{and}\qquad x_{k+1} = 0, \ldots, x_n = 0.
5545  * \f]
5546  *
5547  * If the constraint contains two variables, the branching of course simplifies.
5548  *
5549  * Depending on the parameters (@c branchnonzeros, @c branchweight) there are three ways to choose
5550  * the branching constraint.
5551  *
5552  * <TABLE>
5553  * <TR><TD>@c branchnonzeros</TD><TD>@c branchweight</TD><TD>constraint chosen</TD></TR>
5554  * <TR><TD>@c true </TD><TD> ? </TD><TD>most number of nonzeros</TD></TR>
5555  * <TR><TD>@c false </TD><TD> @c true </TD><TD>maximal weight corresponding to nonzero variable</TD></TR>
5556  * <TR><TD>@c false </TD><TD> @c true </TD><TD>largest sum of variable values</TD></TR>
5557  * </TABLE>
5558  *
5559  * @c branchnonzeros = @c false, @c branchweight = @c true allows the user to specify an order for
5560  * the branching importance of the constraints (setting the weights accordingly).
5561  *
5562  * Constraint branching can also be turned off using parameter @c branchsos.
5563  */
5564 static
5566  SCIP* scip, /**< SCIP pointer */
5567  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5568  int nconss, /**< number of constraints */
5569  SCIP_CONS** conss, /**< indicator constraints */
5570  SCIP_RESULT* result /**< result */
5571  )
5572 {
5573  SCIP_CONSHDLRDATA* conshdlrdata;
5574  SCIP_CONSDATA* consdata;
5575  SCIP_NODE* node1;
5576  SCIP_NODE* node2;
5578  SCIP_Real maxWeight;
5579  SCIP_VAR** vars;
5580  int nvars;
5581  int c;
5582 
5583  assert( scip != NULL );
5584  assert( conshdlr != NULL );
5585  assert( conss != NULL );
5586  assert( result != NULL );
5587 
5588  maxWeight = -SCIP_REAL_MAX;
5589  branchCons = NULL;
5590 
5591  SCIPdebugMessage("Enforcing SOS1 constraints <%s>.\n", SCIPconshdlrGetName(conshdlr) );
5592  *result = SCIP_FEASIBLE;
5593 
5594  /* get constraint handler data */
5595  conshdlrdata = SCIPconshdlrGetData(conshdlr);
5596  assert( conshdlrdata != NULL );
5597 
5598  /* check each constraint */
5599  for (c = 0; c < nconss; ++c)
5600  {
5601  SCIP_CONS* cons;
5602  SCIP_Bool cutoff;
5603  SCIP_Real weight;
5604  int ngen;
5605  int cnt;
5606  int j;
5607 
5608  cons = conss[c];
5609  assert( cons != NULL );
5610  consdata = SCIPconsGetData(cons);
5611  assert( consdata != NULL );
5612 
5613  ngen = 0;
5614  cnt = 0;
5615  nvars = consdata->nvars;
5616  vars = consdata->vars;
5617 
5618  /* do nothing if there are not enough variables - this is usually eliminated by preprocessing */
5619  if ( nvars < 2 )
5620  continue;
5621 
5622  /* first perform propagation (it might happen that standard propagation is turned off) */
5623  SCIP_CALL( propConsSOS1(scip, cons, consdata, &cutoff, &ngen) );
5624  SCIPdebugMessage("propagating <%s> in enforcing (cutoff: %u, domain reductions: %d).\n", SCIPconsGetName(cons), cutoff, ngen);
5625  if ( cutoff )
5626  {
5627  *result = SCIP_CUTOFF;
5628  return SCIP_OKAY;
5629  }
5630  if ( ngen > 0 )
5631  {
5632  *result = SCIP_REDUCEDDOM;
5633  return SCIP_OKAY;
5634  }
5635  assert( ngen == 0 );
5636 
5637  /* check constraint */
5638  weight = 0.0;
5639  for (j = 0; j < nvars; ++j)
5640  {
5641  SCIP_Real val = REALABS(SCIPgetSolVal(scip, NULL, vars[j]));
5642 
5643  if ( ! SCIPisFeasZero(scip, val) )
5644  {
5645  if ( conshdlrdata->branchnonzeros )
5646  weight += 1.0;
5647  else
5648  {
5649  if ( conshdlrdata->branchweight )
5650  {
5651  /* choose maximum nonzero-variable weight */
5652  if ( consdata->weights[j] > weight )
5653  weight = consdata->weights[j];
5654  }
5655  else
5656  weight += val;
5657  }
5658  ++cnt;
5659  }
5660  }
5661  /* if constraint is violated */
5662  if ( cnt > 1 && weight > maxWeight )
5663  {
5664  maxWeight = weight;
5665  branchCons = cons;
5666  }
5667  }
5668 
5669  /* if all constraints are feasible */
5670  if ( branchCons == NULL )
5671  {
5672  SCIPdebugMessage("All SOS1 constraints are feasible.\n");
5673  return SCIP_OKAY;
5674  }
5675 
5676  /* if we should leave branching decision to branching rules */
5677  if ( ! conshdlrdata->branchsos )
5678  {
5679  *result = SCIP_INFEASIBLE;
5680  return SCIP_OKAY;
5681  }
5682 
5683  /* otherwise create branches */
5684  SCIPdebugMessage("Branching on constraint <%s> (weight: %f).\n", SCIPconsGetName(branchCons), maxWeight);
5685  consdata = SCIPconsGetData(branchCons);
5686  assert( consdata != NULL );
5687  nvars = consdata->nvars;
5688  vars = consdata->vars;
5689 
5690  if ( nvars == 2 )
5691  {
5692  SCIP_Bool infeasible;
5693 
5694  /* constraint is infeasible: */
5695  assert( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, NULL, vars[0])) && ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, NULL, vars[1])) );
5696 
5697  /* create branches */
5698  SCIPdebugMessage("Creating two branches.\n");
5699 
5700  SCIP_CALL( SCIPcreateChild(scip, &node1, SCIPcalcNodeselPriority(scip, vars[0], SCIP_BRANCHDIR_DOWNWARDS, 0.0), SCIPcalcChildEstimate(scip, vars[0], 0.0) ) );
5701  SCIP_CALL( fixVariableZeroNode(scip, vars[0], node1, &infeasible) );
5702  assert( ! infeasible );
5703 
5704  SCIP_CALL( SCIPcreateChild(scip, &node2, SCIPcalcNodeselPriority(scip, vars[1], SCIP_BRANCHDIR_DOWNWARDS, 0.0), SCIPcalcChildEstimate(scip, vars[1], 0.0) ) );
5705  SCIP_CALL( fixVariableZeroNode(scip, vars[1], node2, &infeasible) );
5706  assert( ! infeasible );
5707  }
5708  else
5709  {
5710  SCIP_Bool infeasible;
5711  SCIP_Real weight1;
5712  SCIP_Real weight2;
5713  SCIP_Real nodeselest;
5714  SCIP_Real objest;
5715  SCIP_Real w;
5716  int j;
5717  int ind;
5718  int cnt;
5719 
5720  cnt = 0;
5721 
5722  weight1 = 0.0;
5723  weight2 = 0.0;
5724 
5725  /* compute weight */
5726  for (j = 0; j < nvars; ++j)
5727  {
5728  SCIP_Real val = REALABS(SCIPgetSolVal(scip, NULL, vars[j]));
5729  weight1 += val * (SCIP_Real) j;
5730  weight2 += val;
5731 
5732  if ( ! SCIPisFeasZero(scip, val) )
5733  ++cnt;
5734  }
5735 
5736  assert( cnt >= 2 );
5737  assert( !SCIPisFeasZero(scip, weight2) );
5738  w = weight1/weight2; /*lint !e795*/
5739 
5740  ind = (int) SCIPfloor(scip, w);
5741  assert( 0 <= ind && ind < nvars-1 );
5742 
5743  /* branch on variable ind: either all variables up to ind or all variables after ind are zero */
5744  SCIPdebugMessage("Branching on variable <%s>.\n", SCIPvarGetName(vars[ind]));
5745 
5746  /* calculate node selection and objective estimate for node 1 */
5747  nodeselest = 0.0;
5748  objest = 0.0;
5749  for (j = 0; j <= ind; ++j)
5750  {
5751  nodeselest += SCIPcalcNodeselPriority(scip, vars[j], SCIP_BRANCHDIR_DOWNWARDS, 0.0);
5752  objest += SCIPcalcChildEstimate(scip, vars[j], 0.0);
5753  }
5754  /* take the average of the individual estimates */
5755  objest = objest/(SCIP_Real)(ind + 1.0);
5756 
5757  /* create node 1 */
5758  SCIP_CALL( SCIPcreateChild(scip, &node1, nodeselest, objest) );
5759  for (j = 0; j <= ind; ++j)
5760  {
5761  SCIP_CALL( fixVariableZeroNode(scip, vars[j], node1, &infeasible) );
5762  assert( ! infeasible );
5763  }
5764 
5765  /* calculate node selection and objective estimate for node 1 */
5766  nodeselest = 0.0;
5767  objest = 0.0;
5768  for (j = ind+1; j < nvars; ++j)
5769  {
5770  nodeselest += SCIPcalcNodeselPriority(scip, vars[j], SCIP_BRANCHDIR_DOWNWARDS, 0.0);
5771  objest += SCIPcalcChildEstimate(scip, vars[j], 0.0);
5772  }
5773  /* take the average of the individual estimates */
5774  objest = objest/((SCIP_Real) (nvars - ind - 1));
5775 
5776  /* create node 2 */
5777  SCIP_CALL( SCIPcreateChild(scip, &node2, nodeselest, objest) );
5778  for (j = ind+1; j < nvars; ++j)
5779  {
5780  SCIP_CALL( fixVariableZeroNode(scip, vars[j], node2, &infeasible) );
5781  assert( ! infeasible );
5782  }
5783  }
5784  SCIP_CALL( SCIPresetConsAge(scip, branchCons) );
5785  *result = SCIP_BRANCHED;
5786 
5787  return SCIP_OKAY;
5788 }
5789 
5790 
5791 /* ----------------------------- separation ------------------------------------*/
5792 
5793 /** initialitze tclique graph and create clique data */
5794 static
5796  SCIP* scip, /**< SCIP pointer */
5797  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
5798  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5799  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
5800  int nsos1vars /**< number of SOS1 variables */
5801  )
5802 {
5803  TCLIQUE_DATA* tcliquedata;
5804  int j;
5805 
5806  /* try to generate bound cuts */
5807  if ( ! tcliqueCreate(&conshdlrdata->tcliquegraph) )
5808  return SCIP_NOMEMORY;
5809 
5810  /* add nodes */
5811  for (j = 0; j < nsos1vars; ++j)
5812  {
5813  if ( ! tcliqueAddNode(conshdlrdata->tcliquegraph, j, 0 ) )
5814  return SCIP_NOMEMORY;
5815  }
5816 
5817  /* add edges */
5818  for (j = 0; j < nsos1vars; ++j)
5819  {
5820  int* succ;
5821  int nsucc;
5822  int succnode;
5823  int i;
5824 
5825  nsucc = SCIPdigraphGetNSuccessors(conflictgraph, j);
5826  succ = SCIPdigraphGetSuccessors(conflictgraph, j);
5827 
5828  for (i = 0; i < nsucc; ++i)
5829  {
5830  succnode = succ[i];
5831 
5832  if ( succnode > j && SCIPvarIsActive(SCIPnodeGetVarSOS1(conflictgraph, succnode)) )
5833  {
5834  if ( ! tcliqueAddEdge(conshdlrdata->tcliquegraph, j, succnode) )
5835  return SCIP_NOMEMORY;
5836  }
5837  }
5838  }
5839  if ( ! tcliqueFlush(conshdlrdata->tcliquegraph) )
5840  return SCIP_NOMEMORY;
5841 
5842 
5843  /* allocate clique data */
5844  SCIP_CALL( SCIPallocMemory(scip, &conshdlrdata->tcliquedata) );
5845  tcliquedata = conshdlrdata->tcliquedata;
5846 
5847  /* initialize clique data */
5848  tcliquedata->scip = scip;
5849  tcliquedata->sol = NULL;
5850  tcliquedata->conshdlr = conshdlr;
5851  tcliquedata->conflictgraph = conflictgraph;
5852  tcliquedata->scaleval = 1000.0;
5853  tcliquedata->ncuts = 0;
5854  tcliquedata->nboundcuts = conshdlrdata->nboundcuts;
5855  tcliquedata->strthenboundcuts = conshdlrdata->strthenboundcuts;
5856  tcliquedata->maxboundcuts = conshdlrdata->maxboundcutsroot;
5857 
5858  return SCIP_OKAY;
5859 }
5860 
5861 
5862 /** update weights of tclique graph */
5863 static
5865  SCIP* scip, /**< SCIP pointer */
5866  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
5867  TCLIQUE_DATA* tcliquedata, /**< tclique data */
5868  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
5869  SCIP_SOL* sol, /**< LP solution to be separated (or NULL) */
5870  int nsos1vars /**< number of SOS1 variables */
5871  )
5872 {
5873  SCIP_Real scaleval;
5874  int j;
5875 
5876  scaleval = tcliquedata->scaleval;
5877 
5878  for (j = 0; j < nsos1vars; ++j)
5879  {
5880  SCIP_Real solval;
5881  SCIP_Real bound;
5882  SCIP_VAR* var;
5883 
5884  var = SCIPnodeGetVarSOS1(conflictgraph, j);
5885  solval = SCIPgetSolVal(scip, sol, var);
5886 
5887  if ( SCIPisFeasPositive(scip, solval) )
5888  {
5889  if ( conshdlrdata->strthenboundcuts )
5890  bound = REALABS( nodeGetSolvalVarboundUbSOS1(scip, conflictgraph, sol, j) );
5891  else
5892  bound = REALABS( SCIPvarGetUbLocal(var) );
5893  }
5894  else if ( SCIPisFeasNegative(scip, solval) )
5895  {
5896  if ( conshdlrdata->strthenboundcuts )
5897  bound = REALABS( nodeGetSolvalVarboundLbSOS1(scip, conflictgraph, sol, j) );
5898  else
5899  bound = REALABS( SCIPvarGetLbLocal(var) );
5900  }
5901  else
5902  bound = 0.0;
5903 
5904  solval = REALABS( solval );
5905 
5906  if ( ! SCIPisFeasZero(scip, bound) && ! SCIPisInfinity(scip, bound) )
5907  {
5908  SCIP_Real nodeweight;
5909  nodeweight = REALABS( solval/bound ) * scaleval;/*lint !e414*/
5910  tcliqueChangeWeight(conshdlrdata->tcliquegraph, j, (int)nodeweight);
5911  }
5912  else
5913  {
5914  tcliqueChangeWeight(conshdlrdata->tcliquegraph, j, 0);
5915  }
5916  }
5917 
5918  return SCIP_OKAY;
5919 }
5920 
5921 
5922 /** adds bound cut(s) to separation storage */
5923 static
5925  SCIP* scip, /**< SCIP pointer */
5926  TCLIQUE_DATA* tcliquedata, /**< clique data */
5927  SCIP_ROW* rowlb, /**< row for lower bounds (or NULL) */
5928  SCIP_ROW* rowub, /**< row for upper bounds (or NULL) */
5929  SCIP_Bool* success, /**< pointer to store if bound cut was added */
5930  SCIP_Bool* cutoff /**< pointer to store if a cutoff occurred */
5931  )
5932 {
5933  assert( scip != NULL );
5934  assert( tcliquedata != NULL );
5935  assert( success != NULL);
5936  assert( cutoff != NULL );
5937 
5938  *success = FALSE;
5939  *cutoff = FALSE;
5940 
5941  /* add cut for lower bounds */
5942  if ( rowlb != NULL )
5943  {
5944  if ( ! SCIProwIsInLP(rowlb) && SCIPisCutEfficacious(scip, NULL, rowlb) )
5945  {
5946  SCIP_Bool infeasible;
5947 
5948  SCIP_CALL( SCIPaddCut(scip, NULL, rowlb, FALSE, &infeasible) );
5949  if ( infeasible )
5950  *cutoff = TRUE;
5951  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, rowlb, NULL) ) );
5952  ++tcliquedata->nboundcuts;
5953  ++tcliquedata->ncuts;
5954  *success = TRUE;
5955  }
5956  }
5957 
5958  /* add cut for upper bounds */
5959  if ( rowub != NULL )
5960  {
5961  if ( ! SCIProwIsInLP(rowub) && SCIPisCutEfficacious(scip, NULL, rowub) )
5962  {
5963  SCIP_Bool infeasible;
5964 
5965  SCIP_CALL( SCIPaddCut(scip, NULL, rowub, FALSE, &infeasible) );
5966  if ( infeasible )
5967  *cutoff = TRUE;
5968  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, rowub, NULL) ) );
5969  ++tcliquedata->nboundcuts;
5970  ++tcliquedata->ncuts;
5971  *success = TRUE;
5972  }
5973  }
5974 
5975  return SCIP_OKAY;
5976 }
5977 
5978 
5979 /** Generate bound constraint
5980  *
5981  * We generate the row corresponding to the following simple valid inequalities:
5982  * \f[
5983  * \frac{x_1}{u_1} + \ldots + \frac{x_n}{u_n} \leq 1\qquad\mbox{and}\qquad
5984  * \frac{x_1}{\ell_1} + \ldots + \frac{x_n}{\ell_1} \leq 1,
5985  * \f]
5986  * where \f$\ell_1, \ldots, \ell_n\f$ and \f$u_1, \ldots, u_n\f$ are the nonzero and finite lower and upper bounds of
5987  * the variables \f$x_1, \ldots, x_n\f$. If an upper bound < 0 or a lower bound > 0, the constraint itself is
5988  * redundant, so the cut is not applied (lower bounds > 0 and upper bounds < 0 are usually detected in presolving or
5989  * propagation). Infinite bounds and zero are skipped. Thus \f$\ell_1, \ldots, \ell_n\f$ are all negative, which
5990  * results in the \f$\leq\f$ inequality. In case of the presence of variable upper bounds, the bound inequality can
5991  * be further strengthened.
5992  *
5993  * Note that in fact, any mixture of nonzero finite lower and upper bounds would lead to a valid inequality as
5994  * above. However, usually either the lower or upper bound is nonzero. Thus, the above inequalities are the most
5995  * interesting.
5996  */
5997 static
5999  SCIP* scip, /**< SCIP pointer */
6000  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6001  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
6002  int* nodes, /**< conflict graph nodes for bound constraint */
6003  int nnodes, /**< number of conflict graph nodes for bound constraint */
6004  SCIP_Real rhs, /**< right hand side of bound constraint */
6005  SCIP_Bool local, /**< in any case produce a local cut (even if local bounds of variables are valid globally) */
6006  SCIP_Bool global, /**< in any case produce a global cut */
6007  SCIP_Bool strengthen, /**< whether trying to strengthen bound constraint */
6008  SCIP_Bool removable, /**< should the inequality be removed from the LP due to aging or cleanup? */
6009  const char * nameext, /**< part of name of bound constraints */
6010  SCIP_ROW** rowlb, /**< output: row for lower bounds (or NULL if not needed) */
6011  SCIP_ROW** rowub /**< output: row for upper bounds (or NULL if not needed) */
6012  )
6013 {
6014  char name[SCIP_MAXSTRLEN];
6015  SCIP_VAR* lbboundvar = NULL;
6016  SCIP_VAR* ubboundvar = NULL;
6017  SCIP_Bool locallbs;
6018  SCIP_Bool localubs;
6019  SCIP_VAR** vars;
6020  SCIP_Real* vals;
6021 
6022  assert( scip != NULL );
6023  assert( conshdlr != NULL );
6024  assert( conflictgraph != NULL );
6025  assert( ! local || ! global );
6026  assert( nodes != NULL );
6027 
6028  /* allocate buffer array */
6029  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nnodes+1) );
6030  SCIP_CALL( SCIPallocBufferArray(scip, &vals, nnodes+1) );
6031 
6032  /* take care of upper bounds */
6033  if ( rowub != NULL )
6034  {
6035  SCIP_Bool useboundvar;
6036  int cnt = 0;
6037  int j;
6038 
6039  /* Loop through all variables. We check whether all bound variables (if existent) are equal; if this is the
6040  * case then the bound constraint can be strengthened */
6041  localubs = local;
6042  useboundvar = strengthen;
6043  for (j = 0; j < nnodes; ++j)
6044  {
6045  SCIP_NODEDATA* nodedata;
6046  SCIP_VAR* var;
6047  SCIP_Real val;
6048 
6049  nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, nodes[j]);
6050  assert( nodedata != NULL );
6051  var = nodedata->var;
6052  assert( var != NULL );
6053 
6054  /* if variable is not involved in a variable bound constraint */
6055  if ( ! useboundvar || nodedata->ubboundvar == NULL )
6056  {
6057  useboundvar = FALSE;
6058  if ( localubs )
6059  {
6060  assert( ! global );
6061  val = SCIPvarGetUbLocal(var);
6062  }
6063  else
6064  {
6065  val = SCIPvarGetUbGlobal(var);
6066  if ( ! global && ! SCIPisFeasEQ(scip, val, SCIPvarGetUbLocal(var)) )
6067  {
6068  localubs = TRUE;
6069  val = SCIPvarGetUbLocal(var);
6070  }
6071  }
6072  }
6073  else
6074  {
6075  /* in this case the cut is always valid globally */
6076 
6077  /* if we have a bound variable for the first time */
6078  if ( ubboundvar == NULL )
6079  {
6080  ubboundvar = nodedata->ubboundvar;
6081  val = nodedata->ubboundcoef;
6082  }
6083  /* else if the bound variable equals the stored bound variable */
6084  else if ( ubboundvar == nodedata->ubboundvar )
6085  val = nodedata->ubboundcoef;
6086  else /* else use bounds on the variables */
6087  {
6088  useboundvar = FALSE;
6089 
6090  /* restart 'for'-loop */
6091  j = -1;
6092  cnt = 0;
6093  continue;
6094  }
6095  }
6096 
6097  /* should not apply the cut if a variable is fixed to be negative -> constraint is redundant */
6098  if ( SCIPisNegative(scip, val) )
6099  break;
6100 
6101  /* store variable if relevant for bound inequality */
6102  if ( ! SCIPisInfinity(scip, val) && ! SCIPisZero(scip, val) )
6103  {
6104  vars[cnt] = var;
6105  vals[cnt++] = 1.0/val;
6106  }
6107  }
6108 
6109  /* if cut is meaningful */
6110  if ( j == nnodes && cnt >= 2 )/*lint !e850*/
6111  {
6112  if ( useboundvar )
6113  {
6114  /* add bound variable to array */
6115  vars[cnt] = ubboundvar;
6116  vals[cnt++] = -rhs;
6117  assert(ubboundvar != NULL );
6118 
6119  /* create upper bound inequality if at least two of the bounds are finite and nonzero */
6120  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "sosub#%s", nameext);
6121  SCIP_CALL( SCIPcreateEmptyRowCons(scip, rowub, conshdlr, name, -SCIPinfinity(scip), 0.0, localubs, FALSE, removable) );
6122  SCIP_CALL( SCIPaddVarsToRow(scip, *rowub, cnt, vars, vals) );
6123  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, *rowub, NULL) ) );
6124  }
6125  else
6126  {
6127  /* create upper bound inequality if at least two of the bounds are finite and nonzero */
6128  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "sosub#%s", nameext);
6129  SCIP_CALL( SCIPcreateEmptyRowCons(scip, rowub, conshdlr, name, -SCIPinfinity(scip), rhs, localubs, FALSE, removable) );
6130  SCIP_CALL( SCIPaddVarsToRow(scip, *rowub, cnt, vars, vals) );
6131  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, *rowub, NULL) ) );
6132  }
6133  }
6134  }
6135 
6136 
6137  /* take care of lower bounds */
6138  if ( rowlb != NULL )
6139  {
6140  SCIP_Bool useboundvar;
6141  int cnt;
6142  int j;
6143 
6144  /* loop through all variables. We check whether all bound variables (if existent) are equal; if this is the
6145  * case then the bound constraint can be strengthened */
6146  cnt = 0;
6147  locallbs = local;
6148  useboundvar = strengthen;
6149  for (j = 0; j < nnodes; ++j)
6150  {
6151  SCIP_NODEDATA* nodedata;
6152  SCIP_VAR* var;
6153  SCIP_Real val;
6154 
6155  nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, nodes[j]);
6156  assert( nodedata != NULL );
6157  var = nodedata->var;
6158  assert( var != NULL );
6159 
6160  /* if variable is not involved in a variable bound constraint */
6161  if ( ! useboundvar || nodedata->lbboundvar == NULL )
6162  {
6163  useboundvar = FALSE;
6164  if ( locallbs )
6165  {
6166  assert( ! global );
6167  val = SCIPvarGetLbLocal(var);
6168  }
6169  else
6170  {
6171  val = SCIPvarGetLbGlobal(var);
6172  if ( ! global && ! SCIPisFeasEQ(scip, val, SCIPvarGetLbLocal(var)) )
6173  {
6174  locallbs = TRUE;
6175  val = SCIPvarGetUbLocal(var);
6176  }
6177  }
6178  }
6179  else
6180  {
6181  /* in this case the cut is always valid globally */
6182 
6183  /* if we have a bound variable for the first time */
6184  if ( lbboundvar == NULL )
6185  {
6186  lbboundvar = nodedata->lbboundvar;
6187  val = nodedata->lbboundcoef;
6188  }
6189  /* else if the bound variable equals the stored bound variable */
6190  else if ( SCIPvarCompare(lbboundvar, nodedata->lbboundvar) == 0 )
6191  {
6192  val = nodedata->lbboundcoef;
6193  }
6194  else /* else use bounds on the variables */
6195  {
6196  useboundvar = FALSE;
6197 
6198  /* restart 'for'-loop */
6199  j = -1;
6200  cnt = 0;
6201  continue;
6202  }
6203  }
6204 
6205  /* should not apply the cut if a variable is fixed to be positive -> constraint is redundant */
6206  if ( SCIPisPositive(scip, val) )
6207  break;
6208 
6209  /* store variable if relevant for bound inequality */
6210  if ( ! SCIPisInfinity(scip, val) && ! SCIPisZero(scip, val) )
6211  {
6212  vars[cnt] = var;
6213  vals[cnt++] = 1.0/val;
6214  }
6215  }
6216 
6217  /* if cut is meaningful */
6218  if ( j == nnodes && cnt >= 2 )/*lint !e850*/
6219  {
6220  if ( useboundvar )
6221  {
6222  /* add bound variable to array */
6223  vars[cnt] = lbboundvar;
6224  vals[cnt++] = -rhs;
6225  assert(lbboundvar != NULL );
6226 
6227  /* create upper bound inequality if at least two of the bounds are finite and nonzero */
6228  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "soslb#%s", nameext);
6229  SCIP_CALL( SCIPcreateEmptyRowCons(scip, rowlb, conshdlr, name, -SCIPinfinity(scip), 0.0, locallbs, FALSE, TRUE) );
6230  SCIP_CALL( SCIPaddVarsToRow(scip, *rowlb, cnt, vars, vals) );
6231  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, *rowlb, NULL) ) );
6232  }
6233  else
6234  {
6235  /* create upper bound inequality if at least two of the bounds are finite and nonzero */
6236  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "soslb#%s", nameext);
6237  SCIP_CALL( SCIPcreateEmptyRowCons(scip, rowlb, conshdlr, name, -SCIPinfinity(scip), rhs, locallbs, FALSE, TRUE) );
6238  SCIP_CALL( SCIPaddVarsToRow(scip, *rowlb, cnt, vars, vals) );
6239  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, *rowlb, NULL) ) );
6240  }
6241  }
6242  }
6243 
6244  /* free buffer array */
6245  SCIPfreeBufferArray(scip, &vals);
6246  SCIPfreeBufferArray(scip, &vars);
6247 
6248  return SCIP_OKAY;
6249 }
6250 
6251 
6252 /** generates bound cuts using a clique found by algorithm for maximum weight clique
6253  * and decides whether to stop generating cliques with the algorithm for maximum weight clique
6254  */
6255 static
6256 TCLIQUE_NEWSOL(tcliqueNewsolClique)
6257 {
6258  TCLIQUE_WEIGHT minweightinc;
6259 
6260  assert( acceptsol != NULL );
6261  assert( stopsolving != NULL );
6262  assert( tcliquedata != NULL );
6263 
6264  /* we don't accept the solution as new incumbent, because we want to find many violated clique inequalities */
6265  *acceptsol = FALSE;
6266  *stopsolving = FALSE;
6267 
6268  /* slightly increase the minimal weight for additional cliques */
6269  minweightinc = (cliqueweight - *minweight)/10;
6270  minweightinc = MAX(minweightinc, 1);
6271  *minweight += minweightinc;
6272 
6273  /* adds cut if weight of the clique is greater than 1 */
6274  if( cliqueweight > tcliquedata->scaleval )
6275  {
6276  SCIP* scip;
6277  SCIP_SOL* sol;
6278  SCIP_Real unscaledweight;
6279  SCIP_Real solval;
6280  SCIP_Real bound;
6281  SCIP_VAR* var;
6282  int node;
6283  int i;
6284 
6285  scip = tcliquedata->scip;
6286  sol = tcliquedata->sol;
6287  assert( scip != NULL );
6288 
6289  /* calculate the weight of the clique in unscaled fractional variable space */
6290  unscaledweight = 0.0;
6291  for( i = 0; i < ncliquenodes; i++ )
6292  {
6293  node = cliquenodes[i];
6294  var = SCIPnodeGetVarSOS1(tcliquedata->conflictgraph, node);
6295  solval = SCIPgetSolVal(scip, sol, var);
6296 
6297  if ( SCIPisFeasPositive(scip, solval) )
6298  {
6299  if ( tcliquedata->strthenboundcuts )
6300  bound = REALABS( nodeGetSolvalVarboundUbSOS1(scip, tcliquedata->conflictgraph, sol, node) );
6301  else
6302  bound = REALABS( SCIPvarGetUbLocal(var) );
6303  }
6304  else if ( SCIPisFeasNegative(scip, solval) )
6305  {
6306  if ( tcliquedata->strthenboundcuts )
6307  bound = REALABS( nodeGetSolvalVarboundLbSOS1(scip, tcliquedata->conflictgraph, sol, node) );
6308  else
6309  bound = REALABS( SCIPvarGetLbLocal(var) );
6310  }
6311  else
6312  bound = 0.0;
6313 
6314  solval = REALABS( solval );
6315 
6316  if ( ! SCIPisFeasZero(scip, bound) && ! SCIPisInfinity(scip, bound) )
6317  unscaledweight += REALABS( solval/bound );/*lint !e414*/
6318  }
6319 
6320  if ( SCIPisEfficacious(scip, unscaledweight - 1.0) )
6321  {
6322  char nameext[SCIP_MAXSTRLEN];
6323  SCIP_ROW* rowlb = NULL;
6324  SCIP_ROW* rowub = NULL;
6325  SCIP_Bool success;
6326  SCIP_Bool cutoff;
6327 
6328  /* generate bound inequalities for lower and upper bound case
6329  * NOTE: tests have shown that non-removable rows give the best results */
6330  (void) SCIPsnprintf(nameext, SCIP_MAXSTRLEN, "%d", tcliquedata->nboundcuts);
6331  if ( generateBoundInequalityFromSOS1Nodes(scip, tcliquedata->conshdlr, tcliquedata->conflictgraph,
6332  cliquenodes, ncliquenodes, 1.0, FALSE, FALSE, tcliquedata->strthenboundcuts, FALSE, nameext, &rowlb, &rowub) != SCIP_OKAY )
6333  {
6334  SCIPerrorMessage("Unexpected error in bound cut creation.\n");
6335  SCIPABORT();
6336  return; /*lint !e527*/
6337  }
6338 
6339  /* add bound cut(s) to separation storage if existent */
6340  if ( addBoundCutSepa(scip, tcliquedata, rowlb, rowub, &success, &cutoff) != SCIP_OKAY )
6341  {
6342  SCIPerrorMessage("Unexpected error in bound cut creation.\n");
6343  SCIPABORT();
6344  return; /*lint !e527*/
6345  }
6346 
6347  if ( rowlb != NULL )
6348  {
6349  if ( SCIPreleaseRow(scip, &rowlb) != SCIP_OKAY )
6350  {
6351  SCIPerrorMessage("Cannot release row,\n");
6352  SCIPABORT();
6353  return; /*lint !e527*/
6354  }
6355  }
6356  if ( rowub != NULL )
6357  {
6358  if ( SCIPreleaseRow(scip, &rowub) != SCIP_OKAY )
6359  {
6360  SCIPerrorMessage("Cannot release row,\n");
6361  SCIPABORT();
6362  return; /*lint !e527*/
6363  }
6364  }
6365 
6366  /* if at least one cut has been added */
6367  if ( success )
6368  {
6369  SCIPdebugMessage(" -> found bound cut corresponding to clique (act=%g)\n", unscaledweight);
6370 
6371  /* if we found more than half the cuts we are allowed to generate, we accept the clique as new incumbent,
6372  * such that only more violated cuts are generated afterwards
6373  */
6374  if( tcliquedata->maxboundcuts >= 0 )
6375  {
6376  if ( tcliquedata->ncuts > tcliquedata->maxboundcuts/2 )
6377  *acceptsol = TRUE;
6378  if ( tcliquedata->ncuts >= tcliquedata->maxboundcuts )
6379  *stopsolving = TRUE;
6380  }
6381  }
6382  else
6383  *stopsolving = TRUE;
6384  }
6385  }
6386 }
6387 
6388 
6389 /** separate bound inequalities from conflict graph */
6390 static
6392  SCIP* scip, /**< SCIP pointer */
6393  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6394  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6395  SCIP_SOL* sol, /**< LP solution to be separated (or NULL) */
6396  int maxboundcuts, /**< maximal number of bound cuts separated per separation round (-1: no limit) */
6397  int* ngen, /**< pointer to store number of cuts generated */
6398  SCIP_Bool* cutoff /**< pointer whether a cutoff occurred */
6399  )
6400 {
6401  SCIP_DIGRAPH* conflictgraph;
6402  TCLIQUE_DATA* tcliquedata;
6403  TCLIQUE_WEIGHT cliqueweight;
6404  TCLIQUE_STATUS tcliquestatus;
6405  int nsos1vars;
6406 
6407  SCIP_Real scaleval = 1000.0; /* factor for scaling weights */
6408  int maxtreenodes = 10000; /* maximal number of nodes of b&b tree */
6409  int maxzeroextensions = 1000; /* maximal number of zero-valued variables extending the clique (-1: no limit) */
6410  int backtrackfreq = 1000; /* frequency for premature backtracking up to tree level 1 (0: no backtracking) */
6411  int ntreenodes;
6412  int* cliquenodes;
6413  int ncliquenodes;
6414 
6415  assert( scip != NULL );
6416  assert( conshdlr != NULL );
6417  assert( conshdlrdata != NULL );
6418  assert( ngen != NULL );
6419 
6420  /* get conflict graph */
6421  conflictgraph = SCIPgetConflictgraphSOS1(conshdlr);
6422  assert( conflictgraph != NULL );
6423 
6424  /* get number of SOS1 variables */
6425  nsos1vars = SCIPgetNSOS1Vars(conshdlr);
6426 
6427  /* initialize data of tclique graph*/
6428  tcliquedata = conshdlrdata->tcliquedata;
6429  tcliquedata->scaleval = scaleval;
6430  tcliquedata->maxboundcuts = maxboundcuts;
6431  tcliquedata->sol = sol;
6432  tcliquedata->ncuts = 0;
6433  tcliquedata->cutoff = FALSE;
6434 
6435  /* update the weights of the tclique graph */
6436  SCIP_CALL( updateWeightsTCliquegraph(scip, conshdlrdata, tcliquedata, conflictgraph, sol, nsos1vars) );
6437 
6438  /* allocate buffer array */
6439  SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, nsos1vars) );
6440 
6441  /* start algorithm to find maximum weight cliques and use them to generate bound cuts */
6442  tcliqueMaxClique(tcliqueGetNNodes, tcliqueGetWeights, tcliqueIsEdge, tcliqueSelectAdjnodes,
6443  conshdlrdata->tcliquegraph, tcliqueNewsolClique, tcliquedata,
6444  cliquenodes, &ncliquenodes, &cliqueweight, (int)scaleval-1, (int)scaleval+1,
6445  maxtreenodes, backtrackfreq, maxzeroextensions, -1, &ntreenodes, &tcliquestatus);
6446 
6447  /* free buffer array */
6448  SCIPfreeBufferArray(scip, &cliquenodes);
6449 
6450  /* get number of cuts of current separation round */
6451  *ngen = tcliquedata->ncuts;
6452 
6453  /* store whether a cutoff occurred */
6454  *cutoff = tcliquedata->cutoff;
6455 
6456  /* update number of bound cuts in separator data */
6457  conshdlrdata->nboundcuts = tcliquedata->nboundcuts;
6458 
6459  return SCIP_OKAY;
6460 }
6461 
6462 
6463 /** Generate a bound constraint from the variables of an SOS1 constraint (see generateBoundInequalityFromSOS1Nodes() for more information) */
6464 static
6466  SCIP* scip, /**< SCIP pointer */
6467  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6468  SCIP_CONS* cons, /**< SOS1 constraint */
6469  SCIP_Bool local, /**< in any case produce a local cut (even if local bounds of variables are valid globally) */
6470  SCIP_Bool global, /**< in any case produce a global cut */
6471  SCIP_Bool strengthen, /**< whether trying to strengthen bound constraint */
6472  SCIP_Bool removable, /**< should the inequality be removed from the LP due to aging or cleanup? */
6473  SCIP_ROW** rowlb, /**< output: row for lower bounds (or NULL if not needed) */
6474  SCIP_ROW** rowub /**< output: row for upper bounds (or NULL if not needed) */
6475  )
6476 {
6477  SCIP_CONSHDLRDATA* conshdlrdata;
6478  SCIP_CONSDATA* consdata;
6479  int* nodes;
6480  int nvars;
6481  int cnt = 0;
6482  int j;
6483 
6484  assert( scip != NULL );
6485  assert( conshdlr != NULL );
6486  assert( cons != NULL );
6487 
6488  /* get constraint data */
6489  consdata = SCIPconsGetData(cons);
6490  assert( consdata != NULL );
6491  assert( consdata->vars != NULL );
6492  nvars = consdata->nvars;
6493 
6494  /* get constraint handler data */
6495  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6496  assert( conshdlrdata != NULL );
6497  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
6498 
6499  /* allocate buffer array */
6500  SCIP_CALL( SCIPallocBufferArray(scip, &nodes, nvars) );
6501 
6502  /* get nodes in the conflict graph */
6503  for (j = 0; j < nvars; ++j)
6504  {
6505  if ( SCIPisFeasNegative(scip, SCIPvarGetLbLocal(consdata->vars[j])) || SCIPisFeasPositive(scip, SCIPvarGetUbLocal(consdata->vars[j])) )
6506  {
6507  assert( varGetNodeSOS1(conshdlrdata, consdata->vars[j]) >= 0 );
6508  nodes[cnt++] = varGetNodeSOS1(conshdlrdata, consdata->vars[j]);
6509  }
6510  }
6511 
6512  /* generate bound constraint from conflict graph nodes */
6513  if ( cnt > 0 )
6514  {
6515  SCIP_CALL( generateBoundInequalityFromSOS1Nodes(scip, conshdlr, conshdlrdata->conflictgraph, nodes, cnt, 1.0, local, global,
6516  strengthen, removable, SCIPconsGetName(cons), rowlb, rowub) );
6517  }
6518 
6519  /* free buffer array */
6520  SCIPfreeBufferArray(scip, &nodes);
6521 
6522  return SCIP_OKAY;
6523 }
6524 
6525 
6526 /** initialize or separate bound inequalities from SOS1 constraints */
6527 static
6529  SCIP* scip, /**< SCIP pointer */
6530  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6531  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6532  SCIP_CONS** conss, /**< SOS1 constraints */
6533  int nconss, /**< number of SOS1 constraints */
6534  SCIP_SOL* sol, /**< LP solution to be separated (or NULL) */
6535  SCIP_Bool solvedinitlp, /**< TRUE if initial LP relaxation at a node is solved */
6536  int maxboundcuts, /**< maximal number of bound cuts separated per separation round (-1: no limit) */
6537  int* ngen, /**< pointer to store number of cuts generated (or NULL) */
6538  SCIP_Bool* cutoff /**< pointer to store whether a cutoff occurred */
6539  )
6540 {
6541  int cnt = 0;
6542  int c;
6543 
6544  assert( scip != NULL );
6545  assert( conshdlrdata != NULL );
6546  assert( conss != NULL );
6547 
6548  *cutoff = FALSE;
6549 
6550  for (c = 0; c < nconss; ++c)
6551  {
6552  SCIP_CONSDATA* consdata;
6553  SCIP_ROW* row;
6554 
6555  assert( conss != NULL );
6556  assert( conss[c] != NULL );
6557  consdata = SCIPconsGetData(conss[c]);
6558  assert( consdata != NULL );
6559 
6560  if ( solvedinitlp )
6561  SCIPdebugMessage("Separating inequalities for SOS1 constraint <%s>.\n", SCIPconsGetName(conss[c]) );
6562  else
6563  SCIPdebugMessage("Checking for initial rows for SOS1 constraint <%s>.\n", SCIPconsGetName(conss[c]) );
6564 
6565  /* possibly generate rows if not yet done */
6566  if ( consdata->rowub == NULL || consdata->rowlb == NULL )
6567  {
6568  SCIP_CALL( generateBoundInequalityFromSOS1Cons(scip, conshdlr, conss[c], FALSE, TRUE, TRUE, FALSE, &consdata->rowlb, &consdata->rowub) );
6569  }
6570 
6571  /* put corresponding rows into LP */
6572  row = consdata->rowub;
6573  if ( row != NULL && ! SCIProwIsInLP(row) && ( solvedinitlp || SCIPisCutEfficacious(scip, sol, row) ) )
6574  {
6575  assert( SCIPisInfinity(scip, -SCIProwGetLhs(row)) && ( SCIPisEQ(scip, SCIProwGetRhs(row), 1.0) || SCIPisEQ(scip, SCIProwGetRhs(row), 0.0) ) );
6576 
6577  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, cutoff) );
6578  if ( *cutoff )
6579  break;
6580  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
6581 
6582  if ( solvedinitlp )
6583  {
6584  SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
6585  }
6586  ++cnt;
6587  }
6588 
6589  row = consdata->rowlb;
6590  if ( row != NULL && ! SCIProwIsInLP(row) && ( solvedinitlp || SCIPisCutEfficacious(scip, sol, row) ) )
6591  {
6592  assert( SCIPisInfinity(scip, -SCIProwGetLhs(row)) && ( SCIPisEQ(scip, SCIProwGetRhs(row), 1.0) || SCIPisEQ(scip, SCIProwGetRhs(row), 0.0) ) );
6593 
6594  SCIP_CALL( SCIPaddCut(scip, NULL, row, FALSE, cutoff) );
6595  if ( *cutoff )
6596  break;
6597  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, row, NULL) ) );
6598 
6599  if ( solvedinitlp )
6600  {
6601  SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
6602  }
6603  ++cnt;
6604  }
6605 
6606  if ( maxboundcuts >= 0 && cnt >= maxboundcuts )
6607  break;
6608  }
6609 
6610  /* store number of generated cuts */
6611  if ( ngen != NULL )
6612  *ngen = cnt;
6613 
6614  return SCIP_OKAY;
6615 }
6616 
6617 
6618 /** separate implied bound cuts */
6619 static
6621  SCIP* scip, /**< SCIP pointer */
6622  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6623  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
6624  SCIP_SOL* sol, /**< LP solution to be separated (or NULL) */
6625  int maxcuts, /**< maximal number of implied bound cuts separated per separation round (-1: no limit) */
6626  int* ngen, /**< pointer to store number of cuts generated */
6627  SCIP_Bool* cutoff /**< pointer whether a cutoff occurred */
6628  )
6629 {
6630  SCIP_DIGRAPH* implgraph;
6631  SCIP_Bool genbreak;
6632  int nimplnodes;
6633  int i;
6634 
6635  assert( scip != NULL);
6636  assert( conshdlrdata != NULL);
6637  assert( conshdlr != NULL);
6638  assert( ngen != NULL);
6639  assert( cutoff != NULL);
6640 
6641  *cutoff = FALSE;
6642  *ngen = 0;
6643 
6644  /* get implication graph */
6645  implgraph = conshdlrdata->implgraph;
6646 
6647  /* create implication graph if not done already */
6648  if ( implgraph == NULL )
6649  {
6650  int nchbds;
6651 
6652  if ( SCIPgetDepth(scip) == 0 )
6653  {
6654  SCIP_Bool success;
6655  SCIP_CALL( initImplGraphSOS1(scip, conshdlrdata, conshdlrdata->conflictgraph, conshdlrdata->nsos1vars, conshdlrdata->maxtightenbds, &nchbds, cutoff, &success) );
6656  if ( *cutoff || ! success )
6657  return SCIP_OKAY;
6658  implgraph = conshdlrdata->implgraph;
6659  }
6660  else
6661  {
6662  return SCIP_OKAY;
6663  }
6664  }
6665  nimplnodes = conshdlrdata->nimplnodes;
6666  assert( implgraph != NULL );
6667  assert( nimplnodes > 0);
6668 
6669  /* exit if implication graph has no arcs between its nodes */
6670  if ( SCIPdigraphGetNArcs(implgraph) < 1 )
6671  return SCIP_OKAY;
6672 
6673  /* loop through all nodes of the implication graph */
6674  genbreak = FALSE;
6675  for (i = 0; i < nimplnodes && ! genbreak; ++i)
6676  {
6677  SCIP_SUCCDATA** succdatas;
6678  SCIP_NODEDATA* nodedata;
6679  SCIP_Real solval;
6680  SCIP_VAR* var;
6681  int* succ;
6682  int nsucc;
6683  int s;
6684 
6685  succdatas = (SCIP_SUCCDATA**) SCIPdigraphGetSuccessorsData(implgraph, i);
6686  nodedata = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(implgraph, i);
6687  assert( nodedata != NULL );
6688  var = nodedata->var;
6689  assert( var != NULL );
6690  solval = SCIPgetSolVal(scip, sol, var);
6691 
6692  if ( succdatas != NULL && ! SCIPisFeasZero(scip, solval) )
6693  {
6694  succ = SCIPdigraphGetSuccessors(implgraph, i);
6695  nsucc = SCIPdigraphGetNSuccessors(implgraph, i);
6696 
6697  for (s = 0; s < nsucc && ! genbreak; ++s)
6698  {
6699  SCIP_SUCCDATA* succdata;
6700  SCIP_VAR* succvar;
6701  SCIP_ROW* cut = NULL;
6702  SCIP_Bool bound1lower;
6703  SCIP_Bool bound2lower;
6704  SCIP_Real solvalsucc;
6705  SCIP_Real bound1;
6706  SCIP_Real bound2;
6707  SCIP_Real lhsrhs;
6708  SCIP_Real impl;
6709  int k;
6710 
6711  nodedata = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(implgraph, succ[s]);
6712  succdata = succdatas[s];
6713  assert( nodedata != NULL && succdata != NULL && nodedata->var != NULL );
6714  succvar = nodedata->var;
6715  solvalsucc = SCIPgetSolVal(scip, sol, succvar);
6716 
6717  /* determine coefficients for bound inequality */
6718  assert( ! SCIPisFeasZero(scip, solval) );
6719  if ( SCIPisFeasNegative(scip, solval) )
6720  {
6721  bound1lower = TRUE;
6722  bound1 = SCIPvarGetLbGlobal(var);
6723  }
6724  else
6725  {
6726  bound1lower = FALSE;
6727  bound1 = SCIPvarGetUbGlobal(var);
6728  }
6729 
6730  /* handle lower bound upper bound implications */
6731  for (k = 0; k < 2; ++k)
6732  {
6733  if ( k == 0 )
6734  {
6735  SCIP_Real lbsucc;
6736  lbsucc = SCIPvarGetLbGlobal(succvar);
6737  if ( SCIPisFeasLT(scip, lbsucc, succdata->lbimpl) )
6738  {
6739  impl = succdata->lbimpl;
6740  bound2 = lbsucc;
6741  }
6742  else
6743  continue;
6744  }
6745  else
6746  {
6747  SCIP_Real ubsucc;
6748  ubsucc = SCIPvarGetUbGlobal(succvar);
6749  if ( SCIPisFeasGT(scip, ubsucc, succdata->ubimpl) )
6750  {
6751  impl = succdata->ubimpl;
6752  bound2 = ubsucc;
6753  }
6754  else
6755  continue;
6756  }
6757 
6758  if ( SCIPisInfinity(scip, REALABS(bound1)) || SCIPisInfinity(scip, REALABS(bound2)) )
6759  continue;
6760  assert( ! SCIPisInfinity(scip, REALABS(impl)) );
6761 
6762  if ( SCIPisFeasNegative(scip, bound2-impl) )
6763  bound2lower = TRUE;
6764  else
6765  bound2lower = FALSE;
6766 
6767  /* determine left/right hand side of bound inequality */
6768  lhsrhs = (bound2-impl) * bound1 + impl * bound1;
6769 
6770  /* create cut */
6771  if ( bound1lower == bound2lower )
6772  {
6773  if ( SCIPisFeasGT(scip, solval * (bound2-impl) + solvalsucc * bound1, lhsrhs) )
6774  {
6775  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &cut, conshdlr, "", -SCIPinfinity(scip), lhsrhs, FALSE, FALSE, TRUE) );
6776  }
6777  else
6778  continue;
6779  }
6780  else
6781  {
6782  if ( SCIPisFeasLT(scip, solval * (bound2-impl) + solvalsucc * bound1, lhsrhs) )
6783  {
6784  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &cut, conshdlr, "", lhsrhs, SCIPinfinity(scip), FALSE, FALSE, TRUE) );
6785  }
6786  else
6787  continue;
6788  }
6789 
6790  /* add coefficients of variables */
6791  SCIP_CALL( SCIPcacheRowExtensions(scip, cut) );
6792  SCIP_CALL( SCIPaddVarToRow(scip, cut, var, bound2-impl) );
6793  SCIP_CALL( SCIPaddVarToRow(scip, cut, succvar, bound1) );
6794  SCIP_CALL( SCIPflushRowExtensions(scip, cut) );
6795 
6796  /* add cut if useful */
6797  if ( ! SCIProwIsInLP(cut) && SCIPisCutEfficacious(scip, NULL, cut) )
6798  {
6799  SCIP_Bool infeasible;
6800  SCIP_CALL( SCIPaddCut(scip, NULL, cut, FALSE, &infeasible) );
6801  if ( infeasible )
6802  {
6803  genbreak = TRUE;
6804  *cutoff = TRUE;
6805  break;
6806  }
6807  SCIPdebug( SCIP_CALL( SCIPprintRow(scip, cut, NULL) ) );
6808 #ifdef SCIP_DEBUG
6809  if ( k == 0 )
6810  SCIPdebugMessage("added cut for implication %s != 0 -> %s >= %f \n", SCIPvarGetName(var), SCIPvarGetName(succvar), succdata->lbimpl);
6811  else
6812  SCIPdebugMessage("added cut for implication %s != 0 -> %s <= %f \n", SCIPvarGetName(var), SCIPvarGetName(succvar), succdata->ubimpl);
6813 #endif
6814 
6815  ++(*ngen);
6816  }
6817 
6818  if ( maxcuts >= 0 && *ngen > maxcuts )
6819  {
6820  genbreak = TRUE;
6821  break;
6822  }
6823  }
6824 
6825  if ( cut != NULL )
6826  SCIP_CALL( SCIPreleaseRow(scip, &cut) );
6827  }
6828  }
6829  }
6830 
6831  return SCIP_OKAY;
6832 }
6833 
6834 
6835 /** separates SOS1 constraints for arbitrary solutions */
6836 static
6838  SCIP* scip, /**< SCIP pointer */
6839  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
6840  SCIP_SOL* sol, /**< solution to be separated (or NULL) */
6841  int nconss, /**< number of constraints */
6842  SCIP_CONS** conss, /**< SOS1 constraints */
6843  SCIP_RESULT* result /**< result */
6844  )
6845 {
6846  SCIP_CONSHDLRDATA* conshdlrdata;
6847  int depth;
6848 
6849  assert( scip != NULL );
6850  assert( conshdlr != NULL );
6851  assert( conss != NULL );
6852  assert( result != NULL );
6853 
6854  *result = SCIP_DIDNOTRUN;
6855 
6856  if ( nconss == 0 )
6857  return SCIP_OKAY;
6858 
6859  /* only separate cuts if we are not close to terminating */
6860  if( SCIPisStopped(scip) )
6861  return SCIP_OKAY;
6862 
6863  *result = SCIP_DIDNOTFIND;
6864 
6865  /* get constraint handler data */
6866  conshdlrdata = SCIPconshdlrGetData(conshdlr);
6867  assert( conshdlrdata != NULL );
6868 
6869  /* get node depth */
6870  depth = SCIPgetDepth(scip);
6871 
6872 
6873  /* separate bound (clique) inequalities */
6874  if ( conshdlrdata->boundcutsfreq >= 0 && ( (conshdlrdata->boundcutsfreq == 0 && depth == 0) || (conshdlrdata->boundcutsfreq > 0 && depth % conshdlrdata->boundcutsfreq == 0)) )
6875  {
6876  int maxboundcuts;
6877  int ngen = 0;
6878 
6879  /* determine maximal number of cuts*/
6880  if ( depth == 0 )
6881  maxboundcuts = conshdlrdata->maxboundcutsroot;
6882  else
6883  maxboundcuts = conshdlrdata->maxboundcuts;
6884 
6885  if ( maxboundcuts >= 1 )
6886  {
6887  /* separate bound inequalities from SOS1 constraints */
6888  if( conshdlrdata->boundcutsfromsos1 || conshdlrdata->switchcutsfromsos1 )
6889  {
6890  SCIP_Bool cutoff;
6891 
6892  SCIP_CALL( initsepaBoundInequalityFromSOS1Cons(scip, conshdlr, conshdlrdata, conss, nconss, sol, TRUE, maxboundcuts, &ngen, &cutoff) );
6893  if ( cutoff )
6894  {
6895  *result = SCIP_CUTOFF;
6896  return SCIP_OKAY;
6897  }
6898  }
6899 
6900  /* separate bound inequalities from the conflict graph */
6901  if( conshdlrdata->boundcutsfromgraph && ! conshdlrdata->switchcutsfromsos1 )
6902  {
6903  SCIP_Bool cutoff;
6904  SCIP_CALL( sepaBoundInequalitiesFromGraph(scip, conshdlr, conshdlrdata, sol, maxboundcuts, &ngen, &cutoff) );
6905  if ( cutoff )
6906  {
6907  *result = SCIP_CUTOFF;
6908  return SCIP_OKAY;
6909  }
6910  }
6911  }
6912 
6913  /* evaluate results */
6914  if ( ngen > 0 )
6915  *result = SCIP_SEPARATED;
6916  SCIPdebugMessage("Separated %d bound (clique) inequalities.\n", ngen);
6917  }
6918 
6919 
6920  /* separate implied bound inequalities */
6921  if ( conshdlrdata->implcutsfreq >= 0 && ( (conshdlrdata->implcutsfreq == 0 && depth == 0) || (conshdlrdata->implcutsfreq > 0 && depth % conshdlrdata->implcutsfreq == 0)) )
6922  {
6923  int maximplcuts;
6924  int ngen = 0;
6925 
6926  /* determine maximal number of cuts*/
6927  if ( depth == 0 )
6928  maximplcuts = conshdlrdata->maximplcutsroot;
6929  else
6930  maximplcuts = conshdlrdata->maximplcuts;
6931 
6932  /* call separator for implied bound cuts */
6933  if ( maximplcuts >= 1 )
6934  {
6935  SCIP_Bool cutoff;
6936  SCIP_CALL( sepaImplBoundCutsSOS1(scip, conshdlr, conshdlrdata, sol, maximplcuts, &ngen, &cutoff) );
6937  if ( cutoff )
6938  {
6939  *result = SCIP_CUTOFF;
6940  return SCIP_OKAY;
6941  }
6942  }
6943 
6944  /* evaluate results */
6945  if ( ngen > 0 )
6946  *result = SCIP_SEPARATED;
6947  SCIPdebugMessage("Separated %d implied bound inequalities.\n", ngen);
6948  }
6949 
6950  return SCIP_OKAY;
6951 }
6952 
6953 
6954 /* -------------------------- heuristic methods --------------------------------*/
6955 
6956 /** gets weights determining an order of the variables in a heuristic for the maximum weighted independent set problem */
6957 static
6959  SCIP* scip, /**< SCIP pointer */
6960  SCIP_SOL* sol, /**< primal solution or NULL for current LP solution */
6961  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
6962  int nsos1vars, /**< number of SOS1 variables */
6963  SCIP_Bool* indicatorzero, /**< vector that indicates which variables are currently fixed to zero */
6964  SCIP_Real* weights /**< pointer to store weights determining the order of the variables (length = nsos1vars) */
6965  )
6966 {
6967  SCIP_VAR* var;
6968  SCIP_Real val;
6969  SCIP_Real sum;
6970  int nviols;
6971  int* succ;
6972  int nsucc;
6973  int i;
6974  int j;
6975 
6976  assert( scip != NULL );
6977  assert( conflictgraph != NULL );
6978  assert( indicatorzero != NULL );
6979  assert( weights != NULL );
6980 
6981  for (i = 0; i < nsos1vars; ++i)
6982  {
6983  nsucc = SCIPdigraphGetNSuccessors(conflictgraph, i);
6984 
6985  if( nsucc == 0 || indicatorzero[i] )
6986  weights[i] = 0.0;
6987  else
6988  {
6989  var = SCIPnodeGetVarSOS1(conflictgraph, i);
6990  val = REALABS( SCIPgetSolVal(scip, sol, var) );
6991  if ( SCIPisFeasZero(scip, val) )
6992  weights[i] = 0.0;
6993  else
6994  {
6995  succ = SCIPdigraphGetSuccessors(conflictgraph, i);
6996 
6997  nviols = 0;
6998  sum = 0.0;
6999  for (j = 0; j < nsucc; ++j)
7000  {
7001  SCIP_Real valsucc;
7002 
7003  valsucc = REALABS( SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, succ[j])) );
7004  if( ! SCIPisFeasZero(scip, valsucc) )
7005  {
7006  sum += MIN(10E05, valsucc);
7007  ++nviols;
7008  }
7009  }
7010 
7011  if ( nviols == 0 )
7012  weights[i] = 0.0;
7013  else
7014  {
7015  assert( SCIPisFeasPositive(scip, sum * (SCIP_Real)nviols));
7016  val = MIN(1e6, val);
7017  weights[i] = ( val + SCIPsumepsilon(scip) ) / ( sum * (SCIP_Real)nviols + SCIPsumepsilon(scip) );
7018  }
7019  }
7020  }
7021  }
7022 
7023  return SCIP_OKAY;
7024 }
7025 
7026 
7027 /* marks neighbors of a given node as not a member of the maximal independent set */
7028 static
7030  SCIP* scip, /**< SCIP pointer */
7031  SCIP_CONSHDLR* conshdlr, /**< SOS1 constraint handler */
7032  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
7033  int node, /**< node of the conflict graph */
7034  SCIP_Bool* mark, /**< indicator vector of processed nodes */
7035  SCIP_Bool* indset, /**< indicator vector of current independent */
7036  int* cnt, /**< pointer to store number of marked nodes */
7037  SCIP_Bool* cutoff /**< pointer to store whether operation is infeasible */
7038  )
7039 {
7040  int nsucc;
7041  int* succ;
7042  int j;
7043 
7044  assert( scip != NULL );
7045  assert( conflictgraph != NULL );
7046  assert( mark != NULL );
7047  assert( indset != NULL );
7048  assert( cutoff != NULL );
7049  assert( cnt != NULL );
7050 
7051  *cutoff = FALSE;
7052 
7053  nsucc = SCIPdigraphGetNSuccessors(conflictgraph, node);
7054  succ = SCIPdigraphGetSuccessors(conflictgraph, node);
7055 
7056  /* for all successors */
7057  for (j = 0; j < nsucc && !(*cutoff); ++j)
7058  {
7059  int succj;
7060 
7061  succj = succ[j];
7062  if( ! mark[succj] )
7063  {
7064  SCIP_VARSTATUS varstatus;
7065  SCIP_VAR* var;
7066 
7067  /* mark node as processed */
7068  mark[succj] = TRUE;
7069  ++(*cnt);
7070 
7071  /* get variable and variable status corresponding to successor node */
7072  var = SCIPnodeGetVarSOS1(conflictgraph, succj);
7073  varstatus = SCIPvarGetStatus(var);
7074 
7075  /* if variable is aggregated */
7076  if ( varstatus == SCIP_VARSTATUS_AGGREGATED )
7077  {
7078  int aggrnode;
7079 
7080  aggrnode = SCIPvarGetNodeSOS1(conshdlr, SCIPvarGetAggrVar(var));
7081 
7082  /* if aggregated variable is an SOS1 variable */
7083  if ( aggrnode >= 0 )
7084  {
7085  /* if aggregated variable is implied to be zero */
7086  if ( SCIPisFeasZero(scip, SCIPvarGetAggrConstant(var)) )
7087  {
7088  if ( ! mark[aggrnode] )
7089  mark[aggrnode] = TRUE;
7090  else if ( indset[aggrnode] == 1 )
7091  {
7092  *cutoff = TRUE;
7093  return SCIP_OKAY;
7094  }
7095  }
7096  else
7097  {
7098  /* if aggregated variable is not already a member of the maximal independent set */
7099  if ( indset[aggrnode] == 0 )
7100  {
7101  /* if variable is already marked */
7102  if ( mark[aggrnode] )
7103  {
7104  *cutoff = TRUE;
7105  return SCIP_OKAY;
7106  }
7107  else
7108  {
7109  indset[aggrnode] = 1;
7110  mark[aggrnode] = TRUE;
7111  ++(*cnt);
7112  }
7113 
7114  /* mark neighbors of aggregated variable */
7115  SCIP_CALL( markNeighborsMWISHeuristic(scip, conshdlr, conflictgraph, aggrnode, mark, indset, cnt, cutoff) );
7116  }
7117  }
7118  }
7119  }
7120  else if ( varstatus == SCIP_VARSTATUS_NEGATED )
7121  {
7122  int negnode;
7123 
7124  negnode = SCIPvarGetNodeSOS1(conshdlr, SCIPvarGetNegationVar(var));
7125 
7126  /* if negated variable is an SOS1 variable */
7127  if ( negnode >= 0 )
7128  {
7129  if ( SCIPisFeasZero(scip, SCIPvarGetNegationConstant(var) ) )
7130  {
7131  if ( indset[negnode] == 1 )
7132  {
7133  *cutoff = TRUE;
7134  return SCIP_OKAY;
7135  }
7136  else if ( ! mark[negnode] )
7137  {
7138  mark[negnode] = TRUE;
7139  ++(*cnt);
7140  }
7141  }
7142  }
7143  }
7144  }
7145  }
7146 
7147  return SCIP_OKAY;
7148 }
7149 
7150 
7151 /** calls greedy algorithm for the maximum weighted independent set problem (MWIS)
7152  *
7153  * We compute a feasible solution to
7154  * \f[
7155  * \begin{array}{ll}
7156  * \min\limits_{z} & {x^*}^T z \\
7157  * & z_i + z_j \leq 1, \qquad (i,j)\in E \\
7158  * & z_i \in \{0,1\}, \qquad\quad i\in V
7159  * \end{array}
7160  * \f]
7161  * by the algorithm GGWMIN of Shuichi Sakai, Mitsunori Togasaki and Koichi Yamazaki in "A note on greedy algorithms for the
7162  * maximum weighted independent set problem", Discrete Applied Mathematics. Here \f$x^*\f$ denotes the current LP
7163  * relaxation solution. Note that the solution of the MWIS is the indicator vector of an independent set.
7164  */
7165 static
7167  SCIP* scip, /**< SCIP pointer */
7168  SCIP_SOL* sol, /**< primal solution or NULL for current LP solution */
7169  SCIP_CONSHDLR* conshdlr, /**< SOS1 constraint handler */
7170  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
7171  int nsos1vars, /**< number of SOS1 variables */
7172  SCIP_Bool* indicatorzero, /**< vector that indicates which variables are currently fixed to zero */
7173  SCIP_Bool* indset /**< pointer to store indicator vector of an independent set */
7174  )
7175 {
7176  SCIP_Bool* mark = NULL;
7177  SCIP_Real* weights = NULL;
7178  int* indscipvars = NULL;
7179  int ind;
7180  int nsucc;
7181  int i;
7182  int k;
7183 
7184  assert( scip != NULL );
7185  assert( conflictgraph != NULL );
7186  assert( indicatorzero != NULL );
7187  assert( indset != NULL );
7188 
7189  /* allocate buffer arrays */
7190  SCIP_CALL( SCIPallocBufferArray(scip, &mark, nsos1vars) );
7191  SCIP_CALL( SCIPallocBufferArray(scip, &weights, nsos1vars) );
7192  SCIP_CALL( SCIPallocBufferArray(scip, &indscipvars, nsos1vars) );
7193 
7194  /* sort SOS1 variables in nonincreasing order of weights */
7195  for (i = 0; i < nsos1vars; ++i)
7196  indscipvars[i] = i;
7197 
7198  SCIP_CALL( getVectorOfWeights(scip, sol, conflictgraph, nsos1vars, indicatorzero, weights) );
7199  SCIPsortDownRealInt(weights, indscipvars, nsos1vars);
7200 
7201  /* mark fixed variables and variables without any neighbors in the conflict graph */
7202  k = 0;
7203  for (i = 0; i < nsos1vars; ++i)
7204  {
7205  nsucc = SCIPdigraphGetNSuccessors(conflictgraph, i);
7206 
7207  if ( indset[i] == 0 )
7208  {
7209  if( indicatorzero[i] )
7210  {
7211  mark[i] = TRUE;
7212  ++k;
7213  }
7214  else if ( nsucc == 0 )
7215  {
7216  indset[i] = 1;
7217  mark[i] = TRUE;
7218  ++k;
7219  }
7220  else
7221  mark[i] = FALSE;
7222  }
7223  else
7224  {
7225  ++k;
7226  mark[i] = TRUE;
7227  }
7228  }
7229 
7230  /* mark vertices in the order of their largest weight */
7231  for (i = 0; k < nsos1vars; ++i) /*lint !e440*/
7232  {
7233  assert( i < nsos1vars );
7234 
7235  ind = indscipvars[i];
7236 
7237  if ( ! mark[ind] )
7238  {
7239  SCIP_Bool cutoff;
7240 
7241  /* mark ind */
7242  indset[ind] = 1;
7243  mark[ind] = TRUE;
7244  ++k;
7245 
7246  SCIP_CALL( markNeighborsMWISHeuristic(scip, conshdlr, conflictgraph, ind, mark, indset, &k, &cutoff) );
7247  if ( cutoff )
7248  indset[ind] = 0;
7249  }
7250  }
7251  assert( k == nsos1vars );
7252 
7253  /* free buffer arrays */
7254  SCIPfreeBufferArrayNull(scip, &indscipvars);
7255  SCIPfreeBufferArrayNull(scip, &weights);
7256  SCIPfreeBufferArrayNull(scip, &mark);
7257 
7258  return SCIP_OKAY;
7259 }
7260 
7261 
7262 /* --------------------initialization/deinitialization ------------------------*/
7263 
7264 /** check whether \f$x_1\f$ is a bound variable of \f$x_0\f$; i.e., \f$x_0 \leq c\cdot x_1\f$ or \f$x_0 \geq d\cdot x_1\f$
7265  * for positive values \f$c, d\f$. If true, then add this information to the node data of the conflict graph.
7266  */
7267 static
7269  SCIP* scip, /**< SCIP pointer */
7270  SCIP_CONSHDLRDATA* conshdlrdata, /**< SOS1 constraint handler data */
7271  SCIP_VAR* var0, /**< first variable */
7272  SCIP_VAR* var1, /**< second variable */
7273  SCIP_Real val0, /**< first coefficient */
7274  SCIP_Real val1 /**< second coefficient */
7275  )
7276 {
7277  int node0;
7278 
7279  assert( scip != NULL );
7280  assert( conshdlrdata != NULL );
7281  assert( var0 != NULL && var1 != NULL );
7282 
7283  /* get nodes of variable in the conflict graph (node = -1 if no SOS1 variable) */
7284  node0 = varGetNodeSOS1(conshdlrdata, var0);
7285 
7286  /* if var0 is an SOS1 variable */
7287  if ( node0 >= 0 )
7288  {
7289  SCIP_Real val;
7290 
7291  assert( ! SCIPisFeasZero(scip, val0) );
7292  val = -val1/val0;
7293 
7294  /* check variable bound relation of variables */
7295 
7296  /* handle lower bound case */
7297  if ( SCIPisFeasNegative(scip, val0) && SCIPisFeasNegative(scip, val) )
7298  {
7299  SCIP_NODEDATA* nodedata;
7300 
7301  /* get node data of the conflict graph */
7302  nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conshdlrdata->conflictgraph, node0);
7303 
7304  /* @todo: maybe save multiple variable bounds for each SOS1 variable */
7305  if ( nodedata->lbboundvar == NULL )
7306  {
7307  /* add variable bound information to node data */
7308  nodedata->lbboundvar = var1;
7309  nodedata->lbboundcoef = val;
7310 
7311  SCIPdebugMessage("detected variable bound constraint %s >= %f %s.\n", SCIPvarGetName(var0), val, SCIPvarGetName(var1));
7312  }
7313  }
7314  /* handle upper bound case */
7315  else if ( SCIPisFeasPositive(scip, val0) && SCIPisFeasPositive(scip, val) )
7316  {
7317  SCIP_NODEDATA* nodedata;
7318  assert( SCIPisFeasPositive(scip, val0) );
7319 
7320  /* get node data of the conflict graph */
7321  nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conshdlrdata->conflictgraph, node0);
7322 
7323  if ( nodedata->ubboundvar == NULL )
7324  {
7325  /* add variable bound information to node data */
7326  nodedata->ubboundvar = var1;
7327  nodedata->ubboundcoef = val;
7328 
7329  SCIPdebugMessage("detected variable bound constraint %s <= %f %s.\n", SCIPvarGetName(var0), val, SCIPvarGetName(var1));
7330  }
7331  }
7332  }
7333 
7334  return SCIP_OKAY;
7335 }
7336 
7337 
7338 /** pass connected component \f$C\f$ of the conflict graph and check whether all the variables correspond to a unique variable upper bound variable \f$z\f$,
7339  * i.e., \f$x_i \leq u_i z\f$ for every \f$i\in C\f$.
7340  *
7341  * @note if the bound variable is unique, then bound inequalities can be strengthened.
7342  */
7343 static
7345  SCIP* scip, /**< SCIP pointer */
7346  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
7347  int node, /**< current node of connected component */
7348  SCIP_VAR* boundvar, /**< bound variable of connected component */
7349  SCIP_Bool checklb, /**< whether to check lower bound variable (else upper bound variable) */
7350  SCIP_Bool* processed, /**< states for each variable whether it has been processed */
7351  int* concomp, /**< current connected component */
7352  int* nconcomp, /**< pointer to store number of elements of connected component */
7353  SCIP_Bool* unique /**< pointer to store whether bound variable is unique */
7354  )
7355 {
7356  int* succ;
7357  int nsucc;
7358  int s;
7359 
7360  assert( scip != NULL );
7361  assert( conflictgraph != NULL );
7362  assert( processed != NULL );
7363  assert( concomp != NULL );
7364  assert( nconcomp != NULL );
7365  assert( unique != NULL );
7366 
7367  processed[node] = TRUE;/*lint !e737*/
7368  concomp[(*nconcomp)++] = node;
7369 
7370  /* if bound variable of connected component without new node is unique */
7371  if ( *unique )
7372  {
7373  SCIP_NODEDATA* nodedata;
7374  SCIP_VAR* comparevar;
7375  nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, node);
7376  assert( nodedata != NULL );
7377 
7378  if ( checklb )
7379  comparevar = nodedata->lbboundvar;
7380  else
7381  comparevar = nodedata->ubboundvar;
7382 
7383  /* check whether bound variable is unique for connected component without new node */
7384  if ( boundvar == NULL )
7385  {
7386  if ( comparevar != NULL )
7387  *unique = FALSE;
7388  }
7389  else
7390  {
7391  if ( comparevar == NULL )
7392  *unique = FALSE;
7393  else if ( SCIPvarCompare(boundvar, comparevar) != 0 )
7394  *unique = FALSE;
7395  }
7396  }
7397 
7398  /* pass through successor variables */
7399  nsucc = SCIPdigraphGetNSuccessors(conflictgraph, node);
7400  succ = SCIPdigraphGetSuccessors(conflictgraph, node);
7401  for (s = 0; s < nsucc; ++s)
7402  {
7403  if ( ! processed[succ[s]] )
7404  SCIP_CALL( passConComponentVarbound(scip, conflictgraph, succ[s], boundvar, checklb, processed, concomp, nconcomp, unique) );
7405  }
7406 
7407  return SCIP_OKAY;
7408 }
7409 
7410 
7411 /** for each connected component \f$C\f$ of the conflict graph check whether all the variables correspond to a unique variable upper bound variable \f$z\f$
7412  * (e.g., for the upper bound case this means that \f$x_i \leq u_i z\f$ for every \f$i\in C\f$).
7413  *
7414  * @note if the bound variable is unique, then bound inequalities can be strengthened.
7415  */
7416 static
7418  SCIP* scip, /**< SCIP pointer */
7419  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
7420  int nsos1vars, /**< number of SOS1 variables */
7421  SCIP_Bool checklb /**< whether to check lower bound variable (else check upper bound variable) */
7422  )
7423 {
7424  SCIP_Bool* processed; /* states for each variable whether it has been processed */
7425  int* concomp; /* current connected component */
7426  int nconcomp;
7427  int j;
7428 
7429  assert( scip != NULL );
7430  assert( conflictgraph != NULL );
7431 
7432  /* allocate buffer arrays and initialize 'processed' array */
7433  SCIP_CALL( SCIPallocBufferArray(scip, &processed, nsos1vars) );
7434  SCIP_CALL( SCIPallocBufferArray(scip, &concomp, nsos1vars) );
7435  for (j = 0; j < nsos1vars; ++j)
7436  processed[j] = FALSE;
7437 
7438  /* run through all SOS1 variables */
7439  for (j = 0; j < nsos1vars; ++j)
7440  {
7441  /* if variable belongs to a connected component that has not been processed so far */
7442  if ( ! processed[j] )
7443  {
7444  SCIP_NODEDATA* nodedata;
7445  SCIP_VAR* boundvar;
7446  SCIP_Bool unique;
7447  int* succ;
7448  int nsucc;
7449  int s;
7450 
7451  nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, j);
7452  assert( nodedata != NULL );
7453 
7454  if ( checklb )
7455  boundvar = nodedata->lbboundvar;
7456  else
7457  boundvar = nodedata->ubboundvar;
7458  unique = TRUE;
7459 
7460  processed[j] = TRUE;
7461  concomp[0] = j;
7462  nconcomp = 1;
7463 
7464  /* pass through successor variables */
7465  nsucc = SCIPdigraphGetNSuccessors(conflictgraph, j);
7466  succ = SCIPdigraphGetSuccessors(conflictgraph, j);
7467  for (s = 0; s < nsucc; ++s)
7468  {
7469  if ( ! processed[succ[s]] )
7470  {
7471  SCIP_CALL( passConComponentVarbound(scip, conflictgraph, succ[s], boundvar, checklb, processed, concomp, &nconcomp, &unique) );
7472  }
7473  }
7474 
7475  /* if the connected component has a unique bound variable */
7476  if ( unique && boundvar != NULL )
7477  {
7478  for (s = 0; s < nconcomp; ++s)
7479  {
7480  nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, concomp[s]);
7481  assert( processed[concomp[s]] == TRUE );
7482  assert( nodedata != NULL );
7483 
7484  if ( checklb )
7485  nodedata->lbboundcomp = TRUE;
7486  else
7487  nodedata->ubboundcomp = TRUE;
7488  }
7489  SCIPdebugMessage("Found a connected component of size <%i> with unique bound variable.\n", nconcomp);
7490  }
7491  }
7492  }
7493 
7494  /* free buffer arrays */
7495  SCIPfreeBufferArray(scip, &concomp);
7496  SCIPfreeBufferArray(scip, &processed);
7497 
7498  return SCIP_OKAY;
7499 }
7500 
7501 
7502 /** check all linear constraints for variable bound constraints of the form \f$c\cdot z \leq x \leq d\cdot z\f$, where @p x is some SOS1
7503  * variable and @p z is some arbitrary variable (not necessarily binary)
7504  */
7505 static
7507  SCIP* scip, /**< SCIP pointer */
7508  SCIP_CONSHDLRDATA* conshdlrdata, /**< SOS1 constraint handler data */
7509  SCIP_CONS** linconss, /**< linear constraints */
7510  int nlinconss /**< number of linear constraints */
7511  )
7512 {
7513  int c;
7514 
7515  /* loop through linear constraints */
7516  for (c = 0; c < nlinconss; ++c)
7517  {
7518  SCIP_CONS* lincons;
7519  int nvars;
7520 
7521  lincons = linconss[c];
7522 
7523  /* variable bound constraints only contain two variables */
7524  nvars = SCIPgetNVarsLinear(scip, lincons);
7525  if ( nvars == 2 )
7526  {
7527  SCIP_VAR** vars;
7528  SCIP_Real* vals;
7529  SCIP_VAR* var0;
7530  SCIP_VAR* var1;
7531  SCIP_Real lhs;
7532  SCIP_Real rhs;
7533 
7534  /* get constraint data */
7535  vars = SCIPgetVarsLinear(scip, lincons);
7536  vals = SCIPgetValsLinear(scip, lincons);
7537  lhs = SCIPgetLhsLinear(scip, lincons);
7538  rhs = SCIPgetRhsLinear(scip, lincons);
7539 
7540  var0 = vars[0];
7541  var1 = vars[1];
7542  assert( var0 != NULL && var1 != NULL );
7543 
7544  /* at least one variable should be an SOS1 variable */
7545  if ( varIsSOS1(conshdlrdata, var0) || varIsSOS1(conshdlrdata, var1) )
7546  {
7547  SCIP_Real val0;
7548  SCIP_Real val1;
7549 
7550  /* check whether right hand side or left hand side of constraint is zero */
7551  if ( SCIPisFeasZero(scip, lhs) )
7552  {
7553  val0 = -vals[0];
7554  val1 = -vals[1];
7555 
7556  /* check whether the two variables are in a variable bound relation */
7557  SCIP_CALL( detectVarboundSOS1(scip, conshdlrdata, var0, var1, val0, val1) );
7558  SCIP_CALL( detectVarboundSOS1(scip, conshdlrdata, var1, var0, val1, val0) );
7559  }
7560  else if( SCIPisFeasZero(scip, rhs) )
7561  {
7562  val0 = vals[0];
7563  val1 = vals[1];
7564 
7565  /* check whether the two variables are in a variable bound relation */
7566  SCIP_CALL( detectVarboundSOS1(scip, conshdlrdata, var0, var1, val0, val1) );
7567  SCIP_CALL( detectVarboundSOS1(scip, conshdlrdata, var1, var0, val1, val0) );
7568  }
7569  }
7570  }
7571  }
7572 
7573  return SCIP_OKAY;
7574 }
7575 
7576 
7577 /** switch to SOS1 branching and separating bound iniqualities from SOS1 constraints if the SOS1 constraints do not overlap */
7578 static
7580  SCIP* scip, /**< SCIP pointer */
7581  SCIP_CONSHDLRDATA* conshdlrdata, /**< SOS1 constraint handler data */
7582  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
7583  SCIP_CONS** conss, /**< SOS1 constraints */
7584  int nconss /**< number of SOS1 constraints */
7585  )
7586 {
7587  SCIP_Bool nonoverlap = TRUE;
7588  int c;
7589 
7590  /* loop through all SOS1 constraints */
7591  if ( conshdlrdata->nsos1vars > 0 )
7592  {
7593  for (c = 0; c < nconss && nonoverlap; ++c)
7594  {
7595  SCIP_CONSDATA* consdata;
7596  SCIP_VAR** vars;
7597  int notfixed = 0;
7598  int nvars;
7599  int i;
7600 
7601  assert( conss[c] != NULL );
7602 
7603  /* get constraint data field of the constraint */
7604  consdata = SCIPconsGetData(conss[c]);
7605  assert( consdata != NULL );
7606 
7607  /* get variables and number of variables of constraint */
7608  nvars = consdata->nvars;
7609  vars = consdata->vars;
7610 
7611  /* get number of variables of SOS1 constraint that are not fixed to zero */
7612  for (i = 0; i < nvars; ++i)
7613  {
7614  if ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(vars[i])) || ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(vars[i])) )
7615  ++notfixed;
7616  }
7617 
7618  /* check variables of SOS1 constraint */
7619  for (i = 0; i < nvars; ++i)
7620  {
7621  int node;
7622 
7623  assert( vars[i] != NULL );
7624 
7625  node = varGetNodeSOS1(conshdlrdata, vars[i]);
7626  assert( node >= 0 || ( SCIPisFeasZero(scip, SCIPvarGetLbLocal(vars[i])) && SCIPisFeasZero(scip, SCIPvarGetUbLocal(vars[i]))) );
7627  assert( node < conshdlrdata->nsos1vars );
7628  assert( node < 0 || SCIPdigraphGetNSuccessors(conflictgraph, node) >= notfixed-1 );
7629  if ( node >= 0 && SCIPdigraphGetNSuccessors(conflictgraph, node) > notfixed-1 )
7630  {
7631  nonoverlap = FALSE;
7632  break;
7633  }
7634  }
7635  }
7636  }
7637 
7638  /* if the SOS1 constraints do not overlap */
7639  if ( nonoverlap )
7640  {
7641  if ( conshdlrdata->autosos1branch )
7642  {
7643  conshdlrdata->switchsos1branch = TRUE;
7644  SCIPdebugMessage("Switched to SOS1 branching, since the SOS1 constraints do not overlap\n");
7645  }
7646 
7647  if ( conshdlrdata->autocutsfromsos1 )
7648  {
7649  conshdlrdata->switchcutsfromsos1 = TRUE;
7650  SCIPdebugMessage("Switched to separating bound cuts from SOS1 constraints (and not from the conflict graph), since the SOS1 constraints do not overlap\n");
7651  }
7652  }
7653 
7654  return SCIP_OKAY;
7655 }
7656 
7657 
7658 /** sets node data of conflict graph nodes */
7659 static
7661  SCIP* scip, /**< SCIP pointer */
7662  SCIP_CONSHDLRDATA* conshdlrdata, /**< SOS1 constraint handler data */
7663  int nsos1vars /**< number of SOS1 variables */
7664  )
7666  SCIP_CONSHDLR* linconshdlr;
7667  SCIP_CONS** linconss;
7668  int nlinconss;
7669 
7670  /* if no SOS1 variables exist -> exit */
7671  if ( nsos1vars == 0 )
7672  return SCIP_OKAY;
7673 
7674  /* get constraint handler data of linear constraints */
7675  linconshdlr = SCIPfindConshdlr(scip, "linear");
7676  if ( linconshdlr == NULL )
7677  return SCIP_OKAY;
7678 
7679  /* get linear constraints and number of linear constraints */
7680  nlinconss = SCIPconshdlrGetNConss(linconshdlr);
7681  linconss = SCIPconshdlrGetConss(linconshdlr);
7682 
7683  /* check linear constraints for variable bound constraints */
7684  SCIP_CALL( checkLinearConssVarboundSOS1(scip, conshdlrdata, linconss, nlinconss) );
7685 
7686  /* for each connected component of the conflict graph check whether all the variables correspond to a unique variable
7687  * upper bound variable */
7688  SCIP_CALL( checkConComponentsVarbound(scip, conshdlrdata->conflictgraph, conshdlrdata->nsos1vars, TRUE) );
7689  SCIP_CALL( checkConComponentsVarbound(scip, conshdlrdata->conflictgraph, conshdlrdata->nsos1vars, FALSE) );
7690 
7691  return SCIP_OKAY;
7692 }
7693 
7694 
7695 /** initialize conflictgraph and create hashmap for SOS1 variables */
7696 static
7698  SCIP* scip, /**< SCIP pointer */
7699  SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
7700  SCIP_CONS** conss, /**< SOS1 constraints */
7701  int nconss /**< number of SOS1 constraints */
7702  )
7703 {
7704  SCIP_Bool* nodecreated; /* nodecreated[i] = TRUE if a node in the conflict graph is already created for index i
7705  * (with i index of the original variables) */
7706  int* nodeorig; /* nodeorig[i] = node of original variable x_i in the conflict graph */
7707  int ntotalvars;
7708  int cntsos;
7709  int i;
7710  int j;
7711  int c;
7712 
7713  assert( conshdlrdata != NULL );
7714  assert( nconss == 0 || conss != NULL );
7715 
7716  /* get the number of original problem variables */
7717  ntotalvars = SCIPgetNTotalVars(scip);
7718 
7719  /* initialize vector 'nodecreated' */
7720  SCIP_CALL( SCIPallocBufferArray(scip, &nodeorig, ntotalvars) );
7721  SCIP_CALL( SCIPallocBufferArray(scip, &nodecreated, ntotalvars) );
7722  for (i = 0; i < ntotalvars; ++i)
7723  nodecreated[i] = FALSE;
7724 
7725  /* compute number of SOS1 variables */
7726  cntsos = 0;
7727  for (c = 0; c < nconss; ++c)
7728  {
7729  SCIP_CONSDATA* consdata;
7730  SCIP_VAR** vars;
7731  int nvars;
7732 
7733  assert( conss[c] != NULL );
7734 
7735  /* get constraint data field of the constraint */
7736  consdata = SCIPconsGetData(conss[c]);
7737  assert( consdata != NULL );
7738 
7739  /* get variables and number of variables of constraint */
7740  nvars = consdata->nvars;
7741  vars = consdata->vars;
7742 
7743  /* update number of SOS1 variables */
7744  for (i = 0; i < nvars; ++i)
7745  {
7746  SCIP_VAR* var;
7747 
7748  var = vars[i];
7749 
7750  /* if the variable is not fixed to zero */
7751  if ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) || ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) )
7752  {
7753  int ind;
7754 
7755  ind = SCIPvarGetIndex(var);
7756  assert( ind >= 0 && ind < ntotalvars );
7757  if ( ! nodecreated[ind] )
7758  {
7759  nodecreated[ind] = TRUE; /* mark node as counted */
7760  nodeorig[ind] = cntsos;
7761  ++cntsos;
7762  }
7763  }
7764  }
7765  }
7766  if ( cntsos <= 0 )
7767  {
7768  /* free buffer arrays */
7769  SCIPfreeBufferArray(scip, &nodecreated);
7770  SCIPfreeBufferArray(scip, &nodeorig);
7771  conshdlrdata->nsos1vars = 0;
7772  return SCIP_OKAY;
7773  }
7774 
7775  /* reinitialize vector 'nodecreated' */
7776  for (i = 0; i < ntotalvars; ++i)
7777  nodecreated[i] = FALSE;
7778 
7779  /* create conflict graph */
7780  SCIP_CALL( SCIPdigraphCreate(&conshdlrdata->conflictgraph, cntsos) );
7781 
7782  /* set up hash map */
7783  SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->varhash, SCIPblkmem(scip), cntsos) );
7784 
7785  /* for every SOS1 constraint */
7786  cntsos = 0;
7787  for (c = 0; c < nconss; ++c)
7788  {
7789  SCIP_CONSDATA* consdata;
7790  SCIP_VAR** vars;
7791  int nvars;
7792 
7793  assert( conss[c] != NULL );
7794 
7795  /* get constraint data field of the constraint */
7796  consdata = SCIPconsGetData(conss[c]);
7797  assert( consdata != NULL );
7798 
7799  /* get variables and number of variables of constraint */
7800  nvars = consdata->nvars;
7801  vars = consdata->vars;
7802 
7803  /* add edges to the conflict graph and create node data for each of its nodes */
7804  for (i = 0; i < nvars; ++i)
7805  {
7806  SCIP_VAR* var;
7807 
7808  var = vars[i];
7809 
7810  /* if the variable is not fixed to zero */
7811  if ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) || ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) )
7812  {
7813  int indi;
7814 
7815  indi = SCIPvarGetIndex(var);
7816 
7817  if ( ! nodecreated[indi] )
7818  {
7819  SCIP_NODEDATA* nodedata = NULL;
7820 
7821  /* insert node number to hash map */
7822  assert( ! SCIPhashmapExists(conshdlrdata->varhash, var) );
7823  SCIP_CALL( SCIPhashmapInsert(conshdlrdata->varhash, var, (void*) (size_t) cntsos) );/*lint !e571*/
7824  assert( cntsos == (int) (size_t) SCIPhashmapGetImage(conshdlrdata->varhash, var) );
7825  assert( SCIPhashmapExists(conshdlrdata->varhash, var) );
7826 
7827  /* create node data */
7828  SCIP_CALL( SCIPallocMemory(scip, &nodedata) );
7829  nodedata->var = var;
7830  nodedata->lbboundvar = NULL;
7831  nodedata->ubboundvar = NULL;
7832  nodedata->lbboundcoef = 0.0;
7833  nodedata->ubboundcoef = 0.0;
7834  nodedata->lbboundcomp = FALSE;
7835  nodedata->ubboundcomp = FALSE;
7836 
7837  /* set node data */
7838  SCIPdigraphSetNodeData(conshdlrdata->conflictgraph, (void*)nodedata, cntsos);
7839 
7840  /* mark node and var data of node as created and update SOS1 counter */
7841  nodecreated[indi] = TRUE;
7842  ++cntsos;
7843  }
7844 
7845  /* add edges to the conflict graph */
7846  for (j = i+1; j < nvars; ++j)
7847  {
7848  var = vars[j];
7849 
7850  /* if the variable is not fixed to zero */
7851  if ( ! SCIPisFeasZero(scip, SCIPvarGetLbLocal(var)) || ! SCIPisFeasZero(scip, SCIPvarGetUbLocal(var)) )
7852  {
7853  int indj;
7854 
7855  indj = SCIPvarGetIndex(var);
7856 
7857  /* in case indi = indj the variable will be deleted in the presolving step */
7858  if ( indi != indj )
7859  {
7860  /* arcs have to be added 'safe' */
7861  SCIP_CALL( SCIPdigraphAddArcSafe(conshdlrdata->conflictgraph, nodeorig[indi], nodeorig[indj], NULL) );
7862  SCIP_CALL( SCIPdigraphAddArcSafe(conshdlrdata->conflictgraph, nodeorig[indj], nodeorig[indi], NULL) );
7863  }
7864  }
7865  }
7866  }
7867  }
7868  }
7869 
7870  /* set number of problem variables that are contained in at least one SOS1 constraint */
7871  conshdlrdata->nsos1vars = cntsos;
7872 
7873  /* free buffer arrays */
7874  SCIPfreeBufferArray(scip, &nodecreated);
7875  SCIPfreeBufferArray(scip, &nodeorig);
7876 
7877  /* sort successors in ascending order */
7878  for (j = 0; j < conshdlrdata->nsos1vars; ++j)
7879  {
7880  int nsucc;
7881 
7882  nsucc = SCIPdigraphGetNSuccessors(conshdlrdata->conflictgraph, j);
7883  SCIPsortInt(SCIPdigraphGetSuccessors(conshdlrdata->conflictgraph, j), nsucc);
7884  }
7885 
7886  return SCIP_OKAY;
7887 }
7888 
7889 
7890 /** free conflict graph, nodedata and hashmap */
7891 static
7893  SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
7894  )
7895 {
7896  int j;
7898  if ( conshdlrdata->conflictgraph == NULL )
7899  return SCIP_OKAY;
7900 
7901  /* for every SOS1 variable */
7902  assert( conshdlrdata->nsos1vars > 0 );
7903  for (j = 0; j < conshdlrdata->nsos1vars; ++j)
7904  {
7905  SCIP_NODEDATA* nodedata;
7906 
7907  /* get node data */
7908  assert( conshdlrdata->conflictgraph != NULL );
7909  nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conshdlrdata->conflictgraph, j);
7910  assert( nodedata != NULL );
7911 
7912  /* free node data */
7913  SCIPfreeMemory(scip, &nodedata);
7914  SCIPdigraphSetNodeData(conshdlrdata->conflictgraph, NULL, j);
7915  }
7916 
7917  /* free conflict graph and hash map */
7918  assert( conshdlrdata->varhash != NULL );
7919  SCIPhashmapFree(&conshdlrdata->varhash);
7920  SCIPdigraphFree(&conshdlrdata->conflictgraph);
7921 
7922  return SCIP_OKAY;
7923 }
7924 
7925 
7926 /* ---------------------------- constraint handler callback methods ----------------------*/
7927 
7928 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
7929 static
7930 SCIP_DECL_CONSHDLRCOPY(conshdlrCopySOS1)
7931 { /*lint --e{715}*/
7932  assert( scip != NULL );
7933  assert( conshdlr != NULL );
7934  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
7936  /* call inclusion method of constraint handler */
7938 
7939  *valid = TRUE;
7940 
7941  return SCIP_OKAY;
7942 }
7943 
7944 
7945 /** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
7946 static
7947 SCIP_DECL_CONSFREE(consFreeSOS1)
7948 {
7949  SCIP_CONSHDLRDATA* conshdlrdata;
7950 
7951  assert( scip != NULL );
7952  assert( conshdlr != NULL );
7953  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
7954 
7955  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7956  assert(conshdlrdata != NULL);
7957 
7958  SCIPfreeMemory(scip, &conshdlrdata);
7959 
7960  return SCIP_OKAY;
7961 }
7962 
7963 
7964 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
7965 static
7966 SCIP_DECL_CONSINITSOL(consInitsolSOS1)
7967 { /*lint --e{715}*/
7968  SCIP_CONSHDLRDATA* conshdlrdata;
7969 
7970  assert( scip != NULL );
7971  assert( conshdlr != NULL );
7972  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
7973 
7974  conshdlrdata = SCIPconshdlrGetData(conshdlr);
7975  assert( conshdlrdata != NULL );
7976 
7977  conshdlrdata->nsos1vars = 0;
7978  conshdlrdata->varhash = NULL;
7979 
7980  if ( nconss > 0 )
7981  {
7982  /* initialize conflict graph and hashmap for SOS1 variables */
7983  SCIP_CALL( initConflictgraph(scip, conshdlrdata, conss, nconss) );
7984 
7985  /* add data to conflict graph nodes */
7986  SCIP_CALL( computeNodeDataSOS1(scip, conshdlrdata, conshdlrdata->nsos1vars) );
7987 
7988  if ( (! conshdlrdata->sos1branch || ! conshdlrdata->boundcutsfromsos1 )
7989  && ( conshdlrdata->autosos1branch || conshdlrdata->autocutsfromsos1 )
7990  && ( ! conshdlrdata->switchsos1branch || ! conshdlrdata->switchcutsfromsos1 )
7991  )
7992  {
7993  /* switch to nonoverlapping methods if the SOS1 constraints do not overlap */
7994  SCIP_CALL( checkSwitchNonoverlappingSOS1Methods(scip, conshdlrdata, conshdlrdata->conflictgraph, conss, nconss) );
7995  }
7996 
7997  /* initialize tclique graph */
7998  SCIP_CALL( initTCliquegraph(scip, conshdlr, conshdlrdata, conshdlrdata->conflictgraph, conshdlrdata->nsos1vars) );
7999 
8000  /* create local conflict graph if needed */
8001  if ( conshdlrdata->addcomps )
8002  {
8003  SCIP_CALL( SCIPdigraphCreate(&conshdlrdata->localconflicts, conshdlrdata->nsos1vars) );
8004  }
8005 
8006  /* initialize stack of variables fixed to nonzero (memory may be already allocated in consTransSOS1()) */
8007  if ( conshdlrdata->fixnonzerovars == NULL )
8008  {
8009  conshdlrdata->maxnfixnonzerovars = conshdlrdata->nsos1vars;
8010  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &conshdlrdata->fixnonzerovars, conshdlrdata->maxnfixnonzerovars) );
8011  }
8012  }
8013 
8014  return SCIP_OKAY;
8015 }
8016 
8017 
8018 /** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
8019 static
8020 SCIP_DECL_CONSEXITSOL(consExitsolSOS1)
8021 { /*lint --e{715}*/
8022  SCIP_CONSHDLRDATA* conshdlrdata;
8023  int c;
8024 
8025  assert( scip != NULL );
8026  assert( conshdlr != NULL );
8027  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8028  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8029  assert( conshdlrdata != NULL );
8030 
8031  /* check each constraint */
8032  for (c = 0; c < nconss; ++c)
8033  {
8034  SCIP_CONSDATA* consdata;
8035 
8036  assert( conss != NULL );
8037  assert( conss[c] != NULL );
8038  consdata = SCIPconsGetData(conss[c]);
8039  assert( consdata != NULL );
8040 
8041  SCIPdebugMessage("Exiting SOS1 constraint <%s>.\n", SCIPconsGetName(conss[c]) );
8042 
8043  /* free rows */
8044  if ( consdata->rowub != NULL )
8045  {
8046  SCIP_CALL( SCIPreleaseRow(scip, &consdata->rowub) );
8047  }
8048 
8049  if ( consdata->rowlb != NULL )
8050  {
8051  SCIP_CALL( SCIPreleaseRow(scip, &consdata->rowlb) );
8052  }
8053  }
8054 
8055  /* free implication graph */
8056  if ( conshdlrdata->implgraph != NULL )
8057  {
8058  SCIP_CALL( freeImplGraphSOS1(scip, conshdlrdata) );
8059  }
8060 
8061  /* free tclique graph and tclique data */
8062  if ( conshdlrdata->tcliquegraph != NULL )
8063  {
8064  assert( conshdlrdata->tcliquedata != NULL );
8065  SCIPfreeMemory(scip, &conshdlrdata->tcliquedata);
8066  tcliqueFree(&conshdlrdata->tcliquegraph);
8067  }
8068  assert(conshdlrdata->tcliquegraph == NULL);
8069  assert(conshdlrdata->tcliquedata == NULL);
8070 
8071  /* free stack of variables fixed to nonzero */
8072  SCIPfreeBlockMemoryArrayNull(scip, &conshdlrdata->fixnonzerovars, conshdlrdata->maxnfixnonzerovars); /*lint !e737*/
8073 
8074  /* free graph for storing local conflicts */
8075  if ( conshdlrdata->localconflicts != NULL )
8076  SCIPdigraphFree(&conshdlrdata->localconflicts);
8077  assert( conshdlrdata->localconflicts == NULL );
8078 
8079  /* free conflict graph */
8080  SCIP_CALL( freeConflictgraph(conshdlrdata) );
8081  assert( conshdlrdata->conflictgraph == NULL );
8082 
8083  return SCIP_OKAY;
8084 }
8085 
8086 
8087 /** frees specific constraint data */
8088 static
8089 SCIP_DECL_CONSDELETE(consDeleteSOS1)
8090 {
8091  assert( scip != NULL );
8092  assert( conshdlr != NULL );
8093  assert( cons != NULL );
8094  assert( consdata != NULL );
8095  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8096 
8097  SCIPdebugMessage("Deleting SOS1 constraint <%s>.\n", SCIPconsGetName(cons) );
8098 
8099  /* drop events on transformed variables */
8100  if ( SCIPconsIsTransformed(cons) )
8101  {
8102  SCIP_CONSHDLRDATA* conshdlrdata;
8103  int j;
8104 
8105  /* get constraint handler data */
8106  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8107  assert( conshdlrdata != NULL );
8108  assert( conshdlrdata->eventhdlr != NULL );
8109 
8110  for (j = 0; j < (*consdata)->nvars; ++j)
8111  {
8112  SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->vars[j], SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlr,
8113  (SCIP_EVENTDATA*)cons, -1) ); /*lint !e737 !e740*/
8114  }
8115  }
8116 
8117  SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->maxvars);
8118  if ( (*consdata)->weights != NULL )
8119  {
8120  SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->maxvars);
8121  }
8122 
8123  /* free rows */
8124  if ( (*consdata)->rowub != NULL )
8125  {
8126  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->rowub) );
8127  }
8128  if ( (*consdata)->rowlb != NULL )
8129  {
8130  SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->rowlb) );
8131  }
8132  assert( (*consdata)->rowub == NULL );
8133  assert( (*consdata)->rowlb == NULL );
8134 
8135  SCIPfreeBlockMemory(scip, consdata);
8136 
8137  return SCIP_OKAY;
8138 }
8139 
8140 
8141 /** transforms constraint data into data belonging to the transformed problem */
8142 static
8143 SCIP_DECL_CONSTRANS(consTransSOS1)
8144 {
8145  SCIP_CONSDATA* consdata;
8146  SCIP_CONSHDLRDATA* conshdlrdata;
8147  SCIP_CONSDATA* sourcedata;
8149  int j;
8150 
8151  assert( scip != NULL );
8152  assert( conshdlr != NULL );
8153  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8154  assert( sourcecons != NULL );
8155  assert( targetcons != NULL );
8156 
8157  /* get constraint handler data */
8158  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8159  assert( conshdlrdata != NULL );
8160  assert( conshdlrdata->eventhdlr != NULL );
8161 
8162  SCIPdebugMessage("Transforming SOS1 constraint: <%s>.\n", SCIPconsGetName(sourcecons) );
8163 
8164  /* get data of original constraint */
8165  sourcedata = SCIPconsGetData(sourcecons);
8166  assert( sourcedata != NULL );
8167  assert( sourcedata->nvars > 0 );
8168  assert( sourcedata->nvars <= sourcedata->maxvars );
8169 
8170  /* initialize stack of variables fixed to nonzero */
8171  if ( conshdlrdata->fixnonzerovars == NULL )
8172  {
8173  conshdlrdata->maxnfixnonzerovars = SCIPgetNTotalVars(scip);
8174  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &conshdlrdata->fixnonzerovars, conshdlrdata->maxnfixnonzerovars) );
8175  }
8176 
8177  /* create constraint data */
8178  SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) );
8179 
8180  consdata->nvars = sourcedata->nvars;
8181  consdata->maxvars = sourcedata->nvars;
8182  consdata->rowub = NULL;
8183  consdata->rowlb = NULL;
8184  consdata->nfixednonzeros = 0;
8185  consdata->local = sourcedata->local;
8186  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->vars, consdata->nvars) );
8187  /* if weights were used */
8188  if ( sourcedata->weights != NULL )
8189  {
8190  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->weights, sourcedata->weights, consdata->nvars) );
8191  }
8192  else
8193  consdata->weights = NULL;
8194 
8195  for (j = 0; j < sourcedata->nvars; ++j)
8196  {
8197  assert( sourcedata->vars[j] != 0 );
8198  SCIP_CALL( SCIPgetTransformedVar(scip, sourcedata->vars[j], &(consdata->vars[j])) );
8199 
8200  /* if variable is fixed to be nonzero */
8201  if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(consdata->vars[j])) || SCIPisFeasNegative(scip, SCIPvarGetUbLocal(consdata->vars[j])) )
8202  ++(consdata->nfixednonzeros);
8203  }
8204 
8205  /* create transformed constraint with the same flags */
8206  (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "t_%s", SCIPconsGetName(sourcecons));
8207  SCIP_CALL( SCIPcreateCons(scip, targetcons, s, conshdlr, consdata,
8208  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons),
8209  SCIPconsIsEnforced(sourcecons), SCIPconsIsChecked(sourcecons),
8210  SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
8211  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons),
8212  SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
8213 
8214  /* catch bound change events on variable */
8215  for (j = 0; j < consdata->nvars; ++j)
8216  {
8217  SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[j], SCIP_EVENTTYPE_BOUNDCHANGED, conshdlrdata->eventhdlr,
8218  (SCIP_EVENTDATA*)*targetcons, NULL) ); /*lint !e740*/
8219  }
8220 
8221 #ifdef SCIP_DEBUG
8222  if ( consdata->nfixednonzeros > 0 )
8223  {
8224  SCIPdebugMessage("constraint <%s> has %d variables fixed to be nonzero.\n", SCIPconsGetName(*targetcons),
8225  consdata->nfixednonzeros );
8226  }
8227 #endif
8228 
8229  return SCIP_OKAY;
8230 }
8231 
8232 
8233 /** presolving method of constraint handler */
8234 static
8235 SCIP_DECL_CONSPRESOL(consPresolSOS1)
8236 { /*lint --e{715}*/
8237  SCIP_CONSHDLRDATA* conshdlrdata;
8238  int oldnfixedvars;
8239  int oldndelconss;
8240  int oldnupgdconss;
8241  int nremovedvars;
8242 
8243  assert( scip != NULL );
8244  assert( conshdlr != NULL );
8245  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8246  assert( result != NULL );
8247 
8248  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8249  assert( conshdlrdata != NULL );
8250 
8251  SCIPdebugMessage("Presolving SOS1 constraints.\n");
8252 
8253  *result = SCIP_DIDNOTRUN;
8254 
8255  oldnfixedvars = *nfixedvars;
8256  oldndelconss = *ndelconss;
8257  oldnupgdconss = *nupgdconss;
8258  nremovedvars = 0;
8259 
8260  /* only run if success if possible */
8261  if( nconss > 0 && ( nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgbds > 0 ) )
8262  {
8263  SCIP_Bool** adjacencymatrix = NULL;
8264  SCIP_DIGRAPH* conflictgraph;
8265  SCIP_EVENTHDLR* eventhdlr;
8266  int nsos1vars;
8267  int i;
8268  int j;
8269 
8270  *result = SCIP_DIDNOTFIND;
8271 
8272  /* get constraint handler data */
8273  assert( SCIPconshdlrGetData(conshdlr) != NULL );
8274  eventhdlr = SCIPconshdlrGetData(conshdlr)->eventhdlr;
8275  assert( eventhdlr != NULL );
8276 
8277  /* initialize conflict graph */
8278  SCIP_CALL( initConflictgraph(scip, conshdlrdata, conss, nconss));
8279 
8280  /* get conflict graph and number of SOS1 variables */
8281  conflictgraph = conshdlrdata->conflictgraph;
8282  nsos1vars = conshdlrdata->nsos1vars;
8283  if ( nsos1vars < 2 )
8284  {
8285  SCIP_CALL( freeConflictgraph(conshdlrdata));
8286  return SCIP_OKAY;
8287  }
8288 
8289  /* we do not create the adjacency matrix of the conflict graph if the number of SOS1 variables is larger than a predefined value */
8290  if ( conshdlrdata->maxsosadjacency == -1 || nsos1vars <= conshdlrdata->maxsosadjacency )
8291  {
8292  /* allocate buffer arrays for adjacency matrix */
8293  SCIP_CALL( SCIPallocBufferArray(scip, &adjacencymatrix, nsos1vars) );
8294  for (i = 0; i < nsos1vars; ++i)
8295  {
8296  SCIP_CALL( SCIPallocBufferArray(scip, &adjacencymatrix[i], i+1) );/*lint !e866*/
8297  }
8298 
8299  /* create adjacency matrix */
8300  for (i = 0; i < nsos1vars; ++i)
8301  {
8302  for (j = 0; j < i+1; ++j)
8303  adjacencymatrix[i][j] = 0;
8304  }
8305  for (i = 0; i < nsos1vars; ++i)
8306  {
8307  int* succ;
8308  int nsucc;
8309 
8310  succ = SCIPdigraphGetSuccessors(conflictgraph, i);
8311  nsucc = SCIPdigraphGetNSuccessors(conflictgraph, i);
8312 
8313  for (j = 0; j < nsucc; ++j)
8314  {
8315  if ( i > succ[j] )
8316  adjacencymatrix[i][succ[j]] = 1;
8317  }
8318  }
8319  }
8320  else
8321  {
8322  SCIPdebugMessage("Adjacency matrix was not created since number of SOS1 variables (%d) is larger than %d.\n", nsos1vars, conshdlrdata->maxsosadjacency);
8323  }
8324 
8325  /* perform one presolving round for SOS1 constraints */
8326  SCIP_CALL( presolRoundConssSOS1(scip, eventhdlr, conshdlrdata, conflictgraph, adjacencymatrix, conss, nconss, nsos1vars, naddconss, ndelconss, nupgdconss, nfixedvars, &nremovedvars, result) );
8327 
8328  if ( adjacencymatrix != NULL )
8329  {
8330  /* perform one presolving round for SOS1 variables */
8331  if ( conshdlrdata->maxtightenbds != 0 && *result != SCIP_CUTOFF )
8332  {
8333  SCIP_CALL( presolRoundVarsSOS1(scip, conshdlrdata, conflictgraph, adjacencymatrix, nsos1vars, nchgbds, naddconss, result) );
8334  }
8335 
8336  /* free adjacency matrix */
8337  for (j = nsos1vars-1; j >= 0; --j)
8338  SCIPfreeBufferArrayNull(scip, &adjacencymatrix[j]);
8339  SCIPfreeBufferArrayNull(scip, &adjacencymatrix);
8340  }
8341 
8342  /* free memory allocated in function initConflictgraph() */
8343  SCIP_CALL( freeConflictgraph(conshdlrdata));
8344  }
8345  (*nchgcoefs) += nremovedvars;
8346 
8347  SCIPdebugMessage("presolving fixed %d variables, removed %d variables, deleted %d constraints, and upgraded %d constraints.\n",
8348  *nfixedvars - oldnfixedvars, nremovedvars, *ndelconss - oldndelconss, *nupgdconss - oldnupgdconss);
8349 
8350  return SCIP_OKAY;
8351 }
8352 
8353 
8354 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
8355 static
8356 SCIP_DECL_CONSINITLP(consInitlpSOS1)
8357 {
8358  SCIP_CONSHDLRDATA* conshdlrdata;
8359 
8360  assert( scip != NULL );
8361  assert( conshdlr != NULL );
8362  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8363 
8364  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8365  assert( conshdlrdata != NULL );
8366 
8367  /* checking for initial rows for SOS1 constraints */
8368  if( conshdlrdata->boundcutsfromsos1 || conshdlrdata->switchcutsfromsos1 )
8369  {
8370  SCIP_Bool cutoff;
8371  SCIP_CALL( initsepaBoundInequalityFromSOS1Cons(scip, conshdlr, conshdlrdata, conss, nconss, NULL, FALSE, -1, NULL, &cutoff) );
8372  assert( ! cutoff );
8373  }
8374 
8375  return SCIP_OKAY;
8376 }
8377 
8378 
8379 /** separation method of constraint handler for LP solutions */
8380 static
8381 SCIP_DECL_CONSSEPALP(consSepalpSOS1)
8382 { /*lint --e{715}*/
8383  assert( scip != NULL );
8384  assert( conshdlr != NULL );
8385  assert( conss != NULL );
8386  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8387  assert( result != NULL );
8388 
8389  SCIP_CALL( separateSOS1(scip, conshdlr, NULL, nconss, conss, result) );
8390 
8391  return SCIP_OKAY;
8392 }
8393 
8394 
8395 /** separation method of constraint handler for arbitrary primal solutions */
8396 static
8397 SCIP_DECL_CONSSEPASOL(consSepasolSOS1)
8398 { /*lint --e{715}*/
8399  assert( scip != NULL );
8400  assert( conshdlr != NULL );
8401  assert( conss != NULL );
8402  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8403  assert( result != NULL );
8404 
8405  SCIP_CALL( separateSOS1(scip, conshdlr, sol, nconss, conss, result) );
8406 
8407  return SCIP_OKAY;
8408 }
8409 
8410 
8411 /** constraint enforcing method of constraint handler for LP solutions */
8412 static
8413 SCIP_DECL_CONSENFOLP(consEnfolpSOS1)
8414 { /*lint --e{715}*/
8415  SCIP_CONSHDLRDATA* conshdlrdata;
8416 
8417  assert( scip != NULL );
8418  assert( conshdlr != NULL );
8419  assert( conss != NULL );
8420  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8421  assert( result != NULL );
8422 
8423  /* get constraint handler data */
8424  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8425  assert( conshdlrdata != NULL );
8426 
8427  if ( conshdlrdata->sos1branch + conshdlrdata->neighbranch + conshdlrdata->bipbranch != 1 )
8428  {
8429  SCIPerrorMessage("Branching rule needs to be defined clearly.\n");
8430  return SCIP_PARAMETERWRONGVAL;
8431  }
8432 
8433  if ( conshdlrdata->addcomps && conshdlrdata->fixnonzero )
8434  {
8435  SCIPerrorMessage("Incompatible parameter setting: addcomps = TRUE and fixnonzero = TRUE.\n");
8436  return SCIP_PARAMETERWRONGVAL;
8437  }
8438 
8439  if ( conshdlrdata->fixnonzero && ( conshdlrdata->bipbranch || conshdlrdata->sos1branch ) )
8440  {
8441  SCIPerrorMessage("Incompatible parameter setting: nonzero fixing is not compatible with bipartite or sos1 branching.\n");
8442  return SCIP_PARAMETERWRONGVAL;
8443  }
8444 
8445  if ( conshdlrdata->sos1branch && conshdlrdata->nstrongrounds != 0 )
8446  {
8447  SCIPerrorMessage("Strong branching is not available for SOS1 branching.\n");
8448  return SCIP_PARAMETERWRONGVAL;
8449  }
8450 
8451  if ( conshdlrdata->sos1branch || conshdlrdata->switchsos1branch )
8452  {
8453  /* enforce SOS1 constraints */
8454  SCIP_CALL( enforceConssSOS1(scip, conshdlr, nconss, conss, result) );
8455  }
8456  else
8457  {
8458  /* enforce conflict graph */
8459  SCIP_CALL( enforceConflictgraph(scip, conshdlrdata, conshdlr, nconss, conss, result) );
8460  }
8461 
8462  return SCIP_OKAY;
8463 }
8464 
8465 
8466 /** constraint enforcing method of constraint handler for pseudo solutions */
8467 static
8468 SCIP_DECL_CONSENFOPS(consEnfopsSOS1)
8469 { /*lint --e{715}*/
8470  SCIP_CONSHDLRDATA* conshdlrdata;
8471 
8472  assert( scip != NULL );
8473  assert( conshdlr != NULL );
8474  assert( conss != NULL );
8475  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8476  assert( result != NULL );
8477 
8478  /* get constraint handler data */
8479  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8480  assert( conshdlrdata != NULL );
8481 
8482  if ( conshdlrdata->sos1branch + conshdlrdata->neighbranch + conshdlrdata->bipbranch != 1 )
8483  {
8484  SCIPerrorMessage("Branching rule needs to be defined clearly.\n");
8485  return SCIP_PARAMETERWRONGVAL;
8486  }
8487 
8488  if ( conshdlrdata->addcomps && conshdlrdata->fixnonzero )
8489  {
8490  SCIPerrorMessage("Incompatible parameter setting: addcomps = TRUE and fixnonzero = TRUE.\n");
8491  return SCIP_PARAMETERWRONGVAL;
8492  }
8493 
8494  if ( conshdlrdata->fixnonzero && ( conshdlrdata->bipbranch || conshdlrdata->sos1branch ) )
8495  {
8496  SCIPerrorMessage("Incompatible parameter setting: nonzero fixing is not compatible with bipartite or sos1 branching.\n");
8497  return SCIP_PARAMETERWRONGVAL;
8498  }
8499 
8500  if ( conshdlrdata->sos1branch && conshdlrdata->nstrongrounds != 0 )
8501  {
8502  SCIPerrorMessage("Strong branching is not available for SOS1 branching.\n");
8503  return SCIP_PARAMETERWRONGVAL;
8504  }
8505 
8506  if ( conshdlrdata->sos1branch || conshdlrdata->switchsos1branch )
8507  {
8508  /* enforce SOS1 constraints */
8509  SCIP_CALL( enforceConssSOS1(scip, conshdlr, nconss, conss, result) );
8510  }
8511  else
8512  {
8513  /* enforce conflict graph */
8514  SCIP_CALL( enforceConflictgraph(scip, conshdlrdata, conshdlr, nconss, conss, result) );
8515  }
8516 
8517  return SCIP_OKAY;
8518 }
8519 
8520 
8521 /** feasibility check method of constraint handler for integral solutions
8522  *
8523  * We simply check whether at most one variable is nonzero in the given solution.
8524  */
8525 static
8526 SCIP_DECL_CONSCHECK(consCheckSOS1)
8527 { /*lint --e{715}*/
8528  int c;
8529 
8530  assert( scip != NULL );
8531  assert( conshdlr != NULL );
8532  assert( conss != NULL );
8533  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8534  assert( result != NULL );
8535 
8536  /* check each constraint */
8537  for (c = 0; c < nconss; ++c)
8538  {
8539  SCIP_CONSDATA* consdata;
8540  int j;
8541  int cnt;
8542 
8543  cnt = 0;
8544  assert( conss[c] != NULL );
8545  consdata = SCIPconsGetData(conss[c]);
8546  assert( consdata != NULL );
8547  SCIPdebugMessage("Checking SOS1 constraint <%s>.\n", SCIPconsGetName(conss[c]));
8548 
8549  /* check all variables */
8550  for (j = 0; j < consdata->nvars; ++j)
8551  {
8552  /* if variable is nonzero */
8553  if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->vars[j])) )
8554  {
8555  ++cnt;
8556 
8557  /* if more than one variable is nonzero */
8558  if ( cnt > 1 )
8559  {
8560  SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
8561  *result = SCIP_INFEASIBLE;
8562 
8563  if ( printreason )
8564  {
8565  int l;
8566 
8567  SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
8568  SCIPinfoMessage(scip, NULL, ";\nviolation: ");
8569 
8570  for (l = 0; l < consdata->nvars; ++l)
8571  {
8572  /* if variable is nonzero */
8573  if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->vars[l])) )
8574  {
8575  SCIPinfoMessage(scip, NULL, "<%s> = %.15g ",
8576  SCIPvarGetName(consdata->vars[l]), SCIPgetSolVal(scip, sol, consdata->vars[l]));
8577  }
8578  }
8579  SCIPinfoMessage(scip, NULL, "\n");
8580  }
8581  return SCIP_OKAY;
8582  }
8583  }
8584  }
8585  }
8586  *result = SCIP_FEASIBLE;
8587 
8588  return SCIP_OKAY;
8589 }
8590 
8591 
8592 /** domain propagation method of constraint handler */
8593 static
8594 SCIP_DECL_CONSPROP(consPropSOS1)
8595 { /*lint --e{715}*/
8596  SCIP_CONSHDLRDATA* conshdlrdata;
8597  SCIP_DIGRAPH* conflictgraph;
8598  SCIP_DIGRAPH* implgraph;
8599  int ngen = 0;
8600 
8601  assert( scip != NULL );
8602  assert( conshdlr != NULL );
8603  assert( conss != NULL );
8604  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8605  assert( result != NULL );
8606  assert( SCIPisTransformed(scip) );
8607 
8608  /* return if number of SOS1 constraints is zero */
8609  if ( nconss < 1 )
8610  {
8611  *result = SCIP_DIDNOTRUN;
8612  return SCIP_OKAY;
8613  }
8614  *result = SCIP_DIDNOTFIND;
8615 
8616  /* get constraint handler data */
8617  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8618  assert( conshdlrdata != NULL );
8619 
8620  /* get conflict graph */
8621  conflictgraph = conshdlrdata->conflictgraph;
8622 
8623  /* get/initialize implication graph */
8624  implgraph = conshdlrdata->implgraph;
8625  if ( implgraph == NULL && conshdlrdata->implprop )
8626  {
8627  if ( SCIPgetDepth(scip) == 0 )
8628  {
8629  SCIP_Bool success;
8630  SCIP_Bool cutoff;
8631  int nchbds;
8632 
8633  SCIP_CALL( initImplGraphSOS1(scip, conshdlrdata, conflictgraph, conshdlrdata->nsos1vars, conshdlrdata->maxtightenbds, &nchbds, &cutoff, &success) );
8634  if ( ! success )
8635  conshdlrdata->implprop = FALSE;
8636 
8637  if ( cutoff )
8638  {
8639  *result = SCIP_CUTOFF;
8640  return SCIP_OKAY;
8641  }
8642  else if ( nchbds > 0 )
8643  *result = SCIP_REDUCEDDOM;
8644  implgraph = conshdlrdata->implgraph;
8645  }
8646  else
8647  conshdlrdata->implprop = FALSE;
8648  }
8649 
8650  /* if conflict graph propagation shall be used */
8651  if ( conshdlrdata->conflictprop && conflictgraph != NULL )
8652  {
8653  SCIP_VAR** fixnonzerovars;
8654  int nfixnonzerovars;
8655  int j;
8656 
8657  assert( nconss > 0 );
8658 
8659  /* stack of variables fixed to nonzero */
8660  nfixnonzerovars = conshdlrdata->nfixnonzerovars;
8661  fixnonzerovars = conshdlrdata->fixnonzerovars;
8662  assert( fixnonzerovars != NULL );
8663 
8664  /* check each variable from stack */
8665  for (j = 0; j < nfixnonzerovars; ++j)
8666  {
8667  SCIP_VAR* var;
8668 
8669  var = fixnonzerovars[j];
8670  if ( var != NULL )
8671  {
8672  int node;
8673  node = varGetNodeSOS1(conshdlrdata, var);
8674 
8675  /* if variable is involved in an SOS1 constraint */
8676  if ( node >= 0 )
8677  {
8678  assert( varGetNodeSOS1(conshdlrdata, var) < conshdlrdata->nsos1vars );
8679  SCIPdebugMessage("Propagating SOS1 variable <%s>.\n", SCIPvarGetName(var) );
8680 
8681  /* if zero is outside the domain of variable */
8683  {
8684  SCIP_Bool cutoff;
8685 
8686  SCIP_CALL( propVariableNonzero(scip, conflictgraph, implgraph, conss[0], node, conshdlrdata->implprop, &cutoff, &ngen) );
8687  if ( cutoff )
8688  {
8689  *result = SCIP_CUTOFF;
8690  return SCIP_OKAY;
8691  }
8692  }
8693  }
8694  }
8695  }
8696  }
8697 
8698  /* if SOS1 constraint propagation shall be used */
8699  if ( conshdlrdata->sosconsprop || conflictgraph == NULL )
8700  {
8701  int c;
8702 
8703  /* check each constraint */
8704  for (c = 0; c < nconss; ++c)
8705  {
8706  SCIP_CONS* cons;
8707  SCIP_CONSDATA* consdata;
8708  SCIP_Bool cutoff;
8709 
8710  assert( conss[c] != NULL );
8711  cons = conss[c];
8712  consdata = SCIPconsGetData(cons);
8713  assert( consdata != NULL );
8714  SCIPdebugMessage("Propagating SOS1 constraint <%s>.\n", SCIPconsGetName(cons) );
8715 
8716  SCIP_CALL( propConsSOS1(scip, cons, consdata, &cutoff, &ngen) );
8717  if ( cutoff )
8718  {
8719  *result = SCIP_CUTOFF;
8720  return SCIP_OKAY;
8721  }
8722  }
8723  }
8724 
8725  SCIPdebugMessage("Propagated %d domains.\n", ngen);
8726  if ( ngen > 0 )
8727  *result = SCIP_REDUCEDDOM;
8728 
8729  return SCIP_OKAY;
8730 }
8731 
8732 
8733 /** propagation conflict resolving method of constraint handler
8734  *
8735  * We check which bound changes were the reason for infeasibility. We
8736  * use that @a inferinfo stores the index of the variable that has
8737  * bounds that fix it to be nonzero (these bounds are the reason). */
8738 static
8739 SCIP_DECL_CONSRESPROP(consRespropSOS1)
8740 { /*lint --e{715}*/
8741  SCIP_VAR* var;
8742 
8743  assert( scip != NULL );
8744  assert( cons != NULL );
8745  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8746  assert( infervar != NULL );
8747  assert( bdchgidx != NULL );
8748  assert( result != NULL );
8749 
8750  *result = SCIP_DIDNOTFIND;
8751  SCIPdebugMessage("Propagation resolution method of SOS1 constraint <%s>.\n", SCIPconsGetName(cons));
8752 
8753  /* check whether conflict was detected in variable propagation or constraint propagation */
8754  if ( inferinfo < 0 )
8755  {
8756  SCIP_CONSHDLRDATA* conshdlrdata;
8757 
8758  assert( conshdlr != NULL );
8759 
8760  /* get constraint handler data */
8761  conshdlrdata = SCIPconshdlrGetData(conshdlr);
8762  assert( conshdlrdata != NULL );
8763  assert( conshdlrdata->conflictgraph != NULL );
8764  assert( inferinfo >= -conshdlrdata->maxnfixnonzerovars );
8765  assert( inferinfo >= -conshdlrdata->nsos1vars );
8766  assert( inferinfo <= -1 );
8767 
8768  var = SCIPnodeGetVarSOS1(conshdlrdata->conflictgraph, -inferinfo - 1);
8769  }
8770  else
8771  {
8772  SCIP_CONSDATA* consdata;
8773 
8774  /* get constraint data */
8775  consdata = SCIPconsGetData(cons);
8776  assert( consdata != NULL );
8777  assert( inferinfo < consdata->nvars );
8778 
8779  var = consdata->vars[inferinfo];
8780  }
8781  assert( var != NULL );
8782  assert( var != infervar );
8783 
8784  /* check if lower bound of var was the reason */
8785  if ( SCIPisFeasPositive(scip, SCIPvarGetLbAtIndex(var, bdchgidx, FALSE)) )
8786  {
8787  SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
8788  *result = SCIP_SUCCESS;
8789  }
8790 
8791  /* check if upper bound of var was the reason */
8792  if ( SCIPisFeasNegative(scip, SCIPvarGetUbAtIndex(var, bdchgidx, FALSE)) )
8793  {
8794  SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
8795  *result = SCIP_SUCCESS;
8796  }
8797 
8798  return SCIP_OKAY;
8799 }
8800 
8801 
8802 /** variable rounding lock method of constraint handler
8803  *
8804  * Let lb and ub be the lower and upper bounds of a
8805  * variable. Preprocessing usually makes sure that lb <= 0 <= ub.
8806  *
8807  * - If lb < 0 then rounding down may violate the constraint.
8808  * - If ub > 0 then rounding up may violated the constraint.
8809  * - If lb > 0 or ub < 0 then the constraint is infeasible and we do
8810  * not have to deal with it here.
8811  * - If lb == 0 then rounding down does not violate the constraint.
8812  * - If ub == 0 then rounding up does not violate the constraint.
8813  */
8814 static
8815 SCIP_DECL_CONSLOCK(consLockSOS1)
8816 {
8817  SCIP_CONSDATA* consdata;
8818  SCIP_VAR** vars;
8819  int nvars;
8820  int j;
8821 
8822  assert( scip != NULL );
8823  assert( conshdlr != NULL );
8824  assert( cons != NULL );
8825  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8826  consdata = SCIPconsGetData(cons);
8827  assert( consdata != NULL );
8828 
8829  SCIPdebugMessage("Locking constraint <%s>.\n", SCIPconsGetName(cons));
8830 
8831  vars = consdata->vars;
8832  nvars = consdata->nvars;
8833  assert( vars != NULL );
8834 
8835  for (j = 0; j < nvars; ++j)
8836  {
8837  SCIP_VAR* var;
8838  var = vars[j];
8839 
8840  /* if lower bound is negative, rounding down may violate constraint */
8841  if ( SCIPisFeasNegative(scip, SCIPvarGetLbLocal(var)) )
8842  {
8843  SCIP_CALL( SCIPaddVarLocks(scip, var, nlockspos, nlocksneg) );
8844  }
8845 
8846  /* additionally: if upper bound is positive, rounding up may violate constraint */
8847  if ( SCIPisFeasPositive(scip, SCIPvarGetUbLocal(var)) )
8848  {
8849  SCIP_CALL( SCIPaddVarLocks(scip, var, nlocksneg, nlockspos) );
8850  }
8851  }
8852 
8853  return SCIP_OKAY;
8854 }
8855 
8856 
8857 /** constraint display method of constraint handler */
8858 static
8859 SCIP_DECL_CONSPRINT(consPrintSOS1)
8860 { /*lint --e{715}*/
8861  SCIP_CONSDATA* consdata;
8862  int j;
8863 
8864  assert( scip != NULL );
8865  assert( conshdlr != NULL );
8866  assert( cons != NULL );
8867  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8868 
8869  consdata = SCIPconsGetData(cons);
8870  assert( consdata != NULL );
8871 
8872  for (j = 0; j < consdata->nvars; ++j)
8873  {
8874  if ( j > 0 )
8875  SCIPinfoMessage(scip, file, ", ");
8876  SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[j], FALSE) );
8877  if ( consdata->weights == NULL )
8878  SCIPinfoMessage(scip, file, " (%d)", j+1);
8879  else
8880  SCIPinfoMessage(scip, file, " (%3.2f)", consdata->weights[j]);
8881  }
8882 
8883  return SCIP_OKAY;
8884 }
8885 
8886 
8887 /** constraint copying method of constraint handler */
8888 static
8889 SCIP_DECL_CONSCOPY(consCopySOS1)
8890 { /*lint --e{715}*/
8891  SCIP_CONSDATA* sourceconsdata;
8892  SCIP_VAR** sourcevars;
8893  SCIP_VAR** targetvars;
8894  SCIP_Real* sourceweights;
8895  SCIP_Real* targetweights;
8896  const char* consname;
8897  int nvars;
8898  int v;
8899 
8900  assert( scip != NULL );
8901  assert( sourcescip != NULL );
8902  assert( sourcecons != NULL );
8903  assert( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(sourcecons)), CONSHDLR_NAME) == 0 );
8904 
8905  *valid = TRUE;
8906 
8907  if ( name != NULL )
8908  consname = name;
8909  else
8910  consname = SCIPconsGetName(sourcecons);
8911 
8912  SCIPdebugMessage("Copying SOS1 constraint <%s> ...\n", consname);
8913 
8914  sourceconsdata = SCIPconsGetData(sourcecons);
8915  assert( sourceconsdata != NULL );
8916 
8917  /* get variables and weights of the source constraint */
8918  nvars = sourceconsdata->nvars;
8919 
8920  if ( nvars == 0 )
8921  return SCIP_OKAY;
8922 
8923  sourcevars = sourceconsdata->vars;
8924  assert( sourcevars != NULL );
8925  sourceweights = sourceconsdata->weights;
8926  assert( sourceweights != NULL );
8927 
8928  /* duplicate variable array */
8929  SCIP_CALL( SCIPallocBufferArray(sourcescip, &targetvars, nvars) );
8930  SCIP_CALL( SCIPduplicateBufferArray(sourcescip, &targetweights, sourceweights, nvars) );
8931 
8932  /* get copied variables in target SCIP */
8933  for( v = 0; v < nvars && *valid; ++v )
8934  {
8935  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &(targetvars[v]), varmap, consmap, global, valid) );
8936  }
8937 
8938  /* only create the target constraint, if all variables could be copied */
8939  if( *valid )
8940  {
8941  SCIP_CALL( SCIPcreateConsSOS1(scip, cons, consname, nvars, targetvars, targetweights,
8942  initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
8943  }
8944 
8945  /* free buffer array */
8946  SCIPfreeBufferArray(sourcescip, &targetweights);
8947  SCIPfreeBufferArray(sourcescip, &targetvars);
8948 
8949  return SCIP_OKAY;
8950 }
8951 
8952 
8953 /** constraint parsing method of constraint handler */
8954 static
8955 SCIP_DECL_CONSPARSE(consParseSOS1)
8956 { /*lint --e{715}*/
8957  SCIP_VAR* var;
8958  SCIP_Real weight;
8959  const char* s;
8960  char* t;
8961 
8962  assert(scip != NULL);
8963  assert(conshdlr != NULL);
8964  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
8965  assert(cons != NULL);
8966  assert(success != NULL);
8967 
8968  *success = TRUE;
8969  s = str;
8970 
8971  /* create empty SOS1 constraint */
8972  SCIP_CALL( SCIPcreateConsSOS1(scip, cons, name, 0, NULL, NULL, initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
8973 
8974  /* loop through string */
8975  do
8976  {
8977  /* parse variable name */
8978  SCIP_CALL( SCIPparseVarName(scip, s, &var, &t) );
8979  s = t;
8980 
8981  /* skip until beginning of weight */
8982  while ( *s != '\0' && *s != '(' )
8983  ++s;
8984 
8985  if ( *s == '\0' )
8986  {
8987  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "Syntax error: expected weight at input: %s\n", s);
8988  *success = FALSE;
8989  return SCIP_OKAY;
8990  }
8991  /* skip '(' */
8992  ++s;
8993 
8994  /* find weight */
8995  weight = strtod(s, &t);
8996  if ( t == NULL )
8997  {
8998  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "Syntax error during parsing of the weight: %s\n", s);
8999  *success = FALSE;
9000  return SCIP_OKAY;
9001  }
9002  s = t;
9003 
9004  /* skip white space, ',', and ')' */
9005  while ( *s != '\0' && ( isspace((unsigned char)*s) || *s == ',' || *s == ')' ) )
9006  ++s;
9007 
9008  /* add variable */
9009  SCIP_CALL( SCIPaddVarSOS1(scip, *cons, var, weight) );
9010  }
9011  while ( *s != '\0' );
9012 
9013  return SCIP_OKAY;
9014 }
9015 
9016 
9017 /** constraint method of constraint handler which returns the variables (if possible) */
9018 static
9019 SCIP_DECL_CONSGETVARS(consGetVarsSOS1)
9020 { /*lint --e{715}*/
9021  SCIP_CONSDATA* consdata;
9022 
9023  consdata = SCIPconsGetData(cons);
9024  assert(consdata != NULL);
9025 
9026  if( varssize < consdata->nvars )
9027  (*success) = FALSE;
9028  else
9029  {
9030  assert(vars != NULL);
9031 
9032  BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
9033  (*success) = TRUE;
9034  }
9035 
9036  return SCIP_OKAY;
9037 }
9038 
9039 
9040 /** constraint method of constraint handler which returns the number of variables (if possible) */
9041 static
9042 SCIP_DECL_CONSGETNVARS(consGetNVarsSOS1)
9043 { /*lint --e{715}*/
9044  SCIP_CONSDATA* consdata;
9045 
9046  consdata = SCIPconsGetData(cons);
9047  assert(consdata != NULL);
9048 
9049  (*nvars) = consdata->nvars;
9050  (*success) = TRUE;
9051 
9052  return SCIP_OKAY;
9053 }
9054 
9055 
9056 /* ---------------- Callback methods of event handler ---------------- */
9057 
9058 /** exec the event handler
9059  *
9060  * We update the number of variables fixed to be nonzero
9061  */
9062 static
9063 SCIP_DECL_EVENTEXEC(eventExecSOS1)
9064 {
9065  SCIP_CONSHDLRDATA* conshdlrdata;
9066  SCIP_EVENTTYPE eventtype;
9067  SCIP_CONSHDLR* conshdlr;
9068  SCIP_CONSDATA* consdata;
9069  SCIP_CONS* cons;
9070  SCIP_Real oldbound;
9071  SCIP_Real newbound;
9072 
9073  assert( eventhdlr != NULL );
9074  assert( eventdata != NULL );
9075  assert( strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0 );
9076  assert( event != NULL );
9077 
9078  cons = (SCIP_CONS*)eventdata;
9079  assert( cons != NULL );
9080  consdata = SCIPconsGetData(cons);
9081  assert( 0 <= consdata->nfixednonzeros && consdata->nfixednonzeros <= consdata->nvars );
9082 
9083  oldbound = SCIPeventGetOldbound(event);
9084  newbound = SCIPeventGetNewbound(event);
9085 
9086  eventtype = SCIPeventGetType(event);
9087  switch ( eventtype )
9088  {
9090  /* if variable is now fixed to be nonzero */
9091  if ( ! SCIPisFeasPositive(scip, oldbound) && SCIPisFeasPositive(scip, newbound) )
9092  {
9093  conshdlr = SCIPconsGetHdlr(cons);
9094  assert( conshdlr != NULL );
9095  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9096  assert( conshdlrdata != NULL );
9097 
9098  /* store variable fixed to be nonzero on stack */
9099  assert( 0 <= conshdlrdata->nfixnonzerovars && conshdlrdata->nfixnonzerovars <= SCIPgetNTotalVars(scip) );
9100  if ( conshdlrdata->nfixnonzerovars < conshdlrdata->maxnfixnonzerovars )
9101  {
9102  assert( conshdlrdata->fixnonzerovars != NULL );
9103  assert( SCIPeventGetVar(event) != NULL );
9104  conshdlrdata->fixnonzerovars[conshdlrdata->nfixnonzerovars++] = SCIPeventGetVar(event);
9105  }
9106 
9107  ++(consdata->nfixednonzeros);
9108  }
9109  break;
9110 
9112  /* if variable is now fixed to be nonzero */
9113  if ( ! SCIPisFeasNegative(scip, oldbound) && SCIPisFeasNegative(scip, newbound) )
9114  {
9115  conshdlr = SCIPconsGetHdlr(cons);
9116  assert( conshdlr != NULL );
9117  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9118  assert( conshdlrdata != NULL );
9119 
9120  /* store variable fixed to be nonzero on stack */
9121  assert( 0 <= conshdlrdata->nfixnonzerovars && conshdlrdata->nfixnonzerovars <= SCIPgetNTotalVars(scip) );
9122  if ( conshdlrdata->nfixnonzerovars < conshdlrdata->maxnfixnonzerovars )
9123  {
9124  assert( conshdlrdata->fixnonzerovars != NULL );
9125  assert( SCIPeventGetVar(event) != NULL );
9126  conshdlrdata->fixnonzerovars[conshdlrdata->nfixnonzerovars++] = SCIPeventGetVar(event);
9127  }
9128 
9129  ++(consdata->nfixednonzeros);
9130  }
9131  break;
9132 
9134  /* if variable is not fixed to be nonzero anymore */
9135  if ( SCIPisFeasPositive(scip, oldbound) && ! SCIPisFeasPositive(scip, newbound) )
9136  --(consdata->nfixednonzeros);
9137  break;
9138 
9140  /* if variable is not fixed to be nonzero anymore */
9141  if ( SCIPisFeasNegative(scip, oldbound) && ! SCIPisFeasNegative(scip, newbound) )
9142  --(consdata->nfixednonzeros);
9143  break;
9144 
9145  default:
9146  SCIPerrorMessage("invalid event type.\n");
9147  return SCIP_INVALIDDATA;
9148  }
9149  assert( 0 <= consdata->nfixednonzeros && consdata->nfixednonzeros <= consdata->nvars );
9150 
9151  SCIPdebugMessage("changed bound of variable <%s> from %f to %f (nfixednonzeros: %d).\n", SCIPvarGetName(SCIPeventGetVar(event)),
9152  oldbound, newbound, consdata->nfixednonzeros);
9153 
9154  return SCIP_OKAY;
9155 }
9156 
9157 
9158 /** constraint handler method to determine a diving variable by assigning a variable and two values for diving */
9159 static
9160 SCIP_DECL_CONSGETDIVEBDCHGS(consGetDiveBdChgsSOS1)
9161 {
9162  SCIP_DIGRAPH* conflictgraph;
9163  SCIP_VAR* bestvar = NULL;
9164  SCIP_Bool bestvarfixneigh = FALSE;
9166  int bestnode = -1;
9167  int nsos1vars;
9168  int v;
9169 
9170  assert( scip != NULL );
9171  assert( conshdlr != NULL );
9172  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
9173  assert( diveset != NULL );
9174  assert( success != NULL );
9175  assert( infeasible != NULL );
9176 
9177  *infeasible = FALSE;
9178  *success = FALSE;
9179 
9180  /* get number of SOS1 variables */
9181  nsos1vars = SCIPgetNSOS1Vars(conshdlr);
9182 
9183  /* get conflict graph of SOS1 constraints */
9184  conflictgraph = SCIPgetConflictgraphSOS1(conshdlr);
9185 
9186  /* loop over SOS1 variables */
9187  for (v = 0; v < nsos1vars; ++v)
9188  {
9189  /* check whether the variable violates an SOS1 constraint together with at least one other variable */
9190  if ( isViolatedSOS1(scip, conflictgraph, v, sol) )
9191  {
9192  SCIP_VAR* var;
9193  SCIP_Real solval;
9194  SCIP_Real score;
9195  SCIP_Real bound;
9196  SCIP_Real fracval;
9197  SCIP_Bool fixneigh;
9198 
9199  var = SCIPnodeGetVarSOS1(conflictgraph, v);
9200  solval = SCIPgetSolVal(scip, sol, var);
9201 
9202  /* compute (variable) bound of candidate */
9203  if ( SCIPisFeasNegative(scip, solval) )
9204  bound = nodeGetSolvalVarboundLbSOS1(scip, conflictgraph, sol, v);
9205  else
9206  bound = nodeGetSolvalVarboundUbSOS1(scip, conflictgraph, sol, v);
9207 
9208  /* bound may have changed in propagation; ensure that fracval <= 1 */
9209  if ( SCIPisFeasLT(scip, REALABS(bound), REALABS(solval)) )
9210  solval = bound;
9211 
9212  /* ensure finiteness */
9213  bound = MIN(DIVINGCUTOFFVALUE, REALABS(bound)); /*lint !e666*/
9214  fracval = MIN(DIVINGCUTOFFVALUE, REALABS(solval)); /*lint !e666*/
9215  assert( ! SCIPisInfinity(scip, bound) );
9216  assert( ! SCIPisInfinity(scip, fracval) );
9217  assert( SCIPisFeasPositive(scip, bound + SCIPsumepsilon(scip)) );
9218 
9219  /* get fractionality of candidate */
9220  fracval /= (bound + SCIPsumepsilon(scip));
9221 
9222  /* should SOS1 variables be scored by the diving heuristics specific score function;
9223  * otherwise use the score function of the SOS1 constraint handler */
9225  {
9226  SCIP_Bool roundup;
9227 
9228  SCIP_CALL( SCIPgetDivesetScore(scip, diveset, SCIP_DIVETYPE_SOS1VARIABLE, var, solval, fracval, &score, &roundup) );
9229 
9230  fixneigh = roundup;
9231  if ( SCIPisFeasNegative(scip, solval) )
9232  fixneigh = !fixneigh;
9233  }
9234  else
9235  {
9236  /* we always fix the candidates neighbors in the conflict graph to zero */
9237  fixneigh = TRUE;
9238 
9239  /* score fractionality of candidate */
9240  score = fracval;
9241  }
9242 
9243  /* best candidate maximizes the score */
9244  if ( score > bestscore )
9245  {
9246  bestscore = score;
9247 
9248  *success = TRUE;
9249  bestvar = var;
9250  bestnode = v;
9251  bestvarfixneigh = fixneigh;
9252  }
9253  }
9254  }
9255  assert( !(*success) || bestvar != NULL );
9256 
9257  if ( *success )
9258  {
9259  int* succ;
9260  int nsucc;
9261  int s;
9262 
9263  assert( bestnode >= 0 && bestnode < nsos1vars );
9264 
9265  nsucc = SCIPdigraphGetNSuccessors(conflictgraph, bestnode);
9266  succ = SCIPdigraphGetSuccessors(conflictgraph, bestnode);
9267 
9268  /* if the diving score voted for fixing the best variable to 0.0, we add this as the preferred bound change;
9269  * otherwise, fixing the neighbors in the conflict graph to 0.0 is the preferred bound change.
9270  */
9271  assert( SCIPisFeasNegative(scip, SCIPvarGetLbLocal(bestvar)) || SCIPisFeasPositive(scip, SCIPvarGetUbLocal(bestvar)) );
9272  SCIP_CALL( SCIPaddDiveBoundChange(scip, bestvar, SCIP_BRANCHDIR_FIXED, 0.0, !bestvarfixneigh) );
9273  for (s = 0; s < nsucc; ++s)
9274  {
9275  SCIP_VAR* var;
9276 
9277  var = SCIPnodeGetVarSOS1(conflictgraph, succ[s]);
9278 
9279  /* if variable is not already fixed */
9281  {
9282  SCIP_CALL( SCIPaddDiveBoundChange(scip, var, SCIP_BRANCHDIR_FIXED, 0.0, bestvarfixneigh) );
9283  }
9284  }
9285  }
9286 
9287  return SCIP_OKAY;
9288 }
9289 
9290 
9291 /* ---------------- Constraint specific interface methods ---------------- */
9292 
9293 /** creates the handler for SOS1 constraints and includes it in SCIP */
9295  SCIP* scip /**< SCIP data structure */
9296  )
9297 {
9298  SCIP_CONSHDLRDATA* conshdlrdata;
9299  SCIP_CONSHDLR* conshdlr;
9300 
9301  /* create constraint handler data */
9302  SCIP_CALL( SCIPallocMemory(scip, &conshdlrdata) );
9303  conshdlrdata->branchsos = TRUE;
9304  conshdlrdata->switchsos1branch = FALSE;
9305  conshdlrdata->switchcutsfromsos1 = FALSE;
9306  conshdlrdata->eventhdlr = NULL;
9307  conshdlrdata->fixnonzerovars = NULL;
9308  conshdlrdata->maxnfixnonzerovars = 0;
9309  conshdlrdata->nfixnonzerovars = 0;
9310  conshdlrdata->conflictgraph = NULL;
9311  conshdlrdata->localconflicts = NULL;
9312  conshdlrdata->isconflocal = FALSE;
9313  conshdlrdata->implgraph = NULL;
9314  conshdlrdata->nimplnodes = 0;
9315  conshdlrdata->nboundcuts = 0;
9316  conshdlrdata->tcliquegraph = NULL;
9317  conshdlrdata->tcliquedata = NULL;
9318  conshdlrdata->cntextsos1 = -1;
9319  conshdlrdata->varhash = NULL;
9320 
9321  /* create event handler for bound change events */
9322  SCIP_CALL( SCIPincludeEventhdlrBasic(scip, &conshdlrdata->eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, eventExecSOS1, NULL) );
9323  if ( conshdlrdata->eventhdlr == NULL )
9324  {
9325  SCIPerrorMessage("event handler for SOS1 constraints not found.\n");
9326  return SCIP_PLUGINNOTFOUND;
9327  }
9328 
9329  /* include constraint handler */
9332  consEnfolpSOS1, consEnfopsSOS1, consCheckSOS1, consLockSOS1, conshdlrdata) );
9333  assert(conshdlr != NULL);
9334 
9335  /* set non-fundamental callbacks via specific setter functions */
9336  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopySOS1, consCopySOS1) );
9337  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteSOS1) );
9338  SCIP_CALL( SCIPsetConshdlrGetDiveBdChgs(scip, conshdlr, consGetDiveBdChgsSOS1) );
9339  SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolSOS1) );
9340  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolSOS1) );
9341  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeSOS1) );
9342  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsSOS1) );
9343  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsSOS1) );
9344  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpSOS1) );
9345  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseSOS1) );
9346  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolSOS1, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
9347  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintSOS1) );
9349  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropSOS1) );
9350  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpSOS1, consSepasolSOS1, CONSHDLR_SEPAFREQ, CONSHDLR_SEPAPRIORITY, CONSHDLR_DELAYSEPA) );
9351  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransSOS1) );
9352 
9353  /* add SOS1 constraint handler parameters */
9354 
9355  /* adjacency matrix parameters */
9356  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxsosadjacency",
9357  "do not create an adjacency matrix if number of SOS1 variables is larger than predefined value (-1: no limit)",
9358  &conshdlrdata->maxsosadjacency, TRUE, DEFAULT_MAXSOSADJACENCY, -1, INT_MAX, NULL, NULL) );
9359 
9360  /* presolving parameters */
9361  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxextensions",
9362  "maximal number of extensions that will be computed for each SOS1 constraint (-1: no limit)",
9363  &conshdlrdata->maxextensions, TRUE, DEFAULT_MAXEXTENSIONS, -1, INT_MAX, NULL, NULL) );
9364 
9365  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxtightenbds",
9366  "maximal number of bound tightening rounds per presolving round (-1: no limit)",
9367  &conshdlrdata->maxtightenbds, TRUE, DEFAULT_MAXTIGHTENBDS, -1, INT_MAX, NULL, NULL) );
9368 
9369  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/updateconflpresol",
9370  "if TRUE then update conflict graph during presolving procedure",
9371  &conshdlrdata->updateconflpresol, TRUE, DEFAULT_UPDATECONFLPRESOL, NULL, NULL) );
9372 
9373  /* propagation parameters */
9374  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/conflictprop",
9375  "whether to use conflict graph propagation",
9376  &conshdlrdata->conflictprop, TRUE, DEFAULT_CONFLICTPROP, NULL, NULL) );
9377 
9378  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/implprop",
9379  "whether to use implication graph propagation",
9380  &conshdlrdata->implprop, TRUE, DEFAULT_IMPLPROP, NULL, NULL) );
9381 
9382  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/sosconsprop",
9383  "whether to use SOS1 constraint propagation",
9384  &conshdlrdata->sosconsprop, TRUE, DEFAULT_SOSCONSPROP, NULL, NULL) );
9385 
9386  /* branching parameters */
9387  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/neighbranch",
9388  "if TRUE turn neighborhood branching method on (note: an automatic switching to SOS1 branching is possible)",
9389  &conshdlrdata->neighbranch, TRUE, DEFAULT_NEIGHBRANCH, NULL, NULL) );
9390 
9391  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/bipbranch",
9392  "if TRUE turn bipartite branching method on (note: an automatic switching to SOS1 branching is possible)",
9393  &conshdlrdata->bipbranch, TRUE, DEFAULT_BIPBRANCH, NULL, NULL) );
9394 
9395  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/sos1branch",
9396  "if TRUE turn SOS1 branching method on",
9397  &conshdlrdata->sos1branch, TRUE, DEFAULT_SOS1BRANCH, NULL, NULL) );
9398 
9399  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/autosos1branch",
9400  "if TRUE then automatically switch to SOS1 branching if the SOS1 constraints do not overlap",
9401  &conshdlrdata->autosos1branch, TRUE, DEFAULT_AUTOSOS1BRANCH, NULL, NULL) );
9402 
9403  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/fixnonzero",
9404  "if neighborhood branching is used, then fix the branching variable (if positive in sign) to the value of the feasibility tolerance",
9405  &conshdlrdata->fixnonzero, TRUE, DEFAULT_FIXNONZERO, NULL, NULL) );
9406 
9407  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/addcomps",
9408  "if TRUE then add complementarity constraints to the branching nodes (can be used in combination with neighborhood or bipartite branching)",
9409  &conshdlrdata->addcomps, TRUE, DEFAULT_ADDCOMPS, NULL, NULL) );
9410 
9411  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxaddcomps",
9412  "maximal number of complementarity constraints added per branching node (-1: no limit)",
9413  &conshdlrdata->maxaddcomps, TRUE, DEFAULT_MAXADDCOMPS, -1, INT_MAX, NULL, NULL) );
9414 
9415  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/addcompsfeas",
9416  "minimal feasibility value for complementarity constraints in order to be added to the branching node",
9417  &conshdlrdata->addcompsfeas, TRUE, DEFAULT_ADDCOMPSFEAS, -SCIP_REAL_MAX, SCIP_REAL_MAX, NULL, NULL) );
9418 
9419  SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/addbdsfeas",
9420  "minimal feasibility value for bound inequalities in order to be added to the branching node",
9421  &conshdlrdata->addbdsfeas, TRUE, DEFAULT_ADDBDSFEAS, -SCIP_REAL_MAX, SCIP_REAL_MAX, NULL, NULL) );
9422 
9423  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/addextendedbds",
9424  "should added complementarity constraints be extended to SOS1 constraints to get tighter bound inequalities",
9425  &conshdlrdata->addextendedbds, TRUE, DEFAULT_ADDEXTENDEDBDS, NULL, NULL) );
9426 
9427  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branchsos",
9428  "Use SOS1 branching in enforcing (otherwise leave decision to branching rules)?",
9429  &conshdlrdata->branchsos, FALSE, TRUE, NULL, NULL) );
9430 
9431  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branchnonzeros",
9432  "Branch on SOS constraint with most number of nonzeros?",
9433  &conshdlrdata->branchnonzeros, FALSE, FALSE, NULL, NULL) );
9434 
9435  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branchweight",
9436  "Branch on SOS cons. with highest nonzero-variable weight for branching (needs branchnonzeros = false)?",
9437  &conshdlrdata->branchweight, FALSE, FALSE, NULL, NULL) );
9438 
9439  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/addcompsdepth",
9440  "only add complementarity constraints to branching nodes for predefined depth (-1: no limit)",
9441  &conshdlrdata->addcompsdepth, TRUE, DEFAULT_ADDCOMPSDEPTH, -1, INT_MAX, NULL, NULL) );
9442 
9443  /* selection rule parameters */
9444  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/nstrongrounds",
9445  "maximal number of strong branching rounds to perform for each node (-1: auto); only available for neighborhood and bipartite branching",
9446  &conshdlrdata->nstrongrounds, TRUE, DEFAULT_NSTRONGROUNDS, -1, INT_MAX, NULL, NULL) );
9447 
9448  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/nstrongiter",
9449  "maximal number LP iterations to perform for each strong branching round (-2: auto, -1: no limit)",
9450  &conshdlrdata->nstrongiter, TRUE, DEFAULT_NSTRONGITER, -2, INT_MAX, NULL, NULL) );
9451 
9452  /* separation parameters */
9453  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/boundcutsfromsos1",
9454  "if TRUE separate bound inequalities from initial SOS1 constraints",
9455  &conshdlrdata->boundcutsfromsos1, TRUE, DEFAULT_BOUNDCUTSFROMSOS1, NULL, NULL) );
9456 
9457  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/boundcutsfromgraph",
9458  "if TRUE separate bound inequalities from the conflict graph",
9459  &conshdlrdata->boundcutsfromgraph, TRUE, DEFAULT_BOUNDCUTSFROMGRAPH, NULL, NULL) );
9460 
9461  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/autocutsfromsos1",
9462  "if TRUE then automatically switch to separating initial SOS1 constraints if the SOS1 constraints do not overlap",
9463  &conshdlrdata->autocutsfromsos1, TRUE, DEFAULT_AUTOCUTSFROMSOS1, NULL, NULL) );
9464 
9465  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/boundcutsfreq",
9466  "frequency for separating bound cuts; zero means to separate only in the root node",
9467  &conshdlrdata->boundcutsfreq, TRUE, DEFAULT_BOUNDCUTSFREQ, -1, INT_MAX, NULL, NULL) );
9468 
9469  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/boundcutsdepth",
9470  "node depth of separating bound cuts (-1: no limit)",
9471  &conshdlrdata->boundcutsdepth, TRUE, DEFAULT_BOUNDCUTSDEPTH, -1, INT_MAX, NULL, NULL) );
9472 
9473  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxboundcuts",
9474  "maximal number of bound cuts separated per branching node",
9475  &conshdlrdata->maxboundcuts, TRUE, DEFAULT_MAXBOUNDCUTS, 0, INT_MAX, NULL, NULL) );
9476 
9477  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maxboundcutsroot",
9478  "maximal number of bound cuts separated per iteration in the root node",
9479  &conshdlrdata->maxboundcutsroot, TRUE, DEFAULT_MAXBOUNDCUTSROOT, 0, INT_MAX, NULL, NULL) );
9480 
9481  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/strthenboundcuts",
9482  "if TRUE then bound cuts are strengthened in case bound variables are available",
9483  &conshdlrdata->strthenboundcuts, TRUE, DEFAULT_STRTHENBOUNDCUTS, NULL, NULL) );
9484 
9485  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/implcutsfreq",
9486  "frequency for separating implied bound cuts; zero means to separate only in the root node",
9487  &conshdlrdata->implcutsfreq, TRUE, DEFAULT_IMPLCUTSFREQ, -1, INT_MAX, NULL, NULL) );
9488 
9489  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/implcutsdepth",
9490  "node depth of separating implied bound cuts (-1: no limit)",
9491  &conshdlrdata->implcutsdepth, TRUE, DEFAULT_IMPLCUTSDEPTH, -1, INT_MAX, NULL, NULL) );
9492 
9493  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maximplcuts",
9494  "maximal number of implied bound cuts separated per branching node",
9495  &conshdlrdata->maxboundcuts, TRUE, DEFAULT_MAXIMPLCUTS, 0, INT_MAX, NULL, NULL) );
9496 
9497  SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/maximplcutsroot",
9498  "maximal number of implied bound cuts separated per iteration in the root node",
9499  &conshdlrdata->maximplcutsroot, TRUE, DEFAULT_MAXIMPLCUTSROOT, 0, INT_MAX, NULL, NULL) );
9500 
9501  return SCIP_OKAY;
9502 }
9503 
9504 
9505 /** creates and captures a SOS1 constraint
9506  *
9507  * We set the constraint to not be modifable. If the weights are non NULL, the variables are ordered according to these
9508  * weights (in ascending order).
9509  *
9510  * @note The constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons().
9511  */
9513  SCIP* scip, /**< SCIP data structure */
9514  SCIP_CONS** cons, /**< pointer to hold the created constraint */
9515  const char* name, /**< name of constraint */
9516  int nvars, /**< number of variables in the constraint */
9517  SCIP_VAR** vars, /**< array with variables of constraint entries */
9518  SCIP_Real* weights, /**< weights determining the variable order, or NULL if natural order should be used */
9519  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
9520  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
9521  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
9522  * Usually set to TRUE. */
9523  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
9524  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9525  SCIP_Bool check, /**< should the constraint be checked for feasibility?
9526  * TRUE for model constraints, FALSE for additional, redundant constraints. */
9527  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
9528  * Usually set to TRUE. */
9529  SCIP_Bool local, /**< is constraint only valid locally?
9530  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
9531  SCIP_Bool dynamic, /**< is constraint subject to aging?
9532  * Usually set to FALSE. Set to TRUE for own cuts which
9533  * are separated as constraints. */
9534  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
9535  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
9536  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
9537  * if it may be moved to a more global node?
9538  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
9539  )
9540 {
9541  SCIP_CONSHDLR* conshdlr;
9542  SCIP_CONSDATA* consdata;
9543  SCIP_Bool modifiable;
9544  SCIP_Bool transformed;
9545  int v;
9546 
9547  modifiable = FALSE;
9548 
9549  /* find the SOS1 constraint handler */
9550  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
9551  if ( conshdlr == NULL )
9552  {
9553  SCIPerrorMessage("<%s> constraint handler not found\n", CONSHDLR_NAME);
9554  return SCIP_PLUGINNOTFOUND;
9555  }
9556 
9557  /* are we in the transformed problem? */
9558  transformed = SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED;
9559 
9560  /* create constraint data */
9561  SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) );
9562  consdata->vars = NULL;
9563  consdata->nvars = nvars;
9564  consdata->maxvars = nvars;
9565  consdata->rowub = NULL;
9566  consdata->rowlb = NULL;
9567  consdata->nfixednonzeros = transformed ? 0 : -1;
9568  consdata->weights = NULL;
9569  consdata->local = local;
9570 
9571  if ( nvars > 0 )
9572  {
9573  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->vars, vars, nvars) );
9574 
9575  /* check weights */
9576  if ( weights != NULL )
9577  {
9578  /* store weights */
9579  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->weights, weights, nvars) );
9580 
9581  /* sort variables - ascending order */
9582  SCIPsortRealPtr(consdata->weights, (void**)consdata->vars, nvars);
9583  }
9584  }
9585  else
9586  {
9587  assert( weights == NULL );
9588  }
9589 
9590  /* branching on multiaggregated variables does not seem to work well, so avoid it */
9591  for (v = 0; v < nvars; ++v)
9592  {
9593  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, consdata->vars[v]) );
9594  }
9595 
9596  /* create constraint */
9597  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
9598  local, modifiable, dynamic, removable, stickingatnode) );
9599  assert( transformed == SCIPconsIsTransformed(*cons) );
9600 
9601  /* replace original variables by transformed variables in transformed constraint, add locks, and catch events */
9602  for (v = nvars - 1; v >= 0; --v)
9603  {
9604  SCIP_CONSHDLRDATA* conshdlrdata;
9605 
9606  /* always use transformed variables in transformed constraints */
9607  if ( transformed )
9608  {
9609  SCIP_CALL( SCIPgetTransformedVar(scip, consdata->vars[v], &(consdata->vars[v])) );
9610  }
9611  assert( consdata->vars[v] != NULL );
9612  assert( transformed == SCIPvarIsTransformed(consdata->vars[v]) );
9613 
9614  /* get constraint handler data */
9615  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9616  assert( conshdlrdata != NULL );
9617 
9618  /* handle the new variable */
9619  SCIP_CALL( handleNewVariableSOS1(scip, *cons, consdata, conshdlrdata, consdata->vars[v], transformed) );
9620  }
9621 
9622  return SCIP_OKAY;
9623 }
9624 
9625 
9626 /** creates and captures a SOS1 constraint with all constraint flags set to their default values.
9627  *
9628  * @warning Do NOT set the constraint to be modifiable manually, because this might lead
9629  * to wrong results as the variable array will not be resorted
9630  *
9631  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
9632  */
9634  SCIP* scip, /**< SCIP data structure */
9635  SCIP_CONS** cons, /**< pointer to hold the created constraint */
9636  const char* name, /**< name of constraint */
9637  int nvars, /**< number of variables in the constraint */
9638  SCIP_VAR** vars, /**< array with variables of constraint entries */
9639  SCIP_Real* weights /**< weights determining the variable order, or NULL if natural order should be used */
9640  )
9641 {
9642  SCIP_CALL( SCIPcreateConsSOS1( scip, cons, name, nvars, vars, weights, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
9643 
9644  return SCIP_OKAY;
9645 }
9646 
9647 
9648 /** adds variable to SOS1 constraint, the position is determined by the given weight */
9650  SCIP* scip, /**< SCIP data structure */
9651  SCIP_CONS* cons, /**< constraint */
9652  SCIP_VAR* var, /**< variable to add to the constraint */
9653  SCIP_Real weight /**< weight determining position of variable */
9654  )
9655 {
9656  SCIP_CONSHDLRDATA* conshdlrdata;
9657  SCIP_CONSHDLR* conshdlr;
9658 
9659  assert( scip != NULL );
9660  assert( var != NULL );
9661  assert( cons != NULL );
9662 
9663  SCIPdebugMessage("adding variable <%s> to constraint <%s> with weight %g\n", SCIPvarGetName(var), SCIPconsGetName(cons), weight);
9664 
9665  conshdlr = SCIPconsGetHdlr(cons);
9666  assert( conshdlr != NULL );
9667  if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
9668  {
9669  SCIPerrorMessage("constraint is not an SOS1 constraint.\n");
9670  return SCIP_INVALIDDATA;
9671  }
9672 
9673  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9674  assert( conshdlrdata != NULL );
9675 
9676  SCIP_CALL( addVarSOS1(scip, cons, conshdlrdata, var, weight) );
9677 
9678  return SCIP_OKAY;
9679 }
9680 
9681 
9682 /** appends variable to SOS1 constraint */
9684  SCIP* scip, /**< SCIP data structure */
9685  SCIP_CONS* cons, /**< constraint */
9686  SCIP_VAR* var /**< variable to add to the constraint */
9687  )
9689  SCIP_CONSHDLRDATA* conshdlrdata;
9690  SCIP_CONSHDLR* conshdlr;
9691 
9692  assert( scip != NULL );
9693  assert( var != NULL );
9694  assert( cons != NULL );
9695 
9696  SCIPdebugMessage("appending variable <%s> to constraint <%s>\n", SCIPvarGetName(var), SCIPconsGetName(cons));
9697 
9698  conshdlr = SCIPconsGetHdlr(cons);
9699  assert( conshdlr != NULL );
9700  if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
9701  {
9702  SCIPerrorMessage("constraint is not an SOS1 constraint.\n");
9703  return SCIP_INVALIDDATA;
9704  }
9705 
9706  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9707  assert( conshdlrdata != NULL );
9708 
9709  SCIP_CALL( appendVarSOS1(scip, cons, conshdlrdata, var) );
9710 
9711  return SCIP_OKAY;
9712 }
9713 
9714 
9715 /** gets number of variables in SOS1 constraint */
9716 int SCIPgetNVarsSOS1(
9717  SCIP* scip, /**< SCIP data structure */
9718  SCIP_CONS* cons /**< constraint */
9719  )
9720 {
9721  SCIP_CONSDATA* consdata;
9722 
9723  assert( scip != NULL );
9724  assert( cons != NULL );
9725 
9726  if ( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
9727  {
9728  SCIPerrorMessage("constraint is not an SOS1 constraint.\n");
9729  SCIPABORT();
9730  return -1; /*lint !e527*/
9731  }
9732 
9733  consdata = SCIPconsGetData(cons);
9734  assert( consdata != NULL );
9735 
9736  return consdata->nvars;
9737 }
9738 
9739 
9740 /** gets array of variables in SOS1 constraint */
9742  SCIP* scip, /**< SCIP data structure */
9743  SCIP_CONS* cons /**< constraint data */
9744  )
9745 {
9746  SCIP_CONSDATA* consdata;
9747 
9748  assert( scip != NULL );
9749  assert( cons != NULL );
9750 
9751  if ( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
9752  {
9753  SCIPerrorMessage("constraint is not an SOS1 constraint.\n");
9754  SCIPABORT();
9755  return NULL; /*lint !e527*/
9756  }
9757 
9758  consdata = SCIPconsGetData(cons);
9759  assert( consdata != NULL );
9760 
9761  return consdata->vars;
9762 }
9763 
9764 
9765 /** gets array of weights in SOS1 constraint (or NULL if not existent) */
9767  SCIP* scip, /**< SCIP data structure */
9768  SCIP_CONS* cons /**< constraint data */
9769  )
9770 {
9771  SCIP_CONSDATA* consdata;
9772 
9773  assert( scip != NULL );
9774  assert( cons != NULL );
9775 
9776  if ( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
9777  {
9778  SCIPerrorMessage("constraint is not an SOS1 constraint.\n");
9779  SCIPABORT();
9780  return NULL; /*lint !e527*/
9781  }
9782 
9783  consdata = SCIPconsGetData(cons);
9784  assert( consdata != NULL );
9785 
9786  return consdata->weights;
9787 }
9788 
9789 
9790 /** gets conflict graph of SOS1 constraints (or NULL if not existent)
9791  *
9792  * @note The conflict graph is globally valid; local changes are not taken into account.
9793  */
9795  SCIP_CONSHDLR* conshdlr /**< SOS1 constraint handler */
9796  )
9797 {
9798  SCIP_CONSHDLRDATA* conshdlrdata;
9800  assert( conshdlr != NULL );
9801 
9802  if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
9803  {
9804  SCIPerrorMessage("not an SOS1 constraint handler.\n");
9805  SCIPABORT();
9806  return NULL; /*lint !e527*/
9807  }
9808  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9809  assert( conshdlrdata != NULL );
9810 
9811  return conshdlrdata->conflictgraph;
9812 }
9813 
9814 
9815 /** gets number of problem variables that are part of the SOS1 conflict graph */
9816 int SCIPgetNSOS1Vars(
9817  SCIP_CONSHDLR* conshdlr /**< SOS1 constraint handler */
9818  )
9819 {
9820  SCIP_CONSHDLRDATA* conshdlrdata;
9822  assert( conshdlr != NULL );
9823 
9824  if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
9825  {
9826  SCIPerrorMessage("not an SOS1 constraint handler.\n");
9827  SCIPABORT();
9828  return -1; /*lint !e527*/
9829  }
9830  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9831  assert( conshdlrdata != NULL );
9832 
9833  return conshdlrdata->nsos1vars;
9834 }
9835 
9836 
9837 /** returns whether variable is part of the SOS1 conflict graph */
9839  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
9840  SCIP_VAR* var /**< variable */
9841  )
9842 {
9843  SCIP_CONSHDLRDATA* conshdlrdata;
9844 
9845  assert( var != NULL );
9846  assert( conshdlr != NULL );
9847 
9848  if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
9849  {
9850  SCIPerrorMessage("not an SOS1 constraint handler.\n");
9851  SCIPABORT();
9852  return FALSE; /*lint !e527*/
9853  }
9854  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9855  assert( conshdlrdata != NULL );
9856 
9857  return varIsSOS1(conshdlrdata, var);
9858 }
9859 
9860 
9861 /** returns SOS1 index of variable or -1 if variable is part of the SOS1 conflict graph */
9862 int SCIPvarGetNodeSOS1(
9863  SCIP_CONSHDLR* conshdlr, /**< SOS1 constraint handler */
9864  SCIP_VAR* var /**< variable */
9865  )
9866 {
9867  SCIP_CONSHDLRDATA* conshdlrdata;
9868 
9869  assert( conshdlr != NULL );
9870  assert( var != NULL );
9871 
9872  if ( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
9873  {
9874  SCIPerrorMessage("Not an SOS1 constraint handler.\n");
9875  SCIPABORT();
9876  return -1; /*lint !e527*/
9877  }
9878  conshdlrdata = SCIPconshdlrGetData(conshdlr);
9879  assert( conshdlrdata != NULL );
9880 
9881  if ( conshdlrdata->varhash == NULL )
9882  {
9883  SCIPerrorMessage("Hashmap not yet initialized.\n");
9884  SCIPABORT();
9885  return -1; /*lint !e527*/
9886  }
9887 
9888  return varGetNodeSOS1(conshdlrdata, var);
9889 }
9890 
9891 
9892 /** returns variable that belongs to a given node from the conflict graph */
9894  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
9895  int node /**< node from the conflict graph */
9896  )
9897 {
9898  SCIP_NODEDATA* nodedata;
9899 
9900  assert( conflictgraph != NULL );
9901  assert( node >= 0 && node < SCIPdigraphGetNNodes(conflictgraph) );
9902 
9903  /* get node data */
9904  nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conflictgraph, node);
9905 
9906  if ( nodedata == NULL )
9907  {
9908  SCIPerrorMessage("variable is not assigned to an index.\n");
9909  SCIPABORT();
9910  return NULL; /*lint !e527*/
9911  }
9912 
9913  return nodedata->var;
9914 }
9915 
9916 
9917 /** based on solution values of the variables, fixes variables to zero to turn all SOS1 constraints feasible */
9919  SCIP* scip, /**< SCIP pointer */
9920  SCIP_CONSHDLR* conshdlr, /**< SOS1 constraint handler */
9921  SCIP_SOL* sol, /**< solution */
9922  SCIP_Bool* changed, /**< pointer to store whether the solution has been changed */
9923  SCIP_Bool* success /**< pointer to store whether SOS1 constraints have been turned feasible and
9924  * solution was good enough */
9925  )
9926 {
9927  SCIP_DIGRAPH* conflictgraph; /* conflict graph for SOS1 constraints */
9928  SCIP_Bool* indicatorzero; /* indicates which solution values are zero */
9929  SCIP_Bool* indset; /* indicator vector of feasible solution; i.e., an independent set */
9930  SCIP_Bool allroundable;
9931  SCIP_Real roundobjval;
9932  int nsos1vars;
9933  int j;
9934 
9935  assert( scip != NULL );
9936  assert( conshdlr != NULL );
9937  assert( sol != NULL );
9938  assert( changed != NULL );
9939 
9940  *changed = FALSE;
9941  *success = FALSE;
9942 
9943  /* get number of SOS1 variables */
9944  nsos1vars = SCIPgetNSOS1Vars(conshdlr);
9945  if ( nsos1vars < 1 )
9946  {
9947  *success = TRUE;
9948  return SCIP_OKAY;
9949  }
9950 
9951  /* get conflict graph */
9952  conflictgraph = SCIPgetConflictgraphSOS1(conshdlr);
9953  assert( conflictgraph != NULL );
9954 
9955  /* determine if variables with nonzero solution value are roundable */
9956  allroundable = TRUE;
9957  for (j = 0; j < nsos1vars && allroundable; ++j)
9958  {
9959  SCIP_VAR* var;
9960 
9961  var = SCIPnodeGetVarSOS1(conflictgraph, j);
9962 
9963  if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, var)) )
9964  {
9965  assert( ! SCIPvarMayRoundUp(var) || ! SCIPisFeasPositive(scip, SCIPgetSolVal(scip, sol, var)) );
9966  assert( ! SCIPvarMayRoundDown(var) || ! SCIPisFeasNegative(scip, SCIPgetSolVal(scip, sol, var)) );
9967 
9968  if ( ! SCIPvarMayRoundDown(var) && ! SCIPvarMayRoundUp(var) )
9969  allroundable = FALSE;
9970  }
9971  }
9972  if ( ! allroundable )
9973  return SCIP_OKAY;
9974 
9975  /* allocate buffer arrays */
9976  SCIP_CALL( SCIPallocBufferArray(scip, &indset, nsos1vars) );
9977  SCIP_CALL( SCIPallocBufferArray(scip, &indicatorzero, nsos1vars) );
9978 
9979  /* get array that indicates which solution values are zero */
9980  for (j = 0; j < nsos1vars; ++j)
9981  {
9982  indset[j] = 0;
9983  if ( SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, j))) )
9984  indicatorzero[j] = TRUE;
9985  else
9986  indicatorzero[j] = FALSE;
9987  }
9988 
9989  /* call greedy algorithm for the maximum weighted independent set problem */
9990  SCIP_CALL( maxWeightIndSetHeuristic(scip, sol, conshdlr, conflictgraph, nsos1vars, indicatorzero, indset) );
9991 
9992  /* make solution feasible */
9993  for (j = 0; j < nsos1vars; ++j)
9994  {
9995  if ( indset[j] == 0 )
9996  {
9997  SCIP_CALL( SCIPsetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, j), 0.0) );
9998  *changed = TRUE;
9999  }
10000  }
10001 
10002 #ifdef SCIP_NDEBUG
10003  for (j = 0; j < nsos1vars; ++j)
10004  {
10005  SCIP_Real solval;
10006  int* succ;
10007  int nsucc;
10008 
10009  solval = SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, j));
10010 
10011  if ( ! SCIPisFeasZero(scip, solval) )
10012  {
10013  int s;
10014  nsucc = SCIPdigraphGetNSuccessors(conflictgraph, j);
10015  succ = SCIPdigraphGetSuccessors(conflictgraph, j);
10016 
10017  for (s = 0; s < nsucc; ++s)
10018  {
10019  solval = SCIPgetSolVal(scip, sol, SCIPnodeGetVarSOS1(conflictgraph, succ[s]));
10020  assert( ! SCIPisFeasZero(scip, solval) );
10021  }
10022  }
10023  }
10024 #endif
10025 
10026  /* check whether objective value of rounded solution is good enough */
10027  roundobjval = SCIPgetSolOrigObj(scip, sol);
10028  if ( SCIPgetObjsense(scip) == SCIP_OBJSENSE_MAXIMIZE )
10029  roundobjval *= -1;
10030 
10031  if ( SCIPisLT(scip, roundobjval, SCIPgetUpperbound(scip) ) )
10032  *success = TRUE;
10033 
10034  /* free buffer arrays */
10035  SCIPfreeBufferArray(scip, &indicatorzero);
10036  SCIPfreeBufferArray(scip, &indset);
10037 
10038  return SCIP_OKAY;
10039 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:51
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip.c:22764
void SCIPsortRealInt(SCIP_Real *realarray, int *intarray, int len)
#define DEFAULT_IMPLPROP
Definition: cons_sos1.c:115
#define DIVINGCUTOFFVALUE
Definition: cons_sos1.c:160
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41180
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:16759
SCIP_RETCODE SCIPsolveProbingLP(SCIP *scip, int itlim, SCIP_Bool *lperror, SCIP_Bool *cutoff)
Definition: scip.c:32398
void ** SCIPdigraphGetSuccessorsData(SCIP_DIGRAPH *digraph, int node)
Definition: misc.c:5978
SCIP_VAR * SCIPvarGetNegationVar(SCIP_VAR *var)
Definition: var.c:16781
SCIP_RETCODE SCIPwriteVarName(SCIP *scip, FILE *file, SCIP_VAR *var, SCIP_Bool type)
Definition: scip.c:15939
SCIP_RETCODE SCIPaddDiveBoundChange(SCIP *scip, SCIP_VAR *var, SCIP_BRANCHDIR dir, SCIP_Real value, SCIP_Bool preferred)
Definition: scip.c:32649
static SCIP_RETCODE presolRoundConsSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr, SCIP_Bool *substituted, SCIP_Bool *cutoff, SCIP_Bool *success, int *ndelconss, int *nupgdconss, int *nfixedvars, int *nremovedvars)
Definition: cons_sos1.c:1550
static SCIP_RETCODE genConflictgraphLinearCons(SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraphlin, SCIP_DIGRAPH *conflictgraphorig, SCIP_VAR **linvars, int nlinvars, int *posinlinvars)
Definition: cons_sos1.c:1334
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:41293
int SCIPgetNVars(SCIP *scip)
Definition: scip.c:10735
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip.c:5847
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip.c:5557
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:25575
#define DEFAULT_MAXIMPLCUTS
Definition: cons_sos1.c:152
static SCIP_RETCODE fixVariableZero(SCIP *scip, SCIP_VAR *var, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: cons_sos1.c:599
enum TCLIQUE_Status TCLIQUE_STATUS
Definition: tclique.h:57
static SCIP_RETCODE enforceConflictgraph(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONSHDLR *conshdlr, int nconss, SCIP_CONS **conss, SCIP_RESULT *result)
Definition: cons_sos1.c:5147
SCIP_RETCODE SCIPmakeSOS1sFeasible(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_SOL *sol, SCIP_Bool *changed, SCIP_Bool *success)
Definition: cons_sos1.c:9923
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16341
#define DEFAULT_MAXSOSADJACENCY
Definition: cons_sos1.c:104
void tcliqueFree(TCLIQUE_GRAPH **tcliquegraph)
static SCIP_RETCODE detectVarboundSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_VAR *var0, SCIP_VAR *var1, SCIP_Real val0, SCIP_Real val1)
Definition: cons_sos1.c:7273
static SCIP_DECL_CONSENFOPS(consEnfopsSOS1)
Definition: cons_sos1.c:8473
static SCIP_RETCODE getBranchingVerticesSOS1(SCIP *scip, SCIP_DIGRAPH *conflictgraph, SCIP_Bool *verticesarefixed, SCIP_Bool bipbranch, int branchvertex, int *fixingsnode1, int *nfixingsnode1, int *fixingsnode2, int *nfixingsnode2)
Definition: cons_sos1.c:3946
SCIP_RETCODE SCIPgetProbvarLinearSum(SCIP *scip, SCIP_VAR **vars, SCIP_Real *scalars, int *nvars, int varssize, SCIP_Real *constant, int *requiredsize, SCIP_Bool mergemultiples)
Definition: scip.c:17456
static SCIP_RETCODE propVariableNonzero(SCIP *scip, SCIP_DIGRAPH *conflictgraph, SCIP_DIGRAPH *implgraph, SCIP_CONS *cons, int node, SCIP_Bool implprop, SCIP_Bool *cutoff, int *ngen)
Definition: cons_sos1.c:3478
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
Definition: scip.c:41256
TCLIQUE_Bool tcliqueCreate(TCLIQUE_GRAPH **tcliquegraph)
#define CONSHDLR_NAME
Definition: cons_sos1.c:86
#define CONSHDLR_PROPFREQ
Definition: cons_sos1.c:92
static SCIP_DECL_CONSSEPALP(consSepalpSOS1)
Definition: cons_sos1.c:8386
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip.h:20402
struct TCLIQUE_Graph TCLIQUE_GRAPH
Definition: tclique.h:38
#define DEFAULT_ADDCOMPSFEAS
Definition: cons_sos1.c:131
static SCIP_DECL_CONSINITLP(consInitlpSOS1)
Definition: cons_sos1.c:8361
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:11577
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:16521
SCIP_Bool SCIPvarMayRoundDown(SCIP_VAR *var)
Definition: var.c:3259
static SCIP_DECL_CONSFREE(consFreeSOS1)
Definition: cons_sos1.c:7952
TCLIQUE_Bool tcliqueAddNode(TCLIQUE_GRAPH *tcliquegraph, int node, TCLIQUE_WEIGHT weight)
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41528
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip.c:10690
#define SCIP_MAXSTRLEN
Definition: def.h:198
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip.c:5603
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip.c:30487
SCIP_Real * SCIPgetWeightsSOS1(SCIP *scip, SCIP_CONS *cons)
Definition: cons_sos1.c:9771
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition: scip.c:5215
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4292
static SCIP_RETCODE inferVariableZero(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, int inferinfo, SCIP_Bool *infeasible, SCIP_Bool *tightened, SCIP_Bool *success)
Definition: cons_sos1.c:673
#define DEFAULT_MAXBOUNDCUTS
Definition: cons_sos1.c:147
static SCIP_RETCODE cliqueGetCommonSuccessorsSOS1(SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, int *clique, SCIP_VAR **vars, int nvars, int *comsucc, int *ncomsucc)
Definition: cons_sos1.c:1387
static SCIP_RETCODE performStrongbranchSOS1(SCIP *scip, SCIP_DIGRAPH *conflictgraph, int *fixingsexec, int nfixingsexec, int *fixingsop, int nfixingsop, int inititer, SCIP_Bool fixnonzero, int *domainfixings, int *ndomainfixings, SCIP_Bool *infeasible, SCIP_Real *objval, SCIP_Bool *lperror)
Definition: cons_sos1.c:4159
SCIPInterval pow(const SCIPInterval &x, const SCIPInterval &y)
#define NULL
Definition: lpi_spx.cpp:130
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17011
static SCIP_RETCODE updateConflictGraphSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, SCIP_VAR **totalvars, SCIP_DIGRAPH *implgraph, SCIP_HASHMAP *implhash, SCIP_Bool *implnodes, SCIP_Bool **adjacencymatrix, int givennode, int nonznode, int *naddconss)
Definition: cons_sos1.c:2038
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4262
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip.c:1125
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:940
int * SCIPdigraphGetSuccessors(SCIP_DIGRAPH *digraph, int node)
Definition: misc.c:5960
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:7853
SCIP_Real SCIProwGetLhs(SCIP_ROW *row)
Definition: lp.c:18914
static SCIP_RETCODE getSOS1Implications(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_VAR **vars, SCIP_DIGRAPH *implgraph, SCIP_HASHMAP *implhash, SCIP_Bool *implnodes, int node)
Definition: cons_sos1.c:1484
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip.c:5303
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:16965
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip.c:30469
#define CONSHDLR_MAXPREROUNDS
Definition: cons_sos1.c:96
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition: scip.c:34453
static SCIP_RETCODE propConsSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_Bool *cutoff, int *ngen)
Definition: cons_sos1.c:3380
static SCIP_RETCODE extensionOperatorSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_Bool **adjacencymatrix, SCIP_DIGRAPH *vertexcliquegraph, int nsos1vars, int nconss, SCIP_CONS *cons, SCIP_VAR **vars, SCIP_Real *weights, SCIP_Bool firstcall, SCIP_Bool usebacktrack, int **cliques, int *ncliques, int *cliquesizes, int *newclique, int *workingset, int nworkingset, int nexts, int pos, int *maxextensions, int *naddconss, SCIP_Bool *success)
Definition: cons_sos1.c:1072
static SCIP_Bool isImpliedZero(SCIP_DIGRAPH *conflictgraph, SCIP_Bool *implnodes, int node)
Definition: cons_sos1.c:2140
#define DEFAULT_ADDBDSFEAS
Definition: cons_sos1.c:132
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip.c:17512
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip.c:5787
void SCIPswapPointers(void **pointer1, void **pointer2)
Definition: misc.c:7837
SCIP_RETCODE SCIPcreateConsSetpack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: cons_setppc.c:8952
static SCIP_Real nodeGetSolvalBinaryBigMSOS1(SCIP *scip, SCIP_DIGRAPH *conflictgraph, SCIP_SOL *sol, int node)
Definition: cons_sos1.c:402
SCIP_RETCODE SCIPappendVarSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition: cons_sos1.c:9688
#define DEFAULT_CONFLICTPROP
Definition: cons_sos1.c:114
static SCIP_DECL_CONSRESPROP(consRespropSOS1)
Definition: cons_sos1.c:8744
SCIP_RETCODE SCIPpropagateProbing(SCIP *scip, int maxproprounds, SCIP_Bool *cutoff, SCIP_Longint *ndomredsfound)
Definition: scip.c:32162
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:7913
#define FALSE
Definition: def.h:53
static SCIP_RETCODE deleteVarSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr, int pos)
Definition: cons_sos1.c:1033
#define CONSHDLR_EAGERFREQ
Definition: cons_sos1.c:93
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:2052
#define CONSHDLR_SEPAPRIORITY
Definition: cons_sos1.c:88
SCIP_VAR ** SCIPgetVarsSOS1(SCIP *scip, SCIP_CONS *cons)
Definition: cons_sos1.c:9746
static SCIP_Real nodeGetSolvalVarboundLbSOS1(SCIP *scip, SCIP_DIGRAPH *conflictgraph, SCIP_SOL *sol, int node)
Definition: cons_sos1.c:452
static SCIP_RETCODE passConComponentVarbound(SCIP *scip, SCIP_DIGRAPH *conflictgraph, int node, SCIP_VAR *boundvar, SCIP_Bool checklb, SCIP_Bool *processed, int *concomp, int *nconcomp, SCIP_Bool *unique)
Definition: cons_sos1.c:7349
#define CONSHDLR_CHECKPRIORITY
Definition: cons_sos1.c:90
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip.c:7747
miscellaneous datastructures
int SCIPgetNVarsLinear(SCIP *scip, SCIP_CONS *cons)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:8169
#define TRUE
Definition: def.h:52
#define SCIPdebug(x)
Definition: pub_message.h:74
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:7644
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
static SCIP_Real nodeGetSolvalVarboundUbSOS1(SCIP *scip, SCIP_DIGRAPH *conflictgraph, SCIP_SOL *sol, int node)
Definition: cons_sos1.c:479
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip.c:5764
enum SCIP_Varstatus SCIP_VARSTATUS
Definition: type_var.h:48
static SCIP_RETCODE maxWeightIndSetHeuristic(SCIP *scip, SCIP_SOL *sol, SCIP_CONSHDLR *conshdlr, SCIP_DIGRAPH *conflictgraph, int nsos1vars, SCIP_Bool *indicatorzero, SCIP_Bool *indset)
Definition: cons_sos1.c:7171
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
Definition: scip.c:41580
#define EVENTHDLR_NAME
Definition: cons_sos1.c:156
#define CONSHDLR_ENFOPRIORITY
Definition: cons_sos1.c:89
#define DEFAULT_SOS1BRANCH
Definition: cons_sos1.c:121
SCIP_RETCODE SCIPcomputeArraysIntersection(int *array1, int narray1, int *array2, int narray2, int *intersectarray, int *nintersectarray)
Definition: misc.c:7968
static SCIP_RETCODE separateSOS1(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_SOL *sol, int nconss, SCIP_CONS **conss, SCIP_RESULT *result)
Definition: cons_sos1.c:6842
void SCIPsortDownIntInt(int *intarray1, int *intarray2, int len)
int SCIPgetNVarsSOS1(SCIP *scip, SCIP_CONS *cons)
Definition: cons_sos1.c:9721
SCIP_RETCODE SCIPaddVarsToRow(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip.c:27875
static SCIP_RETCODE resetConflictgraphSOS1(SCIP_DIGRAPH *conflictgraph, SCIP_DIGRAPH *localconflicts, int nsos1vars)
Definition: cons_sos1.c:5091
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip.h:20385
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip.c:26426
SCIP_Real SCIPvarGetLbAtIndex(SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: var.c:15695
SCIP_Longint SCIPgetNDualResolveLPIterations(SCIP *scip)
Definition: scip.c:37323
#define SCIPdebugMessage
Definition: pub_message.h:77
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip.c:34593
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip.h:20414
static SCIP_RETCODE initConflictgraph(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss)
Definition: cons_sos1.c:7702
tclique user interface
static SCIP_RETCODE getBoundConsFromVertices(SCIP *scip, SCIP_DIGRAPH *conflictgraph, int v1, int v2, SCIP_VAR *boundvar, SCIP_Bool extend, SCIP_CONS *cons, SCIP_Real *feas)
Definition: cons_sos1.c:4500
void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2111
#define DEFAULT_ADDCOMPSDEPTH
Definition: cons_sos1.c:130
SCIP_Longint SCIPgetNNodeInitLPIterations(SCIP *scip)
Definition: scip.c:37395
static SCIP_DECL_CONSGETVARS(consGetVarsSOS1)
Definition: cons_sos1.c:9024
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:7843
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:7783
enum SCIP_LPSolStat SCIP_LPSOLSTAT
Definition: type_lp.h:42
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip.c:26224
SCIP_RETCODE SCIPaddCut(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip.c:30577
Constraint handler for the set partitioning / packing / covering constraints .
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip.c:24936
#define SCIP_EVENTTYPE_BOUNDCHANGED
Definition: type_event.h:99
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip.h:20418
SCIP_Real SCIPgetLPObjval(SCIP *scip)
Definition: scip.c:26469
static SCIP_RETCODE getBranchingPrioritiesSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, int nsos1vars, SCIP_Bool *verticesarefixed, SCIP_Bool bipbranch, int *fixingsnode1, int *fixingsnode2, SCIP_Real *branchpriors, int *vertexbestprior, SCIP_Bool *relsolfeas)
Definition: cons_sos1.c:4058
static SCIP_RETCODE getVectorOfWeights(SCIP *scip, SCIP_SOL *sol, SCIP_DIGRAPH *conflictgraph, int nsos1vars, SCIP_Bool *indicatorzero, SCIP_Real *weights)
Definition: cons_sos1.c:6963
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11206
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip.c:5328
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:7773
static SCIP_RETCODE updateImplicationGraphSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, SCIP_Bool **adjacencymatrix, SCIP_DIGRAPH *implgraph, SCIP_HASHMAP *implhash, SCIP_Bool *implnodes, SCIP_VAR **totalvars, int **cliquecovers, int *cliquecoversizes, int *varincover, SCIP_VAR **vars, SCIP_Real *coefs, int nvars, SCIP_Real *bounds, SCIP_VAR *var, SCIP_Real bound, SCIP_Real boundnonzero, int ninftynonzero, SCIP_Bool lower, int *nchgbds, SCIP_Bool *update)
Definition: cons_sos1.c:2281
#define DEFAULT_IMPLCUTSDEPTH
Definition: cons_sos1.c:151
SCIP * scip
Definition: cons_sos1.c:205
SCIP_RETCODE SCIPinferVarUbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:20638
SCIP_Real SCIPvarGetAggrConstant(SCIP_VAR *var)
Definition: var.c:16712
SCIP_RETCODE SCIPupdateNodeLowerbound(SCIP *scip, SCIP_NODE *node, SCIP_Real newbound)
Definition: scip.c:12400
static SCIP_DECL_CONSENFOLP(consEnfolpSOS1)
Definition: cons_sos1.c:8418
SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip.c:34676
SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
Definition: tree.c:7016
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:3516
SCIP_Bool SCIPvarIsSOS1(SCIP_CONSHDLR *conshdlr, SCIP_VAR *var)
Definition: cons_sos1.c:9843
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:16460
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:2154
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:3542
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip.c:16242
#define SCIP_EVENTTYPE_LBRELAXED
Definition: type_event.h:56
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:16532
int SCIPdigraphGetNNodes(SCIP_DIGRAPH *digraph)
Definition: misc.c:5887
SCIP_RETCODE SCIPdigraphCreate(SCIP_DIGRAPH **digraph, int nnodes)
Definition: misc.c:5591
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:3921
SCIP_VAR * SCIPvarGetAggrVar(SCIP_VAR *var)
Definition: var.c:16690
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip.c:36232
static SCIP_DECL_CONSINITSOL(consInitsolSOS1)
Definition: cons_sos1.c:7971
static SCIP_RETCODE enforceConssSOS1(SCIP *scip, SCIP_CONSHDLR *conshdlr, int nconss, SCIP_CONS **conss, SCIP_RESULT *result)
Definition: cons_sos1.c:5570
SCIP_Real SCIPeventGetOldbound(SCIP_EVENT *event)
Definition: event.c:1096
SCIP_RETCODE SCIPcreateConsBasicSOS1(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *weights)
Definition: cons_sos1.c:9638
static SCIP_DECL_CONSLOCK(consLockSOS1)
Definition: cons_sos1.c:8820
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41193
static SCIP_DECL_EVENTEXEC(eventExecSOS1)
Definition: cons_sos1.c:9068
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:16483
SCIP_RETCODE SCIPgetVarCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR *sourcevar, SCIP_VAR **targetvar, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *success)
Definition: scip.c:1750
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip.h:20383
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:41592
SCIP_Longint SCIPgetNDualResolveLPs(SCIP *scip)
Definition: scip.c:37303
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:41317
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip.c:17159
TCLIQUE_Bool tcliqueAddEdge(TCLIQUE_GRAPH *tcliquegraph, int node1, int node2)
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:7883
#define SCIPallocMemory(scip, ptr)
Definition: scip.h:20355
SCIP_RETCODE SCIPdigraphSetNSuccessors(SCIP_DIGRAPH *digraph, int node, int nsuccessors)
Definition: misc.c:5871
#define SCIPerrorMessage
Definition: pub_message.h:45
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip.h:20426
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition: lp.c:18924
#define DEFAULT_NSTRONGITER
Definition: cons_sos1.c:139
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip.h:20403
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:19592
SCIP_Real SCIPcalcNodeselPriority(SCIP *scip, SCIP_VAR *var, SCIP_BRANCHDIR branchdir, SCIP_Real targetvalue)
Definition: scip.c:33261
SCIP_VAR * SCIPnodeGetVarSOS1(SCIP_DIGRAPH *conflictgraph, int node)
Definition: cons_sos1.c:9898
#define DEFAULT_IMPLCUTSFREQ
Definition: cons_sos1.c:150
#define DEFAULT_SOSCONSPROP
Definition: cons_sos1.c:116
static SCIP_DECL_CONSPRINT(consPrintSOS1)
Definition: cons_sos1.c:8864
#define CONSHDLR_DELAYSEPA
Definition: cons_sos1.c:97
#define DEFAULT_AUTOCUTSFROMSOS1
Definition: cons_sos1.c:144
SCIP_Real SCIPvarGetAggrScalar(SCIP_VAR *var)
Definition: var.c:16701
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
Definition: scip.c:41604
void tcliqueChangeWeight(TCLIQUE_GRAPH *tcliquegraph, int node, TCLIQUE_WEIGHT weight)
void * SCIPdigraphGetNodeData(SCIP_DIGRAPH *digraph, int node)
Definition: misc.c:5897
static SCIP_RETCODE updateWeightsTCliquegraph(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, TCLIQUE_DATA *tcliquedata, SCIP_DIGRAPH *conflictgraph, SCIP_SOL *sol, int nsos1vars)
Definition: cons_sos1.c:5869
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:3901
SCIP_Real SCIPvarGetUbAtIndex(SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: var.c:15787
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip.c:5496
static SCIP_DECL_CONSGETNVARS(consGetNVarsSOS1)
Definition: cons_sos1.c:9047
static SCIP_RETCODE generateBoundInequalityFromSOS1Cons(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool local, SCIP_Bool global, SCIP_Bool strengthen, SCIP_Bool removable, SCIP_ROW **rowlb, SCIP_ROW **rowub)
Definition: cons_sos1.c:6470
void SCIPdigraphSetNodeData(SCIP_DIGRAPH *digraph, void *dataptr, int node)
Definition: misc.c:5913
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip.c:40927
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:7624
static SCIP_RETCODE sepaBoundInequalitiesFromGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_SOL *sol, int maxboundcuts, int *ngen, SCIP_Bool *cutoff)
Definition: cons_sos1.c:6396
SCIP_OBJSENSE SCIPgetObjsense(SCIP *scip)
Definition: scip.c:10034
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41515
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:19125
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
Definition: scip.c:41366
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:146
SCIP_CONSHDLR * conshdlr
Definition: cons_sos1.c:206
#define DEFAULT_UPDATECONFLPRESOL
Definition: cons_sos1.c:111
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:2070
static SCIP_RETCODE fixVariableZeroNode(SCIP *scip, SCIP_VAR *var, SCIP_NODE *node, SCIP_Bool *infeasible)
Definition: cons_sos1.c:544
SCIP_Real SCIPgetRhsLinear(SCIP *scip, SCIP_CONS *cons)
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip.h:20391
internal miscellaneous methods
#define EVENTHDLR_DESC
Definition: cons_sos1.c:157
#define REALABS(x)
Definition: def.h:148
#define SCIP_EVENTTYPE_UBRELAXED
Definition: type_event.h:58
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:16735
void tcliqueMaxClique(TCLIQUE_GETNNODES((*getnnodes)), TCLIQUE_GETWEIGHTS((*getweights)), TCLIQUE_ISEDGE((*isedge)), TCLIQUE_SELECTADJNODES((*selectadjnodes)), TCLIQUE_GRAPH *tcliquegraph, TCLIQUE_NEWSOL((*newsol)), TCLIQUE_DATA *tcliquedata, int *maxcliquenodes, int *nmaxcliquenodes, TCLIQUE_WEIGHT *maxcliqueweight, TCLIQUE_WEIGHT maxfirstnodeweight, TCLIQUE_WEIGHT minweight, int maxntreenodes, int backtrackfreq, int maxnzeroextensions, int fixednode, int *ntreenodes, TCLIQUE_STATUS *status)
#define DEFAULT_NEIGHBRANCH
Definition: cons_sos1.c:119
SCIP_Real SCIPinfinity(SCIP *scip)
Definition: scip.c:41245
static SCIP_RETCODE appendVarSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_VAR *var)
Definition: cons_sos1.c:987
static SCIP_RETCODE tightenVarsBoundsSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, SCIP_DIGRAPH *implgraph, SCIP_HASHMAP *implhash, SCIP_Bool **adjacencymatrix, SCIP_VAR **totalvars, int ntotalvars, int nsos1vars, int *nchgbds, SCIP_Bool *implupdate, SCIP_Bool *cutoff)
Definition: cons_sos1.c:2546
#define SCIP_CALL(x)
Definition: def.h:263
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip.c:5261
#define SCIP_EVENTTYPE_LBTIGHTENED
Definition: type_event.h:55
#define DEFAULT_MAXADDCOMPS
Definition: cons_sos1.c:129
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip.c:5161
static SCIP_RETCODE computeNodeDataSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nsos1vars)
Definition: cons_sos1.c:7665
static SCIP_RETCODE initsepaBoundInequalityFromSOS1Cons(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool solvedinitlp, int maxboundcuts, int *ngen, SCIP_Bool *cutoff)
Definition: cons_sos1.c:6533
#define DEFAULT_BOUNDCUTSFROMSOS1
Definition: cons_sos1.c:142
SCIP_RETCODE SCIPgetDivesetScore(SCIP *scip, SCIP_DIVESET *diveset, SCIP_DIVETYPE divetype, SCIP_VAR *divecand, SCIP_Real divecandsol, SCIP_Real divecandfrac, SCIP_Real *candscore, SCIP_Bool *roundup)
Definition: scip.c:32511
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41554
SCIP_RETCODE SCIPdigraphAddArc(SCIP_DIGRAPH *digraph, int startnode, int endnode, void *data)
Definition: misc.c:5809
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:50
SCIP_Bool strthenboundcuts
Definition: cons_sos1.c:214
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:7654
SCIP_RETCODE SCIPaddConsNode(SCIP *scip, SCIP_NODE *node, SCIP_CONS *cons, SCIP_NODE *validnode)
Definition: scip.c:11966
#define DEFAULT_NSTRONGROUNDS
Definition: cons_sos1.c:136
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:12117
static SCIP_RETCODE updateArcData(SCIP *scip, SCIP_DIGRAPH *implgraph, SCIP_HASHMAP *implhash, SCIP_VAR **totalvars, SCIP_VAR *varv, SCIP_VAR *varw, SCIP_Real lb, SCIP_Real ub, SCIP_Real newbound, SCIP_Bool lower, int *nchgbds, SCIP_Bool *update)
Definition: cons_sos1.c:2169
SCIP_Real SCIPgetUpperbound(SCIP *scip)
Definition: scip.c:38120
SCIP_RETCODE SCIPcomputeArraysSetminus(int *array1, int narray1, int *array2, int narray2, int *setminusarray, int *nsetminusarray)
Definition: misc.c:8024
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: scip.c:41219
#define CONSHDLR_DELAYPROP
Definition: cons_sos1.c:98
static SCIP_DECL_CONSPROP(consPropSOS1)
Definition: cons_sos1.c:8599
#define CONSHDLR_NEEDSCONS
Definition: cons_sos1.c:99
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:23106
static SCIP_RETCODE checkConComponentsVarbound(SCIP *scip, SCIP_DIGRAPH *conflictgraph, int nsos1vars, SCIP_Bool checklb)
Definition: cons_sos1.c:7422
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:20259
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17021
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip.c:997
public data structures and miscellaneous methods
#define DEFAULT_MAXBOUNDCUTSROOT
Definition: cons_sos1.c:148
unsigned int SCIP_EVENTTYPE
Definition: type_event.h:125
SCIP_RETCODE SCIPdigraphAddArcSafe(SCIP_DIGRAPH *digraph, int startnode, int endnode, void *data)
Definition: misc.c:5837
int SCIPdigraphGetNSuccessors(SCIP_DIGRAPH *digraph, int node)
Definition: misc.c:5945
static SCIP_RETCODE freeImplGraphSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons_sos1.c:3784
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip.c:24759
#define CONSHDLR_PROP_TIMING
Definition: cons_sos1.c:100
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:16638
#define DEFAULT_AUTOSOS1BRANCH
Definition: cons_sos1.c:122
static SCIP_DECL_CONSSEPASOL(consSepasolSOS1)
Definition: cons_sos1.c:8402
#define SCIP_Bool
Definition: def.h:50
static SCIP_DECL_CONSEXITSOL(consExitsolSOS1)
Definition: cons_sos1.c:8025
SCIP_Bool SCIPdivesetSupportsType(SCIP_DIVESET *diveset, SCIP_DIVETYPE divetype)
Definition: heur.c:562
static SCIP_DECL_CONSDELETE(consDeleteSOS1)
Definition: cons_sos1.c:8094
#define DEFAULT_MAXTIGHTENBDS
Definition: cons_sos1.c:110
struct SCIP_NodeData SCIP_NODEDATA
SCIP_RETCODE SCIPsetConshdlrGetDiveBdChgs(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETDIVEBDCHGS((*consgetdivebdchgs)))
Definition: scip.c:5833
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip.c:801
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:7863
SCIP_Bool cutoff
Definition: cons_sos1.c:210
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip.h:20427
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:27798
#define MAX(x, y)
Definition: tclique_def.h:75
SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
Definition: scip.c:24356
int SCIPdigraphGetNArcs(SCIP_DIGRAPH *digraph)
Definition: misc.c:5927
SCIP_RETCODE SCIPflattenVarAggregationGraph(SCIP *scip, SCIP_VAR *var)
Definition: scip.c:17412
#define CONSHDLR_DESC
Definition: cons_sos1.c:87
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:7873
static SCIP_RETCODE addVarSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_VAR *var, SCIP_Real weight)
Definition: cons_sos1.c:917
SCIP_Real SCIPvarGetNegationConstant(SCIP_VAR *var)
Definition: var.c:16792
SCIP_RETCODE SCIPfixVarProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval)
Definition: scip.c:32025
SCIP_Real scaleval
Definition: cons_sos1.c:209
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:16723
SCIP_RETCODE SCIPstartProbing(SCIP *scip)
Definition: scip.c:31763
#define DEFAULT_BOUNDCUTSDEPTH
Definition: cons_sos1.c:146
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip.c:5580
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:89
SCIPInterval log(const SCIPInterval &x)
SCIP_RETCODE SCIPcreateConsSOS1(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *weights, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: cons_sos1.c:9517
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:16747
SCIP_RETCODE SCIPendProbing(SCIP *scip)
Definition: scip.c:31895
#define SCIP_EVENTTYPE_UBTIGHTENED
Definition: type_event.h:57
Constraint handler for linear constraints in their most general form, .
static SCIP_RETCODE initImplGraphSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, int nsos1vars, int maxrounds, int *nchgbds, SCIP_Bool *cutoff, SCIP_Bool *success)
Definition: cons_sos1.c:3620
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopySOS1)
Definition: cons_sos1.c:7935
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip.h:20400
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip.c:36389
static SCIP_RETCODE initTCliquegraph(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, int nsos1vars)
Definition: cons_sos1.c:5800
int SCIPgetDepth(SCIP *scip)
Definition: scip.c:37750
static SCIP_RETCODE addBoundCutSepa(SCIP *scip, TCLIQUE_DATA *tcliquedata, SCIP_ROW *rowlb, SCIP_ROW *rowub, SCIP_Bool *success, SCIP_Bool *cutoff)
Definition: cons_sos1.c:5929
#define CONSHDLR_SEPAFREQ
Definition: cons_sos1.c:91
int maxboundcuts
Definition: cons_sos1.c:213
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip.c:1270
static SCIP_RETCODE addBranchingComplementaritiesSOS1(SCIP *scip, SCIP_NODE *node, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, SCIP_DIGRAPH *localconflicts, int nsos1vars, SCIP_Bool *verticesarefixed, int *fixingsnode1, int nfixingsnode1, int *fixingsnode2, int nfixingsnode2, int *naddedconss, SCIP_Bool onlyviolsos1)
Definition: cons_sos1.c:4727
SCIP_RETCODE SCIPchgVarLbNode(SCIP *scip, SCIP_NODE *node, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip.c:19964
static SCIP_DECL_CONSCOPY(consCopySOS1)
Definition: cons_sos1.c:8894
SCIP_RETCODE SCIPaddCoefLinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
int SCIPgetNTotalVars(SCIP *scip)
Definition: scip.c:11312
#define SCIP_REAL_MAX
Definition: def.h:125
SCIP_RETCODE SCIPinferVarLbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:20535
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip.c:36278
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip.c:5534
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip.c:11514
#define SCIP_REAL_MIN
Definition: def.h:126
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
Definition: scip.c:5400
SCIP_RETCODE SCIPincludeConshdlrSOS1(SCIP *scip)
Definition: cons_sos1.c:9299
#define DEFAULT_BOUNDCUTSFROMGRAPH
Definition: cons_sos1.c:143
SCIP_DIGRAPH * SCIPgetConflictgraphSOS1(SCIP_CONSHDLR *conshdlr)
Definition: cons_sos1.c:9799
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
Definition: scip.c:41378
#define DEFAULT_ADDEXTENDEDBDS
Definition: cons_sos1.c:133
#define SCIPfreeMemory(scip, ptr)
Definition: scip.h:20371
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:16955
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip.c:5741
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip.c:27821
static const SCIP_Real scalars[]
Definition: lp.c:5506
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip.c:1253
static SCIP_DECL_CONSPARSE(consParseSOS1)
Definition: cons_sos1.c:8960
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)
static SCIP_RETCODE checkSwitchNonoverlappingSOS1Methods(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, SCIP_CONS **conss, int nconss)
Definition: cons_sos1.c:7584
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip.h:20422
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip.c:5424
const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
Definition: event.c:278
static SCIP_RETCODE getBranchingDecisionStrongbranchSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, int nsos1vars, SCIP_Real lpobjval, SCIP_Bool bipbranch, int nstrongrounds, SCIP_Bool *verticesarefixed, int *fixingsnode1, int *fixingsnode2, int *vertexbestprior, SCIP_Real *bestobjval1, SCIP_Real *bestobjval2, SCIP_RESULT *result)
Definition: cons_sos1.c:4287
SCIP_RETCODE SCIPchgVarUbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip.c:31962
static SCIP_RETCODE branchCons(SCIP *scip, SCIP_CONS *cons, SCIP_RESULT *result)
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip.c:19519
SCIP_RETCODE SCIPchgVarUbNode(SCIP *scip, SCIP_NODE *node, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip.c:19997
struct SCIP_SuccData SCIP_SUCCDATA
Definition: cons_sos1.c:199
static SCIP_RETCODE lockVariableSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition: cons_sos1.c:716
static SCIP_RETCODE sepaImplBoundCutsSOS1(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_SOL *sol, int maxcuts, int *ngen, SCIP_Bool *cutoff)
Definition: cons_sos1.c:6625
#define SCIP_Real
Definition: def.h:124
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:7803
#define DEFAULT_MAXIMPLCUTSROOT
Definition: cons_sos1.c:153
#define DEFAULT_BOUNDCUTSFREQ
Definition: cons_sos1.c:145
SCIP_RETCODE SCIPchgVarLbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip.c:31928
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip.c:20365
#define MIN(x, y)
Definition: memory.c:63
int SCIPgetNSOS1Vars(SCIP_CONSHDLR *conshdlr)
Definition: cons_sos1.c:9821
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip.c:27587
constraint handler for SOS type 1 constraints
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip.c:28321
#define DEFAULT_FIXNONZERO
Definition: cons_sos1.c:123
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip.h:20397
SCIP_Bool SCIPvarMayRoundUp(SCIP_VAR *var)
Definition: var.c:3267
#define SCIP_INVALID
Definition: def.h:144
SCIP_Real SCIPfeastol(SCIP *scip)
Definition: scip.c:40720
#define SCIP_DIVETYPE_SOS1VARIABLE
Definition: type_heur.h:46
static SCIP_RETCODE getCoverVertices(SCIP_DIGRAPH *conflictgraph, SCIP_Bool *verticesarefixed, int vertex, int *neightocover, int nneightocover, int *coververtices, int *ncoververtices)
Definition: cons_sos1.c:3839
SCIP_Real SCIPgetLhsLinear(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip.c:27725
void SCIPsortInt(int *intarray, int len)
static SCIP_RETCODE freeConflictgraph(SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons_sos1.c:7897
static SCIP_DECL_CONSPRESOL(consPresolSOS1)
Definition: cons_sos1.c:8240
#define SCIP_Longint
Definition: def.h:109
void SCIPsortRealPtr(SCIP_Real *realarray, void **ptrarray, int len)
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:917
static SCIP_RETCODE presolRoundVarsSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, SCIP_Bool **adjacencymatrix, int nsos1vars, int *nchgbds, int *naddconss, SCIP_RESULT *result)
Definition: cons_sos1.c:3246
static SCIP_RETCODE checkLinearConssVarboundSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **linconss, int nlinconss)
Definition: cons_sos1.c:7511
SCIP_RETCODE SCIPaddVarLocks(SCIP *scip, SCIP_VAR *var, int nlocksdown, int nlocksup)
Definition: scip.c:19465
static SCIP_RETCODE handleNewVariableSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_VAR *var, SCIP_Bool transformed)
Definition: cons_sos1.c:782
static SCIP_RETCODE consdataEnsurevarsSizeSOS1(SCIP *scip, SCIP_CONSDATA *consdata, int num, SCIP_Bool reserveWeights)
Definition: cons_sos1.c:754
static SCIP_RETCODE unlockVariableSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition: cons_sos1.c:735
static SCIP_Bool varIsSOS1(SCIP_CONSHDLRDATA *conshdlrdata, SCIP_VAR *var)
Definition: cons_sos1.c:506
static SCIP_DECL_CONSCHECK(consCheckSOS1)
Definition: cons_sos1.c:8531
static SCIP_RETCODE presolRoundConssSOS1(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, SCIP_Bool **adjacencymatrix, SCIP_CONS **conss, int nconss, int nsos1vars, int *naddconss, int *ndelconss, int *nupgdconss, int *nfixedvars, int *nremovedvars, SCIP_RESULT *result)
Definition: cons_sos1.c:1774
TCLIQUE_Bool tcliqueFlush(TCLIQUE_GRAPH *tcliquegraph)
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:49
#define DEFAULT_STRTHENBOUNDCUTS
Definition: cons_sos1.c:149
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:16628
static SCIP_RETCODE markNeighborsMWISHeuristic(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DIGRAPH *conflictgraph, int node, SCIP_Bool *mark, SCIP_Bool *indset, int *cnt, SCIP_Bool *cutoff)
Definition: cons_sos1.c:7034
SCIP_RETCODE SCIPcreateChild(SCIP *scip, SCIP_NODE **node, SCIP_Real nodeselprio, SCIP_Real estimate)
Definition: scip.c:33311
SCIP_VAR ** SCIPgetVarsLinear(SCIP *scip, SCIP_CONS *cons)
#define DEFAULT_BIPBRANCH
Definition: cons_sos1.c:120
SCIP_RETCODE SCIPaddConflictUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
Definition: scip.c:24423
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip.c:40996
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:2089
#define CONSHDLR_PRESOLTIMING
Definition: cons_sos1.c:101
void SCIPswapInts(int *value1, int *value2)
Definition: misc.c:7824
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
Definition: scip.c:41305
int TCLIQUE_WEIGHT
Definition: tclique.h:37
SCIP_Real SCIPeventGetNewbound(SCIP_EVENT *event)
Definition: event.c:1120
SCIP_RETCODE SCIPaddVarSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real weight)
Definition: cons_sos1.c:9654
SCIP_Real SCIPcalcChildEstimate(SCIP *scip, SCIP_VAR *var, SCIP_Real targetvalue)
Definition: scip.c:33288
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip.c:3598
static SCIP_DECL_CONSGETDIVEBDCHGS(consGetDiveBdChgsSOS1)
Definition: cons_sos1.c:9165
void SCIPdigraphFree(SCIP_DIGRAPH **digraph)
Definition: misc.c:5737
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip.c:5810
SCIP_Real SCIPsumepsilon(SCIP *scip)
Definition: scip.c:40706
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip.c:27851
#define SCIPABORT()
Definition: def.h:235
static TCLIQUE_NEWSOL(tcliqueNewsolClique)
Definition: cons_sos1.c:6261
#define DEFAULT_ADDCOMPS
Definition: cons_sos1.c:126
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:7793
static SCIP_RETCODE generateBoundInequalityFromSOS1Nodes(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DIGRAPH *conflictgraph, int *nodes, int nnodes, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool global, SCIP_Bool strengthen, SCIP_Bool removable, const char *nameext, SCIP_ROW **rowlb, SCIP_ROW **rowub)
Definition: cons_sos1.c:6003
#define DEFAULT_MAXEXTENSIONS
Definition: cons_sos1.c:109
int nboundcuts
Definition: cons_sos1.c:212
static SCIP_DECL_CONSTRANS(consTransSOS1)
Definition: cons_sos1.c:8148
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:7823
static int varGetNodeSOS1(SCIP_CONSHDLRDATA *conshdlrdata, SCIP_VAR *var)
Definition: cons_sos1.c:523
SCIP_Real * SCIPgetValsLinear(SCIP *scip, SCIP_CONS *cons)
SCIP_SOL * sol
Definition: cons_sos1.c:208
SCIP_DIGRAPH * conflictgraph
Definition: cons_sos1.c:207
static SCIP_RETCODE computeVarsCoverSOS1(SCIP *scip, SCIP_DIGRAPH *conflictgraphroot, SCIP_DIGRAPH *conflictgraphlin, SCIP_VAR **linvars, SCIP_Bool *coveredvars, int *clique, int *cliquesize, int v, SCIP_Bool considersolvals)
Definition: cons_sos1.c:2435
SCIP_Longint SCIPgetNNodeInitLPs(SCIP *scip)
Definition: scip.c:37377
static SCIP_Bool isConnectedSOS1(SCIP_Bool **adjacencymatrix, SCIP_DIGRAPH *conflictgraph, int vertex1, int vertex2)
Definition: cons_sos1.c:297
SCIP_Longint SCIPgetNNodes(SCIP *scip)
Definition: scip.c:36982
static SCIP_Bool isViolatedSOS1(SCIP *scip, SCIP_DIGRAPH *conflictgraph, int node, SCIP_SOL *sol)
Definition: cons_sos1.c:357
int SCIPvarGetNodeSOS1(SCIP_CONSHDLR *conshdlr, SCIP_VAR *var)
Definition: cons_sos1.c:9867