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