Scippy

SCIP

Solving Constraint Integer Programs

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