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