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