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