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