SCIP Doxygen Documentation
Loading...
Searching...
No Matches
cons_cardinality.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_cardinality.c
26 * @ingroup DEFPLUGINS_CONS
27 * @brief constraint handler for cardinality constraints
28 * @author Tobias Fischer
29 *
30 * This constraint handler handles cardinality constraints of the form
31 * \f[
32 * |\mbox{supp}(x)| \leq b
33 * \f]
34 * with integer right-hand side \f$b\f$. Here, \f$|\mbox{supp}(x)|\f$ denotes the number of nonzero entries of the
35 * vector \f$x\f$.
36 *
37 * Note that cardinality constraints generalize special ordered set of type one (SOS1) constraints in which \f$b = 1\f$.
38 *
39 * The implementation of this constraint handler is based on@n
40 * "On the Structure of Linear Programs with Overlapping Cardinality Constraints"@n
41 * T. Fischer and M. E. Pfetsch, Tech. rep., 2016
42 */
43
44/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
45
48#include "scip/cons_knapsack.h"
49#include "scip/cons_linear.h"
50#include "scip/pub_cons.h"
51#include "scip/pub_event.h"
52#include "scip/pub_lp.h"
53#include "scip/pub_message.h"
54#include "scip/pub_misc.h"
55#include "scip/pub_misc_sort.h"
56#include "scip/pub_var.h"
57#include "scip/scip_branch.h"
58#include "scip/scip_cons.h"
59#include "scip/scip_copy.h"
60#include "scip/scip_cut.h"
61#include "scip/scip_event.h"
62#include "scip/scip_general.h"
63#include "scip/scip_lp.h"
64#include "scip/scip_mem.h"
65#include "scip/scip_message.h"
66#include "scip/scip_numerics.h"
67#include "scip/scip_param.h"
68#include "scip/scip_prob.h"
69#include "scip/scip_sol.h"
71#include "scip/scip_tree.h"
72#include "scip/scip_var.h"
73#include "scip/symmetry_graph.h"
75#include <ctype.h>
76#include <stdlib.h>
77
78
79/* constraint handler properties */
80#define CONSHDLR_NAME "cardinality"
81#define CONSHDLR_DESC "cardinality constraint handler"
82#define CONSHDLR_SEPAPRIORITY 10 /**< priority of the constraint handler for separation */
83#define CONSHDLR_ENFOPRIORITY 100 /**< priority of the constraint handler for constraint enforcing */
84#define CONSHDLR_CHECKPRIORITY -10 /**< priority of the constraint handler for checking feasibility */
85#define CONSHDLR_SEPAFREQ 10 /**< frequency for separating cuts; zero means to separate only in the root node */
86#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
87#define CONSHDLR_EAGERFREQ 100 /**< frequency for using all instead of only the useful constraints in separation,
88 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
89#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in
90 * (-1: no limit) */
91#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
92#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
93#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
94
95#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
96#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_FAST
97
98/* branching rules */
99#define DEFAULT_BRANCHBALANCED FALSE /**< whether to use balanced instead of unbalanced branching */
100#define DEFAULT_BALANCEDDEPTH 20 /**< maximum depth for using balanced branching (-1: no limit) */
101#define DEFAULT_BALANCEDCUTOFF 2.0 /**< determines that balanced branching is only used if the branching cut off value
102 * w.r.t. the current LP solution is greater than a given value */
103
104/* event handler properties */
105#define EVENTHDLR_NAME "cardinality"
106#define EVENTHDLR_DESC "bound change event handler for cardinality constraints"
107
108#define EVENTHDLR_EVENT_TYPE (SCIP_EVENTTYPE_BOUNDCHANGED | SCIP_EVENTTYPE_GBDCHANGED)
109
110
111/** constraint data for cardinality constraints */
112struct SCIP_ConsData
113{
114 SCIP_CONS* cons; /**< cardinality constraint */
115 int cardval; /**< number of variables that the constraint allows to be nonzero */
116 int nvars; /**< number of variables in the constraint */
117 int maxvars; /**< maximal number of variables (= size of storage) */
118 int ntreatnonzeros; /**< number of variables in constraint that are either known to be nonzero
119 * (because zero is not in variable domain) or may be treated as nonzero */
120 SCIP_EVENTDATA** eventdatascurrent; /**< event datas for current bound change events */
121 SCIP_VAR** eventvarscurrent; /**< event variables for current bound change events */
122 int neventdatascurrent; /**< number of current bound change events */
123 SCIP_EVENTDATA** eventdatas; /**< event data array for bound change events */
124 SCIP_VAR** vars; /**< variables in constraint */
125 SCIP_VAR** indvars; /**< indicator variables that indicate which variables may be treated as
126 * nonzero in cardinality constraint */
127 SCIP_Real* weights; /**< weights determining the order (ascending), or NULL if not used */
128 SCIP_ROW* rowlb; /**< row corresponding to lower bounds, or NULL if not yet created */
129 SCIP_ROW* rowub; /**< row corresponding to upper bounds, or NULL if not yet created */
130};
131
132/** cardinality constraint handler data */
133struct SCIP_ConshdlrData
134{
135 SCIP_HASHMAP* varhash; /**< hash map from implied variable to (binary) indicator variable */
136 SCIP_Bool branchbalanced; /**< whether to use balanced instead of unbalanced branching */
137 int balanceddepth; /**< maximum depth for using balanced branching (-1: no limit) */
138 SCIP_Real balancedcutoff; /**< determines that balanced branching is only used if the branching cut off
139 * value w.r.t. the current LP solution is greater than a given value */
140 SCIP_EVENTHDLR* eventhdlr; /**< event handler for bound change events */
141};
142
143/** event data for bound changes events */
144struct SCIP_EventData
145{
146 SCIP_CONSDATA* consdata; /**< cardinality constraint data to process the bound change for */
147 SCIP_VAR* var; /**< implied variable */
148 SCIP_VAR* indvar; /**< indicator variable */
149 unsigned int pos:30; /**< position in constraint */
150 unsigned int varmarked:1; /**< whether implied variable is marked for propagation */
151 unsigned int indvarmarked:1; /**< whether indicator variable is marked for propagation */
152};
153
154/** catches bound change events for a variable and its indicator variable */
155static
157 SCIP* scip, /**< SCIP data structure */
158 SCIP_EVENTHDLR* eventhdlr, /**< event handler for bound change events */
159 SCIP_CONSDATA* consdata, /**< constraint data */
160 SCIP_VAR* var, /**< implied variable */
161 SCIP_VAR* indvar, /**< indicator variable */
162 int pos, /**< position in constraint */
163 SCIP_EVENTDATA** eventdata /**< pointer to store event data for bound change events */
164 )
165{
166 assert(eventhdlr != NULL);
167 assert(consdata != NULL);
168 assert(var != NULL);
169 assert(indvar != NULL);
170 assert(pos >= 0);
171
172 /* create event data of indicator variable */
173 SCIP_CALL( SCIPallocBlockMemory(scip, eventdata) );
174
175 (*eventdata)->consdata = consdata;
176 (*eventdata)->var = var;
177 (*eventdata)->indvar = indvar;
178 (*eventdata)->varmarked = FALSE;
179 (*eventdata)->indvarmarked = FALSE;
180 (*eventdata)->pos = (unsigned int)pos;
181
182 /* catch bound change events of each variable */
183 SCIP_CALL( SCIPcatchVarEvent(scip, var, EVENTHDLR_EVENT_TYPE, eventhdlr, *eventdata, NULL) );
184 SCIP_CALL( SCIPcatchVarEvent(scip, indvar, SCIP_EVENTTYPE_BOUNDCHANGED, eventhdlr, *eventdata, NULL) );
185
186 return SCIP_OKAY;
187}
188
189/** drops bound change events for a variable and its indicator variable */
190static
192 SCIP* scip, /**< SCIP data structure */
193 SCIP_EVENTHDLR* eventhdlr, /**< event handler for bound change events */
194 SCIP_CONSDATA* consdata, /**< constraint data */
195 SCIP_VAR* var, /**< implied variable */
196 SCIP_VAR* indvar, /**< indicator variable */
197 SCIP_EVENTDATA** eventdata /**< pointer of event data for bound change events */
198 )
199{
200 assert(eventhdlr != NULL);
201 assert(consdata != NULL);
202 assert(var != NULL);
203 assert(indvar != NULL);
204 assert(eventdata != NULL);
205
206 /* drop bound change events of each variable */
207 SCIP_CALL( SCIPdropVarEvent(scip, var, EVENTHDLR_EVENT_TYPE, eventhdlr, *eventdata, -1) );
208 SCIP_CALL( SCIPdropVarEvent(scip, indvar, SCIP_EVENTTYPE_BOUNDCHANGED, eventhdlr, *eventdata, -1) );
209
210 /* free event data of indicator variable */
211 SCIPfreeBlockMemory(scip, eventdata);
212 *eventdata = NULL;
213
214 return SCIP_OKAY;
215}
216
217/** fix variable in given node to 0 or add constraint if variable is multi-aggregated
218 *
219 * @todo Try to handle multi-aggregated variables as in \ref fixVariableZero() below.
220 */
221static
223 SCIP* scip, /**< SCIP pointer */
224 SCIP_VAR* var, /**< variable to be fixed to 0 */
225 SCIP_NODE* node, /**< node */
226 SCIP_Bool* infeasible /**< pointer to store if fixing is infeasible */
227 )
228{
229 /* if variable cannot be nonzero */
230 *infeasible = FALSE;
232 {
233 *infeasible = TRUE;
234 return SCIP_OKAY;
235 }
236
237 /* if variable is multi-aggregated */
239 {
240 SCIP_CONS* cons;
241 SCIP_Real val;
242
243 val = 1.0;
244
246 {
247 SCIPdebugMsg(scip, "creating constraint to force multi-aggregated variable <%s> to 0.\n", SCIPvarGetName(var));
248
249 /* we have to insert a local constraint var = 0 */
250 SCIP_CALL( SCIPcreateConsLinear(scip, &cons, "branch", 1, &var, &val, 0.0, 0.0, TRUE, TRUE, TRUE, TRUE, TRUE,
251 TRUE, FALSE, FALSE, FALSE, FALSE) );
252 SCIP_CALL( SCIPaddConsNode(scip, node, cons, NULL) );
253 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
254 }
255 }
256 else
257 {
259 {
260 SCIP_CALL( SCIPchgVarLbNode(scip, node, var, 0.0) );
261 }
263 {
264 SCIP_CALL( SCIPchgVarUbNode(scip, node, var, 0.0) );
265 }
266 }
267
268 return SCIP_OKAY;
269}
270
271/** try to fix variable to 0
272 *
273 * Try to treat fixing by special consideration of multiaggregated variables. For a multi-aggregation
274 * \f[
275 * x = \sum_{i=1}^n \alpha_i x_i + c,
276 * \f]
277 * we can express the fixing \f$x = 0\f$ by fixing all \f$x_i\f$ to 0 if \f$c = 0\f$ and the lower bounds of \f$x_i\f$
278 * are nonnegative if \f$\alpha_i > 0\f$ or the upper bounds are nonpositive if \f$\alpha_i < 0\f$.
279 */
280static
282 SCIP* scip, /**< SCIP pointer */
283 SCIP_VAR* var, /**< variable to be fixed to 0*/
284 SCIP_Bool* infeasible, /**< if fixing is infeasible */
285 SCIP_Bool* tightened /**< if fixing was performed */
286 )
287{
288 assert(scip != NULL);
289 assert(var != NULL);
290 assert(infeasible != NULL);
291 assert(tightened != NULL);
292
293 *infeasible = FALSE;
294 *tightened = FALSE;
295
297 {
298 SCIP_Real aggrconst;
299
300 /* if constant is 0 */
301 aggrconst = SCIPvarGetMultaggrConstant(var);
302 if( SCIPisZero(scip, aggrconst) )
303 {
304 SCIP_VAR** aggrvars;
305 SCIP_Real* aggrvals;
306 SCIP_Bool allnonnegative = TRUE;
307 int naggrvars;
308 int i;
309
311
312 /* check whether all variables are "nonnegative" */
313 naggrvars = SCIPvarGetMultaggrNVars(var);
314 aggrvars = SCIPvarGetMultaggrVars(var);
315 aggrvals = SCIPvarGetMultaggrScalars(var);
316 for( i = 0; i < naggrvars; ++i )
317 {
318 if( (SCIPisPositive(scip, aggrvals[i]) && SCIPisNegative(scip, SCIPvarGetLbLocal(aggrvars[i]))) ||
319 (SCIPisNegative(scip, aggrvals[i]) && SCIPisPositive(scip, SCIPvarGetUbLocal(aggrvars[i]))) )
320 {
321 allnonnegative = FALSE;
322 break;
323 }
324 }
325
326 if( allnonnegative )
327 {
328 /* all variables are nonnegative -> fix variables */
329 for( i = 0; i < naggrvars; ++i )
330 {
331 SCIP_Bool fixed;
332 SCIP_CALL( SCIPfixVar(scip, aggrvars[i], 0.0, infeasible, &fixed) );
333 if( *infeasible )
334 return SCIP_OKAY;
335 *tightened = *tightened || fixed;
336 }
337 }
338 }
339 }
340 else
341 {
342 SCIP_CALL( SCIPfixVar(scip, var, 0.0, infeasible, tightened) );
343 }
344
345 return SCIP_OKAY;
346}
347
348/** add lock on variable */
349static
351 SCIP* scip, /**< SCIP data structure */
352 SCIP_CONS* cons, /**< constraint */
353 SCIP_VAR* var, /**< variable */
354 SCIP_VAR* indvar /**< indicator variable */
355 )
356{
357 assert(scip != NULL);
358 assert(cons != NULL);
359 assert(var != NULL);
360
361 /* rounding down == bad if lb < 0, rounding up == bad if ub > 0 */
364 SCIP_CALL( SCIPlockVarCons(scip, indvar, cons, TRUE, TRUE) );
365
366 return SCIP_OKAY;
367}
368
369/* remove lock on variable */
370static
372 SCIP* scip, /**< SCIP data structure */
373 SCIP_CONS* cons, /**< constraint */
374 SCIP_VAR* var, /**< variable */
375 SCIP_VAR* indvar /**< indicator variable */
376 )
377{
378 assert(scip != NULL);
379 assert(cons != NULL);
380 assert(var != NULL);
381
382 /* rounding down == bad if lb < 0, rounding up == bad if ub > 0 */
385 SCIP_CALL( SCIPunlockVarCons(scip, indvar, cons, TRUE, TRUE) );
386
387 return SCIP_OKAY;
388}
389
390/** ensures that the vars and weights array can store at least num entries */
391static
393 SCIP* scip, /**< SCIP data structure */
394 SCIP_CONSDATA* consdata, /**< constraint data */
395 int num, /**< minimum number of entries to store */
396 SCIP_Bool reserveweights /**< whether the weights array is handled */
397 )
398{
399 assert(consdata != NULL);
400 assert(consdata->nvars <= consdata->maxvars);
401
402 if( num > consdata->maxvars )
403 {
404 int newsize;
405
406 newsize = SCIPcalcMemGrowSize(scip, num);
407 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->vars, consdata->maxvars, newsize) );
408 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->indvars, consdata->maxvars, newsize) );
409 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventdatas, consdata->maxvars, newsize) );
410 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventdatascurrent, 4*consdata->maxvars, 4*newsize) );/*lint !e647*/
411 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->eventvarscurrent, 4*consdata->maxvars, 4*newsize) );/*lint !e647*/
412
413 if ( reserveweights )
414 {
415 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &consdata->weights, consdata->maxvars, newsize) );
416 }
417 consdata->maxvars = newsize;
418 }
419 assert(num <= consdata->maxvars);
420
421 return SCIP_OKAY;
422}
423
424/** handle new variable that was added to the constraint
425 *
426 * We perform the following steps:
427 *
428 * - Catch bound change events of variable.
429 * - Update rounding locks of variable.
430 * - Don't allow multiaggregation of variable, since this cannot be handled by branching in the current implementation.
431 * - Update lower and upper bound row, i.e., the linear representations of the cardinality constraints.
432 */
433static
435 SCIP* scip, /**< SCIP data structure */
436 SCIP_CONS* cons, /**< constraint */
437 SCIP_CONSDATA* consdata, /**< constraint data */
438 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
439 SCIP_VAR* var, /**< variable */
440 SCIP_VAR* indvar, /**< indicator variable to indicate whether variable may be treated as
441 * nonzero in cardinality constraint */
442 int pos, /**< position in constraint */
443 SCIP_Bool transformed, /**< whether original variable was transformed */
444 SCIP_EVENTDATA** eventdata /**< pointer to store event data for bound change events */
445 )
446{
447 assert(scip != NULL);
448 assert(cons != NULL);
449 assert(consdata != NULL);
450 assert(conshdlrdata != NULL);
451 assert(var != NULL);
452
453 /* if we are in transformed problem, catch the variable's events */
454 if( transformed )
455 {
456 /* catch bound change events of variable */
457 SCIP_CALL( catchVarEventCardinality(scip, conshdlrdata->eventhdlr, consdata, var, indvar, pos, eventdata) );
458 assert(eventdata != NULL );
459
460 /* if the variable is fixed to nonzero */
461 assert(consdata->ntreatnonzeros >= 0);
462 assert(SCIPvarIsBinary(indvar));
463 if( SCIPvarGetLbLocal(indvar) > 0.5 )
464 ++consdata->ntreatnonzeros;
465 }
466
467 /* branching on multiaggregated variables does not seem to work well, so avoid it */
469
470 /* install the rounding locks for the new variable */
471 SCIP_CALL( lockVariableCardinality(scip, cons, var, indvar) );
472
473 /* add the new coefficient to the upper bound LP row, if necessary */
474 if( consdata->rowub != NULL && !SCIPisInfinity(scip, SCIPvarGetUbGlobal(var))
476 {
477 SCIP_CALL( SCIPaddVarToRow(scip, consdata->rowub, var, 1.0/SCIPvarGetUbGlobal(var)) );
478 }
479
480 /* add the new coefficient to the lower bound LP row, if necessary */
481 if( consdata->rowlb != NULL && !SCIPisInfinity(scip, SCIPvarGetLbGlobal(var))
483 {
484 SCIP_CALL( SCIPaddVarToRow(scip, consdata->rowlb, var, 1.0/SCIPvarGetLbGlobal(var)) );
485 }
486
487 return SCIP_OKAY;
488}
489
490/** adds a variable to a cardinality constraint, at position given by weight - ascending order */
491static
493 SCIP* scip, /**< SCIP data structure */
494 SCIP_CONS* cons, /**< constraint */
495 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
496 SCIP_VAR* var, /**< variable to add to the constraint */
497 SCIP_VAR* indvar, /**< indicator variable to indicate whether variable may be treated as nonzero
498 * in cardinality constraint (or NULL) */
499 SCIP_Real weight /**< weight to determine position */
500 )
501{
502 SCIP_EVENTDATA* eventdata = NULL;
503 SCIP_CONSDATA* consdata;
504 SCIP_Bool transformed;
505 int pos;
506
507 assert(var != NULL);
508 assert(cons != NULL);
509 assert(conshdlrdata != NULL);
510
511 consdata = SCIPconsGetData(cons);
512 assert(consdata != NULL );
513
514 if( consdata->weights == NULL && consdata->maxvars > 0 )
515 {
516 SCIPerrorMessage("cannot add variable to cardinality constraint <%s> that does not contain weights.\n",
517 SCIPconsGetName(cons));
518 return SCIP_INVALIDCALL;
519 }
520
521 /* check indicator variable */
522 if( indvar == NULL )
523 {
524 if( conshdlrdata->varhash == NULL )
525 {
526 /* set up hash map */
527 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->varhash, SCIPblkmem(scip), SCIPgetNTotalVars(scip)) );
528 }
529
530 /* check whether an indicator variable already exists for implied variable */
531 if( SCIPhashmapExists(conshdlrdata->varhash, var) )
532 {
533 assert((SCIP_VAR*) SCIPhashmapGetImage(conshdlrdata->varhash, var) != NULL);
534 indvar = (SCIP_VAR*) SCIPhashmapGetImage(conshdlrdata->varhash, var);
535 assert(indvar != NULL);
536 }
537 else
538 {
539 /* if implied variable is binary, then it is also not necessary to create an indicator variable */
540 if( SCIPvarIsBinary(var) )
541 indvar = var;
542 else
543 {
544 char varname[SCIP_MAXSTRLEN];
545 SCIP_VAR* newvar;
546
547 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "ind_%s", SCIPvarGetName(var));
548 SCIP_CALL( SCIPcreateVar(scip, &newvar, varname, 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY, FALSE, FALSE,
549 NULL, NULL, NULL, NULL, NULL) );
550 SCIP_CALL( SCIPaddVar(scip, newvar) );
551 indvar = newvar;
552
553 SCIP_CALL( SCIPreleaseVar(scip, &newvar) );
554 }
555 assert(indvar != NULL);
556
557 /* insert implied variable to hash map */
558 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->varhash, var, (void*) indvar) );/*lint !e571*/
559 assert(indvar == (SCIP_VAR*) SCIPhashmapGetImage(conshdlrdata->varhash, var));
560 assert(SCIPhashmapExists(conshdlrdata->varhash, var));
561 }
562 }
563
564 /* are we in the transformed problem? */
565 transformed = SCIPconsIsTransformed(cons);
566
567 /* always use transformed variables in transformed constraints */
568 if( transformed )
569 {
571 SCIP_CALL( SCIPgetTransformedVar(scip, indvar, &indvar) );
572 }
573 assert(var != NULL);
574 assert(indvar != NULL);
575 assert(transformed == SCIPvarIsTransformed(var));
576 assert(transformed == SCIPvarIsTransformed(indvar));
577
578 /* ensure that the new information can be storend in the constraint data */
579 SCIP_CALL( consdataEnsurevarsSizeCardinality(scip, consdata, consdata->nvars + 1, TRUE) );
580 assert(consdata->weights != NULL);
581 assert(consdata->maxvars >= consdata->nvars+1);
582
583 /* move other variables, if necessary */
584 for( pos = consdata->nvars; pos >= 1; --pos )
585 {
586 /* coverity[var_deref_model] */
587 if( consdata->weights[pos-1] > weight )
588 {
589 consdata->vars[pos] = consdata->vars[pos-1];
590 consdata->indvars[pos] = consdata->indvars[pos-1];
591 consdata->eventdatas[pos] = consdata->eventdatas[pos-1];
592 consdata->weights[pos] = consdata->weights[pos-1];
593
594 if( consdata->eventdatas[pos] != NULL )
595 {
596 consdata->eventdatas[pos]->pos = (unsigned int)pos;
597 }
598 }
599 else
600 break;
601 }
602 assert(0 <= pos && pos <= consdata->nvars);
603
604 /* handle the new variable */
605 SCIP_CALL( handleNewVariableCardinality(scip, cons, consdata, conshdlrdata, var, indvar, pos, transformed, &eventdata) );
606 assert(! transformed || eventdata != NULL);
607
608 /* insert variable */
609 consdata->vars[pos] = var;
610 consdata->indvars[pos] = indvar;
611 consdata->eventdatas[pos] = eventdata;
612 consdata->weights[pos] = weight;
613 ++consdata->nvars;
614
615 return SCIP_OKAY;
616}
617
618/** appends a variable to a cardinality constraint */
619static
621 SCIP* scip, /**< SCIP data structure */
622 SCIP_CONS* cons, /**< constraint */
623 SCIP_CONSHDLRDATA* conshdlrdata, /**< constraint handler data */
624 SCIP_VAR* var, /**< variable to add to the constraint */
625 SCIP_VAR* indvar /**< indicator variable to indicate whether variable may be treated as nonzero
626 * in cardinality constraint */
627 )
628{
629 SCIP_EVENTDATA* eventdata = NULL;
630 SCIP_CONSDATA* consdata;
631 SCIP_Bool transformed;
632
633 assert(var != NULL);
634 assert(cons != NULL);
635 assert(conshdlrdata != NULL);
636
637 consdata = SCIPconsGetData(cons);
638 assert(consdata != NULL);
639
640 /* check indicator variable */
641 if( indvar == NULL )
642 {
643 if( conshdlrdata->varhash == NULL )
644 {
645 /* set up hash map */
646 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->varhash, SCIPblkmem(scip), SCIPgetNTotalVars(scip)) );
647 }
648
649 /* check whether an indicator variable already exists for implied variable */
650 if( SCIPhashmapExists(conshdlrdata->varhash, var) )
651 {
652 assert((SCIP_VAR*) SCIPhashmapGetImage(conshdlrdata->varhash, var) != NULL);
653 indvar = (SCIP_VAR*) SCIPhashmapGetImage(conshdlrdata->varhash, var);
654 assert(indvar != NULL);
655 }
656 else
657 {
658 /* if implied variable is binary, then it is also not necessary to create an indicator variable */
659 if( SCIPvarIsBinary(var) )
660 indvar = var;
661 else
662 {
663 char varname[SCIP_MAXSTRLEN];
664 SCIP_VAR* newvar;
665
666 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "ind_%s", SCIPvarGetName(var));
667 SCIP_CALL( SCIPcreateVar(scip, &newvar, varname, 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY, FALSE, FALSE,
668 NULL, NULL, NULL, NULL, NULL) );
669 SCIP_CALL( SCIPaddVar(scip, newvar) );
670 indvar = newvar;
671
672 SCIP_CALL( SCIPreleaseVar(scip, &newvar) );
673 }
674 assert(indvar != NULL);
675
676 /* insert implied variable to hash map */
677 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->varhash, var, (void*) indvar) );/*lint !e571*/
678 assert(indvar == (SCIP_VAR*) SCIPhashmapGetImage(conshdlrdata->varhash, var));
679 assert(SCIPhashmapExists(conshdlrdata->varhash, var));
680 }
681 }
682
683 /* are we in the transformed problem? */
684 transformed = SCIPconsIsTransformed(cons);
685
686 /* always use transformed variables in transformed constraints */
687 if( transformed )
688 {
690 SCIP_CALL( SCIPgetTransformedVar(scip, indvar, &indvar) );
691 }
692 assert(var != NULL);
693 assert(indvar != NULL);
694 assert(transformed == SCIPvarIsTransformed(var));
695 assert(transformed == SCIPvarIsTransformed(indvar));
696
697 /* ensure that the new information can be stored in the constraint data */
698 SCIP_CALL( consdataEnsurevarsSizeCardinality(scip, consdata, consdata->nvars + 1, FALSE) );
699
700 /* handle the new variable */
701 SCIP_CALL( handleNewVariableCardinality(scip, cons, consdata, conshdlrdata, var, indvar, consdata->nvars, transformed,
702 &eventdata) );
703 assert(!transformed || eventdata != NULL);
704
705 /* insert variable */
706 consdata->vars[consdata->nvars] = var;
707 consdata->indvars[consdata->nvars] = indvar;
708 consdata->eventdatas[consdata->nvars] = eventdata;
709
710 if( consdata->weights != NULL && consdata->nvars > 0 )
711 consdata->weights[consdata->nvars] = consdata->weights[consdata->nvars-1] + 1.0;
712 ++consdata->nvars;
713
714 assert(consdata->weights != NULL || consdata->nvars > 0);
715
716 return SCIP_OKAY;
717}
718
719/** deletes a variable from a cardinality constraint */
720static
722 SCIP* scip, /**< SCIP data structure */
723 SCIP_CONS* cons, /**< constraint */
724 SCIP_CONSDATA* consdata, /**< constraint data */
725 SCIP_EVENTHDLR* eventhdlr, /**< corresponding event handler */
726 int pos /**< position of variable in array */
727 )
728{ /*lint --e{679}*/
729 int j;
730
731 assert(0 <= pos && pos < consdata->nvars);
732
733 /* remove lock of variable */
734 SCIP_CALL( unlockVariableCardinality(scip, cons, consdata->vars[pos], consdata->indvars[pos]) );
735
736 /* drop events on indicator variable and implied variable */
737 SCIP_CALL( dropVarEventCardinality(scip, eventhdlr, consdata, consdata->vars[pos], consdata->indvars[pos],
738 &consdata->eventdatas[pos]) );
739
740 /* update number of variables that may be treated as nonzero */
741 assert(SCIPvarIsBinary(consdata->indvars[pos]));
742 if( SCIPvarGetLbLocal(consdata->indvars[pos]) > 0.5 )
743 --(consdata->ntreatnonzeros);
744
745 /* delete variable - need to copy since order is important */
746 for( j = pos; j < consdata->nvars-1; ++j )
747 {
748 consdata->vars[j] = consdata->vars[j+1];
749 consdata->indvars[j] = consdata->indvars[j+1];
750 consdata->eventdatas[j] = consdata->eventdatas[j+1];
751 if( consdata->weights != NULL )
752 consdata->weights[j] = consdata->weights[j+1];
753
754 consdata->eventdatas[j]->pos = (unsigned int)j;
755 }
756 --consdata->nvars;
757
758 return SCIP_OKAY;
759}
760
761/** for each indicator variable sets solution to 1.0 if the solution value of the implied variable is nonzero */
762static
764 SCIP* scip, /**< SCIP pointer */
765 SCIP_CONS** conss, /**< constraints */
766 int nconss, /**< number of constraints */
767 SCIP_SOL* sol, /**< solution to be enforced (or NULL) */
768 SCIP_SOL* primsol /**< primal solution */
769 )
770{
771 SCIP_CONSDATA* consdata;
772 SCIP_VAR** indvars;
773 SCIP_VAR** vars;
774 int nvars;
775 int c;
776
777 /* check each constraint */
778 for( c = 0; c < nconss; ++c )
779 {
780 SCIP_CONS* cons;
781 int j;
782
783 cons = conss[c];
784 assert(cons != NULL);
785 consdata = SCIPconsGetData(cons);
786 assert(consdata != NULL);
787
788 nvars = consdata->nvars;
789 vars = consdata->vars;
790 indvars = consdata->indvars;
791
792 for( j = 0; j < nvars; ++j )
793 {
795 {
796 SCIP_CALL( SCIPsetSolVal(scip, primsol, indvars[j], 0.0) );
797 }
798 else
799 {
800 SCIP_CALL( SCIPsetSolVal(scip, primsol, indvars[j], 1.0) );
801 }
802 }
803 }
804
805 return SCIP_OKAY;
806}
807
808/** unmark variables that are marked for propagation */
809static
811 SCIP_CONSDATA* consdata /**< constraint data */
812 )
813{
814 SCIP_EVENTDATA** eventdatas;
815 int nvars;
816 int j;
817
818 eventdatas = consdata->eventdatas;
819 nvars = consdata->nvars;
820 assert(eventdatas != NULL);
821
822 for( j = 0; j < nvars; ++j )
823 {
824 SCIP_EVENTDATA* eventdata;
825
826 eventdata = eventdatas[j];
827 eventdata->varmarked = FALSE;
828 eventdata->indvarmarked = FALSE;
829 }
830}
831
832/** perform one presolving round
833 *
834 * We perform the following presolving steps:
835 *
836 * - If the bounds of some variable force it to be nonzero, we can
837 * fix all other variables to zero and remove the cardinality constraints
838 * that contain it.
839 * - If a variable is fixed to zero, we can remove the variable.
840 * - If a variable appears twice, it can be fixed to 0.
841 * - We substitute appregated variables.
842 */
843static
845 SCIP* scip, /**< SCIP pointer */
846 SCIP_CONS* cons, /**< constraint */
847 SCIP_CONSDATA* consdata, /**< constraint data */
848 SCIP_EVENTHDLR* eventhdlr, /**< event handler */
849 SCIP_Bool* cutoff, /**< whether a cutoff happened */
850 SCIP_Bool* success, /**< whether we performed a successful reduction */
851 int* ndelconss, /**< number of deleted constraints */
852 int* nupgdconss, /**< number of upgraded constraints */
853 int* nfixedvars, /**< number of fixed variables */
854 int* nremovedvars /**< number of variables removed */
855 )
856{
857 SCIP_VAR** indvars;
858 SCIP_VAR** vars;
859 SCIP_Bool allvarsbinary;
860 SCIP_Bool infeasible;
861 SCIP_Bool fixed;
862 int j;
863
864 assert(scip != NULL);
865 assert(cons != NULL);
866 assert(consdata != NULL);
867 assert(eventhdlr != NULL);
868 assert(cutoff != NULL);
869 assert(success != NULL);
870 assert(ndelconss != NULL);
871 assert(nfixedvars != NULL);
872 assert(nremovedvars != NULL);
873
874 *cutoff = FALSE;
875 *success = FALSE;
876
877 SCIPdebugMsg(scip, "Presolving cardinality constraint <%s>.\n", SCIPconsGetName(cons) );
878
879 /* reset number of events stored for propagation, since presolving already performs a
880 * complete propagation of all variables */
881 consdata->neventdatascurrent = 0;
883
884 j = 0;
885 allvarsbinary = TRUE;
886 vars = consdata->vars;
887 indvars = consdata->indvars;
888
889 /* check for variables fixed to 0 and bounds that fix a variable to be nonzero */
890 while ( j < consdata->nvars )
891 {
892 SCIP_VAR* var;
893 SCIP_VAR* indvar;
894 SCIP_Real lb;
895 SCIP_Real ub;
896 SCIP_Real indlb;
897 SCIP_Real indub;
898 SCIP_Real scalar;
899 SCIP_Real constant;
900
901 scalar = 1.0;
902 constant = 0.0;
903
904 indvar = indvars[j];
905 assert(SCIPvarIsBinary(indvar));
906
907 /* check for aggregation: if the constant is zero the variable is zero iff the aggregated
908 * variable is 0 */
909 var = vars[j];
910 SCIP_CALL( SCIPgetProbvarSum(scip, &var, &scalar, &constant) );
911
912 /* try to substitute variable entry */
913 if( var != vars[j] )
914 {
915 /* only if constant is zero and scalar not zero, the variable condition is equivalent */
916 if( SCIPisZero(scip, constant) && !SCIPisZero(scip, scalar) )
917 {
918 SCIPdebugMsg(scip, "substituted variable <%s> by <%s>.\n", SCIPvarGetName(vars[j]), SCIPvarGetName(var));
919
920 /* we reuse the same indicator variable for the new variable */
921 SCIP_CALL( dropVarEventCardinality(scip, eventhdlr, consdata, consdata->vars[j], consdata->indvars[j],
922 &consdata->eventdatas[j]) );
923 SCIP_CALL( catchVarEventCardinality(scip, eventhdlr, consdata, var, consdata->indvars[j], j,
924 &consdata->eventdatas[j]) );
925 assert(consdata->eventdatas[j] != NULL);
926
927 /* change the rounding locks */
928 SCIP_CALL( unlockVariableCardinality(scip, cons, consdata->vars[j], consdata->indvars[j]) );
929 SCIP_CALL( lockVariableCardinality(scip, cons, var, consdata->indvars[j]) );
930
931 /* update event data */
932 consdata->eventdatas[j]->var = var;
933
934 vars[j] = var;
935 }
936 /* otherwise reset variable */
937 else
938 var = vars[j];
939 }
940 assert(var == vars[j]);
941
942 /* get bounds of variable */
945
946 /* if the variable is fixed to nonzero */
948 {
949 /* fix (binary) indicator variable to 1.0 (the cardinality constraint will then be modified below) */
950 SCIP_CALL( SCIPfixVar(scip, indvar, 1.0, &infeasible, &fixed) );
951 if( infeasible )
952 {
953 *cutoff = TRUE;
954 return SCIP_OKAY;
955 }
956
957 if( fixed )
958 {
959 SCIPdebugMsg(scip, "fixed binary variable <%s> to 1.0.\n", SCIPvarGetName(indvar));
960 ++(*nfixedvars);
961 }
962 }
963
964 /* if the variable is fixed to 0 and strong dual reductions are allowed */
966 {
967 /* fix (binary) indicator variable to 0.0, if possible (the cardinality constraint will then be modified below)
968 * note that an infeasibility implies no cut off */
969 SCIP_CALL( SCIPfixVar(scip, indvar, 0.0, &infeasible, &fixed) );
970 if( fixed )
971 {
972 SCIPdebugMsg(scip, "fixed binary variable <%s> to 0.0.\n", SCIPvarGetName(indvar));
973 ++(*nfixedvars);
974 }
975 }
976
977 /* get bounds of indicator variable */
978 indlb = SCIPvarGetLbLocal(indvar);
979 indub = SCIPvarGetUbLocal(indvar);
980
981 /* if the variable may be treated as nonzero */
982 if( indlb > 0.5 )
983 {
984 assert(indub == 1.0);
985
986 /* modify row and delete variable */
987 SCIP_CALL( deleteVarCardinality(scip, cons, consdata, eventhdlr, j) );
988 SCIPdebugMsg(scip, "deleting variable <%s> from constraint <%s>, since it may be treated as nonzero.\n",
990 --(consdata->cardval);
991 ++(*nremovedvars);
992 }
993 /* if the indicator variable is fixed to 0 */
994 else if( indub < 0.5 )
995 {
996 assert(indlb == 0.0);
997
998 /* fix variable to 0.0 */
999 SCIP_CALL( SCIPfixVar(scip, var, 0.0, &infeasible, &fixed) );
1000 if( infeasible )
1001 {
1002 *cutoff = TRUE;
1003 return SCIP_OKAY;
1004 }
1005 if( fixed )
1006 {
1007 SCIPdebugMsg(scip, "fixed variable <%s> to 0.0.\n", SCIPvarGetName(var));
1008 ++(*nfixedvars);
1009 }
1010
1011 /* delete variable */
1012 SCIP_CALL( deleteVarCardinality(scip, cons, consdata, eventhdlr, j) );
1013 SCIPdebugMsg(scip, "deleting variable <%s> from constraint <%s>, since it is fixed to 0.\n", SCIPvarGetName(var),
1014 SCIPconsGetName(cons));
1015 ++(*nremovedvars);
1016 }
1017 else
1018 {
1019 /* check whether all variables are binary */
1020 if( !SCIPvarIsBinary(var) )
1021 allvarsbinary = FALSE;
1022
1023 ++j;
1024 }
1025 }
1026
1027 /* if the cardinality value is smaller than 0, then the problem is infeasible */
1028 if( consdata->cardval < 0 )
1029 {
1030 SCIPdebugMsg(scip, "The problem is infeasible: more variables have bounds that keep them from being 0 than allowed.\n");
1031
1032 *cutoff = TRUE;
1033 return SCIP_OKAY;
1034 }
1035 /* else if the cardinality value is 0 */
1036 else if( consdata->cardval == 0 )
1037 {
1038 /* fix all variables of the constraint to 0 */
1039 for( j = 0; j < consdata->nvars; ++j )
1040 {
1041 SCIP_CALL( SCIPfixVar(scip, consdata->vars[j], 0.0, &infeasible, &fixed) );
1042 if( infeasible )
1043 {
1044 *cutoff = TRUE;
1045 return SCIP_OKAY;
1046 }
1047 if( fixed )
1048 {
1049 SCIPdebugMsg(scip, "fixed variable <%s> to 0.0.\n", SCIPvarGetName(consdata->vars[j]));
1050 ++(*nfixedvars);
1051 }
1052 }
1053 }
1054
1055 /* if the cardinality constraint is redundant */
1056 if( consdata->nvars <= consdata->cardval )
1057 {
1058 SCIPdebugMsg(scip, "Deleting cardinality constraint <%s> with <%d> variables and cardinality value <%d>.\n",
1059 SCIPconsGetName(cons), consdata->nvars, consdata->cardval);
1060
1061 /* delete constraint */
1063 SCIP_CALL( SCIPdelCons(scip, cons) );
1064 ++(*ndelconss);
1065 *success = TRUE;
1066 return SCIP_OKAY;
1067 }
1068 else
1069 {
1070 /* if all variables are binary create a knapsack constraint */
1071 if( allvarsbinary )
1072 {
1073 SCIP_CONS* knapsackcons;
1074 SCIP_Longint* vals;
1075
1076 SCIP_CALL( SCIPallocBufferArray(scip, &vals, consdata->nvars) );
1077 for( j = 0; j < consdata->nvars; ++j )
1078 vals[j] = 1;
1079
1080 /* create, add, and release the knapsack constraint */
1081 SCIP_CALL( SCIPcreateConsKnapsack(scip, &knapsackcons, SCIPconsGetName(cons), consdata->nvars, consdata->vars,
1082 vals, (SCIP_Longint) consdata->cardval, SCIPconsIsInitial(cons), SCIPconsIsSeparated(cons),
1085 SCIPconsIsStickingAtNode(cons)) );/*lint !e524*/
1086 SCIP_CALL( SCIPaddCons(scip, knapsackcons) );
1087 SCIP_CALL( SCIPreleaseCons(scip, &knapsackcons) );
1088
1089 SCIPfreeBufferArray(scip, &vals);
1090
1091 SCIPdebugMsg(scip, "Upgrading cardinality constraint <%s> to knapsack constraint.\n", SCIPconsGetName(cons));
1092
1093 /* remove the cardinality constraint globally */
1095 SCIP_CALL( SCIPdelCons(scip, cons) );
1096 ++(*nupgdconss);
1097 *success = TRUE;
1098 }
1099 }
1100
1101 return SCIP_OKAY;
1102}
1103
1104/** propagates a cardinality constraint and its variables
1105 *
1106 * The number 'ntreatnonzeros' that is assigned to the constraint data returns the number of variables that are either
1107 * known to be nonzero or can be treated as nonzero. We say that a variable is known to be nonzero, if zero is outside
1108 * the domain of this variable. A variable can be treated as nonzero, if its corresponding indicator variable 'indvar' is
1109 * fixed to 1.0, e.g., by branching.
1110 *
1111 * We perform the following propagation steps:
1112 *
1113 * - If the number 'ntreatnonzeros' is greater than the cardinality value of the constraint, then the current subproblem
1114 * is marked as infeasible.
1115 * - If the cardinality constraint is saturated, i.e., the number 'ntreatnonzeros' is equal to the cardinality value of
1116 * the constraint, then fix all the other variables of the constraint to zero.
1117 * - Remove the cardinality constraint locally if all variables are either fixed to zero or can be treated as nonzero.
1118 * - If a (binary) indicator variable is fixed to zero, then fix the corresponding implied variable to zero.
1119 * - If zero is outside of the domain of an implied variable, then fix the corresponding indicator variable to one.
1120 */
1121static
1123 SCIP* scip, /**< SCIP pointer */
1124 SCIP_CONS* cons, /**< constraint */
1125 SCIP_CONSDATA* consdata, /**< constraint data */
1126 SCIP_Bool* cutoff, /**< whether a cutoff happened */
1127 int* nchgdomain /**< number of domain changes */
1128 )
1129{
1130 assert(scip != NULL);
1131 assert(cons != NULL);
1132 assert(consdata != NULL);
1133 assert(cutoff != NULL);
1134 assert(nchgdomain != NULL);
1135
1136 *cutoff = FALSE;
1137
1138 /* if more variables may be treated as nonzero than allowed */
1139 if( consdata->ntreatnonzeros > consdata->cardval )
1140 {
1141 SCIPdebugMsg(scip, "the node is infeasible, more than %d variables are fixed to be nonzero.\n", consdata->cardval);
1143 *cutoff = TRUE;
1144
1145 return SCIP_OKAY;
1146 }
1147
1148 /* if number of nonzeros is saturated */
1149 if( consdata->ntreatnonzeros == consdata->cardval )
1150 {
1151 SCIP_VAR** vars;
1152 SCIP_VAR** indvars;
1153 SCIP_Bool infeasible;
1154 SCIP_Bool tightened;
1155 SCIP_Bool allvarfixed;
1156 int nvars;
1157#ifndef NDEBUG
1158 int cnt = 0;
1159#endif
1160 int j;
1161
1162 nvars = consdata->nvars;
1163 vars = consdata->vars;
1164 indvars = consdata->indvars;
1165 assert(vars != NULL);
1166 assert(indvars != NULL);
1167
1168 /* fix free variables to zero */
1169 allvarfixed = TRUE;
1170 for( j = 0; j < nvars; ++j )
1171 {
1172 /* if variable is implied to be treated as nonzero */
1173 assert( SCIPvarIsBinary(indvars[j]) );
1174 if( SCIPvarGetLbLocal(indvars[j]) > 0.5 )
1175 {
1176#ifndef NDEBUG
1177 ++cnt;
1178#endif
1179 }
1180 /* else fix variable to zero if not done already */
1181 else
1182 {
1183 SCIP_VAR* var;
1184
1185 var = vars[j];
1186
1187 /* fix variable */
1189 {
1190 SCIP_CALL( fixVariableZero(scip, var, &infeasible, &tightened) );
1191 if( infeasible )
1192 {
1193 SCIPdebugMsg(scip, "the node is infeasible, more than %d variables are fixed to be nonzero.\n",
1194 consdata->cardval);
1196 *cutoff = TRUE;
1197
1198 return SCIP_OKAY;
1199 }
1200
1201 if( tightened )
1202 {
1203 SCIPdebugMsg(scip, "fixed variable <%s> to 0, since constraint <%s> with cardinality value %d is \
1204 saturated.\n", SCIPvarGetName(var), SCIPconsGetName(cons), consdata->cardval);
1205 ++(*nchgdomain);
1206 }
1207 else
1208 allvarfixed = FALSE;
1209 }
1210 }
1211 }
1212 assert(cnt == consdata->ntreatnonzeros);
1213
1214 /* reset constraint age counter */
1215 if( *nchgdomain > 0 )
1216 {
1218 }
1219
1220 /* delete constraint locally */
1221 if( allvarfixed )
1222 {
1225
1226 return SCIP_OKAY;
1227 }
1228 }
1229
1230 /* if relevant bound change events happened */
1231 if( consdata->neventdatascurrent > 0 )
1232 {
1233 SCIP_EVENTDATA** eventdatas;
1234 SCIP_VAR** eventvars;
1235 int neventdatas;
1236 int j;
1237
1238 neventdatas = consdata->neventdatascurrent;
1239 eventvars = consdata->eventvarscurrent;
1240 eventdatas = consdata->eventdatascurrent;
1241 assert(eventdatas != NULL && eventvars != NULL);
1242
1243 for( j = 0; j < neventdatas; ++j )
1244 {
1245 SCIP_EVENTDATA* eventdata;
1246 SCIP_Bool infeasible;
1247 SCIP_Bool tightened;
1248 SCIP_VAR* var;
1249
1250 eventdata = eventdatas[j];
1251 var = eventvars[j];
1252 assert(var != NULL && eventdata != NULL);
1253 assert(eventdata->var != NULL);
1254 assert(eventdata->indvar != NULL);
1255 assert(var == eventdata->var || var == eventdata->indvar);
1256 assert(SCIPvarIsBinary(eventdata->indvar));
1257
1258 /* if variable is an indicator variable */
1259 if( eventdata->indvar == var )
1260 {
1261 assert(eventdata->indvarmarked);
1262
1263 /* if variable is fixed to zero */
1265 {
1266 SCIP_VAR* implvar;
1267
1268 implvar = eventdata->var;
1269
1270 /* fix implied variable to zero if not done already */
1271 if( SCIPisFeasNegative(scip, SCIPvarGetLbLocal(implvar)) ||
1273 {
1274 SCIP_CALL( fixVariableZero(scip, implvar, &infeasible, &tightened) );
1275
1276 if( infeasible )
1277 {
1278 SCIPdebugMsg(scip, "the node is infeasible, indicator variable %s is fixed to zero although implied "
1279 "variable %s is nonzero.\n", SCIPvarGetName(var), SCIPvarGetName(implvar));
1281 *cutoff = TRUE;
1282
1283 return SCIP_OKAY;
1284 }
1285
1286 if( tightened )
1287 {
1288 SCIPdebugMsg(scip, "fixed variable <%s> to 0, since indicator variable %s is 0.\n",
1289 SCIPvarGetName(implvar), SCIPvarGetName(var));
1290 ++(*nchgdomain);
1291 }
1292 }
1293 }
1294 eventdata->indvarmarked = FALSE;
1295 }
1296 /* else if variable is an implied variable */
1297 else
1298 {
1299 assert(eventdata->var == var);
1300 assert(eventdata->varmarked);
1301
1302 /* if variable is is nonzero */
1304 {
1305 SCIP_VAR* indvar;
1306
1307 indvar = eventdata->indvar;
1308 assert(SCIPvarIsBinary(indvar));
1309
1310 /* fix indicator variable to 1.0 if not done already */
1311 if( SCIPvarGetLbLocal(indvar) < 0.5 )
1312 {
1313 /* if fixing is infeasible */
1314 if( SCIPvarGetUbLocal(indvar) < 0.5 )
1315 {
1316 SCIPdebugMsg(scip, "the node is infeasible, implied variable %s is fixed to nonzero "
1317 "although indicator variable %s is 0.\n", SCIPvarGetName(var), SCIPvarGetName(indvar));
1319 *cutoff = TRUE;
1320
1321 return SCIP_OKAY;
1322 }
1323 SCIP_CALL( SCIPchgVarLb(scip, indvar, 1.0) );
1324 SCIPdebugMsg(scip, "fixed variable <%s> to 1.0, since implied variable %s is nonzero.\n",
1326 ++(*nchgdomain);
1327 }
1328 }
1329 eventdata->varmarked = FALSE;
1330 }
1331 }
1332 }
1333 consdata->neventdatascurrent = 0;
1334
1335 return SCIP_OKAY;
1336}
1337
1338/** apply unbalanced branching (see the function \ref enforceCardinality() for further information) */
1339static
1341 SCIP* scip, /**< SCIP pointer */
1342 SCIP_SOL* sol, /**< solution to be enforced (or NULL) */
1343 SCIP_CONS* branchcons, /**< cardinality constraint */
1344 SCIP_VAR** vars, /**< variables of constraint */
1345 SCIP_VAR** indvars, /**< indicator variables */
1346 int nvars, /**< number of variables of constraint */
1347 int cardval, /**< cardinality value of constraint */
1348 int branchnnonzero, /**< number of variables that are fixed to be nonzero */
1349 int branchpos /**< position in array 'vars' */
1350 )
1351{
1352 SCIP_Bool infeasible;
1353 SCIP_NODE* node1;
1354 SCIP_NODE* node2;
1355
1356 /* check whether the variable selected for branching has a nonzero LP solution */
1358 assert(SCIPisFeasZero(scip, SCIPvarGetLbLocal(indvars[branchpos])));
1359 assert(SCIPisFeasEQ(scip, SCIPvarGetUbLocal(indvars[branchpos]), 1.0));
1360
1361 /* create branches */
1362 SCIPdebugMsg(scip, "apply unbalanced branching on variable <%s> of constraint <%s>.\n",
1363 SCIPvarGetName(indvars[branchpos]), SCIPconsGetName(branchcons));
1364
1365 /* create node 1 */
1366
1367 /* calculate node selection and objective estimate for node 1 */
1369 SCIPcalcChildEstimate(scip, vars[branchpos], 0.0) ) );
1370
1371 /* fix branching variable to zero */
1372 SCIP_CALL( fixVariableZeroNode(scip, vars[branchpos], node1, &infeasible) );
1373 assert(! infeasible);
1374
1375 /* create node 2 */
1376
1377 /* if the new number of nonzero variables is equal to the number of allowed nonzero variables;
1378 * i.e. cardinality constraint is saturated */
1379 assert(branchnnonzero + 1 <= cardval);
1380 if( branchnnonzero + 1 == cardval )
1381 {
1382 SCIP_Real nodeselest;
1383 SCIP_Real objest;
1384#ifndef NDEBUG
1385 int cnt = 0;
1386#endif
1387 int j;
1388
1389 /* calculate node selection and objective estimate for node 2 */
1390 nodeselest = 0.0;
1392 for( j = 0; j < nvars; ++j )
1393 {
1394 /* we only consider variables in constraint that are not the branching variable and are not fixed to nonzero */
1395 if( j != branchpos && SCIPvarGetLbLocal(indvars[j]) < 0.5 && !SCIPisFeasPositive(scip, SCIPvarGetLbLocal(vars[j]))
1397 )
1398 {
1401#ifndef NDEBUG
1402 ++cnt;
1403#endif
1404 }
1405 }
1407 assert(cnt == nvars - (1 + branchnnonzero));
1408 assert(cnt > 0);
1409
1410 /* create node 2 */
1411 SCIP_CALL( SCIPcreateChild(scip, &node2, nodeselest, objest) );
1412
1413 /* indicate that branching variable may be treated as nonzero */
1414 SCIP_CALL( SCIPchgVarLbNode(scip, node2, indvars[branchpos], 1.0) );
1415
1416 /* fix variables to zero since cardinality constraint is now saturated */
1417 for( j = 0; j < nvars; ++j )
1418 {
1419 /* we only consider variables in constraint that are not the branching variable and are not fixed to nonzero */
1420 if( j != branchpos && SCIPvarGetLbLocal(indvars[j]) < 0.5
1423 )
1424 {
1425 SCIP_CALL( fixVariableZeroNode(scip, vars[j], node2, &infeasible) );
1426 assert(!infeasible);
1427 }
1428 }
1429 }
1430 else
1431 {
1432 /* calculate node selection estimate for node 2 */
1434
1435 /* indicate that branching variable may be treated as nonzero */
1436 SCIP_CALL( SCIPchgVarLbNode(scip, node2, indvars[branchpos], 1.0) );
1437 }
1438
1439 return SCIP_OKAY;
1440}
1441
1442/** apply balanced branching (see the function enforceCardinality() for further information) */
1443static
1445 SCIP* scip, /**< SCIP pointer */
1446 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1447 SCIP_SOL* sol, /**< solution to be enforced (or NULL) */
1448 SCIP_CONS* branchcons, /**< cardinality constraint */
1449 SCIP_VAR** vars, /**< variables of constraint */
1450 SCIP_VAR** indvars, /**< indicator variables */
1451 int nvars, /**< number of variables of constraint */
1452 int cardval, /**< cardinality value of constraint */
1453 int branchnnonzero, /**< number of variables that are fixed to be nonzero */
1454 int branchpos, /**< position in array 'vars' */
1455 SCIP_Real balancedcutoff /**< cut off value for deciding whether to apply balanced branching */
1456 )
1457{
1458 SCIP_VAR** branchvars;
1459 SCIP_VAR** branchindvars;
1460 int nbranchvars;
1461 SCIP_Real splitval1;
1462 SCIP_Real splitval2;
1463 SCIP_Real weight1;
1464 SCIP_Real weight2;
1465 SCIP_Real sum1;
1466 SCIP_Real sum2;
1467 SCIP_Real w;
1468 int newcardval;
1469 int nnonzero;
1470 int nzero;
1471 int nbuffer;
1472 int ind;
1473 int cnt;
1474 int j;
1475
1476 /* check parameters */
1477 if( SCIPconshdlrGetSepaFreq(conshdlr) != 1 )
1478 {
1479 SCIPerrorMessage("balanced branching is only possible if separation frequency of constraint handler is 1.\n");
1481 }
1482
1483 cnt = 0;
1484 nzero = 0;
1485 nnonzero = 0;
1486 nbranchvars = 0;
1487
1488 weight1 = 0.0;
1489 weight2 = 0.0;
1490 sum1 = 0.0;
1491 sum2 = 0.0;
1492
1493 /* allocate buffer arrays */
1494 nbuffer = nvars-branchnnonzero;
1495 SCIP_CALL( SCIPallocBufferArray(scip, &branchvars, nbuffer) );
1496 SCIP_CALL( SCIPallocBufferArray(scip, &branchindvars, nbuffer) );
1497
1498 /* compute weight */
1499 for( j = 0; j < nvars; ++j )
1500 {
1501 SCIP_VAR* var;
1502
1503 var = vars[j];
1504
1505 /* if(binary) indicator variable is not fixed to 1.0 */
1508 {
1509 /* if implied variable is not already fixed to zero */
1511 {
1513
1514 weight1 += val * (SCIP_Real) (j - (nnonzero + nzero));
1515 weight2 += val;
1516 branchindvars[nbranchvars] = indvars[j];
1517 branchvars[nbranchvars++] = var;
1518
1519 if( !SCIPisFeasZero(scip, val) )
1520 ++cnt;
1521 }
1522 else
1523 ++nzero;
1524 }
1525 else
1526 ++nnonzero;
1527 }
1528 assert(nnonzero == branchnnonzero);
1529 assert(nbranchvars <= nvars - branchnnonzero);
1530
1531 assert(cnt >= cardval-nnonzero);
1532 assert(!SCIPisFeasZero(scip, weight2));
1533 w = weight1/weight2; /*lint !e414*/
1534
1535 ind = (int)SCIPfloor(scip, w);
1536 assert(0 <= ind && ind < nbranchvars-1);
1537
1538 /* compute LP sums */
1539 for( j = 0; j <= ind; ++j )
1540 {
1541 SCIP_Real val;
1542
1543 val = SCIPgetSolVal(scip, sol, branchvars[j]);
1544
1545 if( SCIPisFeasPositive(scip, val) )
1546 {
1548 sum1 += val / SCIPvarGetUbLocal(branchvars[j]);
1549 }
1550 else if( SCIPisFeasNegative(scip, val) )
1551 {
1553 sum1 += val / SCIPvarGetLbLocal(branchvars[j]);
1554 }
1555 }
1556 for( j = ind+1; j < nbranchvars; ++j )
1557 {
1558 SCIP_Real val;
1559
1560 val = SCIPgetSolVal(scip, sol, branchvars[j]);
1561
1562 if( SCIPisFeasPositive(scip, val) )
1563 {
1565 sum2 += val/SCIPvarGetUbLocal(branchvars[j]);
1566 }
1567 else if( SCIPisFeasNegative(scip, val) )
1568 {
1570 sum2 += val/SCIPvarGetLbLocal(branchvars[j]);
1571 }
1572 }
1573
1574 /* compute cardinality values of branching constraints */
1575 newcardval = cardval - nnonzero;
1576 splitval1 = sum1 + (SCIP_Real)newcardval - sum2 - 1.0;/*lint !e834*/
1577 splitval1 = SCIPfloor(scip, splitval1/2);
1578 splitval1 = MAX(splitval1, 0);
1579 assert((int)splitval1 >= 0);
1580 assert((int)splitval1 <= MIN(newcardval-1, ind));
1581 splitval2 = (SCIP_Real)(newcardval-1);
1582 splitval2 -= splitval1;
1583
1584 /* the lower or upper LP row of each branching constraint should cut off the current LP solution
1585 * if this is not the case, then use unbalanced branching */
1586 if ( !SCIPisFeasLT(scip, (SCIP_Real) splitval1 + balancedcutoff, sum1) ||
1587 !SCIPisFeasLT(scip, (SCIP_Real) splitval2 + balancedcutoff, sum2) )
1588 {
1589 SCIP_CALL( branchUnbalancedCardinality(scip, sol, branchcons, vars, indvars, nvars, cardval,
1590 branchnnonzero, branchpos) );
1591 }
1592 else
1593 {
1594 char name[SCIP_MAXSTRLEN];
1595 SCIP_NODE* node1;
1596 SCIP_NODE* node2;
1597 SCIP_CONS* cons1;
1598 SCIP_CONS* cons2;
1599
1600 SCIPdebugMsg(scip, "apply balanced branching on constraint <%s>.\n", SCIPconsGetName(branchcons));
1601
1602 if( SCIPisFeasZero(scip, splitval1) )
1603 {
1604 SCIP_Bool infeasible;
1605 SCIP_Real nodeselest;
1606 SCIP_Real objest;
1607
1608 nodeselest = 0.0;
1610
1611 /* calculate node selection and objective estimate for node */
1612 for( j = 0; j <= ind; ++j )
1613 {
1614 objest += SCIPcalcChildEstimateIncrease(scip, branchvars[j], SCIPgetSolVal(scip, sol, branchvars[j]), 0.0);
1615 nodeselest += SCIPcalcNodeselPriority(scip, branchvars[j], SCIP_BRANCHDIR_DOWNWARDS, 0.0);
1616 }
1618
1619 /* create node 1 */
1620 SCIP_CALL( SCIPcreateChild(scip, &node1, nodeselest, objest) );
1621
1622 for( j = 0; j <= ind; ++j )
1623 {
1624 SCIP_CALL( fixVariableZeroNode(scip, branchvars[j], node1, &infeasible) );
1625 assert(!infeasible);
1626 }
1627 }
1628 else
1629 {
1630 /* calculate node selection and objective estimate for node */
1632
1633 /* create branching constraint for node 1 */
1635 SCIP_CALL( SCIPcreateConsCardinality(scip, &cons1, name, ind+1, branchvars, (int)splitval1, branchindvars, NULL,
1637
1638 /* add constraint to node */
1639 SCIP_CALL( SCIPaddConsNode(scip, node1, cons1, NULL) );
1640
1641 /* release constraint */
1642 SCIP_CALL( SCIPreleaseCons(scip, &cons1) );
1643 }
1644
1645 if( SCIPisFeasZero(scip, splitval2) )
1646 {
1647 SCIP_Bool infeasible;
1648 SCIP_Real nodeselest;
1649 SCIP_Real objest;
1650
1651 nodeselest = 0.0;
1653
1654 /* calculate node selection and objective estimate for node */
1655 for( j = ind+1; j < nbranchvars; ++j )
1656 {
1657 objest += SCIPcalcChildEstimateIncrease(scip, branchvars[j], SCIPgetSolVal(scip, sol, branchvars[j]), 0.0);
1658 nodeselest += SCIPcalcNodeselPriority(scip, branchvars[j], SCIP_BRANCHDIR_DOWNWARDS, 0.0);
1659 }
1660 assert(nbranchvars - (ind + 1) > 0);
1662
1663 /* create node 1 */
1664 SCIP_CALL( SCIPcreateChild(scip, &node2, nodeselest, objest) );
1665
1666 for( j = ind+1; j < nbranchvars; ++j )
1667 {
1668 SCIP_CALL( fixVariableZeroNode(scip, branchvars[j], node2, &infeasible) );
1669 assert(!infeasible);
1670 }
1671 }
1672 else
1673 {
1674 /* calculate node selection and objective estimate for node */
1676
1677 /* shift the second half of variables */
1678 cnt = 0;
1679 for( j = ind+1; j < nbranchvars; ++j )
1680 {
1681 branchvars[cnt] = branchvars[j];
1682 branchindvars[cnt++] = branchindvars[j];
1683 }
1684 assert(cnt == nbranchvars - (ind + 1));
1685
1686 /* create branching constraint for node 2 */
1687 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "brright_#% " SCIP_LONGINT_FORMAT , SCIPgetNNodes(scip));
1688 SCIP_CALL( SCIPcreateConsCardinality(scip, &cons2, name, cnt, branchvars, (int)splitval2, branchindvars, NULL,
1690
1691 /* add constraint to node */
1692 SCIP_CALL( SCIPaddConsNode(scip, node2, cons2, NULL) );
1693
1694 /* release constraint */
1695 SCIP_CALL( SCIPreleaseCons(scip, &cons2) );
1696 }
1697 }
1698
1699 /* free buffer arrays */
1700 SCIPfreeBufferArray(scip, &branchindvars);
1701 SCIPfreeBufferArray(scip, &branchvars);
1702
1703 return SCIP_OKAY;
1704}
1705
1706/** enforcement method
1707 *
1708 * We check whether the current solution is feasible. If not, the cardinality constraints can be enforced by different
1709 * branching rules:
1710 *
1711 * - Unbalanced branching: Branch on the neighborhood of a single variable \f$i\f$, i.e., in one branch \f$x_i\f$ is
1712 * fixed to zero and in the other we modify cardinality constraints \f$|\mbox{supp}(x)| \leq k\f$ with \f$i\in D\f$ to
1713 * \f$|\mbox{supp}(x_{D\setminus i}) \leq k-1\f$
1714 *
1715 * - Balanced branching: First, choose a cardinality constraint \f$|\mbox{supp}(x_D) \leq k\f$ that is violated by the
1716 * current LP solution. Then, we compute \f$W = \sum_{j=1}^n |x_i|\f$ and \f$w = \sum_{j=1}^n j\, |x_i|\f$. Next,
1717 * search for the index \f$r\f$ that satisfies
1718 * \f[
1719 * r \leq \frac{w}{W} < r+1.
1720 * \f]
1721 * Choose a number \f$s\f$ with \f$0\leq s < \min\{k, r\}\f$. The branches are then
1722 * \f[
1723 * |\mbox{supp}(x_{d_1}, \ldots, x_{d_r})| \leq s \qquad \mbox{and}\qquad
1724 * |\mbox{supp}(x_{d_{r+1}}, \ldots, x_{d_{n}})| \leq k-s-1,
1725 * \f]
1726 * where \f$d_1, \ldots, d_n\f$ are the elements of the set \f$D\f$.
1727 *
1728 * The branching constraint is chosen by the largest sum of variable values.
1729 */
1730static
1732 SCIP* scip, /**< SCIP pointer */
1733 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
1734 SCIP_SOL* sol, /**< solution to be enforced (or NULL) */
1735 int nconss, /**< number of constraints */
1736 SCIP_CONS** conss, /**< indicator constraints */
1737 SCIP_RESULT* result /**< result */
1738 )
1739{
1740 SCIP_CONSHDLRDATA* conshdlrdata;
1741 SCIP_CONSDATA* consdata;
1742 SCIP_CONS* branchcons;
1743 SCIP_Real maxweight;
1744 SCIP_VAR** indvars;
1745 SCIP_VAR** vars;
1746 int nvars;
1747 int cardval;
1748
1749 SCIP_Bool branchbalanced = FALSE;
1750 SCIP_Bool branchallpos = TRUE;
1751 SCIP_Bool branchallneg = TRUE;
1752 int branchnnonzero;
1753 int branchpos;
1754 int c;
1755
1756 assert(scip != NULL);
1757 assert(conshdlr != NULL);
1758 assert(conss != NULL);
1759 assert(result != NULL);
1760
1761 maxweight = -SCIP_REAL_MAX;
1762 branchcons = NULL;
1763 branchnnonzero = -1;
1764 branchpos = -1;
1765
1766 SCIPdebugMsg(scip, "Enforcing cardinality constraints <%s>.\n", SCIPconshdlrGetName(conshdlr) );
1768
1769 /* get constraint handler data */
1770 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1771 assert(conshdlrdata != NULL);
1772
1773 /* search for a constraint with largest violation; from this constraint, we select the variable with largest LP value */
1774 for( c = 0; c < nconss; ++c )
1775 {
1776 SCIP_CONS* cons;
1778 SCIP_Real weight;
1779 SCIP_Real maxval;
1780 SCIP_Bool allpos = TRUE;
1781 SCIP_Bool allneg = TRUE;
1782 int nnonzero; /* number of variables that are currently deactivated in constraint */
1783 int pos; /* position of variable with largest LP solution value */
1784 int nchgdomain;
1785 int cnt;
1786 int j;
1787
1788 cons = conss[c];
1789 assert(cons != NULL);
1790 consdata = SCIPconsGetData(cons);
1791 assert(consdata != NULL);
1792
1793 nchgdomain = 0;
1794 cnt = 0;
1795 nnonzero = 0;
1796 pos = -1;
1797 nvars = consdata->nvars;
1798 vars = consdata->vars;
1799 indvars = consdata->indvars;
1800 cardval = consdata->cardval;
1801
1802 /* do nothing if there are not enough variables - this is usually eliminated by preprocessing */
1803 if( nvars < 2 )
1804 continue;
1805
1806 /* first perform propagation (it might happen that standard propagation is turned off) */
1807 SCIP_CALL( propCardinality(scip, cons, consdata, &cutoff, &nchgdomain) );
1808
1809 SCIPdebugMsg(scip, "propagating <%s> in enforcing (cutoff: %u, domain reductions: %d).\n",
1810 SCIPconsGetName(cons), cutoff, nchgdomain);
1811 if( cutoff )
1812 {
1814 return SCIP_OKAY;
1815 }
1816 if( nchgdomain > 0 )
1817 {
1819 return SCIP_OKAY;
1820 }
1821 assert(nchgdomain == 0);
1822
1823 /* check constraint */
1824 weight = 0.0;
1825 maxval = -SCIPinfinity(scip);
1826
1827 for( j = 0; j < nvars; ++j )
1828 {
1829 SCIP_VAR* var;
1830
1831 /* check whether indicator variable is zero, but variable in cardinality constraint is not fixed to zero;
1832 * if the variable is not multiaggregated this case should already be handled in propagation */
1833 if( SCIPvarGetUbLocal(indvars[j]) == 0.0 &&
1834 (
1836 )
1837 )
1838 {
1840 return SCIP_OKAY;
1841 }
1842
1844
1845 var = vars[j];
1846
1847 /* variable is not fixed to nonzero */
1848 if( SCIPvarGetLbLocal(indvars[j]) < 0.5
1851 )
1852 {
1853 SCIP_Real val;
1854
1855 val = SCIPgetSolVal(scip, sol, var);
1856 if( SCIPisFeasPositive(scip, val))
1857 allneg = FALSE;
1858 else if( SCIPisFeasNegative(scip, val))
1859 allpos = FALSE;
1860 val = REALABS(val);
1861
1862 if( !SCIPisFeasZero(scip, val) )
1863 {
1864 /* determine maximum nonzero-variable solution value */
1865 if( SCIPisFeasGT(scip, val, maxval) )
1866 {
1867 pos = j;
1868 maxval = val;
1869 }
1870
1871 weight += val;
1872 ++cnt;
1873 }
1874 }
1875 else
1876 ++nnonzero;
1877 }
1878 weight -= cardval;
1879 weight += nnonzero;
1880
1881 /* if we detected a cut off */
1882 if( nnonzero > cardval )
1883 {
1884 SCIPdebugMsg(scip, "Detected cut off: constraint <%s> has %d many variables that can be treated as nonzero, \
1885 although only %d many are feasible.\n", SCIPconsGetName(cons), nnonzero, cardval);
1887 return SCIP_OKAY;
1888 }
1889 /* else if domain can be reduced (since node 2 created in branchUnbalancedCardinality() would be infeasible) */
1890 else if( cnt > 0 && nnonzero + 1 > cardval )
1891 {
1892 SCIP_Bool infeasible;
1893 int v;
1894
1895 for( v = 0; v < nvars; ++v )
1896 {
1897 SCIP_VAR* var;
1898
1899 var = vars[v];
1900
1901 /* variable is not fixed to nonzero */
1902 assert(SCIPvarIsBinary(indvars[v]));
1903 if( SCIPvarGetLbLocal(indvars[v]) < 0.5
1906 )
1907 {
1909 assert(!infeasible);
1910 SCIPdebugMsg(scip, "detected domain reduction in enforcing: fixed variable <%s> to zero.\n", SCIPvarGetName(var));
1911 }
1912 }
1913
1915 return SCIP_OKAY;
1916 }
1917
1918 /* if constraint is violated */
1919 if( cnt > cardval - nnonzero && weight > maxweight )
1920 {
1921 maxweight = weight;
1922 branchcons = cons;
1923 branchnnonzero = nnonzero;
1924 branchpos = pos;
1925 branchallneg = allneg;
1926 branchallpos = allpos;
1927 }
1928 }
1929
1930 /* if all constraints are feasible */
1931 if( branchcons == NULL )
1932 {
1934 SCIP_Bool success;
1935
1936 /* polish primal solution */
1938 SCIP_CALL( polishPrimalSolution(scip, conss, nconss, sol, primsol) );
1941
1942 SCIPdebugMsg(scip, "All cardinality constraints are feasible.\n");
1943 return SCIP_OKAY;
1944 }
1945 assert(branchnnonzero >= 0);
1946 assert(branchpos >= 0);
1947
1948 /* get data for branching or domain reduction */
1949 consdata = SCIPconsGetData(branchcons);
1950 assert(consdata != NULL);
1951 nvars = consdata->nvars;
1952 vars = consdata->vars;
1953 indvars = consdata->indvars;
1954 cardval = consdata->cardval;
1955
1956 /* we only use balanced branching if either the lower or the upper bound row of the branching constraint is known
1957 * to be tight or violated */
1958 if( conshdlrdata->branchbalanced && !SCIPisFeasNegative(scip, maxweight) && ( branchallneg || branchallpos )
1959 && (conshdlrdata->balanceddepth == -1 || SCIPgetDepth(scip) <= conshdlrdata->balanceddepth)
1960 )
1961 {
1962 branchbalanced = TRUE;
1963 }
1964
1965 /* apply branching rule */
1966 if( branchbalanced )
1967 {
1968 SCIP_CALL( branchBalancedCardinality(scip, conshdlr, sol, branchcons, vars, indvars, nvars, cardval, branchnnonzero, branchpos,
1969 conshdlrdata->balancedcutoff) );
1970 }
1971 else
1972 {
1973 SCIP_CALL( branchUnbalancedCardinality(scip, sol, branchcons, vars, indvars, nvars, cardval, branchnnonzero,
1974 branchpos) );
1975 }
1976
1977 SCIP_CALL( SCIPresetConsAge(scip, branchcons) );
1979
1980 return SCIP_OKAY;
1981}
1982
1983/** Generate row
1984 *
1985 * We generate the row corresponding to the following simple valid inequalities:
1986 * \f[
1987 * \frac{x_1}{u_1} + \ldots + \frac{x_n}{u_n} \leq k\qquad\mbox{and}\qquad
1988 * \frac{x_1}{\ell_1} + \ldots + \frac{x_n}{\ell_1} \leq k,
1989 * \f]
1990 * where \f$\ell_1, \ldots, \ell_n\f$ and \f$u_1, \ldots, u_n\f$ are the nonzero and finite lower and upper bounds of
1991 * the variables \f$x_1, \ldots, x_n\f$ and k is the right hand side of the cardinality constraint. If at least k upper
1992 * bounds < 0 or a lower bounds > 0, the constraint itself is redundant, so the cut is not applied (lower bounds > 0
1993 * and upper bounds < 0 are usually detected in presolving or propagation). Infinite bounds and zero are skipped. Thus
1994 * \f$\ell_1, \ldots, \ell_n\f$ are all negative, which results in the \f$\leq\f$ inequality.
1995 *
1996 * Note that in fact, any mixture of nonzero finite lower and upper bounds would lead to a valid inequality as
1997 * above. However, usually either the lower or upper bound is nonzero. Thus, the above inequalities are the most
1998 * interesting.
1999 */
2000static
2002 SCIP* scip, /**< SCIP pointer */
2003 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2004 SCIP_CONS* cons, /**< constraint */
2005 SCIP_Bool local, /**< produce local cut? */
2006 SCIP_ROW** rowlb, /**< output: row for lower bounds (or NULL if not needed) */
2007 SCIP_ROW** rowub /**< output: row for upper bounds (or NULL if not needed) */
2008 )
2009{
2010 char name[SCIP_MAXSTRLEN];
2011 SCIP_CONSDATA* consdata;
2012 SCIP_VAR** vars;
2013 SCIP_Real* vals;
2014 SCIP_Real val;
2015 int nvars;
2016 int cnt;
2017 int j;
2018
2019 assert(scip != NULL);
2020 assert(conshdlr != NULL);
2021 assert(cons != NULL);
2022
2023 consdata = SCIPconsGetData(cons);
2024 assert(consdata != NULL);
2025 assert(consdata->vars != NULL);
2026 assert(consdata->indvars != NULL);
2027
2028 nvars = consdata->nvars;
2031
2032 /* take care of upper bounds */
2033 if( rowub != NULL )
2034 {
2035 int cardval;
2036
2037 cnt = 0;
2038 cardval = consdata->cardval;
2039 for( j = 0; j < nvars; ++j )
2040 {
2041 if( local )
2042 val = SCIPvarGetLbLocal(consdata->vars[j]);
2043 else
2044 val = SCIPvarGetUbGlobal(consdata->vars[j]);
2045
2046 /* if a variable may be treated as nonzero, then update cardinality value */
2047 if( SCIPisFeasEQ(scip, SCIPvarGetLbGlobal(consdata->indvars[j]), 1.0) )
2048 {
2049 --cardval;
2050 continue;
2051 }
2052
2053 if( !SCIPisInfinity(scip, val) && !SCIPisZero(scip, val) && !SCIPisNegative(scip, val) )
2054 {
2055 assert(consdata->vars[j] != NULL);
2056 vars[cnt] = consdata->vars[j];
2057 vals[cnt++] = 1.0/val;
2058 }
2059 }
2060 assert(cardval >= 0);
2061
2062 /* if cut is meaningful */
2063 if( cnt > cardval )
2064 {
2065 /* create upper bound inequality if at least two of the bounds are finite and nonzero */
2066 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "cardub#%s", SCIPconsGetName(cons));
2067 SCIP_CALL( SCIPcreateEmptyRowCons(scip, rowub, cons, name, -SCIPinfinity(scip), (SCIP_Real)cardval,
2068 local, TRUE, FALSE) );
2069 SCIP_CALL( SCIPaddVarsToRow(scip, *rowub, cnt, vars, vals) );
2070 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, *rowub, NULL) ) );
2071 }
2072 }
2073
2074 /* take care of lower bounds */
2075 if( rowlb != NULL )
2076 {
2077 int cardval;
2078
2079 cnt = 0;
2080 cardval = consdata->cardval;
2081 for( j = 0; j < nvars; ++j )
2082 {
2083 if( local )
2084 val = SCIPvarGetLbLocal(consdata->vars[j]);
2085 else
2086 val = SCIPvarGetLbGlobal(consdata->vars[j]);
2087
2088 /* if a variable may be treated as nonzero, then update cardinality value */
2089 if( SCIPvarGetLbGlobal(consdata->indvars[j]) > 0.5 )
2090 {
2091 --cardval;
2092 continue;
2093 }
2094
2095 if( !SCIPisInfinity(scip, -val) && !SCIPisZero(scip, val) && !SCIPisPositive(scip, val) )
2096 {
2097 assert(consdata->vars[j] != NULL);
2098 vars[cnt] = consdata->vars[j];
2099 vals[cnt++] = 1.0/val;
2100 }
2101 }
2102 assert(cardval >= 0);
2103
2104 /* if cut is meaningful */
2105 /* coverity[copy_paste_error] */
2106 if( cnt > cardval )
2107 {
2108 /* create lower bound inequality if at least two of the bounds are finite and nonzero */
2109 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "cardlb#%s", SCIPconsGetName(cons));
2110 SCIP_CALL( SCIPcreateEmptyRowCons(scip, rowlb, cons, name, -SCIPinfinity(scip), (SCIP_Real)cardval,
2111 local, TRUE, FALSE) );
2112 SCIP_CALL( SCIPaddVarsToRow(scip, *rowlb, nvars, vars, vals) );
2113 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, *rowlb, NULL) ) );
2114 }
2115 }
2116
2117 SCIPfreeBufferArray(scip, &vals);
2119
2120 return SCIP_OKAY;
2121}
2122
2123/** initialize or separate bound inequalities from cardinality constraints
2124 * (see the function \ref generateRowCardinality() for an explanation of bound inequalities)
2125 */
2126static
2128 SCIP* scip, /**< SCIP pointer */
2129 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2130 SCIP_CONS** conss, /**< cardinality constraints */
2131 int nconss, /**< number of cardinality constraints */
2132 SCIP_SOL* sol, /**< LP solution to be separated (or NULL) */
2133 SCIP_Bool solvedinitlp, /**< TRUE if initial LP relaxation at a node is solved */
2134 int* ngen, /**< pointer to store number of cuts generated (or NULL) */
2135 SCIP_Bool* cutoff /**< pointer to store whether a cutoff occurred */
2136 )
2137{
2138 int cnt = 0;
2139 int c;
2140
2141 assert(scip != NULL);
2142 assert(conss != NULL);
2143
2144 *cutoff = FALSE;
2145
2146 for( c = nconss-1; c >= 0; --c )
2147 {
2148 SCIP_CONSDATA* consdata;
2149 SCIP_ROW* rowub = NULL;
2150 SCIP_ROW* rowlb = NULL;
2151 SCIP_Bool release = FALSE;
2152
2153 assert(conss != NULL);
2154 assert(conss[c] != NULL);
2155 consdata = SCIPconsGetData(conss[c]);
2156 assert(consdata != NULL);
2157
2158 if( solvedinitlp )
2159 SCIPdebugMsg(scip, "Separating inequalities for cardinality constraint <%s>.\n", SCIPconsGetName(conss[c]) );
2160 else
2161 SCIPdebugMsg(scip, "Checking for initial rows for cardinality constraint <%s>.\n", SCIPconsGetName(conss[c]) );
2162
2163 /* generate rows associated to cardinality constraint; the rows are stored in the constraint data
2164 * if they are globally valid */
2165 if( SCIPconsIsLocal(conss[c]) )
2166 {
2167 SCIP_CALL( generateRowCardinality(scip, conshdlr, conss[c], TRUE, &rowlb, &rowub) );
2168 release = TRUE;
2169 }
2170 else
2171 {
2172 if( consdata->rowub == NULL || consdata->rowlb == NULL )
2173 {
2174 SCIP_CALL( generateRowCardinality(scip, conshdlr, conss[c], FALSE,
2175 (consdata->rowlb == NULL) ? &consdata->rowlb : NULL,
2176 (consdata->rowub == NULL) ? &consdata->rowub : NULL) );/*lint !e826*/
2177 }
2178 rowub = consdata->rowub;
2179 rowlb = consdata->rowlb;
2180 }
2181
2182 /* put corresponding rows into LP */
2183 if( rowub != NULL && !SCIProwIsInLP(rowub) && ( solvedinitlp || SCIPisCutEfficacious(scip, sol, rowub) ) )
2184 {
2186 assert(SCIPisLE(scip, SCIProwGetRhs(rowub), (SCIP_Real)consdata->cardval));
2187
2188 SCIP_CALL( SCIPaddRow(scip, rowub, FALSE, cutoff) );
2189 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, rowub, NULL) ) );
2190
2191 if( solvedinitlp )
2192 {
2193 SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
2194 }
2195 ++cnt;
2196 }
2197
2198 if( ! (*cutoff) && rowlb != NULL && !SCIProwIsInLP(rowlb)
2199 && ( solvedinitlp || SCIPisCutEfficacious(scip, sol, rowlb) )
2200 )
2201 {
2203 assert(SCIPisLE(scip, SCIProwGetRhs(rowlb), (SCIP_Real)consdata->cardval));
2204
2205 SCIP_CALL( SCIPaddRow(scip, rowlb, FALSE, cutoff) );
2206 SCIPdebug( SCIP_CALL( SCIPprintRow(scip, rowlb, NULL) ) );
2207
2208 if( solvedinitlp )
2209 {
2210 SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
2211 }
2212 ++cnt;
2213 }
2214
2215 if( release )
2216 {
2217 if( rowlb != NULL )
2218 {
2219 SCIP_CALL( SCIPreleaseRow(scip, &rowlb) );
2220 }
2221 if( rowub != NULL )
2222 {
2223 SCIP_CALL( SCIPreleaseRow(scip, &rowub) );
2224 }
2225 }
2226
2227 if( *cutoff )
2228 break;
2229 }
2230
2231 /* store number of generated cuts */
2232 if( ngen != NULL )
2233 *ngen = cnt;
2234
2235 return SCIP_OKAY;
2236}
2237
2238/** separates cardinality constraints for arbitrary solutions */
2239static
2241 SCIP* scip, /**< SCIP pointer */
2242 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2243 SCIP_SOL* sol, /**< solution to be separated (or NULL) */
2244 int nconss, /**< number of constraints */
2245 SCIP_CONS** conss, /**< cardinality constraints */
2246 SCIP_RESULT* result /**< result */
2247 )
2248{
2250 int ngen = 0;
2251
2252 assert(scip != NULL);
2253 assert(conshdlr != NULL);
2254 assert(conss != NULL);
2255 assert(result != NULL);
2256
2258
2259 if( nconss == 0 )
2260 return SCIP_OKAY;
2261
2262 /* only separate cuts if we are not close to terminating */
2263 if( SCIPisStopped(scip) )
2264 return SCIP_OKAY;
2265
2267
2268 /* separate bound inequalities from cardinality constraints */
2269 SCIP_CALL( initsepaBoundInequalityFromCardinality(scip, conshdlr, conss, nconss, sol, TRUE, &ngen, &cutoff) );
2270 if( cutoff )
2271 {
2273 return SCIP_OKAY;
2274 }
2275
2276 /* evaluate results */
2277 if( ngen > 0 )
2279 SCIPdebugMsg(scip, "Separated %d bound inequalities.\n", ngen);
2280
2281 return SCIP_OKAY;
2282}
2283
2284/* ---------------------------- constraint handler callback methods ----------------------*/
2285
2286/** copy method for constraint handler plugins (called when SCIP copies plugins) */
2287static
2288SCIP_DECL_CONSHDLRCOPY(conshdlrCopyCardinality)
2289{ /*lint --e{715}*/
2290 assert(scip != NULL);
2291 assert(conshdlr != NULL);
2292
2294
2295 /* call inclusion method of constraint handler */
2297
2298 *valid = TRUE;
2299
2300 return SCIP_OKAY;
2301}
2302
2303/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
2304static
2305SCIP_DECL_CONSFREE(consFreeCardinality)
2306{
2307 SCIP_CONSHDLRDATA* conshdlrdata;
2308
2309 assert(scip != NULL);
2310 assert(conshdlr != NULL);
2311
2313
2314 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2315 assert(conshdlrdata != NULL);
2316
2317 /* free hash map */
2318 if( conshdlrdata->varhash != NULL )
2319 {
2320 SCIPhashmapFree(&conshdlrdata->varhash);
2321 }
2322
2323 SCIPfreeBlockMemory(scip, &conshdlrdata);
2324
2325 return SCIP_OKAY;
2326}
2327
2328/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
2329static
2330SCIP_DECL_CONSEXITSOL(consExitsolCardinality)
2331{ /*lint --e{715}*/
2332 SCIP_CONSHDLRDATA* conshdlrdata;
2333 int c;
2334
2335 assert(scip != NULL);
2336 assert(conshdlr != NULL);
2337
2339
2340 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2341 assert(conshdlrdata != NULL);
2342
2343 /* check each constraint */
2344 for( c = 0; c < nconss; ++c )
2345 {
2346 SCIP_CONSDATA* consdata;
2347
2348 assert(conss != NULL);
2349 assert(conss[c] != NULL);
2350 consdata = SCIPconsGetData(conss[c]);
2351 assert(consdata != NULL);
2352
2353 SCIPdebugMsg(scip, "Exiting cardinality constraint <%s>.\n", SCIPconsGetName(conss[c]) );
2354
2355 /* free rows */
2356 if( consdata->rowub != NULL )
2357 {
2358 SCIP_CALL( SCIPreleaseRow(scip, &consdata->rowub) );
2359 }
2360 if( consdata->rowlb != NULL )
2361 {
2362 SCIP_CALL( SCIPreleaseRow(scip, &consdata->rowlb) );
2363 }
2364 }
2365
2366 /* free hash map */
2367 if( conshdlrdata->varhash != NULL )
2368 {
2369 SCIPhashmapFree(&conshdlrdata->varhash);
2370 }
2371
2372 return SCIP_OKAY;
2373}
2374
2375/** frees specific constraint data */
2376static
2377SCIP_DECL_CONSDELETE(consDeleteCardinality)
2378{ /*lint --e{737, 647}*/
2379 assert(scip != NULL);
2380 assert(conshdlr != NULL);
2381 assert(cons != NULL);
2382 assert(consdata != NULL);
2383
2385
2386 SCIPdebugMsg(scip, "Deleting cardinality constraint <%s>.\n", SCIPconsGetName(cons) );
2387
2388 /* drop events on transformed variables */
2389 if( SCIPconsIsTransformed(cons) )
2390 {
2391 SCIP_CONSHDLRDATA* conshdlrdata;
2392 int j;
2393
2394 /* get constraint handler data */
2395 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2396 assert(conshdlrdata != NULL);
2397 assert(conshdlrdata->eventhdlr != NULL);
2398
2399 for( j = 0; j < (*consdata)->nvars; ++j )
2400 {
2401 SCIP_CALL( dropVarEventCardinality(scip, conshdlrdata->eventhdlr, *consdata, (*consdata)->vars[j],
2402 (*consdata)->indvars[j], &(*consdata)->eventdatas[j]) );
2403 assert((*consdata)->eventdatas[j] == NULL);
2404 }
2405 }
2406
2407 if( (*consdata)->weights != NULL )
2408 {
2409 SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->maxvars);
2410 }
2411 SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdatas, (*consdata)->maxvars);
2412 SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventvarscurrent, 4 * (*consdata)->maxvars);/*lint !e647*/
2413 SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdatascurrent, 4 * (*consdata)->maxvars);/*lint !e647*/
2414 SCIPfreeBlockMemoryArray(scip, &(*consdata)->indvars, (*consdata)->maxvars);
2415 SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->maxvars);
2416
2417 /* free rows */
2418 if( (*consdata)->rowub != NULL )
2419 {
2420 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->rowub) );
2421 }
2422 if( (*consdata)->rowlb != NULL )
2423 {
2424 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->rowlb) );
2425 }
2426 assert((*consdata)->rowub == NULL);
2427 assert((*consdata)->rowlb == NULL);
2428
2429 SCIPfreeBlockMemory(scip, consdata);
2430
2431 /* Make sure that the hash for indicator binary variables is freed. If we read a problem and then another problem without
2432 * solving (transforming) between, then no callback of constraint handlers are called. Thus, we cannot easily free the
2433 * hash map there. */
2434 if ( SCIPconshdlrGetNConss(conshdlr) == 0 )
2435 {
2436 SCIP_CONSHDLRDATA* conshdlrdata;
2437
2438 /* get constraint handler data */
2439 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2440 assert( conshdlrdata != NULL );
2441
2442 if ( conshdlrdata->varhash != NULL )
2443 SCIPhashmapFree(&conshdlrdata->varhash);
2444 }
2445
2446 return SCIP_OKAY;
2447}
2448
2449/** transforms constraint data into data belonging to the transformed problem */
2450static
2451SCIP_DECL_CONSTRANS(consTransCardinality)
2452{
2453 SCIP_CONSDATA* consdata;
2454 SCIP_CONSHDLRDATA* conshdlrdata;
2455 SCIP_CONSDATA* sourcedata;
2456 char s[SCIP_MAXSTRLEN];
2457 int j;
2458
2459 assert(scip != NULL);
2460 assert(conshdlr != NULL);
2461 assert(sourcecons != NULL);
2462 assert(targetcons != NULL);
2463
2465
2466 /* get constraint handler data */
2467 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2468 assert(conshdlrdata != NULL);
2469 assert(conshdlrdata->eventhdlr != NULL);
2470
2471 SCIPdebugMsg(scip, "Transforming cardinality constraint: <%s>.\n", SCIPconsGetName(sourcecons) );
2472
2473 /* get data of original constraint */
2474 sourcedata = SCIPconsGetData(sourcecons);
2475 assert(sourcedata != NULL);
2476 assert(sourcedata->nvars > 0);
2477 assert(sourcedata->nvars <= sourcedata->maxvars);
2478
2479 /* create constraint data */
2480 SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) );
2481
2482 consdata->cons = NULL;
2483 consdata->nvars = sourcedata->nvars;
2484 consdata->maxvars = sourcedata->nvars;
2485 consdata->cardval = sourcedata->cardval;
2486 consdata->rowub = NULL;
2487 consdata->rowlb = NULL;
2488 consdata->eventdatascurrent = NULL;
2489 consdata->neventdatascurrent = 0;
2490 consdata->ntreatnonzeros = 0;
2491 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->vars, consdata->nvars) );
2492 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->indvars, consdata->nvars) );
2493 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eventdatas, consdata->nvars) );
2494 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eventdatascurrent, 4*consdata->nvars) );/*lint !e647*/
2495 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eventvarscurrent, 4*consdata->nvars) );/*lint !e647*/
2496
2497 /* if weights were used */
2498 if( sourcedata->weights != NULL )
2499 {
2500 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->weights, sourcedata->weights, consdata->nvars) );
2501 }
2502 else
2503 consdata->weights = NULL;
2504
2505 for( j = 0; j < sourcedata->nvars; ++j )
2506 {
2507 assert(sourcedata->vars[j] != 0);
2508 assert(sourcedata->indvars[j] != 0);
2509 SCIP_CALL( SCIPgetTransformedVar(scip, sourcedata->vars[j], &(consdata->vars[j])) );
2510 SCIP_CALL( SCIPgetTransformedVar(scip, sourcedata->indvars[j], &(consdata->indvars[j])) );
2511
2512 /* if variable is fixed to be nonzero */
2513 if( SCIPvarGetLbLocal(consdata->indvars[j]) > 0.5 )
2514 ++(consdata->ntreatnonzeros);
2515 }
2516
2517 /* create transformed constraint with the same flags */
2518 (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "t_%s", SCIPconsGetName(sourcecons));
2519 SCIP_CALL( SCIPcreateCons(scip, targetcons, s, conshdlr, consdata,
2520 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons),
2521 SCIPconsIsEnforced(sourcecons), SCIPconsIsChecked(sourcecons),
2522 SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
2523 SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons),
2524 SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
2525
2526 consdata->cons = *targetcons;
2527 assert(consdata->cons != NULL);
2528
2529 /* catch bound change events on variable */
2530 for( j = 0; j < consdata->nvars; ++j )
2531 {
2532 SCIP_CALL( catchVarEventCardinality(scip, conshdlrdata->eventhdlr, consdata,
2533 consdata->vars[j], consdata->indvars[j], j, &consdata->eventdatas[j]) );
2534 assert(consdata->eventdatas[j] != NULL);
2535 }
2536
2537#ifdef SCIP_DEBUG
2538 if( SCIPisGT(scip, (SCIP_Real)consdata->ntreatnonzeros, consdata->cardval) )
2539 {
2540 SCIPdebugMsg(scip, "constraint <%s> has %d variables fixed to be nonzero, allthough the constraint allows \
2541 only %d nonzero variables\n", SCIPconsGetName(*targetcons), consdata->ntreatnonzeros, consdata->cardval);
2542 }
2543#endif
2544
2545 return SCIP_OKAY;
2546}
2547
2548/** presolving method of constraint handler */
2549static
2550SCIP_DECL_CONSPRESOL(consPresolCardinality)
2551{ /*lint --e{715}*/
2552 SCIPdebug( int oldnfixedvars; )
2553 SCIPdebug( int oldndelconss; )
2554 SCIPdebug( int oldnupgdconss; )
2555 int nremovedvars;
2556 SCIP_EVENTHDLR* eventhdlr;
2557 int c;
2558
2559 assert(scip != NULL);
2560 assert(conshdlr != NULL);
2561 assert(result != NULL);
2562
2564
2565 SCIPdebugMsg(scip, "Presolving cardinality constraints.\n");
2566
2568 SCIPdebug( oldnfixedvars = *nfixedvars; )
2569 SCIPdebug( oldndelconss = *ndelconss; )
2570 SCIPdebug( oldnupgdconss = *nupgdconss; )
2571 nremovedvars = 0;
2572
2573 /* only run if success if possible */
2574 if( nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 )
2575 {
2576 /* get constraint handler data */
2577 assert(SCIPconshdlrGetData(conshdlr) != NULL);
2578 eventhdlr = SCIPconshdlrGetData(conshdlr)->eventhdlr;
2579 assert(eventhdlr != NULL);
2580
2582
2583 /* check each constraint */
2584 for( c = 0; c < nconss; ++c )
2585 {
2586 SCIP_CONSDATA* consdata;
2587 SCIP_CONS* cons;
2589 SCIP_Bool success;
2590
2591 assert(conss != NULL);
2592 assert(conss[c] != NULL);
2593 cons = conss[c];
2594 consdata = SCIPconsGetData(cons);
2595
2596 assert(consdata != NULL);
2597 assert(consdata->nvars >= 0);
2598 assert(consdata->nvars <= consdata->maxvars);
2600
2601 /* perform one presolving round */
2602 SCIP_CALL( presolRoundCardinality(scip, cons, consdata, eventhdlr, &cutoff, &success,
2603 ndelconss, nupgdconss, nfixedvars, &nremovedvars) );
2604
2605 if( cutoff )
2606 {
2607 SCIPdebugMsg(scip, "presolving detected cutoff.\n");
2609 return SCIP_OKAY;
2610 }
2611
2612 if( success )
2614 }
2615 }
2616 (*nchgcoefs) += nremovedvars;
2617
2618 SCIPdebug( SCIPdebugMsg(scip, "presolving fixed %d variables, removed %d variables, deleted %d constraints, "
2619 "and upgraded %d constraints.\n", *nfixedvars - oldnfixedvars, nremovedvars, *ndelconss - oldndelconss,
2620 *nupgdconss - oldnupgdconss); )
2621
2622 return SCIP_OKAY;
2623}
2624
2625/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
2626static
2627SCIP_DECL_CONSINITLP(consInitlpCardinality)
2628{ /*lint --e{715}*/
2630
2631 assert(scip != NULL);
2632 assert(conshdlr != NULL);
2633
2634 /* checking for initial rows for cardinality constraints */
2635 SCIP_CALL( initsepaBoundInequalityFromCardinality(scip, conshdlr, conss, nconss, NULL, FALSE, NULL, &cutoff) );
2636 assert(!cutoff);
2637
2638 return SCIP_OKAY;
2639}
2640
2641/** separation method of constraint handler for LP solutions */
2642static
2643SCIP_DECL_CONSSEPALP(consSepalpCardinality)
2644{ /*lint --e{715}*/
2645 assert(scip != NULL);
2646 assert(conshdlr != NULL);
2647 assert(conss != NULL);
2648 assert(result != NULL);
2649
2650 SCIP_CALL( separateCardinality(scip, conshdlr, NULL, nconss, conss, result) );
2651
2652 return SCIP_OKAY;
2653}
2654
2655/** separation method of constraint handler for arbitrary primal solutions */
2656static
2657SCIP_DECL_CONSSEPASOL(consSepasolCardinality)
2658{ /*lint --e{715}*/
2659 assert(scip != NULL);
2660 assert(conshdlr != NULL);
2661 assert(conss != NULL);
2662 assert(result != NULL);
2663
2664 SCIP_CALL( separateCardinality(scip, conshdlr, sol, nconss, conss, result) );
2665
2666 return SCIP_OKAY;
2667}
2668
2669/** constraint enforcing method of constraint handler for LP solutions */
2670static
2671SCIP_DECL_CONSENFOLP(consEnfolpCardinality)
2672{ /*lint --e{715}*/
2673 assert(scip != NULL);
2674 assert(conshdlr != NULL);
2675 assert(conss != NULL);
2676 assert(result != NULL);
2677
2679
2680 SCIP_CALL( enforceCardinality(scip, conshdlr, NULL, nconss, conss, result) );
2681
2682 return SCIP_OKAY;
2683}
2684
2685/** constraint enforcing method of constraint handler for relaxation solutions */
2686static
2687SCIP_DECL_CONSENFORELAX(consEnforelaxCardinality)
2688{ /*lint --e{715}*/
2689 assert( scip != NULL );
2690 assert( conshdlr != NULL );
2691 assert( conss != NULL );
2692 assert( result != NULL );
2693
2695
2696 SCIP_CALL( enforceCardinality(scip, conshdlr, sol, nconss, conss, result) );
2697
2698 return SCIP_OKAY;
2699}
2700
2701/** constraint enforcing method of constraint handler for pseudo solutions */
2702static
2703SCIP_DECL_CONSENFOPS(consEnfopsCardinality)
2704{ /*lint --e{715}*/
2705 assert(scip != NULL);
2706 assert(conshdlr != NULL);
2707 assert(conss != NULL);
2708 assert(result != NULL);
2709
2711
2712 SCIP_CALL( enforceCardinality(scip, conshdlr, NULL, nconss, conss, result) );
2713
2714 return SCIP_OKAY;
2715}
2716
2717/** feasibility check method of constraint handler for integral solutions
2718 *
2719 * We simply check whether more variables than allowed are nonzero in the given solution.
2720 */
2721static
2722SCIP_DECL_CONSCHECK(consCheckCardinality)
2723{ /*lint --e{715}*/
2724 int c;
2725
2726 assert(scip != NULL);
2727 assert(conshdlr != NULL);
2728 assert(conss != NULL);
2729 assert(result != NULL);
2730
2732
2733 /* check each constraint */
2734 for( c = 0; c < nconss; ++c )
2735 {
2736 SCIP_CONSDATA* consdata;
2737 int cardval;
2738 int j;
2739 int cnt;
2740
2741 cnt = 0;
2742 assert(conss[c] != NULL);
2743 consdata = SCIPconsGetData(conss[c]);
2744 assert(consdata != NULL);
2745 cardval = consdata->cardval;
2746 SCIPdebugMsg(scip, "Checking cardinality constraint <%s>.\n", SCIPconsGetName(conss[c]));
2747
2748 /* check all variables */
2749 for( j = 0; j < consdata->nvars; ++j )
2750 {
2751 /* if variable is nonzero */
2752 if( !SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->vars[j])) )
2753 {
2754 ++cnt;
2755
2756 /* if more variables than allowed are nonzero */
2757 if( cnt > cardval )
2758 {
2759 SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
2761
2762 if( printreason )
2763 {
2764 int l;
2765
2766 SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
2767 SCIPinfoMessage(scip, NULL, ";\nviolation: ");
2768
2769 for( l = 0; l < consdata->nvars; ++l )
2770 {
2771 /* if variable is nonzero */
2772 if( !SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->vars[l])) )
2773 {
2774 SCIPinfoMessage(scip, NULL, "<%s> = %.15g ",
2775 SCIPvarGetName(consdata->vars[l]), SCIPgetSolVal(scip, sol, consdata->vars[l]));
2776 }
2777 }
2778 SCIPinfoMessage(scip, NULL, "\n");
2779 }
2780 if( sol != NULL )
2782 return SCIP_OKAY;
2783 }
2784 }
2785 }
2786 }
2788
2789 return SCIP_OKAY;
2790}
2791
2792/** domain propagation method of constraint handler */
2793static
2794SCIP_DECL_CONSPROP(consPropCardinality)
2795{ /*lint --e{715}*/
2796 int nchgdomain = 0;
2797 int c;
2798
2799 assert(scip != NULL);
2800 assert(conshdlr != NULL);
2801 assert(conss != NULL);
2802 assert(result != NULL);
2803
2805
2807
2809
2810 /* check each constraint */
2811 for( c = 0; c < nconss; ++c )
2812 {
2813 SCIP_CONS* cons;
2814 SCIP_CONSDATA* consdata;
2816
2818 assert(conss[c] != NULL);
2819 cons = conss[c];
2820 consdata = SCIPconsGetData(cons);
2821 assert(consdata != NULL);
2822 SCIPdebugMsg(scip, "Propagating cardinality constraint <%s>.\n", SCIPconsGetName(cons) );
2823
2825 SCIP_CALL( propCardinality(scip, cons, consdata, &cutoff, &nchgdomain) );
2826 if( cutoff )
2827 {
2829 return SCIP_OKAY;
2830 }
2831 }
2832 SCIPdebugMsg(scip, "Propagated %d domains.\n", nchgdomain);
2833 if( nchgdomain > 0 )
2835
2836 return SCIP_OKAY;
2837}
2838
2839/** variable rounding lock method of constraint handler
2840 *
2841 * Let lb and ub be the lower and upper bounds of a
2842 * variable. Preprocessing usually makes sure that lb <= 0 <= ub.
2843 *
2844 * - If lb < 0 then rounding down may violate the constraint.
2845 * - If ub > 0 then rounding up may violated the constraint.
2846 * - If lb > 0 or ub < 0 then the rhs of the constraint can be updated and the variable
2847 * can be removed from the constraint. Thus, we do not have to deal with it here.
2848 * - If lb == 0 then rounding down does not violate the constraint.
2849 * - If ub == 0 then rounding up does not violate the constraint.
2850 */
2851static
2852SCIP_DECL_CONSLOCK(consLockCardinality)
2853{
2854 SCIP_CONSDATA* consdata;
2855 SCIP_VAR** vars;
2856 int nvars;
2857 SCIP_VAR** indvars;
2858 int j;
2859
2860 assert(scip != NULL);
2861 assert(conshdlr != NULL);
2862 assert(cons != NULL);
2863 assert(locktype == SCIP_LOCKTYPE_MODEL);
2864
2866
2867 consdata = SCIPconsGetData(cons);
2868 assert(consdata != NULL);
2869
2870 SCIPdebugMsg(scip, "Locking constraint <%s>.\n", SCIPconsGetName(cons));
2871
2872 vars = consdata->vars;
2873 indvars = consdata->indvars;
2874 nvars = consdata->nvars;
2875 assert(vars != NULL);
2876
2877 for( j = 0; j < nvars; ++j )
2878 {
2879 SCIP_VAR* var;
2880 SCIP_VAR* indvar;
2881 var = vars[j];
2882 indvar = indvars[j];
2883
2884 /* if lower bound is negative, rounding down may violate constraint */
2886 {
2887 SCIP_CALL( SCIPaddVarLocksType(scip, var, locktype, nlockspos, nlocksneg) );
2888 }
2889
2890 /* additionally: if upper bound is positive, rounding up may violate constraint */
2892 {
2893 SCIP_CALL( SCIPaddVarLocksType(scip, var, locktype, nlocksneg, nlockspos) );
2894 }
2895
2896 /* add lock on indicator variable in both directions; @todo write constraint handler to handle down locks */
2897 SCIP_CALL( SCIPaddVarLocksType(scip, indvar, locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
2898 }
2899
2900 return SCIP_OKAY;
2901}
2902
2903/** constraint display method of constraint handler */
2904static
2905SCIP_DECL_CONSPRINT(consPrintCardinality)
2906{ /*lint --e{715}*/
2907 SCIP_CONSDATA* consdata;
2908 int j;
2909
2910 assert(scip != NULL);
2911 assert(conshdlr != NULL);
2912 assert(cons != NULL);
2913
2915
2916 consdata = SCIPconsGetData(cons);
2917 assert(consdata != NULL);
2918
2919 for( j = 0; j < consdata->nvars; ++j )
2920 {
2921 if( j > 0 )
2922 SCIPinfoMessage(scip, file, ", ");
2923 SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[j], FALSE) );
2924
2925 if( consdata->indvars[j] != NULL )
2926 {
2927 SCIPinfoMessage(scip, file, " [");
2928 SCIP_CALL( SCIPwriteVarName(scip, file, consdata->indvars[j], FALSE) );
2929 SCIPinfoMessage(scip, file, "]");
2930 }
2931
2932 if( consdata->weights == NULL )
2933 SCIPinfoMessage(scip, file, " (%d)", j+1);
2934 else
2935 SCIPinfoMessage(scip, file, " (%3.2f)", consdata->weights[j]);
2936 }
2937 SCIPinfoMessage(scip, file, " <= %d", consdata->cardval);
2938
2939 return SCIP_OKAY;
2940}
2941
2942/** constraint copying method of constraint handler */
2943static
2944SCIP_DECL_CONSCOPY(consCopyCardinality)
2945{ /*lint --e{715}*/
2946 SCIP_CONSDATA* sourceconsdata;
2947 SCIP_VAR** sourcevars;
2948 SCIP_VAR** targetvars;
2949 SCIP_VAR** sourceindvars;
2950 SCIP_VAR** targetindvars;
2951 SCIP_Real* sourceweights;
2952 SCIP_Real* targetweights;
2953 const char* consname;
2954 int nvars;
2955 int v;
2956
2957 assert(scip != NULL);
2958 assert(sourcescip != NULL);
2959 assert(sourcecons != NULL);
2960 assert(SCIPisTransformed(sourcescip));
2961
2963
2964 *valid = TRUE;
2965
2966 if( name != NULL )
2967 consname = name;
2968 else
2969 consname = SCIPconsGetName(sourcecons);
2970
2971 SCIPdebugMsg(scip, "Copying cardinality constraint <%s> ...\n", consname);
2972
2973 sourceconsdata = SCIPconsGetData(sourcecons);
2974 assert(sourceconsdata != NULL);
2975
2976 /* get variables and weights of the source constraint */
2977 nvars = sourceconsdata->nvars;
2978
2979 if( nvars == 0 )
2980 return SCIP_OKAY;
2981
2982 sourcevars = sourceconsdata->vars;
2983 assert(sourcevars != NULL);
2984 sourceindvars = sourceconsdata->indvars;
2985 assert(sourceindvars != NULL);
2986 sourceweights = sourceconsdata->weights;
2987 assert(sourceweights != NULL);
2988
2989 /* duplicate variable array */
2990 SCIP_CALL( SCIPallocBufferArray(sourcescip, &targetvars, nvars) );
2991 SCIP_CALL( SCIPallocBufferArray(sourcescip, &targetindvars, nvars) );
2992 SCIP_CALL( SCIPduplicateBufferArray(sourcescip, &targetweights, sourceweights, nvars) );
2993
2994 /* get copied variables in target SCIP */
2995 for( v = 0; v < nvars && *valid; ++v )
2996 {
2997 assert(sourcevars[v] != NULL);
2998 assert(sourceindvars[v] != NULL);
2999
3000 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &(targetvars[v]), varmap, consmap, global, valid) );
3001 if( *valid )
3002 {
3003 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourceindvars[v], &(targetindvars[v]), varmap, consmap, global, valid) );
3004 }
3005 }
3006
3007 /* only create the target constraint, if all variables could be copied */
3008 if( *valid )
3009 {
3010 SCIP_CALL( SCIPcreateConsCardinality(scip, cons, consname, nvars, targetvars, sourceconsdata->cardval, targetindvars,
3011 targetweights, initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
3012 }
3013
3014 /* free buffer array */
3015 SCIPfreeBufferArray(sourcescip, &targetweights);
3016 SCIPfreeBufferArray(sourcescip, &targetindvars);
3017 SCIPfreeBufferArray(sourcescip, &targetvars);
3018
3019 return SCIP_OKAY;
3020}
3021
3022/** constraint parsing method of constraint handler */
3023static
3024SCIP_DECL_CONSPARSE(consParseCardinality)
3025{ /*lint --e{715}*/
3026 SCIP_VAR* var;
3027 SCIP_VAR* indvar;
3028 SCIP_Real weight;
3029 int cardval;
3030 const char* s;
3031 char* t;
3032
3033 assert(scip != NULL);
3034 assert(conshdlr != NULL);
3035 assert(cons != NULL);
3036 assert(success != NULL);
3037
3039
3040 *success = TRUE;
3041 s = str;
3042
3043 /* create empty cardinality constraint */
3044 SCIP_CALL( SCIPcreateConsCardinality(scip, cons, name, 0, NULL, 0, NULL, NULL, initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
3045
3046 /* loop through string */
3047 while( *s != '\0' )
3048 {
3049 /* parse variable name */
3050 SCIP_CALL( SCIPparseVarName(scip, s, &var, &t) );
3051
3052 if( var == NULL )
3053 {
3054 t = strchr(t, '<');
3055
3056 if( t != NULL )
3057 s = t;
3058
3059 break;
3060 }
3061
3062 /* skip until beginning of indicator variable or weight */
3063 while( *t != '\0' && *t != '(' && *t != '[' )
3064 ++t;
3065
3066 if( *t == '\0' )
3067 {
3068 SCIPerrorMessage("Syntax error: expected opening '[' or '(' at input: %s\n", s);
3069 *success = FALSE;
3070 break;
3071 }
3072
3073 s = t;
3074
3075 /* parse indicator variable */
3076 indvar = NULL;
3077 if( *s == '[' )
3078 {
3079 ++s;
3080 SCIP_CALL( SCIPparseVarName(scip, s, &indvar, &t) );
3081
3082 if( indvar == NULL )
3083 {
3084 SCIPerrorMessage("Syntax error: expected indicator variable name at input: %s\n", s);
3085 *success = FALSE;
3086 break;
3087 }
3088 s = t;
3089
3090 /* skip ']' */
3091 if( *s != ']' )
3092 {
3093 SCIPerrorMessage("Syntax error: expected closing ']' at input: %s\n", s);
3094 *success = FALSE;
3095 break;
3096 }
3097 ++s;
3098
3099 /* skip white space */
3100 SCIP_CALL( SCIPskipSpace((char**)&s) );
3101 }
3102
3103 /* skip '(' */
3104 if( *s != '(' )
3105 {
3106 SCIPerrorMessage("Syntax error: expected opening '(' at input: %s\n", s);
3107 *success = FALSE;
3108 break;
3109 }
3110 ++s;
3111
3112 /* find weight */
3113 weight = strtod(s, &t);
3114
3115 if( t == NULL )
3116 {
3117 SCIPerrorMessage("Syntax error during parsing of the weight: %s\n", s);
3118 *success = FALSE;
3119 break;
3120 }
3121
3122 s = t;
3123
3124 /* skip until ending of weight */
3125 t = strchr(t, ')');
3126
3127 if( t == NULL )
3128 {
3129 SCIPerrorMessage("Syntax error: expected closing ')' at input %s\n", s);
3130 *success = FALSE;
3131 break;
3132 }
3133
3134 s = t;
3135
3136 /* skip ')' */
3137 ++s;
3138
3139 /* skip white space */
3140 SCIP_CALL( SCIPskipSpace((char**)&s) );
3141
3142 /* skip ',' */
3143 if( *s == ',' )
3144 ++s;
3145
3146 /* add variable */
3147 SCIP_CALL( SCIPaddVarCardinality(scip, *cons, var, indvar, weight) );
3148 }
3149
3150 /* check if there is a '<=' */
3151 if( *success && *s == '<' && *(s+1) == '=' )
3152 {
3153 s = s + 2;
3154
3155 /* skip white space */
3156 SCIP_CALL( SCIPskipSpace((char**)&s) );
3157
3158 cardval = (int)strtod(s, &t);
3159
3160 if( t == NULL )
3161 {
3162 SCIPerrorMessage("Syntax error during parsing of the cardinality restriction value: %s\n", s);
3163 *success = FALSE;
3164 }
3165 else
3166 SCIP_CALL( SCIPchgCardvalCardinality(scip, *cons, cardval) );
3167 }
3168
3169 if( !*success )
3170 SCIP_CALL( SCIPreleaseCons(scip, cons) );
3171
3172 return SCIP_OKAY;
3173}
3174
3175/** constraint method of constraint handler which returns the variables (if possible) */
3176static
3177SCIP_DECL_CONSGETVARS(consGetVarsCardinality)
3178{ /*lint --e{715}*/
3179 SCIP_CONSDATA* consdata;
3180
3181 consdata = SCIPconsGetData(cons);
3182 assert(consdata != NULL);
3183
3184 if( varssize < 2 * consdata->nvars )
3185 (*success) = FALSE;
3186 else
3187 {
3188 int v;
3189 int cnt = 0;
3190
3191 assert(vars != NULL);
3192
3193 for (v = 0; v < consdata->nvars; ++v)
3194 {
3195 vars[cnt++] = consdata->vars[v];
3196 vars[cnt++] = consdata->indvars[v];
3197 }
3198 (*success) = TRUE;
3199 }
3200
3201 return SCIP_OKAY;
3202}
3203
3204/** constraint method of constraint handler which returns the number of variables (if possible) */
3205static
3206SCIP_DECL_CONSGETNVARS(consGetNVarsCardinality)
3207{ /*lint --e{715}*/
3208 SCIP_CONSDATA* consdata;
3209
3210 consdata = SCIPconsGetData(cons);
3211 assert(consdata != NULL);
3212
3213 (*nvars) = 2 * consdata->nvars;
3214 (*success) = TRUE;
3215
3216 return SCIP_OKAY;
3217}
3218
3219/** constraint handler method which returns the permutation symmetry detection graph of a constraint */
3220static
3221SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphCardinality)
3222{ /*lint --e{715}*/
3223 SCIP_CONSDATA* consdata;
3224 SCIP_VAR** vars;
3225 SCIP_Real* vals;
3226 SCIP_Real constant;
3227 SCIP_Real rhs;
3228 int consnodeidx;
3229 int pairnodeidx;
3230 int nodeidx;
3231 int nconsvars;
3232 int nlocvars;
3233 int nvars;
3234 int i;
3235
3236 consdata = SCIPconsGetData(cons);
3237 assert(consdata != NULL);
3238 assert(graph != NULL);
3239
3240 nconsvars = consdata->nvars;
3241 rhs = (SCIP_Real) consdata->cardval;
3242
3243 /* add node for constraint */
3244 SCIP_CALL( SCIPaddSymgraphConsnode(scip, graph, cons, -SCIPinfinity(scip), rhs, &consnodeidx) );
3245
3246 /* create nodes and edges for each variable */
3250
3251 for( i = 0; i < nconsvars; ++i )
3252 {
3253 /* connect each variable and its indicator variable with an intermediate node, which is connected with consnode */
3254 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_CARD_TUPLE , &pairnodeidx) );
3255
3256 /* connect variable with pair node*/
3257 vars[0] = consdata->vars[i];
3258 vals[0] = 1.0;
3259 nlocvars = 1;
3260 constant = 0.0;
3261
3263 &nlocvars, &constant, SCIPisTransformed(scip)) );
3264
3265 /* check whether variable is (multi-)aggregated or negated */
3266 if( nlocvars > 1 || !SCIPisEQ(scip, vals[0], 1.0) || !SCIPisZero(scip, constant) )
3267 {
3268 /* encode aggregation by a sum-expression */
3269 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &nodeidx) ); /*lint !e641*/
3270
3271 /* we do not need to take weights of variables into account;
3272 * they are only used to sort variables within the constraint */
3273 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, pairnodeidx, nodeidx, FALSE, 0.0) );
3274
3275 /* add nodes and edges for variables in aggregation */
3276 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, nodeidx, vars, vals, nlocvars, constant) );
3277 }
3278 else if( nlocvars == 1 )
3279 {
3280 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, vars[0]);
3281
3282 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, pairnodeidx, nodeidx, FALSE, 0.0) );
3283 }
3284
3285 /* connect indicator variable with pair node*/
3286 vars[0] = consdata->indvars[i];
3287 vals[0] = 1.0;
3288 nlocvars = 1;
3289 constant = 0.0;
3290
3292 &nlocvars, &constant, SCIPisTransformed(scip)) );
3293
3294 /* check whether variable is (multi-)aggregated or negated */
3295 if( nlocvars > 1 || !SCIPisEQ(scip, vals[0], 1.0) || !SCIPisZero(scip, constant) )
3296 {
3297 /* encode aggregation by a sum-expression */
3298 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &nodeidx) ); /*lint !e641*/
3299
3300 /* we do not need to take weights of variables into account;
3301 * they are only used to sort variables within the constraint */
3302 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, pairnodeidx, nodeidx, FALSE, 0.0) );
3303
3304 /* add nodes and edges for variables in aggregation */
3305 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, nodeidx, vars, vals, nlocvars, constant) );
3306 }
3307 else if( nlocvars == 1 )
3308 {
3309 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, vars[0]);
3310
3311 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, pairnodeidx, nodeidx, FALSE, 0.0) );
3312 }
3313 }
3314
3315 SCIPfreeBufferArray(scip, &vals);
3317
3318 assert(success != NULL);
3319 *success = TRUE;
3320
3321 return SCIP_OKAY;
3322}
3323
3324/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */
3325static
3326SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphCardinality)
3327{ /*lint --e{715}*/
3328 SCIP_CONSDATA* consdata;
3329 SCIP_VAR** vars;
3330 SCIP_Real* vals;
3331 SCIP_Real constant;
3332 SCIP_Real rhs;
3333 int consnodeidx;
3334 int pairnodeidx;
3335 int nodeidx;
3336 int nconsvars;
3337 int nlocvars;
3338 int nvars;
3339 int i;
3340
3341 consdata = SCIPconsGetData(cons);
3342 assert(consdata != NULL);
3343 assert(graph != NULL);
3344
3345 nconsvars = consdata->nvars;
3346 rhs = (SCIP_Real) consdata->cardval;
3347
3348 /* add node for constraint */
3349 SCIP_CALL( SCIPaddSymgraphConsnode(scip, graph, cons, -SCIPinfinity(scip), rhs, &consnodeidx) );
3350
3351 /* create nodes and edges for each variable */
3355
3356 for( i = 0; i < nconsvars; ++i )
3357 {
3358 /* connect each variable and its indicator variable with an intermediate node, which is connected with consnode */
3359 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_CARD_TUPLE , &pairnodeidx) );
3360
3361 vars[0] = consdata->vars[i];
3362 vals[0] = 1.0;
3363 nlocvars = 1;
3364 constant = 0.0;
3365
3366 /* use SYM_SYMTYPE_PERM here to NOT center variable domains at 0, as the latter might not preserve
3367 * cardinality constraints */
3369 &nlocvars, &constant, SCIPisTransformed(scip)) );
3370
3371 /* check whether variable is (multi-) aggregated or negated */
3372 if( nlocvars > 1 || !SCIPisEQ(scip, vals[0], 1.0) || !SCIPisZero(scip, constant) )
3373 {
3374 int sumnodeidx;
3375 int j;
3376
3377 /* encode aggregation by a sum-expression */
3378 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &sumnodeidx) ); /*lint !e641*/
3379
3380 /* we do not need to take weights of variables into account;
3381 * they are only used to sort variables within the constraint */
3382 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, pairnodeidx, sumnodeidx, FALSE, 0.0) );
3383
3384 /* add nodes and edges for variables in aggregation, do not add edges to negated variables
3385 * since this might not necessarily be a symmetry of the cardinality constraint; therefore,
3386 * do not use SCIPaddSymgraphVarAggregation() */
3387 for( j = 0; j < nlocvars; ++j )
3388 {
3389 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, vars[j]);
3390 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, sumnodeidx, nodeidx, TRUE, vals[j]) );
3391 }
3392
3393 /* possibly add node for constant */
3394 if( ! SCIPisZero(scip, constant) )
3395 {
3396 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, constant, &nodeidx) );
3397
3398 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, sumnodeidx, nodeidx, FALSE, 0.0) );
3399 }
3400 }
3401 else if( nlocvars == 1 )
3402 {
3403 SCIP_Bool allownegation = FALSE;
3404
3405 /* a negation is allowed if it is centered around 0 */
3409 allownegation = TRUE;
3410
3411 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, vars[0]);
3412 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, pairnodeidx, nodeidx, TRUE, 1.0) );
3413
3414 nodeidx = SCIPgetSymgraphNegatedVarnodeidx(scip, graph, vars[0]);
3415 if( allownegation )
3416 {
3417 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, pairnodeidx, nodeidx, TRUE, 1.0) );
3418 }
3419 else
3420 {
3421 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, pairnodeidx, nodeidx, FALSE, 0.0) );
3422 }
3423 }
3424
3425 /* connect indicator variable with pair node, do not add edges to negated variables since negating
3426 * might not preserve the cardinality requirement
3427 */
3428 vars[0] = consdata->indvars[i];
3429 vals[0] = 1.0;
3430 nlocvars = 1;
3431 constant = 0.0;
3432
3434 &nlocvars, &constant, SCIPisTransformed(scip)) );
3435
3436 /* check whether variable is (multi-)aggregated or negated */
3437 if( nlocvars > 1 || !SCIPisEQ(scip, vals[0], 1.0) || !SCIPisZero(scip, constant) )
3438 {
3439 /* encode aggregation by a sum-expression */
3440 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &nodeidx) ); /*lint !e641*/
3441
3442 /* we do not need to take weights of variables into account;
3443 * they are only used to sort variables within the constraint */
3444 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, pairnodeidx, nodeidx, FALSE, 0.0) );
3445
3446 /* add nodes and edges for variables in aggregation */
3447 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, nodeidx, vars, vals, nlocvars, constant) );
3448 }
3449 else if( nlocvars == 1 )
3450 {
3451 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, vars[0]);
3452
3453 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, pairnodeidx, nodeidx, FALSE, 0.0) );
3454 }
3455 }
3456
3457 SCIPfreeBufferArray(scip, &vals);
3459
3460 assert(success != NULL);
3461 *success = TRUE;
3462
3463 return SCIP_OKAY;
3464}
3465
3466/* ---------------- Callback methods of event handler ---------------- */
3467
3468/* exec the event handler
3469 *
3470 * update the number of variables fixed to be nonzero
3471 * update the bound constraints
3472 */
3473static
3474SCIP_DECL_EVENTEXEC(eventExecCardinality)
3475{
3476 SCIP_EVENTTYPE eventtype;
3477 SCIP_CONSDATA* consdata;
3478 SCIP_Real oldbound;
3479 SCIP_Real newbound;
3480 SCIP_VAR* var;
3481
3482 assert(eventhdlr != NULL);
3483 assert(eventdata != NULL);
3484 assert(event != NULL);
3485
3487
3488 consdata = eventdata->consdata;
3489 assert(consdata != NULL);
3490 assert(0 <= consdata->ntreatnonzeros && consdata->ntreatnonzeros <= consdata->nvars);
3491 assert(consdata->eventdatascurrent != NULL);
3492 assert(consdata->eventvarscurrent != NULL);
3493
3494 var = SCIPeventGetVar(event);
3495 assert(var != NULL);
3496 oldbound = SCIPeventGetOldbound(event);
3497 newbound = SCIPeventGetNewbound(event);
3498 eventtype = SCIPeventGetType(event);
3499
3500#ifdef SCIP_DEBUG
3501 if( ( eventdata->varmarked && var == eventdata->var) || ( eventdata->indvarmarked && var == eventdata->indvar) )
3502 {
3503 int i;
3504
3505 for( i = 0; i < consdata->neventdatascurrent; ++i )
3506 {
3507 if( var == consdata->eventvarscurrent[i] )
3508 {
3509 break;
3510 }
3511 }
3512 assert(i < consdata->neventdatascurrent);
3513 }
3514#endif
3515
3516 if( eventtype & SCIP_EVENTTYPE_GBDCHANGED )
3517 {
3518 if( eventtype == SCIP_EVENTTYPE_GLBCHANGED )
3519 {
3520 /* global lower bound is not negative anymore -> remove down lock */
3521 if ( SCIPisFeasNegative(scip, oldbound) && ! SCIPisFeasNegative(scip, newbound) )
3522 SCIP_CALL( SCIPunlockVarCons(scip, var, consdata->cons, TRUE, FALSE) );
3523 /* global lower bound turned negative -> add down lock */
3524 else if ( ! SCIPisFeasNegative(scip, oldbound) && SCIPisFeasNegative(scip, newbound) )
3525 SCIP_CALL( SCIPlockVarCons(scip, var, consdata->cons, TRUE, FALSE) );
3526
3527 return SCIP_OKAY;
3528 }
3529 if( eventtype == SCIP_EVENTTYPE_GUBCHANGED )
3530 {
3531 /* global upper bound is not positive anymore -> remove up lock */
3532 if ( SCIPisFeasPositive(scip, oldbound) && ! SCIPisFeasPositive(scip, newbound) )
3533 SCIP_CALL( SCIPunlockVarCons(scip, var, consdata->cons, FALSE, TRUE) );
3534 /* global upper bound turned positive -> add up lock */
3535 else if ( ! SCIPisFeasPositive(scip, oldbound) && SCIPisFeasPositive(scip, newbound) )
3536 SCIP_CALL( SCIPlockVarCons(scip, var, consdata->cons, FALSE, TRUE) );
3537
3538 return SCIP_OKAY;
3539 }
3540 }
3541
3542 /* if variable is an indicator variable */
3543 if( var == eventdata->indvar )
3544 {
3546 assert(consdata->cons != NULL);
3547
3548 if( eventtype == SCIP_EVENTTYPE_LBTIGHTENED )
3549 ++(consdata->ntreatnonzeros);
3550 else if( eventtype == SCIP_EVENTTYPE_LBRELAXED )
3551 --(consdata->ntreatnonzeros);
3552 else if( eventtype == SCIP_EVENTTYPE_UBTIGHTENED && ! eventdata->indvarmarked )
3553 {
3554 assert(oldbound == 1.0 && newbound == 0.0 );
3555
3556 /* save event data for propagation */
3557 consdata->eventdatascurrent[consdata->neventdatascurrent] = eventdata;
3558 consdata->eventvarscurrent[consdata->neventdatascurrent] = var;
3559 ++consdata->neventdatascurrent;
3560 eventdata->indvarmarked = TRUE;
3561 assert(consdata->neventdatascurrent <= 4 * consdata->maxvars);
3562 assert(var == eventdata->indvar );
3563 }
3564 assert(0 <= consdata->ntreatnonzeros && consdata->ntreatnonzeros <= consdata->nvars);
3565 }
3566
3567 /* if variable is an implied variable,
3568 * notice that the case consdata->var = consdata->indvar is possible */
3569 if( var == eventdata->var && ! eventdata->varmarked )
3570 {
3571 if( eventtype == SCIP_EVENTTYPE_LBTIGHTENED )
3572 {
3573 /* if variable is now fixed to be nonzero */
3574 if( !SCIPisFeasPositive(scip, oldbound) && SCIPisFeasPositive(scip, newbound) )
3575 {
3576 /* save event data for propagation */
3577 consdata->eventdatascurrent[consdata->neventdatascurrent] = eventdata;
3578 consdata->eventvarscurrent[consdata->neventdatascurrent] = var;
3579 ++consdata->neventdatascurrent;
3580 eventdata->varmarked = TRUE;
3581 assert(consdata->neventdatascurrent <= 4 * consdata->maxvars );
3582 assert(var == eventdata->var );
3583 }
3584 }
3585 else if( eventtype == SCIP_EVENTTYPE_UBTIGHTENED )
3586 {
3587 /* if variable is now fixed to be nonzero */
3588 if( !SCIPisFeasNegative(scip, oldbound) && SCIPisFeasNegative(scip, newbound) )
3589 {
3590 /* save event data for propagation */
3591 consdata->eventdatascurrent[consdata->neventdatascurrent] = eventdata;
3592 consdata->eventvarscurrent[consdata->neventdatascurrent] = var;
3593 ++consdata->neventdatascurrent;
3594 eventdata->varmarked = TRUE;
3595 assert(consdata->neventdatascurrent <= 4 * consdata->maxvars );
3596 assert(var == eventdata->var);
3597 }
3598 }
3599 }
3600 assert(0 <= consdata->ntreatnonzeros && consdata->ntreatnonzeros <= consdata->nvars);
3601
3602 SCIPdebugMsg(scip, "event exec cons <%s>: changed %s bound of variable <%s> from %g to %g (ntreatnonzeros: %d).\n",
3603 SCIPconsGetName(consdata->cons), eventtype & (SCIP_EVENTTYPE_UBTIGHTENED | SCIP_EVENTTYPE_GUBCHANGED) ? "upper" : "lower", SCIPvarGetName(SCIPeventGetVar(event)),
3604 oldbound, newbound, consdata->ntreatnonzeros);
3605
3606 return SCIP_OKAY;
3607}
3608
3609/* ---------------- Constraint specific interface methods ---------------- */
3610
3611/** creates the handler for cardinality constraints and includes it in SCIP */
3613 SCIP* scip /**< SCIP data structure */
3614 )
3615{
3616 SCIP_CONSHDLRDATA* conshdlrdata;
3617 SCIP_CONSHDLR* conshdlr;
3618
3619 /* create constraint handler data */
3620 SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
3621 conshdlrdata->eventhdlr = NULL;
3622 conshdlrdata->varhash = NULL;
3623
3624 /* create event handler for bound change events */
3626 eventExecCardinality, NULL) );
3627 if( conshdlrdata->eventhdlr == NULL )
3628 {
3629 SCIPerrorMessage("event handler for cardinality constraints not found.\n");
3630 return SCIP_PLUGINNOTFOUND;
3631 }
3632
3633 /* include constraint handler */
3636 consEnfolpCardinality, consEnfopsCardinality, consCheckCardinality, consLockCardinality, conshdlrdata) );
3637 assert(conshdlr != NULL);
3638
3639 /* set non-fundamental callbacks via specific setter functions */
3640 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyCardinality, consCopyCardinality) );
3641 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteCardinality) );
3642 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolCardinality) );
3643 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeCardinality) );
3644 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsCardinality) );
3645 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsCardinality) );
3646 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpCardinality) );
3647 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseCardinality) );
3649 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintCardinality) );
3650 SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropCardinality, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
3652 /*SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropCardinality) ); @todo: implement repropagation */
3653 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpCardinality, consSepasolCardinality, CONSHDLR_SEPAFREQ,
3655 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransCardinality) );
3656 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxCardinality) );
3657 SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphCardinality) );
3658 SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphCardinality) );
3659
3660 /* add cardinality constraint handler parameters */
3661 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branchbalanced",
3662 "whether to use balanced instead of unbalanced branching",
3663 &conshdlrdata->branchbalanced, TRUE, DEFAULT_BRANCHBALANCED, NULL, NULL) );
3664
3665 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/balanceddepth",
3666 "maximum depth for using balanced branching (-1: no limit)",
3667 &conshdlrdata->balanceddepth, TRUE, DEFAULT_BALANCEDDEPTH, -1, INT_MAX, NULL, NULL) );
3668
3669 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/balancedcutoff",
3670 "determines that balanced branching is only used if the branching cut off value "
3671 "w.r.t. the current LP solution is greater than a given value",
3672 &conshdlrdata->balancedcutoff, TRUE, DEFAULT_BALANCEDCUTOFF, 0.01, SCIP_REAL_MAX, NULL, NULL) );
3673
3674 return SCIP_OKAY;
3675}
3676
3677/** creates and captures a cardinality constraint
3678 *
3679 * We set the constraint to not be modifable. If the weights are non
3680 * NULL, the variables are ordered according to these weights (in
3681 * ascending order).
3682 *
3683 * @note the constraint gets captured, hence at one point you have to release it using the method \ref SCIPreleaseCons()
3684 */
3686 SCIP* scip, /**< SCIP data structure */
3687 SCIP_CONS** cons, /**< pointer to hold the created constraint */
3688 const char* name, /**< name of constraint */
3689 int nvars, /**< number of variables in the constraint */
3690 SCIP_VAR** vars, /**< array with variables of constraint entries */
3691 int cardval, /**< number of variables allowed to be nonzero */
3692 SCIP_VAR** indvars, /**< indicator variables indicating which variables may be treated as nonzero
3693 * in cardinality constraint, or NULL if new indicator variables should be
3694 * introduced automatically */
3695 SCIP_Real* weights, /**< weights determining the variable order, or NULL if variables should be
3696 * ordered in the same way they were added to the constraint */
3697 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
3698 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
3699 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
3700 * Usually set to TRUE. */
3701 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
3702 * TRUE for model constraints, FALSE for additional, redundant constraints. */
3703 SCIP_Bool check, /**< should the constraint be checked for feasibility?
3704 * TRUE for model constraints, FALSE for additional, redundant constraints. */
3705 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
3706 * Usually set to TRUE. */
3707 SCIP_Bool local, /**< is constraint only valid locally?
3708 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
3709 SCIP_Bool dynamic, /**< is constraint subject to aging?
3710 * Usually set to FALSE. Set to TRUE for own cuts which
3711 * are separated as constraints. */
3712 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
3713 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
3714 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
3715 * if it may be moved to a more global node?
3716 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
3717 )
3718{
3719 SCIP_CONSHDLRDATA* conshdlrdata;
3720 SCIP_CONSHDLR* conshdlr;
3721 SCIP_CONSDATA* consdata;
3722 SCIP_Bool modifiable;
3723 SCIP_Bool transformed;
3724 int v;
3725
3726 modifiable = FALSE;
3727
3728#ifndef NDEBUG
3729 /* Check that the weights are sensible (not nan or inf); although not strictly needed, such values are likely a mistake. */
3730 if ( nvars > 0 && weights != NULL )
3731 {
3732 for (v = 0; v < nvars; ++v)
3733 assert( SCIPisFinite(weights[v]) );
3734 }
3735#endif
3736
3737 /* find the cardinality constraint handler */
3738 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
3739 if( conshdlr == NULL )
3740 {
3741 SCIPerrorMessage("<%s> constraint handler not found\n", CONSHDLR_NAME);
3742 return SCIP_PLUGINNOTFOUND;
3743 }
3744
3745 /* check whether indicator variables are binary */
3746 if( indvars != NULL )
3747 {
3748 for( v = 0; v < nvars; ++v )
3749 {
3750 if( !SCIPvarIsBinary(indvars[v]) )
3751 {
3752 SCIPerrorMessage("indicator <%s> is not binary\n", SCIPvarGetName(indvars[v]));
3753 return SCIP_INVALIDDATA;
3754 }
3755 }
3756 }
3757
3758 /* get constraint handler data */
3759 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3760 assert(conshdlrdata != NULL);
3761
3762 /* are we in the transformed problem? */
3763 transformed = SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED;
3764
3765 /* create constraint data */
3766 SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) );
3767 consdata->cons = NULL;
3768 consdata->vars = NULL;
3769 consdata->indvars = NULL;
3770 consdata->eventdatas = NULL;
3771 consdata->nvars = nvars;
3772 consdata->cardval = cardval;
3773 consdata->maxvars = nvars;
3774 consdata->rowub = NULL;
3775 consdata->rowlb = NULL;
3776 consdata->eventdatascurrent = NULL;
3777 consdata->eventvarscurrent = NULL;
3778 consdata->neventdatascurrent = 0;
3779 consdata->ntreatnonzeros = transformed ? 0 : -1;
3780 consdata->weights = NULL;
3781
3782 if( nvars > 0 )
3783 {
3784 /* duplicate memory for implied variables */
3785 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->vars, vars, nvars) );
3786
3787 /* create indicator variables if not present */
3788 if( indvars != NULL )
3789 {
3790 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->indvars, indvars, nvars) );
3791 }
3792 else
3793 {
3794 if( conshdlrdata->varhash == NULL )
3795 {
3796 /* set up hash map */
3797 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->varhash, SCIPblkmem(scip), SCIPgetNTotalVars(scip)) );
3798 }
3799
3800 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->indvars, nvars) );
3801 for( v = 0; v < nvars; ++v )
3802 {
3803 SCIP_VAR* implvar;
3804
3805 implvar = vars[v];
3806 assert(implvar != NULL);
3807
3808 /* check whether an indicator variable already exists for implied variable */
3809 if( SCIPhashmapExists(conshdlrdata->varhash, implvar) )
3810 {
3811 assert((SCIP_VAR*) SCIPhashmapGetImage(conshdlrdata->varhash, implvar) != NULL);
3812 consdata->indvars[v] = (SCIP_VAR*) SCIPhashmapGetImage(conshdlrdata->varhash, implvar);
3813 }
3814 else
3815 {
3816 /* if implied variable is binary, then it is not necessary to create an indicator variable */
3817 if( SCIPvarIsBinary(implvar) )
3818 consdata->indvars[v] = implvar;
3819 else
3820 {
3821 char varname[SCIP_MAXSTRLEN];
3822 SCIP_VAR* var;
3823
3824 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "ind_%s", SCIPvarGetName(vars[v]));
3825 SCIP_CALL( SCIPcreateVar(scip, &var, varname, 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY, FALSE, FALSE,
3826 NULL, NULL, NULL, NULL, NULL) );
3828 consdata->indvars[v] = var;
3830 }
3831
3832 /* insert implied variable to hash map */
3833 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->varhash, implvar, (void*) consdata->indvars[v]) );/*lint !e571*/
3834 assert(consdata->indvars[v] == (SCIP_VAR*) SCIPhashmapGetImage(conshdlrdata->varhash, implvar));
3835 assert(SCIPhashmapExists(conshdlrdata->varhash, implvar));
3836 }
3837 }
3838 }
3839
3840 /* allocate block memory */
3841 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eventdatascurrent, 4*nvars) );/*lint !e647*/
3842 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eventvarscurrent, 4*nvars) );/*lint !e647*/
3843 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eventdatas, nvars) );
3844
3845 /* check weights */
3846 if( weights != NULL )
3847 {
3848 /* store weights */
3849 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->weights, weights, nvars) );
3850
3851 /* sort variables - ascending order */
3852 SCIPsortRealPtrPtr(consdata->weights, (void**)consdata->vars, (void**)consdata->indvars, nvars);
3853 }
3854 }
3855 else
3856 {
3857 assert(weights == NULL);
3858 }
3859
3860 /* create cardinality constraint */
3861 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
3862 local, modifiable, dynamic, removable, stickingatnode) );
3863
3864 consdata->cons = *cons;
3865 assert(consdata->cons != NULL);
3866
3867 /* replace original variables by transformed variables in transformed constraint, add locks, and catch events */
3868 for( v = nvars - 1; v >= 0; --v )
3869 {
3870 /* always use transformed variables in transformed constraints */
3871 if( transformed )
3872 {
3873 SCIP_CALL( SCIPgetTransformedVar(scip, consdata->vars[v], &(consdata->vars[v])) );
3874 SCIP_CALL( SCIPgetTransformedVar(scip, consdata->indvars[v], &(consdata->indvars[v])) );
3875 }
3876 assert(consdata->vars[v] != NULL);
3877 assert(consdata->indvars[v] != NULL);
3878 assert(transformed == SCIPvarIsTransformed(consdata->vars[v]));
3879 assert(transformed == SCIPvarIsTransformed(consdata->indvars[v]));
3880
3881 /* handle the new variable */
3882 SCIP_CALL( handleNewVariableCardinality(scip, *cons, consdata, conshdlrdata, consdata->vars[v],
3883 consdata->indvars[v], v, transformed, &consdata->eventdatas[v]) );
3884 assert(! transformed || consdata->eventdatas[v] != NULL);
3885 }
3886
3887 return SCIP_OKAY;
3888}
3889
3890/** creates and captures a cardinality constraint with all constraint flags set to their default values.
3891 *
3892 * @warning Do NOT set the constraint to be modifiable manually, because this might lead
3893 * to wrong results as the variable array will not be re-sorted
3894 *
3895 * @note the constraint gets captured, hence at one point you have to release it using the method \ref SCIPreleaseCons()
3896 */
3898 SCIP* scip, /**< SCIP data structure */
3899 SCIP_CONS** cons, /**< pointer to hold the created constraint */
3900 const char* name, /**< name of constraint */
3901 int nvars, /**< number of variables in the constraint */
3902 SCIP_VAR** vars, /**< array with variables of constraint entries */
3903 int cardval, /**< number of variables allowed to be nonzero */
3904 SCIP_VAR** indvars, /**< indicator variables indicating which variables may be treated as nonzero
3905 * in cardinality constraint, or NULL if new indicator variables should be
3906 * introduced automatically */
3907 SCIP_Real* weights /**< weights determining the variable order, or NULL if variables should be
3908 * ordered in the same way they were added to the constraint */
3909 )
3910{
3911 SCIP_CALL( SCIPcreateConsCardinality(scip, cons, name, nvars, vars, cardval, indvars, weights, TRUE, TRUE, TRUE, TRUE,
3912 TRUE, FALSE, FALSE, FALSE, FALSE) );
3913
3914 return SCIP_OKAY;
3915}
3916
3917/** changes cardinality value of cardinality constraint (i.e., right hand side of cardinality constraint) */
3919 SCIP* scip, /**< SCIP data structure */
3920 SCIP_CONS* cons, /**< pointer to hold the created constraint */
3921 int cardval /**< number of variables allowed to be nonzero */
3922 )
3923{
3924 SCIP_CONSDATA* consdata;
3925
3926 assert(scip != NULL);
3927 assert(cons != NULL);
3928
3930
3931 consdata = SCIPconsGetData(cons);
3932 assert(consdata != NULL);
3933
3934 SCIPdebugMsg(scip, "modify right hand side of cardinality constraint from <%i> to <%i>\n", consdata->cardval, cardval);
3935
3936 /* create constraint data */
3937 consdata->cardval = cardval;
3938
3939 return SCIP_OKAY;
3940}
3941
3942/** adds variable to cardinality constraint, the position is determined by the given weight */
3944 SCIP* scip, /**< SCIP data structure */
3945 SCIP_CONS* cons, /**< constraint */
3946 SCIP_VAR* var, /**< variable to add to the constraint */
3947 SCIP_VAR* indvar, /**< indicator variable indicating whether variable may be treated as nonzero
3948 * in cardinality constraint (or NULL if this variable should be created
3949 * automatically) */
3950 SCIP_Real weight /**< weight determining position of variable */
3951 )
3952{
3953 SCIP_CONSHDLRDATA* conshdlrdata;
3954 SCIP_CONSHDLR* conshdlr;
3955
3956 assert(scip != NULL);
3957 assert(var != NULL);
3958 assert(cons != NULL);
3959
3960 SCIPdebugMsg(scip, "adding variable <%s> to constraint <%s> with weight %g\n", SCIPvarGetName(var),
3961 SCIPconsGetName(cons), weight);
3962
3963 conshdlr = SCIPconsGetHdlr(cons);
3964 assert(conshdlr != NULL);
3965
3967
3968 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3969 assert(conshdlrdata != NULL);
3970
3971 SCIP_CALL( addVarCardinality(scip, cons, conshdlrdata, var, indvar, weight) );
3972
3973 return SCIP_OKAY;
3974}
3975
3976/** appends variable to cardinality constraint */
3978 SCIP* scip, /**< SCIP data structure */
3979 SCIP_CONS* cons, /**< constraint */
3980 SCIP_VAR* var, /**< variable to add to the constraint */
3981 SCIP_VAR* indvar /**< indicator variable indicating whether variable may be treated as nonzero
3982 * in cardinality constraint (or NULL if this variable should be created
3983 * automatically) */
3984 )
3985{
3986 SCIP_CONSHDLRDATA* conshdlrdata;
3987 SCIP_CONSHDLR* conshdlr;
3988
3989 assert(scip != NULL);
3990 assert(var != NULL);
3991 assert(cons != NULL);
3992
3993 SCIPdebugMsg(scip, "appending variable <%s> to constraint <%s>\n", SCIPvarGetName(var), SCIPconsGetName(cons));
3994
3995 conshdlr = SCIPconsGetHdlr(cons);
3996 assert(conshdlr != NULL);
3997
3999
4000 conshdlrdata = SCIPconshdlrGetData(conshdlr);
4001 assert(conshdlrdata != NULL);
4002
4003 SCIP_CALL( appendVarCardinality(scip, cons, conshdlrdata, var, indvar) );
4004
4005 return SCIP_OKAY;
4006}
4007
4008/** gets number of variables in cardinality constraint */
4010 SCIP* scip, /**< SCIP data structure */
4011 SCIP_CONS* cons /**< constraint */
4012 )
4013{
4014 SCIP_CONSDATA* consdata;
4015
4016 assert(scip != NULL);
4017 assert(cons != NULL);
4018
4020
4021 consdata = SCIPconsGetData(cons);
4022 assert(consdata != NULL);
4023
4024 return consdata->nvars;
4025}
4026
4027/** gets array of variables in cardinality constraint */
4029 SCIP* scip, /**< SCIP data structure */
4030 SCIP_CONS* cons /**< constraint data */
4031 )
4032{
4033 SCIP_CONSDATA* consdata;
4034
4035 assert(scip != NULL);
4036 assert(cons != NULL);
4037
4039
4040 consdata = SCIPconsGetData(cons);
4041 assert(consdata != NULL);
4042
4043 return consdata->vars;
4044}
4045
4046/** gets cardinality value of cardinality constraint (i.e., right hand side of cardinality constraint) */
4048 SCIP* scip, /**< SCIP data structure */
4049 SCIP_CONS* cons /**< constraint data */
4050 )
4051{
4052 SCIP_CONSDATA* consdata;
4053
4054 assert(scip != NULL);
4055 assert(cons != NULL);
4056
4058
4059 consdata = SCIPconsGetData(cons);
4060 assert(consdata != NULL);
4061
4062 return consdata->cardval;
4063}
4064
4065/** gets array of weights in cardinality constraint (or NULL if not existent) */
4067 SCIP* scip, /**< SCIP data structure */
4068 SCIP_CONS* cons /**< constraint data */
4069 )
4070{
4071 SCIP_CONSDATA* consdata;
4072
4073 assert(scip != NULL);
4074 assert(cons != NULL);
4075
4077
4078 consdata = SCIPconsGetData(cons);
4079 assert(consdata != NULL);
4080
4081 return consdata->weights;
4082}
#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
static SCIP_RETCODE unlockVariableCardinality(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_VAR *indvar)
static SCIP_RETCODE consdataEnsurevarsSizeCardinality(SCIP *scip, SCIP_CONSDATA *consdata, int num, SCIP_Bool reserveweights)
static SCIP_RETCODE lockVariableCardinality(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_VAR *indvar)
static SCIP_RETCODE appendVarCardinality(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_VAR *var, SCIP_VAR *indvar)
static void consdataUnmarkEventdataVars(SCIP_CONSDATA *consdata)
static SCIP_RETCODE fixVariableZeroNode(SCIP *scip, SCIP_VAR *var, SCIP_NODE *node, SCIP_Bool *infeasible)
static SCIP_RETCODE generateRowCardinality(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_Bool local, SCIP_ROW **rowlb, SCIP_ROW **rowub)
static SCIP_RETCODE deleteVarCardinality(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr, int pos)
static SCIP_RETCODE fixVariableZero(SCIP *scip, SCIP_VAR *var, SCIP_Bool *infeasible, SCIP_Bool *tightened)
static SCIP_RETCODE polishPrimalSolution(SCIP *scip, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_SOL *primsol)
static SCIP_RETCODE branchBalancedCardinality(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_SOL *sol, SCIP_CONS *branchcons, SCIP_VAR **vars, SCIP_VAR **indvars, int nvars, int cardval, int branchnnonzero, int branchpos, SCIP_Real balancedcutoff)
#define DEFAULT_BALANCEDDEPTH
static SCIP_RETCODE initsepaBoundInequalityFromCardinality(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, SCIP_SOL *sol, SCIP_Bool solvedinitlp, int *ngen, SCIP_Bool *cutoff)
#define DEFAULT_BALANCEDCUTOFF
static SCIP_RETCODE enforceCardinality(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_SOL *sol, int nconss, SCIP_CONS **conss, SCIP_RESULT *result)
static SCIP_RETCODE presolRoundCardinality(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_EVENTHDLR *eventhdlr, SCIP_Bool *cutoff, SCIP_Bool *success, int *ndelconss, int *nupgdconss, int *nfixedvars, int *nremovedvars)
#define DEFAULT_BRANCHBALANCED
static SCIP_RETCODE catchVarEventCardinality(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONSDATA *consdata, SCIP_VAR *var, SCIP_VAR *indvar, int pos, SCIP_EVENTDATA **eventdata)
static SCIP_RETCODE addVarCardinality(SCIP *scip, SCIP_CONS *cons, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_VAR *var, SCIP_VAR *indvar, SCIP_Real weight)
static SCIP_RETCODE separateCardinality(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_SOL *sol, int nconss, SCIP_CONS **conss, SCIP_RESULT *result)
static SCIP_RETCODE handleNewVariableCardinality(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_CONSHDLRDATA *conshdlrdata, SCIP_VAR *var, SCIP_VAR *indvar, int pos, SCIP_Bool transformed, SCIP_EVENTDATA **eventdata)
#define EVENTHDLR_EVENT_TYPE
static SCIP_RETCODE propCardinality(SCIP *scip, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_Bool *cutoff, int *nchgdomain)
static SCIP_RETCODE dropVarEventCardinality(SCIP *scip, SCIP_EVENTHDLR *eventhdlr, SCIP_CONSDATA *consdata, SCIP_VAR *var, SCIP_VAR *indvar, SCIP_EVENTDATA **eventdata)
static SCIP_RETCODE branchUnbalancedCardinality(SCIP *scip, SCIP_SOL *sol, SCIP_CONS *branchcons, SCIP_VAR **vars, SCIP_VAR **indvars, int nvars, int cardval, int branchnnonzero, int branchpos)
constraint handler for cardinality constraints
Constraint handler for knapsack constraints of the form , x binary and .
Constraint handler for linear constraints in their most general form, .
#define NULL
Definition def.h:257
#define SCIP_MAXSTRLEN
Definition def.h:278
#define SCIP_Longint
Definition def.h:150
#define SCIP_REAL_MAX
Definition def.h:167
#define SCIP_Bool
Definition def.h:100
#define MIN(x, y)
Definition def.h:233
#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 MAX(x, y)
Definition def.h:229
#define SCIP_LONGINT_FORMAT
Definition def.h:157
#define REALABS(x)
Definition def.h:191
#define SCIP_CALL(x)
Definition def.h:364
SCIP_Real * SCIPgetWeightsCardinality(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateConsCardinality(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int cardval, SCIP_VAR **indvars, SCIP_Real *weights, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPcreateConsBasicCardinality(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, int cardval, SCIP_VAR **indvars, SCIP_Real *weights)
int SCIPgetCardvalCardinality(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPappendVarCardinality(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_VAR *indvar)
SCIP_RETCODE SCIPcreateConsKnapsack(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Longint *weights, SCIP_Longint capacity, 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 SCIPaddVarCardinality(SCIP *scip, SCIP_CONS *cons, SCIP_VAR *var, SCIP_VAR *indvar, SCIP_Real weight)
int SCIPgetNVarsCardinality(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_VAR ** SCIPgetVarsCardinality(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPchgCardvalCardinality(SCIP *scip, SCIP_CONS *cons, int cardval)
SCIP_RETCODE SCIPincludeConshdlrCardinality(SCIP *scip)
SCIP_RETCODE SCIPgetVarCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR *sourcevar, SCIP_VAR **targetvar, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *success)
Definition scip_copy.c:713
SCIP_Bool SCIPisTransformed(SCIP *scip)
SCIP_Bool SCIPisStopped(SCIP *scip)
SCIP_STAGE SCIPgetStage(SCIP *scip)
SCIP_RETCODE SCIPaddVar(SCIP *scip, SCIP_VAR *var)
Definition scip_prob.c:1907
int SCIPgetNVars(SCIP *scip)
Definition scip_prob.c:2246
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:3274
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:3420
int SCIPgetNTotalVars(SCIP *scip)
Definition scip_prob.c:3064
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition misc.c:3095
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3284
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition misc.c:3143
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition misc.c:3061
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition misc.c:3466
SCIP_RETCODE 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_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:83
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:139
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition scip_param.c:57
SCIP_Real SCIPcalcNodeselPriority(SCIP *scip, SCIP_VAR *var, SCIP_BRANCHDIR branchdir, SCIP_Real targetvalue)
SCIP_Real SCIPcalcChildEstimate(SCIP *scip, SCIP_VAR *var, SCIP_Real targetvalue)
SCIP_Real SCIPcalcChildEstimateIncrease(SCIP *scip, SCIP_VAR *var, SCIP_Real varsol, SCIP_Real targetvalue)
SCIP_RETCODE SCIPcreateChild(SCIP *scip, SCIP_NODE **node, SCIP_Real nodeselprio, SCIP_Real estimate)
SCIP_RETCODE 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
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4782
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
int SCIPconshdlrGetSepaFreq(SCIP_CONSHDLR *conshdlr)
Definition cons.c:5276
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:601
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
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition scip_mem.c:57
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition scip_mem.c:139
#define SCIPallocBufferArray(scip, ptr, num)
Definition scip_mem.h:124
#define 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 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_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_Bool SCIProwIsInLP(SCIP_ROW *row)
Definition lp.c:17917
SCIP_RETCODE SCIPaddVarsToRow(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition scip_lp.c:1672
SCIP_RETCODE SCIPcreateSolCopy(SCIP *scip, SCIP_SOL **sol, SCIP_SOL *sourcesol)
Definition scip_sol.c:882
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition scip_sol.c:451
SCIP_RETCODE SCIPtrySol(SCIP *scip, SCIP_SOL *sol, SCIP_Bool printreason, SCIP_Bool completely, SCIP_Bool checkbounds, SCIP_Bool checkintegrality, SCIP_Bool checklprows, SCIP_Bool *stored)
Definition scip_sol.c:4017
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition scip_sol.c:1569
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition scip_sol.c:1763
SCIP_Longint SCIPgetNNodes(SCIP *scip)
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisFeasEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
SCIP_Real SCIPfloor(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisFeasLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasNegative(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisNegative(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)
int SCIPgetDepth(SCIP *scip)
Definition scip_tree.c:672
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition scip_tree.c:91
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition scip_var.c:5210
SCIP_Real SCIPvarGetMultaggrConstant(SCIP_VAR *var)
Definition var.c:23875
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition var.c:23510
SCIP_RETCODE SCIPchgVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition scip_var.c:5697
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 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
const char * SCIPvarGetName(SCIP_VAR *var)
Definition var.c:23299
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition scip_var.c:1887
SCIP_RETCODE SCIPflattenVarAggregationGraph(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:2332
SCIP_VAR ** SCIPvarGetMultaggrVars(SCIP_VAR *var)
Definition var.c:23838
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition var.c:23826
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:24266
SCIP_RETCODE SCIPcreateVar(SCIP *scip, SCIP_VAR **var, const char *name, SCIP_Real lb, SCIP_Real ub, SCIP_Real obj, SCIP_VARTYPE vartype, SCIP_Bool initial, SCIP_Bool removable, SCIP_DECL_VARDELORIG((*vardelorig)), SCIP_DECL_VARTRANS((*vartrans)), SCIP_DECL_VARDELTRANS((*vardeltrans)), SCIP_DECL_VARCOPY((*varcopy)), SCIP_VARDATA *vardata)
Definition scip_var.c:120
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition var.c:24152
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:11057
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition scip_var.c:10318
SCIP_RETCODE SCIPchgVarLbNode(SCIP *scip, SCIP_NODE *node, SCIP_VAR *var, SCIP_Real newbound)
Definition scip_var.c:6044
SCIP_RETCODE SCIPwriteVarName(SCIP *scip, FILE *file, SCIP_VAR *var, SCIP_Bool type)
Definition scip_var.c:361
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition scip_var.c:2078
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition scip_var.c:10984
SCIP_Real * SCIPvarGetMultaggrScalars(SCIP_VAR *var)
Definition var.c:23850
void SCIPsortRealPtrPtr(SCIP_Real *realarray, void **ptrarray1, void **ptrarray2, 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
SCIPfreeSol(scip, &heurdata->sol))
int c
SCIP_Bool cutoff
static SCIP_SOL * sol
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
SCIP_VAR * var
SCIP_Real primsol
static SCIP_Bool propagate
static SCIP_VAR ** vars
memory allocation routines
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 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 SCIP parameter handling
public methods for global and local (sub)problems
public methods for solutions
public methods for querying solving statistics
public methods for the branch-and-bound tree
public methods for SCIP variables
static SCIP_RETCODE separate(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_RESULT *result)
Main separation function.
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_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_BOUNDCHANGED
Definition type_event.h:127
#define SCIP_EVENTTYPE_GUBCHANGED
Definition type_event.h:76
#define SCIP_EVENTTYPE_GBDCHANGED
Definition type_event.h:122
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
@ SCIP_BRANCHDIR_DOWNWARDS
struct SCIP_Row SCIP_ROW
Definition type_lp.h:105
struct SCIP_HashMap SCIP_HASHMAP
Definition type_misc.h:106
@ SCIP_DIDNOTRUN
Definition type_result.h:42
@ SCIP_CUTOFF
Definition type_result.h:48
@ SCIP_FEASIBLE
Definition type_result.h:45
@ SCIP_REDUCEDDOM
Definition type_result.h:51
@ SCIP_DIDNOTFIND
Definition type_result.h:44
@ SCIP_BRANCHED
Definition type_result.h:54
@ SCIP_SEPARATED
Definition type_result.h:49
@ SCIP_SUCCESS
Definition type_result.h:58
@ SCIP_INFEASIBLE
Definition type_result.h:46
enum SCIP_Result SCIP_RESULT
Definition type_result.h:61
@ SCIP_INVALIDDATA
@ SCIP_PLUGINNOTFOUND
@ SCIP_PARAMETERWRONGVAL
@ SCIP_INVALIDCALL
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
@ SCIP_STAGE_TRANSFORMED
Definition type_set.h:47
struct SCIP_Sol SCIP_SOL
Definition type_sol.h:57
@ SYM_CONSOPTYPE_CARD_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_VARTYPE_BINARY
Definition type_var.h:64
@ SCIP_VARSTATUS_MULTAGGR
Definition type_var.h:56
@ SCIP_LOCKTYPE_MODEL
Definition type_var.h:141