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
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"
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
135
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) */
145
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 */
150
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 */
165
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 */
184
185/* event handler properties */
186#define EVENTHDLR_NAME "SOS1"
187#define EVENTHDLR_DESC "bound change event handler for SOS1 constraints"
188
189#define EVENTHDLR_EVENT_TYPE (SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_GBDCHANGED)
190
191/* defines */
192#define DIVINGCUTOFFVALUE 1e6
193
194
195/** constraint data for SOS1 constraints */
196struct 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 */
210struct 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};
222typedef struct SCIP_NodeData SCIP_NODEDATA;
223
224
225/** successor data of a given nodes successor in the implication graph */
226struct SCIP_SuccData
227{
228 SCIP_Real lbimpl; /**< lower bound implication */
229 SCIP_Real ubimpl; /**< upper bound implication */
230};
231typedef struct SCIP_SuccData SCIP_SUCCDATA;
232
233
234/** tclique data for bound cut generation */
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};
248
249
250/** SOS1 constraint handler data */
251struct 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 */
328static
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 */
388static
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 */
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);
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 */
433static
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 {
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 {
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 */
483static
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{
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 */
510static
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{
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 */
537static
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 */
554static
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 */
575static
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
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 {
612 SCIP_CALL( SCIPchgVarLbNode(scip, node, var, 0.0) );
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 */
630static
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 */
704static
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 */
747static
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 */
761
762 return SCIP_OKAY;
763}
764
765
766/** remove lock on variable */
767static
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 */
781
782 return SCIP_OKAY;
783}
784
785
786/** ensures that the vars and weights array can store at least num entries */
787static
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 */
815static
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 */
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 */
950static
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 */
1020static
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 )
1027{
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 */
1078static
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 */
1117static
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 */
1378static
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 */
1431static
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 */
1532static
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 */
1598static
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 */
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 */
1824static
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 */
2096static
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' */
2254static
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 */
2283static
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 );
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 */
2409static
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 */
2571static
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 */
2682static
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 */
3363static
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 */
3537static
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");
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 {
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 {
3620 }
3621
3622 /* delete constraint locally */
3623 if ( allVarFixed )
3624 {
3625 assert( !SCIPconsIsModifiable(cons) );
3627 }
3628 }
3629
3630 return SCIP_OKAY;
3631}
3632
3633
3634/** propagate a variable that is known to be nonzero */
3635static
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 */
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;
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 */
3778static
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 {
3869
3870 /* create node data */
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 */
3949static
3951 SCIP* scip, /**< SCIP pointer */
3952 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
3953 )
3954{
3955 int j;
3956
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 {
3988 nodedata = (SCIP_NODEDATA*)SCIPdigraphGetNodeData(conshdlrdata->implgraph, j);
3989 assert( nodedata != NULL );
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 */
4008static
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 */
4115static
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 */
4228static
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 */
4332static
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 */
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 {
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 {
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 {
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 */
4468
4469 return SCIP_OKAY;
4470}
4471
4472
4473/** apply strong branching to determine the vertex for the next branching decision */
4474static
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);
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 {
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 */
4691static
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{
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 */
4919static
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
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 */
5283static
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 */
5339static
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
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
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");
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;
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;
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 */
5811static
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");
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
5966 SCIP_CALL( fixVariableZeroNode(scip, vars[0], node1, &infeasible) );
5967 assert( ! infeasible );
5968
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;
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;
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 }
6050 *result = SCIP_BRANCHED;
6051
6052 return SCIP_OKAY;
6053}
6054
6055
6056/** constraint enforcing method of constraint handler */
6057static
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");
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");
6088 }
6089
6090 if ( conshdlrdata->branchingrule == 's' && conshdlrdata->nstrongrounds != 0 )
6091 {
6092 SCIPerrorMessage("Strong branching is not available for SOS1 branching.\n");
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);
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 */
6120static
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 */
6189static
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;
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
6219 }
6220 else if ( SCIPisFeasNegative(scip, solval) )
6221 {
6222 if ( conshdlrdata->strthenboundcuts )
6223 bound = REALABS( nodeGetSolvalVarboundLbSOS1(scip, conflictgraph, sol, j) );
6224 else
6226 }
6227 else
6228 bound = 0.0;
6229
6230 solval = REALABS( solval );
6231
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 */
6249static
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 */
6323static
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 */
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 {
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 {
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 */
6613static
6614TCLIQUE_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;
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
6661 }
6662 else if ( SCIPisFeasNegative(scip, solval) )
6663 {
6664 if ( tcliquedata->strthenboundcuts )
6665 bound = REALABS( nodeGetSolvalVarboundLbSOS1(scip, tcliquedata->conflictgraph, sol, node) );
6666 else
6668 }
6669 else
6670 bound = 0.0;
6671
6672 solval = REALABS( solval );
6673
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 */
6748static
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) */
6822static
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 */
6885static
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 {
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 */
6999static
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;
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);
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 */
7176 SCIP_CALL( SCIPaddVarToRow(scip, cut, var, bound2-impl) );
7177 SCIP_CALL( SCIPaddVarToRow(scip, cut, succvar, bound1) );
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 }
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 */
7224static
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 */
7345static
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 */
7416static
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 */
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 {
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 */
7557static
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);
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 */
7663static
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 */
7793static
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 */
7928static
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;
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 */
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 */
8069static
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))
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;
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 */
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 */
8250static
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 {
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 {
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 */
8326static
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 {
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 */
8399static
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 )
8406{
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 {
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 */
8488static
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 )
8495{
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 */
8561static
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 */
8642static
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 */
8679static
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 )
8686{
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 */
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 */
8795 {
8796 int indi;
8797
8798 indi = SCIPvarGetIndex(var);
8799
8800 if ( ! nodecreated[indi] )
8801 {
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 */
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 */
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 */
8874static
8876 SCIP* scip, /**< SCIP pointer */
8877 SCIP_CONSHDLRDATA* conshdlrdata /**< constraint handler data */
8878 )
8879{
8880 int j;
8881
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 {
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 */
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) */
8920static
8921SCIP_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) */
8937static
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) */
8959static
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) */
9012static
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 */
9084static
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 */
9138static
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 */
9232static
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) */
9351static
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 */
9376static
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 */
9392static
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 */
9408static
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 */
9424static
9425SCIP_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 */
9440static
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 */
9459static
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 */
9531static
9533{ /*lint --e{715}*/
9534 SCIP_CONSHDLRDATA* conshdlrdata;
9535 SCIP_DIGRAPH* conflictgraph;
9536 SCIP_DIGRAPH* implgraph;
9537 int ngen = 0;
9538
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). */
9677static
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 */
9753static
9755{
9756 SCIP_CONSDATA* consdata;
9757 SCIP_VAR** vars;
9758 int nvars;
9759 int j;
9760
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 */
9783 {
9784 SCIP_CALL( SCIPaddVarLocksType(scip, var, locktype, nlockspos, nlocksneg) );
9785 }
9786
9787 /* additionally: if upper bound is positive, rounding up may violate constraint */
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 */
9799static
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 */
9829static
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 */
9893static
9895{ /*lint --e{715}*/
9896 SCIP_VAR* var;
9897 SCIP_Real weight;
9898 const char* s;
9899 char* t;
9900
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) */
9983static
9985{ /*lint --e{715}*/
9986 SCIP_CONSDATA* consdata;
9987
9988 consdata = SCIPconsGetData(cons);
9989 assert(consdata != NULL);
9990
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) */
10006static
10007SCIP_DECL_CONSGETNVARS(consGetNVarsSOS1)
10008{ /*lint --e{715}*/
10009 SCIP_CONSDATA* consdata;
10010
10011 consdata = SCIPconsGetData(cons);
10012 assert(consdata != NULL);
10013
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 */
10027static
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 */
10149static
10150SCIP_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 */
10189static
10190SCIP_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) */
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 */
10255static
10256SCIP_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 */
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;
10368
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) );
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 )
10722{
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 */
10784 SCIP* scip, /**< SCIP data structure */
10785 SCIP_CONS* cons /**< constraint */
10786 )
10787{
10788 SCIP_CONSDATA* consdata;
10789
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;
10814
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;
10839
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 */
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;
10911
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 */
10930 SCIP_CONSHDLR* conshdlr, /**< SOS1 constraint handler */
10931 SCIP_VAR* var /**< variable */
10932 )
10933{
10934 SCIP_CONSHDLRDATA* conshdlrdata;
10935
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{
10966
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");
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);
11040 roundobjval *= -1;
11041
11042 if ( SCIPisLT(scip, roundobjval, SCIPgetUpperbound(scip) ) )
11043 *success = TRUE;
11044
11045 return SCIP_OKAY;
11046}
static long bound
SCIP_VAR * w
Definition: circlepacking.c:67
struct SCIP_NodeData SCIP_NODEDATA
static SCIP_RETCODE branchCons(SCIP *scip, SCIP_CONS *cons, SCIP_RESULT *result)
Constraint handler for linear constraints in their most general form, .
Constraint handler for the set partitioning / packing / covering constraints .
#define DEFAULT_MAXSOSADJACENCY
Definition: cons_sos1.c:137
static SCIP_RETCODE lockVariableSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition: cons_sos1.c:748
#define DEFAULT_AUTOCUTSFROMSOS1
Definition: cons_sos1.c:174
#define DEFAULT_MAXADDCOMPS
Definition: cons_sos1.c:160
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopySOS1)
Definition: cons_sos1.c:8921
static SCIP_Bool isImpliedZero(SCIP_DIGRAPH *conflictgraph, SCIP_Bool *implnodes, int node)
Definition: cons_sos1.c:2255
#define CONSHDLR_NEEDSCONS
Definition: cons_sos1.c:132
#define CONSHDLR_SEPAFREQ
Definition: cons_sos1.c:125
static SCIP_RETCODE getDiveBdChgsSOS1constraints(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DIVESET *diveset, SCIP_SOL *sol, SCIP_Bool *success)
Definition: cons_sos1.c:8070
#define DEFAULT_BRANCHINGRULE
Definition: cons_sos1.c:153
static SCIP_RETCODE updateWeightsTCliquegraph(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, TCLIQUE_DATA *tcliquedata, SCIP_DIGRAPH *conflictgraph, SCIP_SOL *sol, int nsos1vars)
Definition: cons_sos1.c:6190
static SCIP_RETCODE initTCliquegraph(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, int nsos1vars)
Definition: cons_sos1.c:6121
#define DEFAULT_NSTRONGROUNDS
Definition: cons_sos1.c:167
static SCIP_RETCODE consdataEnsurevarsSizeSOS1(SCIP *scip, SCIP_CONSDATA *consdata, int num, SCIP_Bool reserveWeights)
Definition: cons_sos1.c:788
#define CONSHDLR_CHECKPRIORITY
Definition: cons_sos1.c:124
#define DEFAULT_MAXBOUNDCUTS
Definition: cons_sos1.c:177
#define DEFAULT_MAXBOUNDCUTSROOT
Definition: cons_sos1.c:178
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:4475
#define CONSHDLR_DESC
Definition: cons_sos1.c:121
static SCIP_RETCODE appendVarSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_VAR *var)
Definition: cons_sos1.c:1021
static SCIP_RETCODE computeNodeDataSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, int nsos1vars)
Definition: cons_sos1.c:8643
#define DIVINGCUTOFFVALUE
Definition: cons_sos1.c:192
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:7558
#define CONSHDLR_PROP_TIMING
Definition: cons_sos1.c:133
static SCIP_Bool varIsSOS1(SCIP_CONSHDLRDATA *conshdlrdata, SCIP_VAR *var)
Definition: cons_sos1.c:538
#define DEFAULT_AUTOSOS1BRANCH
Definition: cons_sos1.c:155
#define DEFAULT_ADDEXTENDEDBDS
Definition: cons_sos1.c:164
static SCIP_DECL_CONSENFOPS(consEnfopsSOS1)
Definition: cons_sos1.c:9441
static SCIP_DECL_CONSCHECK(consCheckSOS1)
Definition: cons_sos1.c:9460
#define DEFAULT_MAXTIGHTENBDS
Definition: cons_sos1.c:142
static SCIP_DECL_CONSSEPASOL(consSepasolSOS1)
Definition: cons_sos1.c:9393
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:2683
static SCIP_Real nodeGetSolvalVarboundUbSOS1(SCIP *scip, SCIP_DIGRAPH *conflictgraph, SCIP_SOL *sol, int node)
Definition: cons_sos1.c:511
static SCIP_DECL_CONSLOCK(consLockSOS1)
Definition: cons_sos1.c:9754
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:816
#define DEFAULT_BOUNDCUTSDEPTH
Definition: cons_sos1.c:176
#define DEFAULT_DEPTHIMPLANALYSIS
Definition: cons_sos1.c:144
#define CONSHDLR_MAXPREROUNDS
Definition: cons_sos1.c:129
static SCIP_RETCODE getVectorOfWeights(SCIP *scip, SCIP_SOL *sol, SCIP_DIGRAPH *conflictgraph, int nsos1vars, SCIP_Bool *indicatorzero, SCIP_Real *weights)
Definition: cons_sos1.c:7346
static SCIP_RETCODE getCoverVertices(SCIP_DIGRAPH *conflictgraph, SCIP_Bool *verticesarefixed, int vertex, int *neightocover, int nneightocover, int *coververtices, int *ncoververtices)
Definition: cons_sos1.c:4009
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:4692
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:2410
static SCIP_DECL_CONSENFOLP(consEnfolpSOS1)
Definition: cons_sos1.c:9409
#define DEFAULT_IMPLPROP
Definition: cons_sos1.c:148
static SCIP_RETCODE checkSwitchNonoverlappingSOS1Methods(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraph, SCIP_CONS **conss, int nconss)
Definition: cons_sos1.c:8562
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:5340
static SCIP_RETCODE makeSOS1conflictgraphFeasible(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_SOL *sol, SCIP_Bool *changed, SCIP_Bool *allroundable)
Definition: cons_sos1.c:7664
static SCIP_RETCODE getDiveBdChgsSOS1conflictgraph(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DIVESET *diveset, SCIP_SOL *sol, SCIP_Bool *success)
Definition: cons_sos1.c:7929
#define CONSHDLR_SEPAPRIORITY
Definition: cons_sos1.c:122
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:7000
static int varGetNodeSOS1(SCIP_CONSHDLRDATA *conshdlrdata, SCIP_VAR *var)
Definition: cons_sos1.c:555
#define DEFAULT_STRTHENBOUNDCUTS
Definition: cons_sos1.c:179
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:8327
#define DEFAULT_BRANCHSTRATEGIES
Definition: cons_sos1.c:152
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:8251
static SCIP_Bool isViolatedSOS1(SCIP *scip, SCIP_DIGRAPH *conflictgraph, int node, SCIP_SOL *sol)
Definition: cons_sos1.c:389
#define DEFAULT_SOSCONSPROP
Definition: cons_sos1.c:149
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:3636
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:1599
static SCIP_RETCODE checkLinearConssVarboundSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **linconss, int nlinconss)
Definition: cons_sos1.c:8489
static SCIP_DECL_CONSPROP(consPropSOS1)
Definition: cons_sos1.c:9532
#define DEFAULT_MAXEXTENSIONS
Definition: cons_sos1.c:141
#define DEFAULT_FIXNONZERO
Definition: cons_sos1.c:156
static SCIP_RETCODE fixVariableZeroNode(SCIP *scip, SCIP_VAR *var, SCIP_NODE *node, SCIP_Bool *infeasible)
Definition: cons_sos1.c:576
static SCIP_RETCODE makeSOS1constraintsFeasible(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_SOL *sol, SCIP_Bool *changed, SCIP_Bool *allroundable)
Definition: cons_sos1.c:7794
static SCIP_RETCODE freeConflictgraph(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons_sos1.c:8875
static SCIP_DECL_CONSEXITSOL(consExitsolSOS1)
Definition: cons_sos1.c:9013
static SCIP_DECL_CONSTRANS(consTransSOS1)
Definition: cons_sos1.c:9139
static SCIP_DECL_CONSENFORELAX(consEnforelaxSOS1)
Definition: cons_sos1.c:9425
#define DEFAULT_ADDCOMPSFEAS
Definition: cons_sos1.c:162
#define DEFAULT_ADDCOMPS
Definition: cons_sos1.c:158
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:2284
static SCIP_DECL_CONSFREE(consFreeSOS1)
Definition: cons_sos1.c:8938
static SCIP_DECL_CONSCOPY(consCopySOS1)
Definition: cons_sos1.c:9830
#define DEFAULT_MAXIMPLCUTS
Definition: cons_sos1.c:182
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:705
static SCIP_DECL_EVENTEXEC(eventExecSOS1)
Definition: cons_sos1.c:10028
#define DEFAULT_BOUNDCUTSFROMSOS1
Definition: cons_sos1.c:172
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:4116
static SCIP_DECL_CONSINITSOL(consInitsolSOS1)
Definition: cons_sos1.c:8960
static SCIP_DECL_CONSPRESOL(consPresolSOS1)
Definition: cons_sos1.c:9233
#define DEFAULT_ADDCOMPSDEPTH
Definition: cons_sos1.c:161
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:4229
static SCIP_RETCODE genConflictgraphLinearCons(SCIP_CONSHDLRDATA *conshdlrdata, SCIP_DIGRAPH *conflictgraphlin, SCIP_DIGRAPH *conflictgraphorig, SCIP_VAR **linvars, int nlinvars, int *posinlinvars)
Definition: cons_sos1.c:1379
static SCIP_DECL_CONSGETVARS(consGetVarsSOS1)
Definition: cons_sos1.c:9984
static SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphSOS1)
Definition: cons_sos1.c:10190
static SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphSOS1)
Definition: cons_sos1.c:10256
static SCIP_RETCODE fixVariableZero(SCIP *scip, SCIP_VAR *var, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: cons_sos1.c:631
static SCIP_DECL_CONSGETDIVEBDCHGS(consGetDiveBdChgsSOS1)
Definition: cons_sos1.c:10150
static SCIP_Real nodeGetSolvalBinaryBigMSOS1(SCIP *scip, SCIP_DIGRAPH *conflictgraph, SCIP_SOL *sol, int node)
Definition: cons_sos1.c:434
static SCIP_RETCODE initConflictgraph(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_CONS **conss, int nconss)
Definition: cons_sos1.c:8680
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:6886
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:6324
#define DEFAULT_NSTRONGITER
Definition: cons_sos1.c:169
static SCIP_RETCODE enforceSOS1(SCIP *scip, SCIP_CONSHDLR *conshdlr, int nconss, SCIP_CONS **conss, SCIP_SOL *sol, SCIP_RESULT *result)
Definition: cons_sos1.c:6058
#define DEFAULT_BOUNDCUTSFREQ
Definition: cons_sos1.c:175
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:2572
static SCIP_RETCODE enforceConssSOS1(SCIP *scip, SCIP_CONSHDLR *conshdlr, int nconss, SCIP_CONS **conss, SCIP_SOL *sol, SCIP_RESULT *result)
Definition: cons_sos1.c:5812
static SCIP_DECL_CONSPRINT(consPrintSOS1)
Definition: cons_sos1.c:9800
static SCIP_RETCODE checkConComponentsVarbound(SCIP *scip, SCIP_DIGRAPH *conflictgraph, int nsos1vars, SCIP_Bool checklb)
Definition: cons_sos1.c:8400
static SCIP_RETCODE unlockVariableSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition: cons_sos1.c:768
static SCIP_Bool isConnectedSOS1(SCIP_Bool **adjacencymatrix, SCIP_DIGRAPH *conflictgraph, int vertex1, int vertex2)
Definition: cons_sos1.c:329
#define DEFAULT_BOUNDCUTSFROMGRAPH
Definition: cons_sos1.c:173
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:4920
#define CONSHDLR_PROPFREQ
Definition: cons_sos1.c:126
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:4333
#define DEFAULT_ADDBDSFEAS
Definition: cons_sos1.c:163
static SCIP_DECL_CONSRESPROP(consRespropSOS1)
Definition: cons_sos1.c:9678
static SCIP_DECL_CONSSEPALP(consSepalpSOS1)
Definition: cons_sos1.c:9377
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:6823
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:1533
static SCIP_RETCODE addVarSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_VAR *var, SCIP_Real weight)
Definition: cons_sos1.c:951
static SCIP_RETCODE freeImplGraphSOS1(SCIP *scip, SCIP_CONSHDLRDATA *conshdlrdata)
Definition: cons_sos1.c:3950
#define CONSHDLR_PRESOLTIMING
Definition: cons_sos1.c:134
#define DEFAULT_IMPLCUTSDEPTH
Definition: cons_sos1.c:181
#define DEFAULT_CONFLICTPROP
Definition: cons_sos1.c:147
#define DEFAULT_MAXIMPLCUTSROOT
Definition: cons_sos1.c:183
#define DEFAULT_IMPLCUTSFREQ
Definition: cons_sos1.c:180
struct SCIP_SuccData SCIP_SUCCDATA
Definition: cons_sos1.c:231
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:1825
static SCIP_RETCODE resetConflictgraphSOS1(SCIP_DIGRAPH *conflictgraph, SCIP_DIGRAPH *localconflicts, int nsos1vars)
Definition: cons_sos1.c:5284
#define CONSHDLR_EAGERFREQ
Definition: cons_sos1.c:127
#define EVENTHDLR_DESC
Definition: cons_sos1.c:187
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:3779
#define EVENTHDLR_EVENT_TYPE
Definition: cons_sos1.c:189
static SCIP_DECL_CONSPARSE(consParseSOS1)
Definition: cons_sos1.c:9894
#define CONSHDLR_ENFOPRIORITY
Definition: cons_sos1.c:123
static SCIP_DECL_CONSDELETE(consDeleteSOS1)
Definition: cons_sos1.c:9085
#define DEFAULT_PERFIMPLANALYSIS
Definition: cons_sos1.c:143
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:7417
#define CONSHDLR_DELAYSEPA
Definition: cons_sos1.c:130
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:3364
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:6749
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:6250
static TCLIQUE_NEWSOL(tcliqueNewsolClique)
Definition: cons_sos1.c:6614
static SCIP_RETCODE propConsSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_Bool *cutoff, int *ngen)
Definition: cons_sos1.c:3538
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:1118
#define CONSHDLR_NAME
Definition: cons_sos1.c:120
#define EVENTHDLR_NAME
Definition: cons_sos1.c:186
static SCIP_DECL_CONSGETNVARS(consGetNVarsSOS1)
Definition: cons_sos1.c:10007
static SCIP_RETCODE deleteVarSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr, int pos)
Definition: cons_sos1.c:1079
static SCIP_DECL_CONSINITLP(consInitlpSOS1)
Definition: cons_sos1.c:9352
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:2097
#define CONSHDLR_DELAYPROP
Definition: cons_sos1.c:131
static SCIP_Real nodeGetSolvalVarboundLbSOS1(SCIP *scip, SCIP_DIGRAPH *conflictgraph, SCIP_SOL *sol, int node)
Definition: cons_sos1.c:484
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:1432
static SCIP_RETCODE separateSOS1(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_SOL *sol, int nconss, SCIP_CONS **conss, SCIP_RESULT *result)
Definition: cons_sos1.c:7225
constraint handler for SOS type 1 constraints
#define NULL
Definition: def.h:267
#define SCIP_MAXSTRLEN
Definition: def.h:288
#define SCIP_Longint
Definition: def.h:158
#define SCIP_MAXTREEDEPTH
Definition: def.h:316
#define SCIP_REAL_MAX
Definition: def.h:174
#define SCIP_INVALID
Definition: def.h:193
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:243
#define SCIP_Real
Definition: def.h:173
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:239
#define SCIP_LONGINT_FORMAT
Definition: def.h:165
#define SCIPABORT()
Definition: def.h:346
#define SCIP_REAL_MIN
Definition: def.h:175
#define REALABS(x)
Definition: def.h:197
#define SCIP_CALL(x)
Definition: def.h:374
#define nnodes
Definition: gastrans.c:74
static const NodeData nodedata[]
Definition: gastrans.c:83
void SCIPcomputeArraysSetminusInt(int *array1, int narray1, int *array2, int narray2, int *setminusarray, int *nsetminusarray)
Definition: misc.c:10689
void SCIPcomputeArraysIntersectionInt(int *array1, int narray1, int *array2, int narray2, int *intersectarray, int *nintersectarray)
Definition: misc.c:10559
SCIP_Real SCIPgetRhsLinear(SCIP *scip, SCIP_CONS *cons)
SCIP_DIGRAPH * SCIPgetConflictgraphSOS1(SCIP_CONSHDLR *conshdlr)
Definition: cons_sos1.c:10861
SCIP_VAR ** SCIPgetVarsLinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPvarIsSOS1(SCIP_CONSHDLR *conshdlr, SCIP_VAR *var)
Definition: cons_sos1.c:10905
SCIP_RETCODE SCIPaddCoefLinear(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real val)
SCIP_RETCODE SCIPmakeSOS1sFeasible(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_SOL *sol, SCIP_Bool *changed, SCIP_Bool *success)
Definition: cons_sos1.c:10985
SCIP_Real SCIPgetLhsLinear(SCIP *scip, SCIP_CONS *cons)
int SCIPgetNVarsLinear(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPaddVarSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real weight)
Definition: cons_sos1.c:10716
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:10579
SCIP_RETCODE SCIPcreateConsBasicSOS1(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *weights)
Definition: cons_sos1.c:10700
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:9409
SCIP_Real * SCIPgetWeightsSOS1(SCIP *scip, SCIP_CONS *cons)
Definition: cons_sos1.c:10833
SCIP_RETCODE SCIPappendVarSOS1(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition: cons_sos1.c:10750
int SCIPgetNSOS1Vars(SCIP_CONSHDLR *conshdlr)
Definition: cons_sos1.c:10883
int SCIPvarGetNodeSOS1(SCIP_CONSHDLR *conshdlr, SCIP_VAR *var)
Definition: cons_sos1.c:10929
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)
SCIP_VAR ** SCIPgetVarsSOS1(SCIP *scip, SCIP_CONS *cons)
Definition: cons_sos1.c:10808
int SCIPgetNVarsSOS1(SCIP *scip, SCIP_CONS *cons)
Definition: cons_sos1.c:10783
SCIP_VAR * SCIPnodeGetVarSOS1(SCIP_DIGRAPH *conflictgraph, int node)
Definition: cons_sos1.c:10960
SCIP_RETCODE SCIPincludeConshdlrSOS1(SCIP *scip)
Definition: cons_sos1.c:10362
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
void ** SCIPdigraphGetSuccessorsData(SCIP_DIGRAPH *digraph, int node)
Definition: misc.c:7837
int SCIPdigraphGetNSuccessors(SCIP_DIGRAPH *digraph, int node)
Definition: misc.c:7804
int SCIPdigraphGetNNodes(SCIP_DIGRAPH *digraph)
Definition: misc.c:7746
SCIP_RETCODE SCIPdigraphAddArc(SCIP_DIGRAPH *digraph, int startnode, int endnode, void *data)
Definition: misc.c:7662
SCIP_RETCODE SCIPdigraphAddArcSafe(SCIP_DIGRAPH *digraph, int startnode, int endnode, void *data)
Definition: misc.c:7693
void SCIPdigraphFree(SCIP_DIGRAPH **digraph)
Definition: misc.c:7568
int SCIPdigraphGetNArcs(SCIP_DIGRAPH *digraph)
Definition: misc.c:7786
void * SCIPdigraphGetNodeData(SCIP_DIGRAPH *digraph, int node)
Definition: misc.c:7756
void SCIPdigraphSetNodeData(SCIP_DIGRAPH *digraph, void *dataptr, int node)
Definition: misc.c:7772
SCIP_RETCODE SCIPdigraphSetNSuccessors(SCIP_DIGRAPH *digraph, int node, int nsuccessors)
Definition: misc.c:7730
int * SCIPdigraphGetSuccessors(SCIP_DIGRAPH *digraph, int node)
Definition: misc.c:7819
SCIP_RETCODE SCIPcreateDigraph(SCIP *scip, SCIP_DIGRAPH **digraph, int nnodes)
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip_general.c:596
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:724
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:380
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1992
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2770
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2843
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1947
SCIP_OBJSENSE SCIPgetObjsense(SCIP *scip)
Definition: scip_prob.c:1225
int SCIPgetNTotalVars(SCIP *scip)
Definition: scip_prob.c:2569
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3108
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3281
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3074
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3423
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3192
SCIP_RETCODE SCIPupdateNodeLowerbound(SCIP *scip, SCIP_NODE *node, SCIP_Real newbound)
Definition: scip_prob.c:3757
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3474
SCIP_RETCODE SCIPaddConsNode(SCIP *scip, SCIP_NODE *node, SCIP_CONS *cons, SCIP_NODE *validnode)
Definition: scip_prob.c:3323
SCIP_Real SCIPgetLocalTransEstimate(SCIP *scip)
Definition: scip_prob.c:3546
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:208
#define SCIPdebugMsg
Definition: scip_message.h:78
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
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_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_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
void SCIPswapInts(int *value1, int *value2)
Definition: misc.c:10370
void SCIPswapReals(SCIP_Real *value1, SCIP_Real *value2)
Definition: misc.c:10383
SCIP_Real SCIPcalcNodeselPriority(SCIP *scip, SCIP_VAR *var, SCIP_BRANCHDIR branchdir, SCIP_Real targetvalue)
Definition: scip_branch.c:920
SCIP_Real SCIPcalcChildEstimate(SCIP *scip, SCIP_VAR *var, SCIP_Real targetvalue)
Definition: scip_branch.c:947
SCIP_Real SCIPcalcChildEstimateIncrease(SCIP *scip, SCIP_VAR *var, SCIP_Real varsol, SCIP_Real targetvalue)
Definition: scip_branch.c:971
SCIP_RETCODE SCIPcreateChild(SCIP *scip, SCIP_NODE **node, SCIP_Real nodeselprio, SCIP_Real estimate)
Definition: scip_branch.c:1017
SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
SCIP_RETCODE SCIPaddConflictUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip_cons.c:808
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:540
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:831
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 SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip_cons.c:281
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
SCIP_RETCODE SCIPsetConshdlrGetPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETPERMSYMGRAPH((*consgetpermsymgraph)))
Definition: scip_cons.c:900
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:578
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:372
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip_cons.c:323
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4636
SCIP_RETCODE SCIPsetConshdlrGetDiveBdChgs(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETDIVEBDCHGS((*consgetdivebdchgs)))
Definition: scip_cons.c:877
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4197
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:347
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:941
SCIP_RETCODE SCIPsetConshdlrGetSignedPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH((*consgetsignedpermsymgraph)))
Definition: scip_cons.c:924
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITSOL((*consexitsol)))
Definition: scip_cons.c:468
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip_cons.c:624
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
Definition: scip_cons.c:444
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4217
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:601
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip_cons.c:647
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:854
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4593
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip_cons.c:785
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8244
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8473
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8234
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8383
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2537
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8413
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8523
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8403
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_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8433
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8453
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8214
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition: scip_cons.c:1813
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8463
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8493
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1174
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8393
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8483
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition: scip_cut.c:117
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip_cut.c:135
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:250
SCIP_Bool SCIPdivesetSupportsType(SCIP_DIVESET *diveset, SCIP_DIVETYPE divetype)
Definition: heur.c:753
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
const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
Definition: event.c:324
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:1030
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_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:400
SCIP_Real SCIPeventGetOldbound(SCIP_EVENT *event)
Definition: event.c:1218
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:1053
SCIP_Real SCIPeventGetNewbound(SCIP_EVENT *event)
Definition: event.c:1242
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:168
SCIP_Real SCIPgetLPObjval(SCIP *scip)
Definition: scip_lp.c:247
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:139
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:128
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip_mem.h:132
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:99
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:111
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:137
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:105
SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
Definition: tree.c:7493
SCIP_RETCODE SCIPgetDivesetScore(SCIP *scip, SCIP_DIVESET *diveset, SCIP_DIVETYPE divetype, SCIP_VAR *divecand, SCIP_Real divecandsol, SCIP_Real divecandfrac, SCIP_Real *candscore, SCIP_Bool *roundup)
SCIP_RETCODE SCIPchgVarUbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_probing.c:345
SCIP_RETCODE SCIPchgVarLbProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_probing.c:301
SCIP_RETCODE SCIPpropagateProbing(SCIP *scip, int maxproprounds, SCIP_Bool *cutoff, SCIP_Longint *ndomredsfound)
Definition: scip_probing.c:580
SCIP_RETCODE SCIPstartProbing(SCIP *scip)
Definition: scip_probing.c:119
SCIP_RETCODE SCIPaddDiveBoundChange(SCIP *scip, SCIP_VAR *var, SCIP_BRANCHDIR dir, SCIP_Real value, SCIP_Bool preferred)
SCIP_RETCODE SCIPsolveProbingLP(SCIP *scip, int itlim, SCIP_Bool *lperror, SCIP_Bool *cutoff)
Definition: scip_probing.c:820
SCIP_RETCODE SCIPfixVarProbing(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval)
Definition: scip_probing.c:418
SCIP_RETCODE SCIPendProbing(SCIP *scip)
Definition: scip_probing.c:260
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1635
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1658
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_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1701
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2212
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1562
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition: lp.c:17523
SCIP_RETCODE SCIPaddVarsToRow(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip_lp.c:1727
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition: scip_sol.c:129
SCIP_Real SCIPgetSolOrigObj(SCIP *scip, SCIP_SOL *sol)
Definition: scip_sol.c:1300
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition: scip_sol.c:1077
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1217
SCIP_Real SCIPgetUpperbound(SCIP *scip)
SCIP_Longint SCIPgetNNodes(SCIP *scip)
SCIP_Longint SCIPgetNNodeInitLPs(SCIP *scip)
SCIP_Longint SCIPgetNDualResolveLPIterations(SCIP *scip)
SCIP_Longint SCIPgetNNodeInitLPIterations(SCIP *scip)
SCIP_Longint SCIPgetNDualResolveLPs(SCIP *scip)
SCIP_RETCODE SCIPaddSymgraphEdge(SCIP *scip, SYM_GRAPH *graph, int first, int second, SCIP_Bool hasval, SCIP_Real val)
SCIP_RETCODE SCIPaddSymgraphOpnode(SCIP *scip, SYM_GRAPH *graph, int op, int *nodeidx)
SCIP_RETCODE SCIPgetSymActiveVariables(SCIP *scip, SYM_SYMTYPE symtype, SCIP_VAR ***vars, SCIP_Real **scalars, int *nvars, SCIP_Real *constant, SCIP_Bool transformed)
SCIP_RETCODE SCIPaddSymgraphValnode(SCIP *scip, SYM_GRAPH *graph, SCIP_Real val, int *nodeidx)
int SCIPgetSymgraphVarnodeidx(SCIP *scip, SYM_GRAPH *graph, SCIP_VAR *var)
SCIP_RETCODE SCIPaddSymgraphConsnode(SCIP *scip, SYM_GRAPH *graph, SCIP_CONS *cons, SCIP_Real lhs, SCIP_Real rhs, int *nodeidx)
SCIP_RETCODE SCIPaddSymgraphVarAggregation(SCIP *scip, SYM_GRAPH *graph, int rootidx, SCIP_VAR **vars, SCIP_Real *vals, int nvars, SCIP_Real constant)
int SCIPgetSymgraphNegatedVarnodeidx(SCIP *scip, SYM_GRAPH *graph, SCIP_VAR *var)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfeastol(SCIP *scip)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisNegative(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPceil(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPsumepsilon(SCIP *scip)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:670
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip_tree.c:91
SCIP_RETCODE SCIPgetProbvarLinearSum(SCIP *scip, SCIP_VAR **vars, SCIP_Real *scalars, int *nvars, int varssize, SCIP_Real *constant, int *requiredsize, SCIP_Bool mergemultiples)
Definition: scip_var.c:1738
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5203
SCIP_Real SCIPvarGetNegationConstant(SCIP_VAR *var)
Definition: var.c:17915
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4351
SCIP_Bool SCIPvarMayRoundUp(SCIP_VAR *var)
Definition: var.c:3451
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition: var.c:17882
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17748
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:17599
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:17538
SCIP_Real SCIPvarGetAggrConstant(SCIP_VAR *var)
Definition: var.c:17834
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:18144
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:17561
SCIP_RETCODE SCIPinferVarUbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5615
SCIP_Bool SCIPvarMayRoundDown(SCIP_VAR *var)
Definition: var.c:3440
SCIP_RETCODE SCIPchgVarUbNode(SCIP *scip, SCIP_NODE *node, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_var.c:4890
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5320
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip_var.c:533
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: scip_var.c:1794
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:18088
int SCIPvarGetIndex(SCIP_VAR *var)
Definition: var.c:17758
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4259
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition: scip_var.c:4437
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:2128
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17419
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:17610
SCIP_RETCODE SCIPflattenVarAggregationGraph(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1693
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition: var.c:17858
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition: var.c:17846
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:18134
SCIP_VAR * SCIPvarGetNegationVar(SCIP_VAR *var)
Definition: var.c:17904
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:18078
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:8715
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip_var.c:8276
SCIP_RETCODE SCIPinferVarLbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5501
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:1992
int SCIPvarCompare(SCIP_VAR *var1, SCIP_VAR *var2)
Definition: var.c:11942
SCIP_RETCODE SCIPchgVarLbNode(SCIP *scip, SCIP_NODE *node, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_var.c:4846
SCIP_RETCODE SCIPwriteVarName(SCIP *scip, FILE *file, SCIP_VAR *var, SCIP_Bool type)
Definition: scip_var.c:230
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip_var.c:1439
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition: var.c:17870
SCIP_VAR * SCIPvarGetAggrVar(SCIP_VAR *var)
Definition: var.c:17810
void SCIPsortDownIntInt(int *intarray1, int *intarray2, int len)
void SCIPsortRealPtr(SCIP_Real *realarray, void **ptrarray, int len)
void SCIPsortRealInt(SCIP_Real *realarray, int *intarray, int len)
void SCIPsortDownRealInt(SCIP_Real *realarray, int *intarray, int len)
void SCIPsortInt(int *intarray, int len)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10877
SCIP_RETCODE SCIPskipSpace(char **s)
Definition: misc.c:10866
memory allocation routines
#define BMScopyMemoryArray(ptr, source, num)
Definition: memory.h:134
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:57
public methods for managing constraints
public methods for managing events
public methods for primal heuristics
public methods for LP management
public methods for message output
#define SCIPerrorMessage
Definition: pub_message.h:64
#define SCIPdebug(x)
Definition: pub_message.h:93
public data structures and miscellaneous methods
methods for sorting joint arrays of various types
public methods for branch and bound tree
public methods for problem variables
public methods for branching rule plugins and branching
public methods for conflict handler plugins and conflict analysis
public methods for constraint handler plugins and constraints
public methods for problem copies
public methods for cuts and aggregation rows
public methods for data structures
public methods for event handler plugins and event handlers
general public methods
public methods for the LP relaxation, rows and columns
public methods for memory management
public methods for message handling
public methods for numerical tolerances
public methods for SCIP parameter handling
public methods for global and local (sub)problems
public methods for the probing mode
public methods for solutions
public methods for querying solving statistics
public methods for the branch-and-bound tree
public methods for SCIP variables
int maxboundcuts
Definition: cons_sos1.c:245
SCIP_Bool cutoff
Definition: cons_sos1.c:242
SCIP_Bool strthenboundcuts
Definition: cons_sos1.c:246
SCIP_Real scaleval
Definition: cons_sos1.c:241
SCIP * scip
Definition: cons_sos1.c:237
SCIP_SOL * sol
Definition: cons_sos1.c:240
SCIP_CONSHDLR * conshdlr
Definition: cons_sos1.c:238
int nboundcuts
Definition: cons_sos1.c:244
SCIP_DIGRAPH * conflictgraph
Definition: cons_sos1.c:239
structs for symmetry computations
methods for dealing with symmetry detection graphs
tclique user interface
void tcliqueChangeWeight(TCLIQUE_GRAPH *tcliquegraph, int node, TCLIQUE_WEIGHT weight)
void tcliqueFree(TCLIQUE_GRAPH **tcliquegraph)
enum TCLIQUE_Status TCLIQUE_STATUS
Definition: tclique.h:68
int TCLIQUE_WEIGHT
Definition: tclique.h:48
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)
TCLIQUE_Bool tcliqueFlush(TCLIQUE_GRAPH *tcliquegraph)
struct TCLIQUE_Graph TCLIQUE_GRAPH
Definition: tclique.h:49
TCLIQUE_Bool tcliqueCreate(TCLIQUE_GRAPH **tcliquegraph)
TCLIQUE_Bool tcliqueAddNode(TCLIQUE_GRAPH *tcliquegraph, int node, TCLIQUE_WEIGHT weight)
TCLIQUE_Bool tcliqueAddEdge(TCLIQUE_GRAPH *tcliquegraph, int node1, int node2)
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:64
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:65
#define SCIP_EVENTTYPE_GUBCHANGED
Definition: type_event.h:76
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:173
#define SCIP_EVENTTYPE_UBTIGHTENED
Definition: type_event.h:79
#define SCIP_EVENTTYPE_LBRELAXED
Definition: type_event.h:78
#define SCIP_EVENTTYPE_GLBCHANGED
Definition: type_event.h:75
uint64_t SCIP_EVENTTYPE
Definition: type_event.h:151
#define SCIP_EVENTTYPE_LBTIGHTENED
Definition: type_event.h:77
#define SCIP_EVENTTYPE_UBRELAXED
Definition: type_event.h:80
#define SCIP_DIVETYPE_SOS1VARIABLE
Definition: type_heur.h:61
@ SCIP_BRANCHDIR_DOWNWARDS
Definition: type_history.h:43
@ SCIP_BRANCHDIR_FIXED
Definition: type_history.h:45
enum SCIP_LPSolStat SCIP_LPSOLSTAT
Definition: type_lp.h:51
@ SCIP_LPSOLSTAT_OPTIMAL
Definition: type_lp.h:43
@ SCIP_LPSOLSTAT_TIMELIMIT
Definition: type_lp.h:48
@ SCIP_LPSOLSTAT_INFEASIBLE
Definition: type_lp.h:44
@ SCIP_LPSOLSTAT_OBJLIMIT
Definition: type_lp.h:46
@ SCIP_LPSOLSTAT_ITERLIMIT
Definition: type_lp.h:47
@ SCIP_OBJSENSE_MAXIMIZE
Definition: type_prob.h:47
@ SCIP_DIDNOTRUN
Definition: type_result.h:42
@ SCIP_CUTOFF
Definition: type_result.h:48
@ SCIP_FEASIBLE
Definition: type_result.h:45
@ SCIP_REDUCEDDOM
Definition: type_result.h:51
@ SCIP_DIDNOTFIND
Definition: type_result.h:44
@ SCIP_BRANCHED
Definition: type_result.h:54
@ SCIP_SEPARATED
Definition: type_result.h:49
@ SCIP_SUCCESS
Definition: type_result.h:58
@ SCIP_INFEASIBLE
Definition: type_result.h:46
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:61
@ SCIP_INVALIDDATA
Definition: type_retcode.h:52
@ SCIP_PLUGINNOTFOUND
Definition: type_retcode.h:54
@ SCIP_PARAMETERWRONGVAL
Definition: type_retcode.h:57
@ SCIP_NOMEMORY
Definition: type_retcode.h:44
@ SCIP_OKAY
Definition: type_retcode.h:42
@ SCIP_INVALIDCALL
Definition: type_retcode.h:51
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_STAGE_TRANSFORMED
Definition: type_set.h:47
@ SYM_CONSOPTYPE_SUM
Definition: type_symmetry.h:83
@ SYM_SYMTYPE_PERM
Definition: type_symmetry.h:61
@ SCIP_VARSTATUS_MULTAGGR
Definition: type_var.h:54
@ SCIP_VARSTATUS_NEGATED
Definition: type_var.h:55
@ SCIP_VARSTATUS_AGGREGATED
Definition: type_var.h:53
@ SCIP_LOCKTYPE_MODEL
Definition: type_var.h:97
enum SCIP_Varstatus SCIP_VARSTATUS
Definition: type_var.h:57