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