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