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