Scippy

SCIP

Solving Constraint Integer Programs

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