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