SCIP Doxygen Documentation
Loading...
Searching...
No Matches
cons_sos2.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-2026 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_sos2.c
26 * @ingroup DEFPLUGINS_CONS
27 * @brief constraint handler for SOS type 2 constraints
28 * @author Marc Pfetsch
29 *
30 * A specially ordered set of type 2 (SOS2) is a sequence of variables such that at most two
31 * variables are nonzero and if two variables are nonzero they must be adjacent in the specified
32 * sequence. Note that it is in principle allowed that a variable appears twice, but it then can be
33 * fixed to 0 if it is at least two apart in the sequence.
34 *
35 * This constraint is useful when considering a piecewise affine approximation of a univariate
36 * (nonlinear) function \f$: [a,b] \rightarrow R\f$: Let \f$x_1 < \ldots < x_n\f$ be points in
37 * \f$[a,b]\f$ and introduce variables \f$\lambda_1, \ldots, \lambda_n\f$. To evaluate \f$f(x')\f$
38 * at some point \f$x' \in [a,b]\f$ one can use the following constraints:
39 * \f[
40 * \lambda_1 + \cdots + \lambda_n = 1,\quad x' = x_1 \lambda_1 + \cdots + x_n \lambda_n.
41 * \f]
42 * The value of \f$f(x')\f$ can the be approximated as
43 * \f[
44 * f(x_1) \lambda_1 + \cdots + f(x_n) \lambda_n.
45 * \f]
46 * To get a valid piecewise affine approximation, \f$\lambda_1, \ldots, \lambda_n\f$ have to obey an
47 * SOS constraint of type 2.
48 *
49 * This implementation of this constraint handler is based on classical ideas, see e.g.@n
50 * "Special Facilities in General Mathematical Programming System for
51 * Non-Convex Problems Using Ordered Sets of Variables"@n
52 * E. Beale and J. Tomlin, Proc. 5th IFORS Conference, 447-454 (1970)
53 *
54 * The order of the variables is determined as follows:
55 *
56 * - If the constraint is created with SCIPcreateConsSOS2() and weights are given, the weights
57 * determine the order (decreasing weights). Additional variables can be added with
58 * SCIPaddVarSOS2(), which adds a variable with given weight.
59 *
60 * - If an empty constraint is created and then variables are added with SCIPaddVarSOS2(), weights
61 * are needed and stored.
62 *
63 * - All other calls ignore the weights, i.e., if a nonempty constraint is created or variables are
64 * added with SCIPappendVarSOS2().
65 *
66 * @todo Allow to adapt the order of the constraints, e.g. by priorities. This for instance
67 * determines the branching order.
68 * @todo Separate the following cuts for each pair of variables x, y of at least distance 2 in the
69 * SOS2 constraint: \f$ \min \{l_x, l_y\} \leq x + y \leq \max \{u_x, u_y\}\f$, where \f$l_x, u_x,
70 * l_y, u_y\f$ are the lower and upper bounds of x and y, respectively.
71 * @todo Possibly allow to generate local cuts via strengthened local cuts (would affect lhs/rhs of rows)
72 * @todo Try to compute better estimations for the child nodes in enforceSOS2 when called for a relaxation solution;
73 * currently pseudo costs are used, which are not computed for the relaxation.
74 */
75
76/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
77
79#include "scip/cons_linear.h"
80#include "scip/cons_sos2.h"
81#include "scip/pub_cons.h"
82#include "scip/pub_event.h"
83#include "scip/pub_lp.h"
84#include "scip/pub_message.h"
85#include "scip/pub_misc.h"
86#include "scip/pub_misc_sort.h"
87#include "scip/pub_var.h"
88#include "scip/scip_branch.h"
89#include "scip/scip_conflict.h"
90#include "scip/scip_cons.h"
91#include "scip/scip_copy.h"
92#include "scip/scip_cut.h"
93#include "scip/scip_event.h"
94#include "scip/scip_general.h"
95#include "scip/scip_lp.h"
96#include "scip/scip_mem.h"
97#include "scip/scip_message.h"
98#include "scip/scip_numerics.h"
99#include "scip/scip_prob.h"
100#include "scip/scip_sol.h"
101#include "scip/scip_var.h"
102#include "scip/symmetry_graph.h"
104#include <ctype.h>
105#include <stdlib.h>
106
107
108/* constraint handler properties */
109#define CONSHDLR_NAME "SOS2"
110#define CONSHDLR_DESC "SOS2 constraint handler"
111#define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
112#define CONSHDLR_ENFOPRIORITY 100 /**< priority of the constraint handler for constraint enforcing */
113#define CONSHDLR_CHECKPRIORITY -10 /**< priority of the constraint handler for checking feasibility */
114#define CONSHDLR_SEPAFREQ 0 /**< frequency for separating cuts; zero means to separate only in the root node */
115#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
116#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
117 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
118#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
119#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
120#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
121#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
122
123#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
124#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_FAST
125
126/* event handler properties */
127#define EVENTHDLR_NAME "SOS2"
128#define EVENTHDLR_DESC "bound change event handler for SOS2 constraints"
129
130#define EVENTHDLR_EVENT_TYPE (SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_GBDCHANGED)
131
132
133/** constraint data for SOS2 constraints */
134struct SCIP_ConsData
135{
136 int nvars; /**< number of variables in the constraint */
137 int maxvars; /**< maximal number of variables (= size of storage) */
138 int nfixednonzeros; /**< number of variables fixed to be nonzero */
139 SCIP_VAR** vars; /**< variables in constraint */
140 SCIP_ROW* row; /**< row corresponding to upper and lower bound inequalities, or NULL if not yet created */
141 SCIP_Real* weights; /**< weights determining the order (ascending), or NULL if not used */
142};
143
144/** SOS2 constraint handler data */
145struct SCIP_ConshdlrData
146{
147 SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
148};
149
150
151/** fix variable in given node to 0 or add constraint if variable is multi-aggregated */
152static
154 SCIP* scip, /**< SCIP pointer */
155 SCIP_VAR* var, /**< variable to be fixed to 0*/
156 SCIP_NODE* node, /**< node */
157 SCIP_Bool* infeasible /**< if fixing is infeasible */
158 )
159{
160 /* if variable cannot be nonzero */
161 *infeasible = FALSE;
163 {
164 *infeasible = TRUE;
165 return SCIP_OKAY;
166 }
167
168 /* if variable is multi-aggregated */
170 {
171 SCIP_CONS* cons;
172 SCIP_Real val;
173
174 val = 1.0;
175
177 {
178 SCIPdebugMsg(scip, "creating constraint to force multi-aggregated variable <%s> to 0.\n", SCIPvarGetName(var));
179 /* we have to insert a local constraint var = 0 */
180 SCIP_CALL( SCIPcreateConsLinear(scip, &cons, "branch", 1, &var, &val, 0.0, 0.0, TRUE, TRUE, TRUE, TRUE, TRUE,
181 TRUE, FALSE, FALSE, FALSE, FALSE) );
182 SCIP_CALL( SCIPaddConsNode(scip, node, cons, NULL) );
183 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
184 }
185 }
186 else
187 {
189 SCIP_CALL( SCIPchgVarLbNode(scip, node, var, 0.0) );
191 SCIP_CALL( SCIPchgVarUbNode(scip, node, var, 0.0) );
192 }
193
194 return SCIP_OKAY;
195}
196
197
198/** fix variable in local node to 0, and return whether the operation was feasible
199 *
200 * @note We do not add a linear constraint if the variable is multi-aggregated as in
201 * fixVariableZeroNode(), since this would be too time consuming.
202 */
203static
205 SCIP* scip, /**< SCIP pointer */
206 SCIP_VAR* var, /**< variable to be fixed to 0*/
207 SCIP_CONS* cons, /**< constraint */
208 int inferinfo, /**< info for reverse prop. */
209 SCIP_Bool* infeasible, /**< if fixing is infeasible */
210 SCIP_Bool* tightened, /**< if fixing was performed */
211 SCIP_Bool* success /**< whether fixing was successful, i.e., variable is not multi-aggregated */
212 )
213{
214 *infeasible = FALSE;
215 *tightened = FALSE;
216 *success = FALSE;
217
218 /* if variable cannot be nonzero */
220 {
221 *infeasible = TRUE;
222 return SCIP_OKAY;
223 }
224
225 /* directly fix variable if it is not multi-aggregated, do nothing otherwise */
227 {
228 SCIP_Bool tighten;
229
230 /* fix lower bound */
231 SCIP_CALL( SCIPinferVarLbCons(scip, var, 0.0, cons, inferinfo, FALSE, infeasible, &tighten) );
232 *tightened = *tightened || tighten;
233
234 /* fix upper bound */
235 SCIP_CALL( SCIPinferVarUbCons(scip, var, 0.0, cons, inferinfo, FALSE, infeasible, &tighten) );
236 *tightened = *tightened || tighten;
237
238 *success = TRUE;
239 }
240
241 return SCIP_OKAY;
242}
243
244
245/** add lock on variable */
246static
248 SCIP* scip, /**< SCIP data structure */
249 SCIP_CONS* cons, /**< constraint */
250 SCIP_VAR* var /**< variable */
251 )
252{
253 assert( scip != NULL );
254 assert( cons != NULL );
255 assert( var != NULL );
256
257 /* rounding down == bad if lb < 0, rounding up == bad if ub > 0 */
260
261 return SCIP_OKAY;
262}
263
264
265/** remove lock on variable */
266static
268 SCIP* scip, /**< SCIP data structure */
269 SCIP_CONS* cons, /**< constraint */
270 SCIP_VAR* var /**< variable */
271 )
272{
273 assert( scip != NULL );
274 assert( cons != NULL );
275 assert( var != NULL );
276
277 /* rounding down == bad if lb < 0, rounding up == bad if ub > 0 */
280
281 return SCIP_OKAY;
282}
283
284
285/** ensures that the vars and weights array can store at least num entries */
286static
288 SCIP* scip, /**< SCIP data structure */
289 SCIP_CONSDATA* consdata, /**< constraint data */
290 int num, /**< minimum number of entries to store */
291 SCIP_Bool reserveWeights /**< whether the weights array is handled */
292 )
293{
294 assert( consdata != NULL );
295 assert( consdata->nvars <= consdata->maxvars );
296
297 if ( num > consdata->maxvars )
298 {
299 int newsize;
300
301 newsize = SCIPcalcMemGrowSize(scip, num);
302 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->maxvars, newsize) );
303 if ( reserveWeights )
304 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->maxvars, newsize) );
305 consdata->maxvars = newsize;
306 }
307 assert( num <= consdata->maxvars );
308
309 return SCIP_OKAY;
310}
311
312
313/** handle new variable */
314static
316 SCIP* scip, /**< SCIP data structure */
317 SCIP_CONS* cons, /**< constraint */
318 SCIP_CONSDATA* consdata, /**< constraint data */
319 SCIP_VAR* var, /**< variable */
320 SCIP_Bool transformed /**< whether original variable was transformed */
321 )
322{
323 assert( scip != NULL );
324 assert( cons != NULL );
325 assert( consdata != NULL );
326 assert( var != NULL );
327
328 /* if we are in transformed problem, catch the variable's events */
329 if ( transformed )
330 {
331 SCIP_CONSHDLR* conshdlr;
332 SCIP_CONSHDLRDATA* conshdlrdata;
333
334 /* get event handler */
335 conshdlr = SCIPconsGetHdlr(cons);
336 conshdlrdata = SCIPconshdlrGetData(conshdlr);
337 assert( conshdlrdata != NULL );
338 assert( conshdlrdata->eventhdlr != NULL );
339
340 /* catch bound change events of variable */
341 SCIP_CALL( SCIPcatchVarEvent(scip, var, EVENTHDLR_EVENT_TYPE, conshdlrdata->eventhdlr,
342 (SCIP_EVENTDATA*)cons, NULL) );
343
344 /* if the variable if fixed to nonzero */
345 assert( consdata->nfixednonzeros >= 0 );
347 ++consdata->nfixednonzeros;
348 }
349
350 /* install the rounding locks for the new variable */
352
353 /* add the new coefficient to the LP row, if necessary */
354 if ( consdata->row != NULL )
355 {
356 /* this is currently dead code, since the constraint is not modifiable */
357 SCIP_CALL( SCIPaddVarToRow(scip, consdata->row, var, 1.0) );
358
359 /* update lhs and rhs if necessary */
360 if ( SCIPisFeasGT(scip, SCIPvarGetUbLocal(var), SCIProwGetRhs(consdata->row)) )
361 SCIP_CALL( SCIPchgRowRhs(scip, consdata->row, SCIPvarGetUbLocal(var) ) );
362 if ( SCIPisFeasLT(scip, SCIPvarGetLbLocal(var), SCIProwGetLhs(consdata->row)) )
363 SCIP_CALL( SCIPchgRowLhs(scip, consdata->row, SCIPvarGetLbLocal(var) ) );
364 }
365
366 return SCIP_OKAY;
367}
368
369
370/** adds a variable to an SOS2 constraint, a position given by weight - ascending order */
371static
373 SCIP* scip, /**< SCIP data structure */
374 SCIP_CONS* cons, /**< constraint */
375 SCIP_VAR* var, /**< variable to add to the constraint */
376 SCIP_Real weight /**< weight to determine position */
377 )
378{
379 SCIP_CONSDATA* consdata;
380 SCIP_Bool transformed;
381 int j;
382 int pos;
383
384 assert( var != NULL );
385 assert( cons != NULL );
386
387 consdata = SCIPconsGetData(cons);
388 assert( consdata != NULL );
389
390 if ( consdata->weights == NULL && consdata->maxvars > 0 )
391 {
392 SCIPerrorMessage("cannot add variable to SOS2 constraint <%s> that does not contain weights.\n", SCIPconsGetName(cons));
393 return SCIP_INVALIDCALL;
394 }
395
396 /* are we in the transformed problem? */
397 transformed = SCIPconsIsTransformed(cons);
398
399 /* always use transformed variables in transformed constraints */
400 if ( transformed )
401 {
403 }
404 assert( var != NULL );
405 assert( transformed == SCIPvarIsTransformed(var) );
406
407 SCIP_CALL( consdataEnsurevarsSizeSOS2(scip, consdata, consdata->nvars + 1, TRUE) );
408 assert( consdata->weights != NULL );
409 assert( consdata->maxvars >= consdata->nvars+1 );
410
411 /* find variable position */
412 for (pos = 0; pos < consdata->nvars; ++pos)
413 {
414 if ( consdata->weights[pos] > weight )
415 break;
416 }
417 assert( 0 <= pos && pos <= consdata->nvars );
418
419 /* move other variables, if necessary */
420 for (j = consdata->nvars; j > pos; --j)
421 {
422 consdata->vars[j] = consdata->vars[j-1];
423 consdata->weights[j] = consdata->weights[j-1];
424 }
425
426 /* insert variable */
427 consdata->vars[pos] = var;
428 consdata->weights[pos] = weight;
429 ++consdata->nvars;
430
431 /* handle the new variable */
432 SCIP_CALL( handleNewVariableSOS2(scip, cons, consdata, var, transformed) );
433
434 return SCIP_OKAY;
435}
436
437
438/** appends a variable to an SOS2 constraint */
439static
441 SCIP* scip, /**< SCIP data structure */
442 SCIP_CONS* cons, /**< constraint */
443 SCIP_VAR* var /**< variable to add to the constraint */
444 )
445{
446 SCIP_CONSDATA* consdata;
447 SCIP_Bool transformed;
448
449 assert( var != NULL );
450 assert( cons != NULL );
451
452 consdata = SCIPconsGetData(cons);
453 assert( consdata != NULL );
454 assert( consdata->nvars >= 0 );
455
456 /* are we in the transformed problem? */
457 transformed = SCIPconsIsTransformed(cons);
458
459 /* always use transformed variables in transformed constraints */
460 if ( transformed )
461 {
463 }
464 assert( var != NULL );
465 assert( transformed == SCIPvarIsTransformed(var) );
466
467 if ( consdata->weights != NULL )
468 {
469 SCIP_CALL( consdataEnsurevarsSizeSOS2(scip, consdata, consdata->nvars + 1, TRUE) );
470 }
471 else
472 {
473 SCIP_CALL( consdataEnsurevarsSizeSOS2(scip, consdata, consdata->nvars + 1, FALSE) );
474 }
475
476 /* insert variable */
477 consdata->vars[consdata->nvars] = var;
478 if ( consdata->weights != NULL )
479 {
480 if ( consdata->nvars > 0 )
481 consdata->weights[consdata->nvars] = consdata->weights[consdata->nvars-1] + 1.0;
482 else
483 consdata->weights[consdata->nvars] = 0.0;
484 }
485 ++consdata->nvars;
486
487 /* handle the new variable */
488 SCIP_CALL( handleNewVariableSOS2(scip, cons, consdata, var, transformed) );
489
490 return SCIP_OKAY;
491}
492
493
494/** deletes a variable of an SOS2 constraint */
495static
497 SCIP* scip, /**< SCIP data structure */
498 SCIP_CONS* cons, /**< constraint */
499 SCIP_CONSDATA* consdata, /**< constraint data */
500 SCIP_EVENTHDLR* eventhdlr, /**< corresponding event handler */
501 int pos /**< position of variable in array */
502 )
503{
504 int j;
505
506 assert( 0 <= pos && pos < consdata->nvars );
507
508 /* remove lock of variable */
509 SCIP_CALL( unlockVariableSOS2(scip, cons, consdata->vars[pos]) );
510
511 /* drop events on variable */
512 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[pos], EVENTHDLR_EVENT_TYPE, eventhdlr, (SCIP_EVENTDATA*)cons, -1) );
513
514 /* delete variable - need to copy since order is important */
515 for (j = pos; j < consdata->nvars-1; ++j)
516 {
517 consdata->vars[j] = consdata->vars[j+1]; /*lint !e679*/
518 if ( consdata->weights != NULL )
519 consdata->weights[j] = consdata->weights[j+1]; /*lint !e679*/
520 }
521 --consdata->nvars;
522
523 return SCIP_OKAY;
524}
525
526
527/** perform one presolving round
528 *
529 * We perform the following presolving steps.
530 *
531 * - If the bounds of one variable force it to be nonzero, we can fix all other variables with distance at least two to
532 * zero. If two variables are certain to be nonzero, we can fix all other variables to 0 and remove the constraint.
533 * - All variables fixed to zero, that are at the beginning or end of the constraint can be removed.
534 * - We substitute appregated variables.
535 * - If a constraint has at most two variables, we delete it.
536 *
537 * We currently do not handle the following:
538 *
539 * - If we have at least two variables fixed to zero next to each-other, that are positioned in the inner part of this
540 * constraint, we can delete all but one of these variables.
541 * - If a variable appears twice not next to each-other, it can be fixed to 0. If one variable appears next to
542 * each-other and is already certain to be nonzero, we can fix all variables.
543 * - If a binary variable and its negation appear in the constraint, we might fix variables to zero or can forbid a zero
544 * value for them.
545 * - When, after removing all zero "border" variables, a constraint with more than two variables has at most two
546 * variables that are not fixed to 0, only one of these can take a nonzero value, because these variables need to be
547 * the "border" variables of this constraint. The same holds if we have exactly three variables in one constraint and
548 * the middle variable is certain to be not zero. In both cases we can upgrade this constraint constraint to an sos1
549 * consisting only of the "border" variables. If these "border" variables are negations of each other, we can delete
550 * this constraint.
551 * - When, after removing all variables fixed to 0, that are possible, in a constraint each even positioned variable is
552 * fixed to 0, we can upgrade this constraint to an sos1 that holds all non-fixed variables.
553 * - Extract cliques for all odd and also for all even positioned binary variables
554 */
555static
557 SCIP* scip, /**< SCIP pointer */
558 SCIP_CONS* cons, /**< constraint */
559 SCIP_CONSDATA* consdata, /**< constraint data */
560 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
561 SCIP_Bool* cutoff, /**< whether a cutoff happened */
562 SCIP_Bool* success, /**< whether we performed a successful reduction */
563 int* ndelconss, /**< number of deleted constraints */
564 int* nfixedvars, /**< number of fixed variables */
565 int* nremovedvars /**< number of variables removed */
566 )
567{
568 SCIP_VAR** vars;
569 SCIP_Bool infeasible;
570 SCIP_Bool fixed;
571 int nfixednonzeros;
572 int lastFixedNonzero;
573 int lastzero;
574 int localnremovedvars;
575 int oldnfixedvars;
576 int j;
577
578 assert( scip != NULL );
579 assert( cons != NULL );
580 assert( consdata != NULL );
581 assert( eventhdlr != NULL );
582 assert( cutoff != NULL );
583 assert( success != NULL );
584 assert( ndelconss != NULL );
585 assert( nfixedvars != NULL );
586 assert( nremovedvars != NULL );
587
588 *cutoff = FALSE;
589 *success = FALSE;
590
591 SCIPdebugMsg(scip, "Presolving SOS2 constraint <%s>.\n", SCIPconsGetName(cons) );
592
593 /* if the number of variables is at most 2 */
594 if( consdata->nvars <= 2 )
595 {
596 SCIPdebugMsg(scip, "Deleting constraint with <= 2 variables.\n");
597
598 /* delete constraint */
599 assert( ! SCIPconsIsModifiable(cons) );
600 SCIP_CALL( SCIPdelCons(scip, cons) );
601 ++(*ndelconss);
602 *success = TRUE;
603
604 return SCIP_OKAY;
605 }
606
607 nfixednonzeros = 0;
608 lastFixedNonzero = -1;
609 vars = consdata->vars;
610 lastzero = consdata->nvars;
611 localnremovedvars = 0;
612
613 /* check for variables fixed to 0 and bounds that guarantee a variable to be nonzero; downward loop is important */
614 for( j = consdata->nvars - 1; j >= 0; --j )
615 {
616 SCIP_VAR* var;
617 SCIP_Real lb;
618 SCIP_Real ub;
619 SCIP_Real scalar;
620 SCIP_Real constant;
621
622 /* check that our vars array is still correct */
623 assert(vars == consdata->vars);
624
625 scalar = 1.0;
626 constant = 0.0;
627
628 /* check aggregation: if the constant is zero, the variable is zero iff the aggregated variable is 0 */
629 var = vars[j];
630 SCIP_CALL( SCIPgetProbvarSum(scip, &var, &scalar, &constant) );
631
632 /* if constant is zero and we get a different variable, substitute variable */
633 if ( SCIPisZero(scip, constant) && ! SCIPisZero(scip, scalar) && var != vars[j] )
634 {
635 SCIPdebugMsg(scip, "substituted variable <%s> by <%s>.\n", SCIPvarGetName(vars[j]), SCIPvarGetName(var));
636 SCIP_CALL( SCIPdropVarEvent(scip, consdata->vars[j], EVENTHDLR_EVENT_TYPE, eventhdlr, (SCIP_EVENTDATA*)cons, -1) );
638
639 /* change the rounding locks */
640 SCIP_CALL( unlockVariableSOS2(scip, cons, consdata->vars[j]) );
642
643 vars[j] = var;
644 }
645
646 /* get bounds */
647 lb = SCIPvarGetLbLocal(vars[j]);
648 ub = SCIPvarGetUbLocal(vars[j]);
649
650 /* if the variable if fixed to nonzero */
652 {
653 ++nfixednonzeros;
654
655 /* two variables certain to be nonzero which are not next to each other, so we are infeasible */
656 if( lastFixedNonzero != -1 && lastFixedNonzero != j + 1 )
657 {
658 SCIPdebugMsg(scip, "The problem is infeasible: two non-consecutive variables have bounds that keep them from being 0.\n");
659 *cutoff = TRUE;
660 return SCIP_OKAY;
661 }
662
663 /* if more than two variables are fixed to be nonzero, we are infeasible */
664 if( nfixednonzeros > 2 )
665 {
666 SCIPdebugMsg(scip, "The problem is infeasible: more than two variables have bounds that keep them from being 0.\n");
667 *cutoff = TRUE;
668 return SCIP_OKAY;
669 }
670
671 if( lastFixedNonzero == -1)
672 lastFixedNonzero = j;
673 }
674
675 /* if the variable is fixed to 0 we may delete it from our constraint */
676 if( SCIPisFeasZero(scip, lb) && SCIPisFeasZero(scip, ub) )
677 {
678 /* all rear variables fixed to 0 can be deleted */
679 if( j == consdata->nvars - 1 )
680 {
681 ++(*nremovedvars);
682
683 SCIPdebugMsg(scip, "deleting variable <%s> fixed to 0.\n", SCIPvarGetName(vars[j]));
684 SCIP_CALL( deleteVarSOS2(scip, cons, consdata, eventhdlr, j) );
685
686 *success = TRUE;
687 }
688 /* remember position of last variable for which all up front and this one are fixed to 0 */
689 else if( lastzero > j + 1 )
690 lastzero = j;
691 }
692 else
693 lastzero = consdata->nvars;
694 }
695
696 /* check that our vars array is still correct */
697 assert(vars == consdata->vars);
698
699 /* remove first "lastzero" many variables, that are already fixed to 0 */
700 if( lastzero < consdata->nvars )
701 {
702 assert(lastzero >= 0);
703
704 for( j = lastzero; j >= 0; --j )
705 {
706 /* the variables should all be fixed to zero */
708
709 SCIPdebugMsg(scip, "deleting variable <%s> fixed to 0.\n", SCIPvarGetName(vars[j]));
710 SCIP_CALL( deleteVarSOS2(scip, cons, consdata, eventhdlr, j) );
711 }
712 localnremovedvars += (lastzero + 1);
713 *success = TRUE;
714 }
715
716 /* check that our variable array is still correct */
717 assert(vars == consdata->vars);
718
719 *nremovedvars += localnremovedvars;
720
721 /* we might need to correct the position of the first variable which is certain to be not zero */
722 if( lastFixedNonzero >= 0 )
723 {
724 lastFixedNonzero -= localnremovedvars;
725 assert(0 <= lastFixedNonzero && lastFixedNonzero < consdata->nvars);
727 }
728
729 /* if the number of variables is at most 2 */
730 if( consdata->nvars <= 2 )
731 {
732 SCIPdebugMsg(scip, "Deleting constraint with <= 2 variables.\n");
733
734 /* delete constraint */
735 assert( ! SCIPconsIsModifiable(cons) );
736 SCIP_CALL( SCIPdelCons(scip, cons) );
737 ++(*ndelconss);
738 *success = TRUE;
739
740 return SCIP_OKAY;
741 }
742
743 oldnfixedvars = *nfixedvars;
744
745 /* if there is exactly one fixed nonzero variable */
746 if ( nfixednonzeros == 1 )
747 {
748 assert(0 <= lastFixedNonzero && lastFixedNonzero < consdata->nvars);
750 SCIPisFeasNegative(scip, SCIPvarGetUbGlobal(vars[lastFixedNonzero])));
751
752 /* fix all other variables with distance two to zero */
753 for( j = 0; j < lastFixedNonzero - 1; ++j )
754 {
755 SCIPdebugMsg(scip, "fixing variable <%s> to 0.\n", SCIPvarGetName(vars[j]));
756 SCIP_CALL( SCIPfixVar(scip, vars[j], 0.0, &infeasible, &fixed) );
757
758 if( infeasible )
759 {
760 *cutoff = TRUE;
761 return SCIP_OKAY;
762 }
763
764 if ( fixed )
765 ++(*nfixedvars);
766 }
767 for( j = lastFixedNonzero + 2; j < consdata->nvars; ++j )
768 {
769 SCIPdebugMsg(scip, "fixing variable <%s> to 0.\n", SCIPvarGetName(vars[j]));
770 SCIP_CALL( SCIPfixVar(scip, vars[j], 0.0, &infeasible, &fixed) );
771
772 if( infeasible )
773 {
774 *cutoff = TRUE;
775 return SCIP_OKAY;
776 }
777
778 if ( fixed )
779 ++(*nfixedvars);
780 }
781
782 if( *nfixedvars > oldnfixedvars )
783 *success = TRUE;
784 }
785 /* if there are exactly two fixed nonzero variables */
786 else if ( nfixednonzeros == 2 )
787 {
788 assert(0 < lastFixedNonzero && lastFixedNonzero < consdata->nvars);
790 SCIPisFeasNegative(scip, SCIPvarGetUbGlobal(vars[lastFixedNonzero])));
791 /* the previous variable need also to be nonzero, otherwise the infeasibility should have been detected earlier */
792 assert(SCIPisFeasPositive(scip, SCIPvarGetLbGlobal(vars[lastFixedNonzero - 1])) ||
793 SCIPisFeasNegative(scip, SCIPvarGetUbGlobal(vars[lastFixedNonzero - 1])));
794
795 /* fix all variables before lastFixedNonzero to zero */
796 for( j = 0; j < lastFixedNonzero - 1; ++j )
797 {
798 SCIPdebugMsg(scip, "fixing variable <%s> to 0.\n", SCIPvarGetName(vars[j]));
799 SCIP_CALL( SCIPfixVar(scip, vars[j], 0.0, &infeasible, &fixed) );
800
801 if( infeasible )
802 {
803 *cutoff = TRUE;
804 return SCIP_OKAY;
805 }
806 if ( fixed )
807 ++(*nfixedvars);
808 }
809 /* fix all variables after lastFixedNonzero + 1 to zero */
810 for( j = lastFixedNonzero + 1; j < consdata->nvars; ++j )
811 {
812 SCIPdebugMsg(scip, "fixing variable <%s> to 0.\n", SCIPvarGetName(vars[j]));
813 SCIP_CALL( SCIPfixVar(scip, vars[j], 0.0, &infeasible, &fixed) );
814
815 if( infeasible )
816 {
817 *cutoff = TRUE;
818 return SCIP_OKAY;
819 }
820 if ( fixed )
821 ++(*nfixedvars);
822 }
823
824 /* delete constraint */
825 assert( ! SCIPconsIsModifiable(cons) );
826 SCIP_CALL( SCIPdelCons(scip, cons) );
827 ++(*ndelconss);
828 *success = TRUE;
829 }
830
831 return SCIP_OKAY;
832}
833
834
835/** propagate variables */
836static
838 SCIP* scip, /**< SCIP pointer */
839 SCIP_CONS* cons, /**< constraint */
840 SCIP_CONSDATA* consdata, /**< constraint data */
841 SCIP_Bool* cutoff, /**< whether a cutoff happened */
842 int* ngen /**< pointer to incremental counter for domain changes */
843 )
844{
845 int ngenold;
846
847 assert( scip != NULL );
848 assert( cons != NULL );
849 assert( consdata != NULL );
850 assert( cutoff != NULL );
851 assert( ngen != NULL );
852
853 *cutoff = FALSE;
854 ngenold = *ngen;
855
856 /* if more than two variables are fixed to be nonzero */
857 if ( consdata->nfixednonzeros > 2 )
858 {
859 SCIPdebugMsg(scip, "the node is infeasible, more than 2 variables are fixed to be nonzero.\n");
861 *cutoff = TRUE;
862 return SCIP_OKAY;
863 }
864
865 /* if exactly one variable is fixed to be nonzero */
866 if ( consdata->nfixednonzeros == 1 )
867 {
868 SCIP_VAR** vars;
869 SCIP_Bool infeasible;
870 SCIP_Bool tightened;
871 SCIP_Bool success;
872 int firstFixedNonzero;
873 int nvars;
874 int j;
875
876 firstFixedNonzero = -1;
877 nvars = consdata->nvars;
878 vars = consdata->vars;
879 assert( vars != NULL );
880
881 /* search nonzero variable */
882 for (j = 0; j < nvars; ++j)
883 {
885 {
886 firstFixedNonzero = j;
887 break;
888 }
889 }
890 assert( firstFixedNonzero >= 0 );
891
892 SCIPdebugMsg(scip, "variable <%s> is nonzero, fixing variables with distance at least 2 to 0.\n", SCIPvarGetName(vars[firstFixedNonzero]));
893
894 /* fix variables before firstFixedNonzero-1 to 0 */
895 for (j = 0; j < firstFixedNonzero-1; ++j)
896 {
897 /* fix variable */
898 SCIP_CALL( inferVariableZero(scip, vars[j], cons, firstFixedNonzero, &infeasible, &tightened, &success) );
899 assert( ! infeasible );
900
901 if ( tightened )
902 ++(*ngen);
903 }
904
905 /* fix variables after firstFixedNonzero+1 to 0 */
906 for (j = firstFixedNonzero+2; j < nvars; ++j)
907 {
908 /* fix variable */
909 SCIP_CALL( inferVariableZero(scip, vars[j], cons, firstFixedNonzero, &infeasible, &tightened, &success) );
910
911 /* no variable after firstFixedNonzero+1 should be fixed to be nonzero */
912 if ( infeasible )
913 {
915 SCIPdebugMsg(scip, "the node is infeasible: variable <%s> is fixed nonzero and variable <%s> with distance at least 2 as well.\n",
916 SCIPvarGetName(vars[firstFixedNonzero]), SCIPvarGetName(vars[j]));
917 *cutoff = TRUE;
918 return SCIP_OKAY;
919 }
920
921 if ( tightened )
922 ++(*ngen);
923 }
924 /* cannot locally delete constraint, since position of second entry is not fixed! */
925 } /*lint !e438*/
926 /* if exactly two variables are fixed to be nonzero */
927 else if ( consdata->nfixednonzeros == 2 )
928 {
929 SCIP_VAR** vars;
930 SCIP_Bool infeasible;
931 SCIP_Bool tightened;
932 SCIP_Bool success;
933 SCIP_Bool allVarFixed;
934 int firstFixedNonzero;
935 int nvars;
936 int j;
937
938 firstFixedNonzero = -1;
939 nvars = consdata->nvars;
940 vars = consdata->vars;
941 assert( vars != NULL );
942
943 /* search nonzero variable */
944 for (j = 0; j < nvars; ++j)
945 {
947 {
948 firstFixedNonzero = j;
949 break;
950 }
951 }
952 assert( 0 <= firstFixedNonzero && firstFixedNonzero < nvars-1 );
953
954 SCIPdebugMsg(scip, "variable <%s> is fixed to be nonzero, fixing variables to 0.\n", SCIPvarGetName(vars[firstFixedNonzero]));
955
956 /* fix variables before firstFixedNonzero to 0 */
957 allVarFixed = TRUE;
958 for (j = 0; j < firstFixedNonzero; ++j)
959 {
960 /* fix variable */
961 SCIP_CALL( inferVariableZero(scip, vars[j], cons, firstFixedNonzero+1, &infeasible, &tightened, &success) );
962 assert( ! infeasible );
963 allVarFixed = allVarFixed && success;
964 if ( tightened )
965 ++(*ngen);
966 }
967
968 /* fix variables after firstFixedNonzero+1 to 0 */
969 for (j = firstFixedNonzero+2; j < nvars; ++j)
970 {
971 /* fix variable */
972 SCIP_CALL( inferVariableZero(scip, vars[j], cons, firstFixedNonzero, &infeasible, &tightened, &success) );
973
974 /* no variable after firstFixedNonzero+1 should be fixed to be nonzero */
975 if ( infeasible )
976 {
978 SCIPdebugMsg(scip, "the node is infeasible: variable <%s> is fixed nonzero and variable <%s> with distance at least 2 as well.\n",
979 SCIPvarGetName(vars[firstFixedNonzero]), SCIPvarGetName(vars[j]));
980 *cutoff = TRUE;
981 return SCIP_OKAY;
982 }
983 allVarFixed = allVarFixed && success;
984
985 if ( tightened )
986 ++(*ngen);
987 }
988
989 /* delete constraint locally, since the nonzero positions are fixed */
990 if ( allVarFixed )
991 {
992 SCIPdebugMsg(scip, "locally deleting constraint <%s>.\n", SCIPconsGetName(cons));
995 }
996 }
997
998 /* reset constraint age counter */
999 if ( *ngen > ngenold )
1001
1002 return SCIP_OKAY;
1003}
1004
1005
1006/** enforcement method
1007 *
1008 * We check whether the current solution is feasible, i.e., contains
1009 * at most one nonzero variable. If not, we branch along the lines
1010 * indicated by Beale and Tomlin:
1011 *
1012 * We first compute \f$W = \sum_{j=1}^n |x_i|\f$ and \f$w =
1013 * \sum_{j=1}^n j\, |x_i|\f$. Then we search for the index \f$k\f$ that
1014 * satisfies
1015 * \f[
1016 * k \leq \frac{w}{W} < k+1.
1017 * \f]
1018 * The branches are then
1019 * \f[
1020 * x_1 = 0, \ldots, x_{k-1} = 0 \qquad \mbox{and}\qquad
1021 * x_{k+1} = 0, \ldots, x_n = 0.
1022 * \f]
1023 *
1024 * There is one special case that we have to consider: It can happen
1025 * that \f$k\f$ is one too small. Example: \f$x_1 = 1 - \epsilon, x_2
1026 * = 0, x_3 = \epsilon\f$. Then \f$w = 1 - \epsilon + 3 \epsilon = 1
1027 * + 2 \epsilon\f$. This yields \f$k = 1\f$ and hence the first
1028 * branch does not change the solution. We therefore increase \f$k\f$
1029 * by one if \f$x_k \neq 0\f$. This is valid, since we know that
1030 * \f$x_{k+1} \neq 0\f$ (with respect to the original \f$k\f$); the
1031 * corresponding branch will cut off the current solution, since
1032 * \f$x_k \neq 0\f$.
1033 */
1034static
1036 SCIP* scip, /**< SCIP pointer */
1037 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1038 int nconss, /**< number of constraints */
1039 SCIP_CONS** conss, /**< indicator constraints */
1040 SCIP_SOL* sol, /**< solution to be enforced (NULL for LP solution) */
1041 SCIP_RESULT* result /**< result */
1042 )
1043{
1044 SCIP_CONSDATA* consdata;
1045 SCIP_Bool infeasible;
1046 SCIP_NODE* node1;
1047 SCIP_NODE* node2;
1049 SCIP_VAR** vars;
1050 SCIP_Real nodeselest;
1051 SCIP_Real objest;
1052 int nvars;
1053 int maxNonzeros;
1054 int maxInd;
1055 int j;
1056 int c;
1057
1058 assert( scip != NULL );
1059 assert( conshdlr != NULL );
1060 assert( conss != NULL );
1061 assert( result != NULL );
1062
1063 maxNonzeros = 0;
1064 maxInd = -1;
1065
1066 SCIPdebugMsg(scip, "Enforcing SOS2 constraints <%s>.\n", SCIPconshdlrGetName(conshdlr) );
1068
1069 /* check each constraint */
1070 for (c = 0; c < nconss; ++c)
1071 {
1072 SCIP_CONS* cons;
1074 SCIP_Real weight1;
1075 SCIP_Real weight2;
1076 SCIP_Real w;
1077 int lastNonzero;
1078 int ngen;
1079 int cnt;
1080 int ind;
1081
1082 cons = conss[c];
1083 assert( cons != NULL );
1084
1085 consdata = SCIPconsGetData(cons);
1086 assert( consdata != NULL );
1087
1088 nvars = consdata->nvars;
1089 vars = consdata->vars;
1090
1091 /* do nothing if there are not enough variables - this is usually eliminated by preprocessing */
1092 if ( nvars <= 2 )
1093 continue;
1094
1095 ngen = 0;
1096
1097 /* first perform propagation (it might happen that standard propagation is turned off) */
1098 SCIP_CALL( propSOS2(scip, cons, consdata, &cutoff, &ngen) );
1099 SCIPdebugMsg(scip, "propagating <%s> in enforcing (cutoff: %u, domain reductions: %d).\n", SCIPconsGetName(cons), cutoff, ngen);
1100 if ( cutoff )
1101 {
1103 return SCIP_OKAY;
1104 }
1105 if ( ngen > 0 )
1106 {
1108 return SCIP_OKAY;
1109 }
1110
1111 cnt = 0;
1112 weight1 = 0.0;
1113 weight2 = 0.0;
1114 lastNonzero = -1;
1115
1116 /* compute weight */
1117 for (j = 0; j < nvars; ++j)
1118 {
1119 SCIP_Real val;
1120
1121 val = REALABS(SCIPgetSolVal(scip, sol, vars[j]));
1122 weight1 += val * (SCIP_Real) j;
1123 weight2 += val;
1124
1125 if ( ! SCIPisFeasZero(scip, val) )
1126 {
1127 lastNonzero = j;
1128 ++cnt;
1129 }
1130 }
1131
1132 /* if at most one variable is nonzero, the constraint is feasible */
1133 if ( cnt < 2 )
1134 continue;
1135
1136 /* if two adjacent variables are nonzero */
1137 assert( 0 < lastNonzero && lastNonzero < nvars );
1138 if ( cnt == 2 && ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, vars[lastNonzero-1])) )
1139 continue;
1140
1141 assert( !SCIPisFeasZero(scip, weight2) );
1142 w = weight1/weight2; /*lint !e795*/
1143
1144 ind = (int) SCIPfeasFloor(scip, w);
1145 assert( 0 <= ind && ind < nvars-1 );
1146
1147 /* correct index if necessary - see above for an explanation */
1148 if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, vars[ind])) && ind < lastNonzero-1 )
1149 ++ind;
1150
1151 /* check if the constraint has more nonzeros */
1152 if ( cnt > maxNonzeros )
1153 {
1154 maxNonzeros = cnt;
1155 branchCons = cons;
1156 maxInd = ind;
1157 }
1158 }
1159
1160 /* if all constraints are feasible */
1161 if ( branchCons == NULL )
1162 {
1163 SCIPdebugMsg(scip, "All SOS2 constraints are feasible.\n");
1164 return SCIP_OKAY;
1165 }
1166
1167 /* create branches */
1168 consdata = SCIPconsGetData(branchCons);
1169 assert( consdata != NULL );
1170 nvars = consdata->nvars;
1171 vars = consdata->vars;
1172
1173 assert( 0 < maxInd && maxInd < nvars-1 );
1174
1175 /* branch on variable ind: either all variables before ind or all variables after ind are zero */
1176 SCIPdebugMsg(scip, "Branching on variable <%s> in constraint <%s> (nonzeros: %d).\n", SCIPvarGetName(vars[maxInd]),
1177 SCIPconsGetName(branchCons), maxNonzeros);
1178
1179 /* calculate node selection and objective estimate for node 1 */
1180 nodeselest = 0.0;
1182 for (j = 0; j < maxInd; ++j)
1183 {
1186 }
1188
1189 /* create node 1 */
1190 SCIP_CALL( SCIPcreateChild(scip, &node1, nodeselest, objest) );
1191
1192 for (j = 0; j < maxInd; ++j)
1193 {
1194 SCIP_CALL( fixVariableZeroNode(scip, vars[j], node1, &infeasible) );
1195 assert( ! infeasible );
1196 }
1197
1198 /* calculate node selection and objective estimate for node 2 */
1199 nodeselest = 0.0;
1201 for (j = maxInd+1; j < nvars; ++j)
1202 {
1205 }
1207
1208 /* create node 2 */
1209 SCIP_CALL( SCIPcreateChild(scip, &node2, nodeselest, objest) );
1210 for (j = maxInd+1; j < nvars; ++j)
1211 {
1212 SCIP_CALL( fixVariableZeroNode(scip, vars[j], node2, &infeasible) );
1213 assert( ! infeasible );
1214 }
1217
1218 return SCIP_OKAY;
1219}
1220
1221
1222/** Generate basic row
1223 *
1224 * We generate the row corresponding to the following simple valid
1225 * inequalities. Let \f$U\f$ and \f$U'\f$ be the largest and second
1226 * largest upper bound of variables appearing in the
1227 * constraint. Similarly let \f$L\f$ and \f$L'\f$ be the smallest and
1228 * second smallest lower bound. The inequalities are:
1229 * \f[
1230 * x_1 + \ldots + x_n \leq U + U' \qquad\mbox{and}\qquad
1231 * x_1 + \ldots + x_n \geq L + L'.
1232 * \f]
1233 * Of course, these inequalities are only added if the upper and
1234 * lower bounds are all finite and \f$L+L' < 0\f$ or \f$U+U' > 0\f$.
1235 */
1236static
1238 SCIP* scip, /**< SCIP pointer */
1239 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1240 SCIP_CONS* cons, /**< constraint */
1241 SCIP_Bool local /**< produce local cut? */
1242 )
1243{
1244 char name[SCIP_MAXSTRLEN];
1245 SCIP_CONSDATA* consdata;
1246 SCIP_VAR** vars;
1247 SCIP_Real minLb = SCIPinfinity(scip);
1248 SCIP_Real minLb2 = SCIPinfinity(scip);
1249 SCIP_Real maxUb = -SCIPinfinity(scip);
1250 SCIP_Real maxUb2 = -SCIPinfinity(scip);
1251 SCIP_Real lhs;
1252 SCIP_Real rhs;
1253 SCIP_ROW* row;
1254 int nvars;
1255 int j;
1256
1257 assert( scip != NULL );
1258 assert( conshdlr != NULL );
1259 assert( cons != NULL );
1260
1261 consdata = SCIPconsGetData(cons);
1262 assert( consdata != NULL );
1263 assert( consdata->row == NULL );
1264
1265 nvars = consdata->nvars;
1266 vars = consdata->vars;
1267 assert( vars != NULL );
1268
1269 /* find minimum and maximum lower and upper bounds */
1270 for (j = 0; j < nvars; ++j)
1271 {
1272 SCIP_Real val;
1273
1274 if ( local )
1275 val = SCIPvarGetLbLocal(vars[j]);
1276 else
1277 val = SCIPvarGetLbGlobal(vars[j]);
1278
1279 if ( val < minLb )
1280 {
1281 minLb2 = minLb;
1282 minLb = val;
1283 }
1284 else
1285 {
1286 if ( val < minLb2 )
1287 minLb2 = val;
1288 }
1289
1290 if ( local )
1291 val = SCIPvarGetUbLocal(vars[j]);
1292 else
1293 val = SCIPvarGetUbGlobal(vars[j]);
1294
1295 if ( val > maxUb )
1296 {
1297 maxUb2 = maxUb;
1298 maxUb = val;
1299 }
1300 else
1301 {
1302 if ( val > maxUb2 )
1303 maxUb2 = val;
1304 }
1305 }
1306 lhs = minLb + minLb2;
1307 rhs = maxUb + maxUb2;
1308
1309 /* ignore trivial inequality if left hand side would be 0 */
1310 if ( SCIPisFeasZero(scip, lhs) )
1311 lhs = -SCIPinfinity(scip);
1312
1313 /* ignore trivial inequality if right hand side would be 0 */
1314 if ( SCIPisFeasZero(scip, rhs) )
1315 rhs = SCIPinfinity(scip);
1316
1317 /* create upper and lower bound inequality if one of the bounds is finite */
1318 if ( ! SCIPisInfinity(scip, REALABS(lhs)) || ! SCIPisInfinity(scip, REALABS(rhs)) )
1319 {
1320 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "sos2bnd#%s", SCIPconsGetName(cons));
1321 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, lhs, rhs, local, FALSE, FALSE) );
1323 consdata->row = row;
1324
1326 }
1327
1328 return SCIP_OKAY;
1329}
1330
1331
1332/* ---------------------------- constraint handler callback methods ----------------------*/
1333
1334/** copy method for constraint handler plugins (called when SCIP copies plugins) */
1335static
1336SCIP_DECL_CONSHDLRCOPY(conshdlrCopySOS2)
1337{ /*lint --e{715}*/
1338 assert( scip != NULL );
1339 assert( conshdlr != NULL );
1340
1342
1343 /* call inclusion method of constraint handler */
1345
1346 *valid = TRUE;
1347
1348 return SCIP_OKAY;
1349}
1350
1351
1352/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
1353static
1355{
1356 SCIP_CONSHDLRDATA* conshdlrdata;
1357
1358 assert( scip != NULL );
1359 assert( conshdlr != NULL );
1360
1362
1363 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1364 assert(conshdlrdata != NULL);
1365
1366 SCIPfreeBlockMemory(scip, &conshdlrdata);
1367
1368 return SCIP_OKAY;
1369}
1370
1371
1372/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
1373static
1375{ /*lint --e{715}*/
1376 int c;
1377
1378 assert( scip != NULL );
1379 assert( conshdlr != NULL );
1380
1382
1383 /* check each constraint */
1384 for (c = 0; c < nconss; ++c)
1385 {
1386 SCIP_CONSDATA* consdata;
1387
1388 assert( conss != NULL );
1389 assert( conss[c] != NULL );
1390 consdata = SCIPconsGetData(conss[c]);
1391 assert( consdata != NULL );
1392
1393 SCIPdebugMsg(scip, "Exiting SOS2 constraint <%s>.\n", SCIPconsGetName(conss[c]) );
1394
1395 /* free row */
1396 if ( consdata->row != NULL )
1397 {
1398 SCIP_CALL( SCIPreleaseRow(scip, &consdata->row) );
1399 }
1400 }
1401 return SCIP_OKAY;
1402}
1403
1404
1405/** frees specific constraint data */
1406static
1408{
1409 assert( scip != NULL );
1410 assert( conshdlr != NULL );
1411 assert( cons != NULL );
1412 assert( consdata != NULL );
1413
1415
1416 SCIPdebugMsg(scip, "Deleting SOS2 constraint <%s>.\n", SCIPconsGetName(cons) );
1417
1418 /* drop events on transformed variables */
1419 if ( SCIPconsIsTransformed(cons) )
1420 {
1421 SCIP_CONSHDLRDATA* conshdlrdata;
1422 int j;
1423
1424 /* get constraint handler data */
1425 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1426 assert( conshdlrdata != NULL );
1427 assert( conshdlrdata->eventhdlr != NULL );
1428
1429 for (j = 0; j < (*consdata)->nvars; ++j)
1430 {
1431 SCIP_CALL( SCIPdropVarEvent(scip, (*consdata)->vars[j], EVENTHDLR_EVENT_TYPE, conshdlrdata->eventhdlr,
1432 (SCIP_EVENTDATA*)cons, -1) );
1433 }
1434 }
1435
1436 SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->maxvars);
1437 if ( (*consdata)->weights != NULL )
1438 {
1439 SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->maxvars);
1440 }
1441
1442 /* free row */
1443 if ( (*consdata)->row != NULL )
1444 {
1445 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->row) );
1446 }
1447 assert( (*consdata)->row == NULL );
1448
1449 SCIPfreeBlockMemory(scip, consdata);
1450
1451 return SCIP_OKAY;
1452}
1453
1454
1455/** transforms constraint data into data belonging to the transformed problem */
1456static
1458{
1459 SCIP_CONSDATA* consdata;
1460 SCIP_CONSHDLRDATA* conshdlrdata;
1461 SCIP_CONSDATA* sourcedata;
1462 char s[SCIP_MAXSTRLEN];
1463 int j;
1464
1465 assert( scip != NULL );
1466 assert( conshdlr != NULL );
1467 assert( sourcecons != NULL );
1468 assert( targetcons != NULL );
1469
1471
1472 /* get constraint handler data */
1473 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1474 assert( conshdlrdata != NULL );
1475 assert( conshdlrdata->eventhdlr != NULL );
1476
1477 SCIPdebugMsg(scip, "Transforming SOS2 constraint: <%s>.\n", SCIPconsGetName(sourcecons) );
1478
1479 /* get data of original constraint */
1480 sourcedata = SCIPconsGetData(sourcecons);
1481 assert( sourcedata != NULL );
1482 assert( sourcedata->nvars > 0 );
1483 assert( sourcedata->nvars <= sourcedata->maxvars );
1484
1485 /* create constraint data */
1486 SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) );
1487
1488 consdata->nvars = sourcedata->nvars;
1489 consdata->maxvars = sourcedata->nvars;
1490 consdata->row = NULL;
1491 consdata->nfixednonzeros = 0;
1492 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->vars, consdata->nvars) );
1493
1494 /* if weights were used */
1495 if ( sourcedata->weights != NULL )
1496 {
1497 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->weights, sourcedata->weights, consdata->nvars) );
1498 }
1499 else
1500 consdata->weights = NULL;
1501
1502 for (j = 0; j < sourcedata->nvars; ++j)
1503 {
1504 assert( sourcedata->vars[j] != 0 );
1505 SCIP_CALL( SCIPgetTransformedVar(scip, sourcedata->vars[j], &(consdata->vars[j])) );
1506
1507 /* if variable is fixed to be nonzero */
1508 if ( SCIPisFeasPositive(scip, SCIPvarGetLbLocal(consdata->vars[j])) || SCIPisFeasNegative(scip, SCIPvarGetUbLocal(consdata->vars[j])) )
1509 ++(consdata->nfixednonzeros);
1510 }
1511
1512 /* create transformed constraint with the same flags */
1513 (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "t_%s", SCIPconsGetName(sourcecons));
1514 SCIP_CALL( SCIPcreateCons(scip, targetcons, s, conshdlr, consdata,
1515 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons),
1516 SCIPconsIsEnforced(sourcecons), SCIPconsIsChecked(sourcecons),
1517 SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
1518 SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons),
1519 SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
1520
1521 /* catch bound change events on variable */
1522 for (j = 0; j < consdata->nvars; ++j)
1523 {
1524 SCIP_CALL( SCIPcatchVarEvent(scip, consdata->vars[j], EVENTHDLR_EVENT_TYPE, conshdlrdata->eventhdlr,
1525 (SCIP_EVENTDATA*)*targetcons, NULL) );
1526 }
1527
1528#ifdef SCIP_DEBUG
1529 if ( consdata->nfixednonzeros > 0 )
1530 {
1531 SCIPdebugMsg(scip, "constraint <%s> has %d variables fixed to be nonzero.\n", SCIPconsGetName(*targetcons), consdata->nfixednonzeros );
1532 }
1533#endif
1534
1535 return SCIP_OKAY;
1536}
1537
1538
1539/** presolving method of constraint handler */
1540static
1542{ /*lint --e{715}*/
1543 SCIPdebug( int oldnfixedvars = *nfixedvars; )
1544 SCIPdebug( int oldndelconss = *ndelconss; )
1545 int nremovedvars;
1546 SCIP_EVENTHDLR* eventhdlr;
1547 int c;
1548
1549 assert( scip != NULL );
1550 assert( conshdlr != NULL );
1551 assert( result != NULL );
1552
1554
1556 nremovedvars = 0;
1557
1558 /* only run if success is possible */
1559 if( nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 || nnewchgcoefs > 0 )
1560 {
1561 /* get constraint handler data */
1562 assert( SCIPconshdlrGetData(conshdlr) != NULL );
1563 eventhdlr = SCIPconshdlrGetData(conshdlr)->eventhdlr;
1564 assert( eventhdlr != NULL );
1565
1567
1568 /* check each constraint */
1569 for (c = 0; c < nconss; ++c)
1570 {
1571 SCIP_CONSDATA* consdata;
1572 SCIP_CONS* cons;
1574 SCIP_Bool success;
1575
1576 assert( conss != NULL );
1577 assert( conss[c] != NULL );
1578
1579 cons = conss[c];
1580 consdata = SCIPconsGetData(cons);
1581
1582 assert( consdata != NULL );
1583 assert( consdata->nvars >= 0 );
1584 assert( consdata->nvars <= consdata->maxvars );
1585 assert( ! SCIPconsIsModifiable(cons) );
1586
1587 /* perform one presolving round */
1588 SCIP_CALL( presolRoundSOS2(scip, cons, consdata, eventhdlr, &cutoff, &success, ndelconss, nfixedvars, &nremovedvars) );
1589
1590 if ( cutoff )
1591 {
1593 return SCIP_OKAY;
1594 }
1595
1596 if ( success )
1598 }
1599 }
1600 (*nchgcoefs) += nremovedvars;
1601
1602 SCIPdebug( SCIPdebugMsg(scip, "presolving fixed %d variables, removed %d variables, and deleted %d constraints.\n",
1603 *nfixedvars - oldnfixedvars, nremovedvars, *ndelconss - oldndelconss); )
1604
1605 return SCIP_OKAY;
1606}
1607
1608
1609/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
1610static
1612{
1613 int c;
1614
1615 assert( scip != NULL );
1616 assert( conshdlr != NULL );
1617
1619
1620 *infeasible = FALSE;
1621
1622 /* check each constraint */
1623 for (c = 0; c < nconss && !(*infeasible); ++c)
1624 {
1625 SCIP_CONSDATA* consdata;
1626
1627 assert( conss != NULL );
1628 assert( conss[c] != NULL );
1629 consdata = SCIPconsGetData(conss[c]);
1630 assert( consdata != NULL );
1631
1632 SCIPdebugMsg(scip, "Checking for initial rows for SOS2 constraint <%s>.\n", SCIPconsGetName(conss[c]) );
1633
1634 /* possibly generate row if not yet done */
1635 if ( consdata->row == NULL )
1636 {
1637 SCIP_CALL( generateRowSOS2(scip, conshdlr, conss[c], FALSE) );
1638 }
1639
1640 /* put corresponding rows into LP */
1641 if ( consdata->row != NULL && ! SCIProwIsInLP(consdata->row) )
1642 {
1643 assert( ! SCIPisInfinity(scip, REALABS(SCIProwGetLhs(consdata->row))) || ! SCIPisInfinity(scip, REALABS(SCIProwGetRhs(consdata->row))) );
1644
1645 SCIP_CALL( SCIPaddRow(scip, consdata->row, FALSE, infeasible) );
1646 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, consdata->row, NULL) ) );
1647 }
1648 }
1649
1650 return SCIP_OKAY;
1651}
1652
1653
1654/** separation method of constraint handler for LP solutions */
1655static
1657{ /*lint --e{715}*/
1659 int c;
1660 int ngen = 0;
1661
1662 assert( scip != NULL );
1663 assert( conshdlr != NULL );
1664 assert( conss != NULL );
1665 assert( result != NULL );
1666
1668
1670
1671 /* check each constraint */
1672 for (c = 0; c < nconss && ! cutoff; ++c)
1673 {
1674 SCIP_CONSDATA* consdata;
1675 SCIP_ROW* row;
1676
1678 assert( conss[c] != NULL );
1679 consdata = SCIPconsGetData(conss[c]);
1680 assert( consdata != NULL );
1681 SCIPdebugMsg(scip, "Separating inequalities for SOS2 constraint <%s>.\n", SCIPconsGetName(conss[c]) );
1682
1683 /* possibly generate row if not yet done */
1684 if ( consdata->row == NULL )
1685 {
1686 SCIP_CALL( generateRowSOS2(scip, conshdlr, conss[c], FALSE) );
1687 }
1688
1689 /* put corresponding rows into LP if they are useful */
1690 row = consdata->row;
1691
1692 /* possibly add row to LP if it is useful */
1693 if ( row != NULL && ! SCIProwIsInLP(row) && SCIPisCutEfficacious(scip, NULL, row) )
1694 {
1695 SCIP_CALL( SCIPaddRow(scip, row, FALSE, &cutoff) );
1697 SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
1698 ++ngen;
1699 }
1700 }
1701 SCIPdebugMsg(scip, "Separated %d SOS2 constraints.\n", ngen);
1702 if ( cutoff )
1704 else if ( ngen > 0 )
1706
1707 return SCIP_OKAY;
1708}
1709
1710
1711/** separation method of constraint handler for arbitrary primal solutions */
1712static
1714{ /*lint --e{715}*/
1716 int c;
1717 int ngen = 0;
1718
1719 assert( scip != NULL );
1720 assert( conshdlr != NULL );
1721 assert( conss != NULL );
1722 assert( result != NULL );
1723
1725
1727
1728 /* check each constraint */
1729 for (c = 0; c < nconss && ! cutoff; ++c)
1730 {
1731 SCIP_CONSDATA* consdata;
1732 SCIP_ROW* row;
1733
1735 assert( conss[c] != NULL );
1736 consdata = SCIPconsGetData(conss[c]);
1737 assert( consdata != NULL );
1738 SCIPdebugMsg(scip, "Separating solution for SOS2 constraint <%s>.\n", SCIPconsGetName(conss[c]) );
1739
1740 /* put corresponding row into LP if it is useful */
1741 row = consdata->row;
1742
1743 /* possibly generate row if not yet done */
1744 if ( row == NULL )
1745 {
1746 SCIP_CALL( generateRowSOS2(scip, conshdlr, conss[c], FALSE) );
1747 }
1748
1749 /* possibly add row to LP if it is useful */
1750 if ( row != NULL && ! SCIProwIsInLP(row) && SCIPisCutEfficacious(scip, sol, row) )
1751 {
1752 SCIP_CALL( SCIPaddRow(scip, row, FALSE, &cutoff) );
1754 SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
1755 ++ngen;
1756 }
1757 }
1758 SCIPdebugMsg(scip, "Separated %d SOS2 constraints.\n", ngen);
1759 if ( cutoff )
1761 else if ( ngen > 0 )
1763
1764 return SCIP_OKAY;
1765}
1766
1767
1768/** constraint enforcing method of constraint handler for LP solutions */
1769static
1771{ /*lint --e{715}*/
1772 assert( scip != NULL );
1773 assert( conshdlr != NULL );
1774 assert( conss != NULL );
1775 assert( result != NULL );
1776
1778
1779 SCIP_CALL( enforceSOS2(scip, conshdlr, nconss, conss, NULL, result) );
1780
1781 return SCIP_OKAY;
1782}
1783
1784
1785/** constraint enforcing method of constraint handler for relaxation solutions */
1786static
1787SCIP_DECL_CONSENFORELAX(consEnforelaxSOS2)
1788{ /*lint --e{715}*/
1789 assert( scip != NULL );
1790 assert( conshdlr != NULL );
1791 assert( conss != NULL );
1792 assert( result != NULL );
1793
1795
1796 SCIP_CALL( enforceSOS2(scip, conshdlr, nconss, conss, sol, result) );
1797
1798 return SCIP_OKAY;
1799}
1800
1801
1802/** constraint enforcing method of constraint handler for pseudo solutions */
1803static
1805{ /*lint --e{715}*/
1806 assert( scip != NULL );
1807 assert( conshdlr != NULL );
1808 assert( conss != NULL );
1809 assert( result != NULL );
1810
1812
1813 SCIP_CALL( enforceSOS2(scip, conshdlr, nconss, conss, NULL, result) );
1814
1815 return SCIP_OKAY;
1816}
1817
1818
1819/** feasibility check method of constraint handler for integral solutions
1820 *
1821 * We simply check whether at most two variable are nonzero and in the
1822 * case there are exactly two nonzero, then they have to be direct
1823 * neighbors in the given solution.
1824 */
1825static
1827{ /*lint --e{715}*/
1828 int c;
1829
1830 assert( scip != NULL );
1831 assert( conshdlr != NULL );
1832 assert( conss != NULL );
1833 assert( result != NULL );
1834
1836
1838
1839 /* check each constraint */
1840 for (c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c)
1841 {
1842 SCIP_CONSDATA* consdata;
1843 int firstNonzero;
1844 int j;
1845
1846 firstNonzero = -1;
1847 assert( conss[c] != NULL );
1848 consdata = SCIPconsGetData(conss[c]);
1849 assert( consdata != NULL );
1850 SCIPdebugMsg(scip, "Checking SOS2 constraint <%s>.\n", SCIPconsGetName(conss[c]));
1851
1852 /* check all variables */
1853 for (j = 0; j < consdata->nvars; ++j)
1854 {
1855 /* if variable is nonzero */
1856 if ( ! SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->vars[j])) )
1857 {
1858 if ( firstNonzero < 0 )
1859 firstNonzero = j;
1860 else
1861 {
1862 /* if we are more than one position away from the firstNonzero variable */
1863 if ( j > firstNonzero+1 )
1864 {
1865 SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
1867
1868 /* update constraint violation in solution */
1869 if ( sol != NULL )
1871
1872 if ( printreason )
1873 {
1874 SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
1875
1876 SCIPinfoMessage(scip, NULL, ";\nviolation: <%s> = %.15g and <%s> = %.15g\n",
1877 SCIPvarGetName(consdata->vars[firstNonzero]),
1878 SCIPgetSolVal(scip, sol, consdata->vars[firstNonzero]),
1879 SCIPvarGetName(consdata->vars[j]),
1880 SCIPgetSolVal(scip, sol, consdata->vars[j]));
1881 }
1882
1883 SCIPdebugMsg(scip, "SOS2 constraint <%s> infeasible.\n", SCIPconsGetName(conss[c]));
1884 }
1885 }
1886 }
1887 }
1888 }
1889
1890 return SCIP_OKAY;
1891}
1892
1893
1894/** domain propagation method of constraint handler */
1895static
1897{ /*lint --e{715}*/
1898 int c;
1899 int ngen = 0;
1900
1901 assert( scip != NULL );
1902 assert( conshdlr != NULL );
1903 assert( conss != NULL );
1904 assert( result != NULL );
1905
1907
1909
1911
1912 /* check each constraint */
1913 for (c = 0; c < nconss; ++c)
1914 {
1915 SCIP_CONS* cons;
1916 SCIP_CONSDATA* consdata;
1918
1919 assert( conss[c] != NULL );
1920 cons = conss[c];
1921 consdata = SCIPconsGetData(cons);
1922 assert( consdata != NULL );
1923 SCIPdebugMsg(scip, "Propagating SOS2 constraint <%s>.\n", SCIPconsGetName(cons) );
1924
1926 SCIP_CALL( propSOS2(scip, cons, consdata, &cutoff, &ngen) );
1927 if ( cutoff )
1928 {
1930 return SCIP_OKAY;
1931 }
1932 }
1933 SCIPdebugMsg(scip, "Propagated %d domains.\n", ngen);
1934 if ( ngen > 0 )
1936
1937 return SCIP_OKAY;
1938}
1939
1940
1941/** propagation conflict resolving method of constraint handler
1942 *
1943 * We check which bound changes were the reason for infeasibility. We
1944 * use that @a inferinfo stores the index of the variable that has
1945 * bounds that fix it to be nonzero (these bounds are the reason). */
1946static
1948{ /*lint --e{715}*/
1949 SCIP_CONSDATA* consdata;
1950 SCIP_VAR* var;
1951
1952 assert( scip != NULL );
1953 assert( cons != NULL );
1954 assert( infervar != NULL );
1955 assert( bdchgidx != NULL );
1956 assert( result != NULL );
1957
1959
1961 SCIPdebugMsg(scip, "Propagation resolution method of SOS2 constraint <%s>.\n", SCIPconsGetName(cons));
1962
1963 consdata = SCIPconsGetData(cons);
1964 assert( consdata != NULL );
1965 assert( 0 <= inferinfo && inferinfo < consdata->nvars );
1966 var = consdata->vars[inferinfo];
1967 assert( var != infervar );
1968
1969 /* check if lower bound of var was the reason */
1971 {
1972 SCIP_CALL( SCIPaddConflictLb(scip, var, bdchgidx) );
1974 }
1975
1976 /* check if upper bound of var was the reason */
1978 {
1979 SCIP_CALL( SCIPaddConflictUb(scip, var, bdchgidx) );
1981 }
1982
1983 return SCIP_OKAY;
1984}
1985
1986
1987/** variable rounding lock method of constraint handler
1988 *
1989 * Let lb and ub be the lower and upper bounds of a
1990 * variable. Preprocessing usually makes sure that lb <= 0 <= ub.
1991 *
1992 * - If lb < 0 then rounding down may violate the constraint.
1993 * - If ub > 0 then rounding up may violated the constraint.
1994 * - If lb > 0 or ub < 0 then the constraint is infeasible and we do
1995 * not have to deal with it here.
1996 * - If lb == 0 then rounding down does not violate the constraint.
1997 * - If ub == 0 then rounding up does not violate the constraint.
1998 */
1999static
2001{
2002 SCIP_CONSDATA* consdata;
2003 SCIP_VAR** vars;
2004 int nvars;
2005 int j;
2006
2007 assert( scip != NULL );
2008 assert( conshdlr != NULL );
2009 assert( cons != NULL );
2010 assert(locktype == SCIP_LOCKTYPE_MODEL);
2011
2013
2014 consdata = SCIPconsGetData(cons);
2015 assert( consdata != NULL );
2016
2017 SCIPdebugMsg(scip, "Locking constraint <%s>.\n", SCIPconsGetName(cons));
2018
2019 vars = consdata->vars;
2020 nvars = consdata->nvars;
2021 assert( vars != NULL );
2022
2023 for (j = 0; j < nvars; ++j)
2024 {
2025 SCIP_VAR* var;
2026 var = vars[j];
2027
2028 /* if lower bound is negative, rounding down may violate constraint */
2030 SCIP_CALL( SCIPaddVarLocksType(scip, var, locktype, nlockspos, nlocksneg) );
2031
2032 /* additionally: if upper bound is positive, rounding up may violate constraint */
2034 SCIP_CALL( SCIPaddVarLocksType(scip, var, locktype, nlocksneg, nlockspos) );
2035 }
2036
2037 return SCIP_OKAY;
2038}
2039
2040
2041/** constraint display method of constraint handler */
2042static
2044{ /*lint --e{715}*/
2045 SCIP_CONSDATA* consdata;
2046 int j;
2047
2048 assert( scip != NULL );
2049 assert( conshdlr != NULL );
2050 assert( cons != NULL );
2051
2053
2054 consdata = SCIPconsGetData(cons);
2055 assert( consdata != NULL );
2056
2057 for (j = 0; j < consdata->nvars; ++j)
2058 {
2059 if ( j > 0 )
2060 SCIPinfoMessage(scip, file, ", ");
2061 SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[j], FALSE) );
2062 if ( consdata->weights == NULL )
2063 SCIPinfoMessage(scip, file, " (%d)", j+1);
2064 else
2065 SCIPinfoMessage(scip, file, " (%3.2f)", consdata->weights[j]);
2066 }
2067
2068 return SCIP_OKAY;
2069}
2070
2071
2072/** constraint copying method of constraint handler */
2073static
2075{ /*lint --e{715}*/
2076 SCIP_CONSDATA* sourceconsdata;
2077 SCIP_VAR** sourcevars;
2078 SCIP_VAR** targetvars;
2079 SCIP_Real* targetweights = NULL;
2080 const char* consname;
2081 int nvars;
2082 int v;
2083
2084 assert( scip != NULL );
2085 assert( sourcescip != NULL );
2086 assert( sourcecons != NULL );
2087 assert( valid != NULL );
2088
2090
2091 *valid = TRUE;
2092
2093 if ( name != NULL )
2094 consname = name;
2095 else
2096 consname = SCIPconsGetName(sourcecons);
2097
2098 SCIPdebugMsg(scip, "Copying SOS2 constraint <%s> ...\n", consname);
2099
2100 sourceconsdata = SCIPconsGetData(sourcecons);
2101 assert( sourceconsdata != NULL );
2102
2103 /* get variables and weights of the source constraint */
2104 nvars = sourceconsdata->nvars;
2105 assert( nvars >= 0 );
2106
2107 /* duplicate weights array */
2108 if ( sourceconsdata->weights != NULL )
2109 {
2110 SCIP_CALL( SCIPduplicateBufferArray(sourcescip, &targetweights, sourceconsdata->weights, nvars) );
2111 }
2112
2113 /* get copied variables in target SCIP */
2114 sourcevars = sourceconsdata->vars;
2115 SCIP_CALL( SCIPallocBufferArray(sourcescip, &targetvars, nvars) );
2116 for (v = 0; v < nvars && *valid; ++v)
2117 {
2118 assert( sourcevars != NULL );
2119 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &(targetvars[v]), varmap, consmap, global, valid) );
2120 }
2121
2122 /* only create the target constraint, if all variables could be copied */
2123 if( *valid )
2124 {
2125 SCIP_CALL( SCIPcreateConsSOS2(scip, cons, consname, nvars, targetvars, targetweights,
2126 initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
2127 }
2128
2129 /* free buffer array */
2130 SCIPfreeBufferArray(sourcescip, &targetvars);
2131 SCIPfreeBufferArrayNull(sourcescip, &targetweights);
2132
2133 return SCIP_OKAY;
2134}
2135
2136
2137/** constraint parsing method of constraint handler */
2138static
2140{ /*lint --e{715}*/
2141 SCIP_VAR* var;
2142 SCIP_Real weight;
2143 const char* s;
2144 char* t;
2145
2146 *success = TRUE;
2147 s = str;
2148
2149 /* create empty SOS2 constraint */
2150 SCIP_CALL( SCIPcreateConsSOS2(scip, cons, name, 0, NULL, NULL, initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
2151
2152 /* loop through string */
2153 while( *s != '\0' )
2154 {
2155 /* parse variable name */
2156 SCIP_CALL( SCIPparseVarName(scip, s, &var, &t) );
2157
2158 if( var == NULL )
2159 break;
2160
2161 /* skip until beginning of weight */
2162 t = strchr(t, '(');
2163
2164 if( t == NULL )
2165 {
2166 SCIPerrorMessage("Syntax error: expected opening '(' at input: %s\n", s);
2167 *success = FALSE;
2168 break;
2169 }
2170
2171 s = t;
2172
2173 /* skip '(' */
2174 ++s;
2175
2176 /* find weight */
2177 weight = strtod(s, &t);
2178
2179 if( t == NULL )
2180 {
2181 SCIPerrorMessage("Syntax error during parsing of the weight: %s\n", s);
2182 *success = FALSE;
2183 break;
2184 }
2185
2186 s = t;
2187
2188 /* skip until ending of weight */
2189 t = strchr(t, ')');
2190
2191 if( t == NULL )
2192 {
2193 SCIPerrorMessage("Syntax error: expected closing ')' at input %s\n", s);
2194 *success = FALSE;
2195 break;
2196 }
2197
2198 s = t;
2199
2200 /* skip ')' */
2201 ++s;
2202
2203 /* skip white space */
2204 SCIP_CALL( SCIPskipSpace((char**)&s) );
2205
2206 /* skip ',' */
2207 if( *s == ',' )
2208 ++s;
2209
2210 /* add variable */
2211 SCIP_CALL( SCIPaddVarSOS2(scip, *cons, var, weight) );
2212 }
2213
2214 if( !*success )
2215 SCIP_CALL( SCIPreleaseCons(scip, cons) );
2216
2217 return SCIP_OKAY;
2218}
2219
2220
2221/** constraint method of constraint handler which returns the variables (if possible) */
2222static
2224{ /*lint --e{715}*/
2225 SCIP_CONSDATA* consdata;
2226
2227 consdata = SCIPconsGetData(cons);
2228 assert(consdata != NULL);
2229
2230 if( varssize < consdata->nvars )
2231 (*success) = FALSE;
2232 else
2233 {
2234 assert(vars != NULL);
2235
2236 BMScopyMemoryArray(vars, consdata->vars, consdata->nvars);
2237 (*success) = TRUE;
2238 }
2239
2240 return SCIP_OKAY;
2241}
2242
2243
2244/** constraint method of constraint handler which returns the number of variables (if possible) */
2245static
2246SCIP_DECL_CONSGETNVARS(consGetNVarsSOS2)
2247{ /*lint --e{715}*/
2248 SCIP_CONSDATA* consdata;
2249
2250 consdata = SCIPconsGetData(cons);
2251 assert(consdata != NULL);
2252
2253 (*nvars) = consdata->nvars;
2254 (*success) = TRUE;
2255
2256 return SCIP_OKAY;
2257}
2258
2259
2260/** constraint handler method which returns the permutation symmetry detection graph of a constraint */
2261static
2262SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphSOS2)
2263{ /*lint --e{715}*/
2264 SCIP_CONSDATA* consdata;
2265 SCIP_VAR** consvars;
2266 SCIP_VAR** locvars;
2267 SCIP_Real* locvals;
2268 SCIP_Real constant;
2269 int consnodeidx;
2270 int opnodeidx;
2271 int nodeidx;
2272 int nconsvars;
2273 int nlocvars;
2274 int nvars;
2275 int i;
2276 int j;
2277
2278 assert(success != NULL);
2279
2280 consdata = SCIPconsGetData(cons);
2281 assert(consdata != NULL);
2282
2283 /* get active variables of the constraint */
2285 nconsvars = consdata->nvars;
2286 consvars = SCIPgetVarsSOS2(scip, cons);
2287 assert(consvars != NULL);
2288
2291
2292 /* add node initializing constraint (with artificial rhs) */
2293 SCIP_CALL( SCIPaddSymgraphConsnode(scip, graph, cons, 0.0, 0.0, &consnodeidx) );
2294
2295 /* for all pairs of variables, add a node indicating a tuple and add nodes for (aggregated) variables */
2296 for( i = 0; i < nconsvars - 1; ++i )
2297 {
2298 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SOS2_TUPLE, &opnodeidx) ); /*lint !e641*/
2299 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, consnodeidx, opnodeidx, FALSE, 0.0) );
2300
2301 for( j = i; j < i + 2; ++j )
2302 {
2303 locvars[0] = consvars[j];
2304 locvals[0] = 1.0;
2305 constant = 0.0;
2306 nlocvars = 1;
2307
2308 /* ignore weights of SOS2 constraint (variables are sorted according to these weights) */
2310 &nlocvars, &constant, SCIPisTransformed(scip)) );
2311
2312 if( nlocvars == 1 && SCIPisZero(scip, constant) && SCIPisEQ(scip, locvals[0], 1.0) )
2313 {
2314 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, locvars[0]);
2315 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, opnodeidx, nodeidx, FALSE, 0.0) );
2316 }
2317 else
2318 {
2319 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &nodeidx) ); /*lint !e641*/
2320 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, opnodeidx, nodeidx, FALSE, 0.0) );
2321 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, nodeidx, locvars, locvals, nlocvars, constant) );
2322 }
2323 }
2324 }
2325
2326 SCIPfreeBufferArray(scip, &locvals);
2327 SCIPfreeBufferArray(scip, &locvars);
2328
2329 *success = TRUE;
2330
2331 return SCIP_OKAY;
2332}
2333
2334
2335/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */
2336static
2337SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphSOS2)
2338{ /*lint --e{715}*/
2339 SCIP_CONSDATA* consdata;
2340 SCIP_VAR** consvars;
2341 SCIP_VAR** locvars;
2342 SCIP_Real* locvals;
2343 SCIP_Real constant;
2344 int consnodeidx;
2345 int opnodeidx;
2346 int nodeidx;
2347 int nconsvars;
2348 int nlocvars;
2349 int nvars;
2350 int i;
2351 int j;
2352
2353 assert(success != NULL);
2354
2355 consdata = SCIPconsGetData(cons);
2356 assert(consdata != NULL);
2357
2358 /* get active variables of the constraint */
2360 nconsvars = consdata->nvars;
2361 consvars = SCIPgetVarsSOS2(scip, cons);
2362 assert(consvars != NULL);
2363
2366
2367 /* add node initializing constraint (with artificial rhs) */
2368 SCIP_CALL( SCIPaddSymgraphConsnode(scip, graph, cons, 0.0, 0.0, &consnodeidx) );
2369
2370 /* for all pairs of variables, add a node indicating a tuple and add nodes for (aggregated) variables */
2371 for( i = 0; i < nconsvars - 1; ++i )
2372 {
2373 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SOS2_TUPLE, &opnodeidx) ); /*lint !e641*/
2374 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, consnodeidx, opnodeidx, FALSE, 0.0) );
2375
2376 for( j = i; j < i + 2; ++j )
2377 {
2378 locvars[0] = consvars[j];
2379 locvals[0] = 1.0;
2380 constant = 0.0;
2381 nlocvars = 1;
2382
2383 /* ignore weights of SOS2 constraint (variables are sorted according to these weights) */
2384
2385 /* use SYM_SYMTYPE_PERM here to NOT center variable domains at 0, as the latter might not preserve
2386 * SOS1 constraints */
2388 &nlocvars, &constant, SCIPisTransformed(scip)) );
2389
2390 if( nlocvars == 1 && SCIPisZero(scip, constant) && SCIPisEQ(scip, locvals[0], 1.0) )
2391 {
2392 SCIP_Bool allownegation = FALSE;
2393
2394 /* a negation is allowed if it is centered around 0 */
2395 if ( SCIPisInfinity(scip, -SCIPvarGetLbGlobal(locvars[0])) == SCIPisInfinity(scip, SCIPvarGetUbGlobal(locvars[0]))
2396 && (SCIPisInfinity(scip, SCIPvarGetUbGlobal(locvars[0]))
2397 || SCIPisZero(scip, (SCIPvarGetLbGlobal(locvars[0]) + SCIPvarGetUbGlobal(locvars[0]))/2)) )
2398 allownegation = TRUE;
2399
2400 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, locvars[0]);
2401 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, opnodeidx, nodeidx, TRUE, 1.0) );
2402
2403 nodeidx = SCIPgetSymgraphNegatedVarnodeidx(scip, graph, locvars[0]);
2404 if( allownegation )
2405 {
2406 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, opnodeidx, nodeidx, TRUE, 1.0) );
2407 }
2408 else
2409 {
2410 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, opnodeidx, nodeidx, TRUE, -1.0) );
2411 }
2412 }
2413 else
2414 {
2415 int sumnodeidx;
2416 int k;
2417
2418 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &sumnodeidx) ); /*lint !e641*/
2419 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, consnodeidx, sumnodeidx, FALSE, 0.0) );
2420
2421 /* add nodes and edges for variables in aggregation, do not add edges to negated variables
2422 * since this might not necessarily be a symmetry of the SOS1 constraint; therefore,
2423 * do not use SCIPaddSymgraphVarAggregation() */
2424 for( k = 0; k < nlocvars; ++k )
2425 {
2426 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, locvars[k]);
2427 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, sumnodeidx, nodeidx, TRUE, locvals[k]) );
2428 }
2429
2430 /* possibly add node for constant */
2431 if( ! SCIPisZero(scip, constant) )
2432 {
2433 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, constant, &nodeidx) );
2434 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, sumnodeidx, nodeidx, FALSE, 0.0) );
2435 }
2436 }
2437 }
2438 }
2439
2440 SCIPfreeBufferArray(scip, &locvals);
2441 SCIPfreeBufferArray(scip, &locvars);
2442
2443 *success = TRUE;
2444
2445 return SCIP_OKAY;
2446}
2447
2448
2449/* ---------------- Callback methods of event handler ---------------- */
2450
2451/** exec the event handler
2452 *
2453 * We update the number of variables fixed to be nonzero
2454 */
2455static
2457{
2458 SCIP_EVENTTYPE eventtype;
2459 SCIP_CONS* cons;
2460 SCIP_CONSDATA* consdata;
2461 SCIP_VAR* var;
2462 SCIP_Real oldbound, newbound;
2463
2464 assert( eventhdlr != NULL );
2465 assert( eventdata != NULL );
2466 assert( event != NULL );
2467
2469
2470 cons = (SCIP_CONS*)eventdata;
2471 assert( cons != NULL );
2472 consdata = SCIPconsGetData(cons);
2473 assert( consdata != NULL );
2474 assert( 0 <= consdata->nfixednonzeros && consdata->nfixednonzeros <= consdata->nvars );
2475
2476 oldbound = SCIPeventGetOldbound(event);
2477 newbound = SCIPeventGetNewbound(event);
2478
2479 eventtype = SCIPeventGetType(event);
2480 switch ( eventtype )
2481 {
2483 /* if variable is now fixed to be nonzero */
2484 if ( ! SCIPisFeasPositive(scip, oldbound) && SCIPisFeasPositive(scip, newbound) )
2485 ++(consdata->nfixednonzeros);
2486 break;
2488 /* if variable is now fixed to be nonzero */
2489 if ( ! SCIPisFeasNegative(scip, oldbound) && SCIPisFeasNegative(scip, newbound) )
2490 ++(consdata->nfixednonzeros);
2491 break;
2493 /* if variable is not fixed to be nonzero anymore */
2494 if ( SCIPisFeasPositive(scip, oldbound) && ! SCIPisFeasPositive(scip, newbound) )
2495 --(consdata->nfixednonzeros);
2496 break;
2498 /* if variable is not fixed to be nonzero anymore */
2499 if ( SCIPisFeasNegative(scip, oldbound) && ! SCIPisFeasNegative(scip, newbound) )
2500 --(consdata->nfixednonzeros);
2501 break;
2503 var = SCIPeventGetVar(event);
2504 assert(var != NULL);
2505
2506 /* global lower bound is not negative anymore -> remove down lock */
2507 if ( SCIPisFeasNegative(scip, oldbound) && ! SCIPisFeasNegative(scip, newbound) )
2509 /* global lower bound turned negative -> add down lock */
2510 else if ( ! SCIPisFeasNegative(scip, oldbound) && SCIPisFeasNegative(scip, newbound) )
2512 break;
2514 var = SCIPeventGetVar(event);
2515 assert(var != NULL);
2516
2517 /* global upper bound is not positive anymore -> remove up lock */
2518 if ( SCIPisFeasPositive(scip, oldbound) && ! SCIPisFeasPositive(scip, newbound) )
2520 /* global upper bound turned positive -> add up lock */
2521 else if ( ! SCIPisFeasPositive(scip, oldbound) && SCIPisFeasPositive(scip, newbound) )
2523 break;
2524 default:
2525 SCIPerrorMessage("invalid event type.\n");
2526 return SCIP_INVALIDDATA;
2527 }
2528 assert( 0 <= consdata->nfixednonzeros && consdata->nfixednonzeros <= consdata->nvars );
2529
2530 SCIPdebugMsg(scip, "changed bound of variable <%s> from %f to %f (nfixednonzeros: %d).\n", SCIPvarGetName(SCIPeventGetVar(event)),
2531 oldbound, newbound, consdata->nfixednonzeros);
2532
2533 return SCIP_OKAY;
2534}
2535
2536
2537/* ---------------- Constraint specific interface methods ---------------- */
2538
2539/** creates the handler for SOS2 constraints and includes it in SCIP */
2541 SCIP* scip /**< SCIP data structure */
2542 )
2543{
2544 SCIP_CONSHDLRDATA* conshdlrdata;
2545 SCIP_CONSHDLR* conshdlr;
2546
2547 /* create constraint handler data */
2548 SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
2549
2550 conshdlrdata->eventhdlr = NULL;
2551 /* create event handler for bound change events */
2553 eventExecSOS2, NULL) );
2554 if ( conshdlrdata->eventhdlr == NULL )
2555 {
2556 SCIPerrorMessage("event handler for SOS2 constraints not found.\n");
2557 return SCIP_PLUGINNOTFOUND;
2558 }
2559
2560 /* include constraint handler */
2563 consEnfolpSOS2, consEnfopsSOS2, consCheckSOS2, consLockSOS2, conshdlrdata) );
2564 assert(conshdlr != NULL);
2565
2566 /* set non-fundamental callbacks via specific setter functions */
2567 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopySOS2, consCopySOS2) );
2568 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteSOS2) );
2569 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolSOS2) );
2570 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeSOS2) );
2571 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsSOS2) );
2572 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsSOS2) );
2573 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpSOS2) );
2574 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseSOS2) );
2576 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintSOS2) );
2578 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropSOS2) );
2579 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpSOS2, consSepasolSOS2, CONSHDLR_SEPAFREQ, CONSHDLR_SEPAPRIORITY, CONSHDLR_DELAYSEPA) );
2580 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransSOS2) );
2581 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxSOS2) );
2582 SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphSOS2) );
2583 SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphSOS2) );
2584
2585 return SCIP_OKAY;
2586}
2587
2588
2589/** creates and captures a SOS2 constraint
2590 *
2591 * We set the constraint to not be modifable. If the weights are non
2592 * NULL, the variables are ordered according to these weights (in
2593 * ascending order).
2594 *
2595 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
2596 */
2598 SCIP* scip, /**< SCIP data structure */
2599 SCIP_CONS** cons, /**< pointer to hold the created constraint */
2600 const char* name, /**< name of constraint */
2601 int nvars, /**< number of variables in the constraint */
2602 SCIP_VAR** vars, /**< array with variables of constraint entries */
2603 SCIP_Real* weights, /**< weights determining the variable order, or NULL if natural order should be used */
2604 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
2605 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
2606 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
2607 * Usually set to TRUE. */
2608 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
2609 * TRUE for model constraints, FALSE for additional, redundant constraints. */
2610 SCIP_Bool check, /**< should the constraint be checked for feasibility?
2611 * TRUE for model constraints, FALSE for additional, redundant constraints. */
2612 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
2613 * Usually set to TRUE. */
2614 SCIP_Bool local, /**< is constraint only valid locally?
2615 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
2616 SCIP_Bool dynamic, /**< is constraint subject to aging?
2617 * Usually set to FALSE. Set to TRUE for own cuts which
2618 * are separated as constraints. */
2619 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
2620 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
2621 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
2622 * if it may be moved to a more global node?
2623 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
2624 )
2625{
2626 SCIP_CONSHDLR* conshdlr;
2627 SCIP_CONSDATA* consdata;
2628 SCIP_Bool modifiable;
2629
2630 modifiable = FALSE;
2631
2632 /* find the SOS2 constraint handler */
2633 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
2634 if ( conshdlr == NULL )
2635 {
2636 SCIPerrorMessage("<%s> constraint handler not found\n", CONSHDLR_NAME);
2637 return SCIP_PLUGINNOTFOUND;
2638 }
2639
2640#ifndef NDEBUG
2641 /* Check that the weights are sensible (not nan or inf); although not strictly needed, such values are likely a mistake. */
2642 if ( nvars > 0 && weights != NULL )
2643 {
2644 int v;
2645 for (v = 0; v < nvars; ++v)
2646 assert( SCIPisFinite(weights[v]) );
2647 }
2648#endif
2649
2650 /* create constraint data */
2651 SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) );
2652 consdata->vars = NULL;
2653 consdata->nvars = nvars;
2654 consdata->maxvars = nvars;
2655 consdata->row = NULL;
2656 consdata->nfixednonzeros = -1;
2657 consdata->weights = NULL;
2658 if ( nvars > 0 )
2659 {
2660 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->vars, vars, nvars) );
2661
2662 /* check weights */
2663 if ( weights != NULL )
2664 {
2665 /* store weights */
2666 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->weights, weights, nvars) );
2667
2668 /* sort variables - ascending order */
2669 SCIPsortRealPtr(consdata->weights, (void**)consdata->vars, nvars);
2670 }
2671 }
2672 else
2673 assert( weights == NULL );
2674
2675 /* create constraint */
2676 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
2677 local, modifiable, dynamic, removable, stickingatnode) );
2678
2679 return SCIP_OKAY;
2680}
2681
2682
2683/** creates and captures a SOS2 constraint with all constraint flags set to their default values.
2684 *
2685 * @warning Do NOT set the constraint to be modifiable manually, because this might lead
2686 * to wrong results as the variable array will not be re-sorted
2687 *
2688 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
2689 */
2691 SCIP* scip, /**< SCIP data structure */
2692 SCIP_CONS** cons, /**< pointer to hold the created constraint */
2693 const char* name, /**< name of constraint */
2694 int nvars, /**< number of variables in the constraint */
2695 SCIP_VAR** vars, /**< array with variables of constraint entries */
2696 SCIP_Real* weights /**< weights determining the variable order, or NULL if natural order should be used */
2697 )
2698{
2699 SCIP_CALL( SCIPcreateConsSOS2( scip, cons, name, nvars, vars, weights, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE) );
2700
2701 return SCIP_OKAY;
2702}
2703
2704
2705/** adds variable to SOS2 constraint, the position is determined by the given weight */
2707 SCIP* scip, /**< SCIP data structure */
2708 SCIP_CONS* cons, /**< constraint */
2709 SCIP_VAR* var, /**< variable to add to the constraint */
2710 SCIP_Real weight /**< weight determining position of variable */
2711 )
2712{
2713 assert( scip != NULL );
2714 assert( var != NULL );
2715 assert( cons != NULL );
2716 /* Check weight is sensible (not nan or inf); although not strictly needed, such values are likely a mistake. */
2717 assert( SCIPisFinite(weight) );
2718
2719 SCIPdebugMsg(scip, "adding variable <%s> to constraint <%s> with weight %g\n", SCIPvarGetName(var), SCIPconsGetName(cons), weight);
2720
2722
2723 SCIP_CALL( addVarSOS2(scip, cons, var, weight) );
2724
2725 return SCIP_OKAY;
2726}
2727
2728
2729/** appends variable to SOS2 constraint */
2731 SCIP* scip, /**< SCIP data structure */
2732 SCIP_CONS* cons, /**< constraint */
2733 SCIP_VAR* var /**< variable to add to the constraint */
2734 )
2735{
2736 assert( scip != NULL );
2737 assert( var != NULL );
2738 assert( cons != NULL );
2739
2740 SCIPdebugMsg(scip, "appending variable <%s> to constraint <%s>\n", SCIPvarGetName(var), SCIPconsGetName(cons));
2741
2743
2744 SCIP_CALL( appendVarSOS2(scip, cons, var) );
2745
2746 return SCIP_OKAY;
2747}
2748
2749
2750/** gets number of variables in SOS2 constraint */
2752 SCIP* scip, /**< SCIP data structure */
2753 SCIP_CONS* cons /**< constraint */
2754 )
2755{
2756 SCIP_CONSDATA* consdata;
2757
2758 assert( scip != NULL );
2759 assert( cons != NULL );
2760
2762
2763 consdata = SCIPconsGetData(cons);
2764 assert( consdata != NULL );
2765
2766 return consdata->nvars;
2767}
2768
2769
2770/** gets array of variables in SOS2 constraint */
2772 SCIP* scip, /**< SCIP data structure */
2773 SCIP_CONS* cons /**< constraint data */
2774 )
2775{
2776 SCIP_CONSDATA* consdata;
2777
2778 assert( scip != NULL );
2779 assert( cons != NULL );
2780
2782
2783 consdata = SCIPconsGetData(cons);
2784 assert( consdata != NULL );
2785
2786 return consdata->vars;
2787}
2788
2789
2790/** gets array of weights in SOS2 constraint (or NULL if not existent) */
2792 SCIP* scip, /**< SCIP data structure */
2793 SCIP_CONS* cons /**< constraint data */
2794 )
2795{
2796 SCIP_CONSDATA* consdata;
2797
2798 assert( scip != NULL );
2799 assert( cons != NULL );
2800
2802
2803 consdata = SCIPconsGetData(cons);
2804 assert( consdata != NULL );
2805
2806 return consdata->weights;
2807}
#define EVENTHDLR_NAME
SCIP_VAR * w
#define EVENTHDLR_DESC
#define CONSHDLR_NEEDSCONS
Definition cons_and.c:96
#define CONSHDLR_SEPAFREQ
Definition cons_and.c:89
#define CONSHDLR_CHECKPRIORITY
Definition cons_and.c:88
#define CONSHDLR_DESC
Definition cons_and.c:85
#define CONSHDLR_PROP_TIMING
Definition cons_and.c:99
#define CONSHDLR_MAXPREROUNDS
Definition cons_and.c:93
#define CONSHDLR_SEPAPRIORITY
Definition cons_and.c:86
#define CONSHDLR_PROPFREQ
Definition cons_and.c:90
#define CONSHDLR_PRESOLTIMING
Definition cons_and.c:98
#define CONSHDLR_EAGERFREQ
Definition cons_and.c:91
#define CONSHDLR_ENFOPRIORITY
Definition cons_and.c:87
#define CONSHDLR_DELAYSEPA
Definition cons_and.c:94
#define CONSHDLR_NAME
Definition cons_and.c:84
#define CONSHDLR_DELAYPROP
Definition cons_and.c:95
#define EVENTHDLR_EVENT_TYPE
static SCIP_RETCODE branchCons(SCIP *scip, SCIP_CONS *cons, SCIP_RESULT *result)
Constraint handler for linear constraints in their most general form, .
static SCIP_RETCODE propSOS2(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_Bool *cutoff, int *ngen)
Definition cons_sos2.c:837
static SCIP_RETCODE handleNewVariableSOS2(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_VAR *var, SCIP_Bool transformed)
Definition cons_sos2.c:315
static SCIP_RETCODE deleteVarSOS2(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr, int pos)
Definition cons_sos2.c:496
static SCIP_RETCODE presolRoundSOS2(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr, SCIP_Bool *cutoff, SCIP_Bool *success, int *ndelconss, int *nfixedvars, int *nremovedvars)
Definition cons_sos2.c:556
static SCIP_RETCODE unlockVariableSOS2(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition cons_sos2.c:267
static SCIP_RETCODE appendVarSOS2(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition cons_sos2.c:440
static SCIP_RETCODE fixVariableZeroNode(SCIP *scip, SCIP_VAR *var, SCIP_NODE *node, SCIP_Bool *infeasible)
Definition cons_sos2.c:153
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_sos2.c:204
static SCIP_RETCODE generateRowSOS2(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool local)
Definition cons_sos2.c:1237
static SCIP_RETCODE lockVariableSOS2(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition cons_sos2.c:247
static SCIP_RETCODE addVarSOS2(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real weight)
Definition cons_sos2.c:372
static SCIP_RETCODE consdataEnsurevarsSizeSOS2(SCIP *scip, SCIP_CONSDATA *consdata, int num, SCIP_Bool reserveWeights)
Definition cons_sos2.c:287
static SCIP_RETCODE enforceSOS2(SCIP *scip, SCIP_CONSHDLR *conshdlr, int nconss, SCIP_CONS **conss, SCIP_SOL *sol, SCIP_RESULT *result)
Definition cons_sos2.c:1035
constraint handler for SOS type 2 constraints
#define NULL
Definition def.h:257
#define SCIP_MAXSTRLEN
Definition def.h:278
#define SCIP_Bool
Definition def.h:100
#define SCIP_STRINGEQ(name, reference, retcode)
Definition def.h:454
#define SCIP_Real
Definition def.h:165
#define TRUE
Definition def.h:102
#define FALSE
Definition def.h:103
#define REALABS(x)
Definition def.h:191
#define SCIP_CALL(x)
Definition def.h:364
SCIP_Real * SCIPgetWeightsSOS2(SCIP *scip, SCIP_CONS *cons)
Definition cons_sos2.c:2791
SCIP_VAR ** SCIPgetVarsSOS2(SCIP *scip, SCIP_CONS *cons)
Definition cons_sos2.c:2771
SCIP_RETCODE SCIPappendVarSOS2(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var)
Definition cons_sos2.c:2730
int SCIPgetNVarsSOS2(SCIP *scip, SCIP_CONS *cons)
Definition cons_sos2.c:2751
SCIP_RETCODE SCIPcreateConsSOS2(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *weights, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition cons_sos2.c:2597
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_RETCODE SCIPaddVarSOS2(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_Real weight)
Definition cons_sos2.c:2706
SCIP_RETCODE SCIPcreateConsBasicSOS2(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *weights)
Definition cons_sos2.c:2690
SCIP_RETCODE SCIPincludeConshdlrSOS2(SCIP *scip)
Definition cons_sos2.c:2540
SCIP_RETCODE SCIPgetVarCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR *sourcevar, SCIP_VAR **targetvar, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *success)
Definition scip_copy.c:713
SCIP_Bool SCIPisTransformed(SCIP *scip)
int SCIPgetNVars(SCIP *scip)
Definition scip_prob.c:2246
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:3420
SCIP_RETCODE SCIPdelConsLocal(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:4067
SCIP_RETCODE SCIPaddConsNode(SCIP *scip, SCIP_NODE *node, SCIP_CONS *cons, SCIP_NODE *validnode)
Definition scip_prob.c:3901
SCIP_Real SCIPgetLocalTransEstimate(SCIP *scip)
Definition scip_prob.c:4139
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
#define SCIPdebugMsg
SCIP_Real SCIPcalcNodeselPriority(SCIP *scip, SCIP_VAR *var, SCIP_BRANCHDIR branchdir, 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:372
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition scip_cons.c:540
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition scip_cons.c:235
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition scip_cons.c:281
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:323
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition scip_cons.c:181
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:808
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:831
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:785
SCIP_RETCODE SCIPsetConshdlrGetSignedPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:924
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4320
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)),)
Definition scip_cons.c:347
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition scip_cons.c:940
SCIP_RETCODE SCIPsetConshdlrGetPermsymGraph(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:900
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:578
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4340
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:601
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:647
SCIP_RETCODE SCIPsetConshdlrExitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:468
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:624
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:854
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition cons.c:8423
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition cons.c:8652
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition cons.c:8413
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition cons.c:8562
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition scip_cons.c:2536
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition cons.c:8592
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition cons.c:8702
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition cons.c:8582
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition scip_cons.c:997
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition cons.c:8612
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition cons.c:8632
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition cons.c:8393
SCIP_RETCODE SCIPresetConsAge(SCIP *scip, SCIP_CONS *cons)
Definition scip_cons.c:1812
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition cons.c:8642
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition cons.c:8672
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition scip_cons.c:1173
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition cons.c:8572
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition cons.c:8662
SCIP_Bool SCIPisCutEfficacious(SCIP *scip, SCIP_SOL *sol, SCIP_ROW *cut)
Definition scip_cut.c:117
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition scip_cut.c:225
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition scip_event.c:111
const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
Definition event.c:396
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition event.c:1194
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition scip_event.c:367
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition scip_event.c:413
SCIP_Real SCIPeventGetOldbound(SCIP_EVENT *event)
Definition event.c:1391
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition event.c:1217
SCIP_Real SCIPeventGetNewbound(SCIP_EVENT *event)
Definition event.c:1415
#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 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 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_Real SCIProwGetLhs(SCIP_ROW *row)
Definition lp.c:17686
SCIP_RETCODE SCIPchgRowLhs(SCIP *scip, SCIP_ROW *row, SCIP_Real lhs)
Definition scip_lp.c:1529
SCIP_RETCODE SCIPaddVarsToRowSameCoef(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real val)
Definition scip_lp.c:1718
SCIP_Real SCIProwGetRhs(SCIP_ROW *row)
Definition lp.c:17696
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONS *cons, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition scip_lp.c:1398
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition scip_lp.c:1646
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition scip_lp.c:2176
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition scip_lp.c:1508
SCIP_RETCODE SCIPchgRowRhs(SCIP *scip, SCIP_ROW *row, SCIP_Real rhs)
Definition scip_lp.c:1553
SCIP_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition lp.c:17917
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition scip_sol.c:451
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition scip_sol.c:1763
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfeasFloor(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_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_Bool SCIPisFeasPositive(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition scip_var.c:5210
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition var.c:23418
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition var.c:24300
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition var.c:23462
SCIP_RETCODE SCIPinferVarUbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:7069
SCIP_RETCODE SCIPchgVarUbNode(SCIP *scip, SCIP_NODE *node, SCIP_VAR *var, SCIP_Real newbound)
Definition scip_var.c:6088
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition scip_var.c:728
SCIP_RETCODE SCIPgetProbvarSum(SCIP *scip, SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition scip_var.c:2499
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition var.c:24174
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition scip_var.c:5118
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition scip_var.c:5296
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition scip_var.c:2872
const char * SCIPvarGetName(SCIP_VAR *var)
Definition var.c:23299
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:24266
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition var.c:24152
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition scip_var.c:10318
SCIP_RETCODE SCIPinferVarLbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:6964
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition scip_var.c:2736
SCIP_RETCODE SCIPchgVarLbNode(SCIP *scip, SCIP_NODE *node, SCIP_VAR *var, SCIP_Real newbound)
Definition scip_var.c:6044
SCIP_RETCODE SCIPwriteVarName(SCIP *scip, FILE *file, SCIP_VAR *var, SCIP_Bool type)
Definition scip_var.c:361
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition scip_var.c:2078
void SCIPsortRealPtr(SCIP_Real *realarray, void **ptrarray, int len)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition misc.c:10827
SCIP_RETCODE SCIPskipSpace(char **s)
Definition misc.c:10816
SCIP_RETCODE SCIPaddSymgraphEdge(SCIP *scip, SYM_GRAPH *graph, int first, int second, SCIP_Bool hasval, SCIP_Real val)
SCIP_RETCODE SCIPaddSymgraphOpnode(SCIP *scip, SYM_GRAPH *graph, int op, int *nodeidx)
SCIP_RETCODE SCIPgetSymActiveVariables(SCIP *scip, SYM_SYMTYPE symtype, SCIP_VAR ***vars, SCIP_Real **scalars, int *nvars, SCIP_Real *constant, SCIP_Bool transformed)
SCIP_RETCODE SCIPaddSymgraphValnode(SCIP *scip, SYM_GRAPH *graph, SCIP_Real val, int *nodeidx)
int SCIPgetSymgraphVarnodeidx(SCIP *scip, SYM_GRAPH *graph, SCIP_VAR *var)
SCIP_RETCODE SCIPaddSymgraphConsnode(SCIP *scip, SYM_GRAPH *graph, SCIP_CONS *cons, SCIP_Real lhs, SCIP_Real rhs, int *nodeidx)
SCIP_RETCODE SCIPaddSymgraphVarAggregation(SCIP *scip, SYM_GRAPH *graph, int rootidx, SCIP_VAR **vars, SCIP_Real *vals, int nvars, SCIP_Real constant)
int SCIPgetSymgraphNegatedVarnodeidx(SCIP *scip, SYM_GRAPH *graph, SCIP_VAR *var)
return SCIP_OKAY
int c
SCIP_Bool cutoff
static SCIP_SOL * sol
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
SCIP_VAR * var
static SCIP_Bool propagate
static SCIP_VAR ** vars
memory allocation routines
#define BMScopyMemoryArray(ptr, source, num)
Definition memory.h:134
public methods for managing constraints
public methods for managing events
public methods for LP management
public methods for message output
#define SCIPerrorMessage
Definition pub_message.h:64
#define SCIPdebug(x)
Definition pub_message.h:93
public data structures and miscellaneous methods
#define SCIPisFinite(x)
Definition pub_misc.h:82
methods for sorting joint arrays of various types
public methods for 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 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 global and local (sub)problems
public methods for solutions
public methods for SCIP variables
static SCIP_RETCODE separate(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_RESULT *result)
Main separation function.
structs for symmetry computations
methods for dealing with symmetry detection graphs
#define SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(x)
Definition type_cons.h:956
#define SCIP_DECL_CONSGETPERMSYMGRAPH(x)
Definition type_cons.h:938
#define SCIP_DECL_CONSENFOLP(x)
Definition type_cons.h:363
#define SCIP_DECL_CONSDELETE(x)
Definition type_cons.h:229
struct SCIP_Cons SCIP_CONS
Definition type_cons.h:63
#define SCIP_DECL_CONSGETVARS(x)
Definition type_cons.h:867
#define SCIP_DECL_CONSPRINT(x)
Definition type_cons.h:769
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition type_cons.h:64
#define SCIP_DECL_CONSSEPALP(x)
Definition type_cons.h:288
#define SCIP_DECL_CONSENFORELAX(x)
Definition type_cons.h:388
#define SCIP_DECL_CONSPROP(x)
Definition type_cons.h:506
#define SCIP_DECL_CONSGETNVARS(x)
Definition type_cons.h:885
#define SCIP_DECL_CONSRESPROP(x)
Definition type_cons.h:612
#define SCIP_DECL_CONSENFOPS(x)
Definition type_cons.h:431
#define SCIP_DECL_CONSPARSE(x)
Definition type_cons.h:845
#define SCIP_DECL_CONSTRANS(x)
Definition type_cons.h:239
#define SCIP_DECL_CONSPRESOL(x)
Definition type_cons.h:561
#define SCIP_DECL_CONSINITLP(x)
Definition type_cons.h:259
#define SCIP_DECL_CONSLOCK(x)
Definition type_cons.h:676
struct SCIP_Conshdlr SCIP_CONSHDLR
Definition type_cons.h:62
#define SCIP_DECL_CONSCOPY(x)
Definition type_cons.h:810
struct SCIP_ConsData SCIP_CONSDATA
Definition type_cons.h:65
#define SCIP_DECL_CONSCHECK(x)
Definition type_cons.h:474
#define SCIP_DECL_CONSHDLRCOPY(x)
Definition type_cons.h:108
#define SCIP_DECL_CONSEXITSOL(x)
Definition type_cons.h:216
#define SCIP_DECL_CONSFREE(x)
Definition type_cons.h:116
#define SCIP_DECL_CONSSEPASOL(x)
Definition type_cons.h:320
struct SCIP_Eventhdlr SCIP_EVENTHDLR
Definition type_event.h:159
#define SCIP_EVENTTYPE_GUBCHANGED
Definition type_event.h:76
struct SCIP_EventData SCIP_EVENTDATA
Definition type_event.h:179
#define SCIP_EVENTTYPE_UBTIGHTENED
Definition type_event.h:79
#define SCIP_DECL_EVENTEXEC(x)
Definition type_event.h:259
#define SCIP_EVENTTYPE_LBRELAXED
Definition type_event.h:78
#define SCIP_EVENTTYPE_GLBCHANGED
Definition type_event.h:75
uint64_t SCIP_EVENTTYPE
Definition type_event.h:156
#define SCIP_EVENTTYPE_LBTIGHTENED
Definition type_event.h:77
#define SCIP_EVENTTYPE_UBRELAXED
Definition type_event.h:80
@ SCIP_BRANCHDIR_DOWNWARDS
struct SCIP_Row SCIP_ROW
Definition type_lp.h:105
@ 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_INVALIDCALL
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
struct SCIP_Sol SCIP_SOL
Definition type_sol.h:57
@ SYM_CONSOPTYPE_SOS2_TUPLE
@ SYM_CONSOPTYPE_SUM
@ SYM_SYMTYPE_PERM
struct SCIP_Node SCIP_NODE
Definition type_tree.h:63
struct SCIP_Var SCIP_VAR
Definition type_var.h:166
@ SCIP_VARSTATUS_MULTAGGR
Definition type_var.h:56
@ SCIP_LOCKTYPE_MODEL
Definition type_var.h:141