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#include <string.h>
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 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2293
2294 /* call inclusion method of constraint handler */
2296
2297 *valid = TRUE;
2298
2299 return SCIP_OKAY;
2300}
2301
2302/** destructor of constraint handler to free constraint handler data (called when SCIP is exiting) */
2303static
2304SCIP_DECL_CONSFREE(consFreeCardinality)
2305{
2306 SCIP_CONSHDLRDATA* conshdlrdata;
2307
2308 assert(scip != NULL);
2309 assert(conshdlr != NULL);
2310 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2311
2312 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2313 assert(conshdlrdata != NULL);
2314
2315 /* free hash map */
2316 if( conshdlrdata->varhash != NULL )
2317 {
2318 SCIPhashmapFree(&conshdlrdata->varhash);
2319 }
2320
2321 SCIPfreeBlockMemory(scip, &conshdlrdata);
2322
2323 return SCIP_OKAY;
2324}
2325
2326/** solving process deinitialization method of constraint handler (called before branch and bound process data is freed) */
2327static
2328SCIP_DECL_CONSEXITSOL(consExitsolCardinality)
2329{ /*lint --e{715}*/
2330 SCIP_CONSHDLRDATA* conshdlrdata;
2331 int c;
2332
2333 assert(scip != NULL);
2334 assert(conshdlr != NULL);
2335 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2336
2337 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2338 assert(conshdlrdata != NULL);
2339
2340 /* check each constraint */
2341 for( c = 0; c < nconss; ++c )
2342 {
2343 SCIP_CONSDATA* consdata;
2344
2345 assert(conss != NULL);
2346 assert(conss[c] != NULL);
2347 consdata = SCIPconsGetData(conss[c]);
2348 assert(consdata != NULL);
2349
2350 SCIPdebugMsg(scip, "Exiting cardinality constraint <%s>.\n", SCIPconsGetName(conss[c]) );
2351
2352 /* free rows */
2353 if( consdata->rowub != NULL )
2354 {
2355 SCIP_CALL( SCIPreleaseRow(scip, &consdata->rowub) );
2356 }
2357 if( consdata->rowlb != NULL )
2358 {
2359 SCIP_CALL( SCIPreleaseRow(scip, &consdata->rowlb) );
2360 }
2361 }
2362
2363 /* free hash map */
2364 if( conshdlrdata->varhash != NULL )
2365 {
2366 SCIPhashmapFree(&conshdlrdata->varhash);
2367 }
2368
2369 return SCIP_OKAY;
2370}
2371
2372/** frees specific constraint data */
2373static
2374SCIP_DECL_CONSDELETE(consDeleteCardinality)
2375{ /*lint --e{737, 647}*/
2376 assert(scip != NULL);
2377 assert(conshdlr != NULL);
2378 assert(cons != NULL);
2379 assert(consdata != NULL);
2380 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2381
2382 SCIPdebugMsg(scip, "Deleting cardinality constraint <%s>.\n", SCIPconsGetName(cons) );
2383
2384 /* drop events on transformed variables */
2385 if( SCIPconsIsTransformed(cons) )
2386 {
2387 SCIP_CONSHDLRDATA* conshdlrdata;
2388 int j;
2389
2390 /* get constraint handler data */
2391 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2392 assert(conshdlrdata != NULL);
2393 assert(conshdlrdata->eventhdlr != NULL);
2394
2395 for( j = 0; j < (*consdata)->nvars; ++j )
2396 {
2397 SCIP_CALL( dropVarEventCardinality(scip, conshdlrdata->eventhdlr, *consdata, (*consdata)->vars[j],
2398 (*consdata)->indvars[j], &(*consdata)->eventdatas[j]) );
2399 assert((*consdata)->eventdatas[j] == NULL);
2400 }
2401 }
2402
2403 if( (*consdata)->weights != NULL )
2404 {
2405 SCIPfreeBlockMemoryArray(scip, &(*consdata)->weights, (*consdata)->maxvars);
2406 }
2407 SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdatas, (*consdata)->maxvars);
2408 SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventvarscurrent, 4 * (*consdata)->maxvars);/*lint !e647*/
2409 SCIPfreeBlockMemoryArray(scip, &(*consdata)->eventdatascurrent, 4 * (*consdata)->maxvars);/*lint !e647*/
2410 SCIPfreeBlockMemoryArray(scip, &(*consdata)->indvars, (*consdata)->maxvars);
2411 SCIPfreeBlockMemoryArray(scip, &(*consdata)->vars, (*consdata)->maxvars);
2412
2413 /* free rows */
2414 if( (*consdata)->rowub != NULL )
2415 {
2416 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->rowub) );
2417 }
2418 if( (*consdata)->rowlb != NULL )
2419 {
2420 SCIP_CALL( SCIPreleaseRow(scip, &(*consdata)->rowlb) );
2421 }
2422 assert((*consdata)->rowub == NULL);
2423 assert((*consdata)->rowlb == NULL);
2424
2425 SCIPfreeBlockMemory(scip, consdata);
2426
2427 /* Make sure that the hash for indicator binary variables is freed. If we read a problem and then another problem without
2428 * solving (transforming) between, then no callback of constraint handlers are called. Thus, we cannot easily free the
2429 * hash map there. */
2430 if ( SCIPconshdlrGetNConss(conshdlr) == 0 )
2431 {
2432 SCIP_CONSHDLRDATA* conshdlrdata;
2433
2434 /* get constraint handler data */
2435 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2436 assert( conshdlrdata != NULL );
2437
2438 if ( conshdlrdata->varhash != NULL )
2439 SCIPhashmapFree(&conshdlrdata->varhash);
2440 }
2441
2442 return SCIP_OKAY;
2443}
2444
2445/** transforms constraint data into data belonging to the transformed problem */
2446static
2447SCIP_DECL_CONSTRANS(consTransCardinality)
2448{
2449 SCIP_CONSDATA* consdata;
2450 SCIP_CONSHDLRDATA* conshdlrdata;
2451 SCIP_CONSDATA* sourcedata;
2452 char s[SCIP_MAXSTRLEN];
2453 int j;
2454
2455 assert(scip != NULL);
2456 assert(conshdlr != NULL);
2457 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2458 assert(sourcecons != NULL);
2459 assert(targetcons != NULL);
2460
2461 /* get constraint handler data */
2462 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2463 assert(conshdlrdata != NULL);
2464 assert(conshdlrdata->eventhdlr != NULL);
2465
2466 SCIPdebugMsg(scip, "Transforming cardinality constraint: <%s>.\n", SCIPconsGetName(sourcecons) );
2467
2468 /* get data of original constraint */
2469 sourcedata = SCIPconsGetData(sourcecons);
2470 assert(sourcedata != NULL);
2471 assert(sourcedata->nvars > 0);
2472 assert(sourcedata->nvars <= sourcedata->maxvars);
2473
2474 /* create constraint data */
2475 SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) );
2476
2477 consdata->cons = NULL;
2478 consdata->nvars = sourcedata->nvars;
2479 consdata->maxvars = sourcedata->nvars;
2480 consdata->cardval = sourcedata->cardval;
2481 consdata->rowub = NULL;
2482 consdata->rowlb = NULL;
2483 consdata->eventdatascurrent = NULL;
2484 consdata->neventdatascurrent = 0;
2485 consdata->ntreatnonzeros = 0;
2486 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->vars, consdata->nvars) );
2487 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->indvars, consdata->nvars) );
2488 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eventdatas, consdata->nvars) );
2489 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eventdatascurrent, 4*consdata->nvars) );/*lint !e647*/
2490 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eventvarscurrent, 4*consdata->nvars) );/*lint !e647*/
2491
2492 /* if weights were used */
2493 if( sourcedata->weights != NULL )
2494 {
2495 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->weights, sourcedata->weights, consdata->nvars) );
2496 }
2497 else
2498 consdata->weights = NULL;
2499
2500 for( j = 0; j < sourcedata->nvars; ++j )
2501 {
2502 assert(sourcedata->vars[j] != 0);
2503 assert(sourcedata->indvars[j] != 0);
2504 SCIP_CALL( SCIPgetTransformedVar(scip, sourcedata->vars[j], &(consdata->vars[j])) );
2505 SCIP_CALL( SCIPgetTransformedVar(scip, sourcedata->indvars[j], &(consdata->indvars[j])) );
2506
2507 /* if variable is fixed to be nonzero */
2508 if( SCIPvarGetLbLocal(consdata->indvars[j]) > 0.5 )
2509 ++(consdata->ntreatnonzeros);
2510 }
2511
2512 /* create transformed constraint with the same flags */
2513 (void) SCIPsnprintf(s, SCIP_MAXSTRLEN, "t_%s", SCIPconsGetName(sourcecons));
2514 SCIP_CALL( SCIPcreateCons(scip, targetcons, s, conshdlr, consdata,
2515 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons),
2516 SCIPconsIsEnforced(sourcecons), SCIPconsIsChecked(sourcecons),
2517 SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
2518 SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons),
2519 SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
2520
2521 consdata->cons = *targetcons;
2522 assert(consdata->cons != NULL);
2523
2524 /* catch bound change events on variable */
2525 for( j = 0; j < consdata->nvars; ++j )
2526 {
2527 SCIP_CALL( catchVarEventCardinality(scip, conshdlrdata->eventhdlr, consdata,
2528 consdata->vars[j], consdata->indvars[j], j, &consdata->eventdatas[j]) );
2529 assert(consdata->eventdatas[j] != NULL);
2530 }
2531
2532#ifdef SCIP_DEBUG
2533 if( SCIPisGT(scip, (SCIP_Real)consdata->ntreatnonzeros, consdata->cardval) )
2534 {
2535 SCIPdebugMsg(scip, "constraint <%s> has %d variables fixed to be nonzero, allthough the constraint allows \
2536 only %d nonzero variables\n", SCIPconsGetName(*targetcons), consdata->ntreatnonzeros, consdata->cardval);
2537 }
2538#endif
2539
2540 return SCIP_OKAY;
2541}
2542
2543/** presolving method of constraint handler */
2544static
2545SCIP_DECL_CONSPRESOL(consPresolCardinality)
2546{ /*lint --e{715}*/
2547 SCIPdebug( int oldnfixedvars; )
2548 SCIPdebug( int oldndelconss; )
2549 SCIPdebug( int oldnupgdconss; )
2550 int nremovedvars;
2551 SCIP_EVENTHDLR* eventhdlr;
2552 int c;
2553
2554 assert(scip != NULL);
2555 assert(conshdlr != NULL);
2556 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2557 assert(result != NULL);
2558
2559 SCIPdebugMsg(scip, "Presolving cardinality constraints.\n");
2560
2562 SCIPdebug( oldnfixedvars = *nfixedvars; )
2563 SCIPdebug( oldndelconss = *ndelconss; )
2564 SCIPdebug( oldnupgdconss = *nupgdconss; )
2565 nremovedvars = 0;
2566
2567 /* only run if success if possible */
2568 if( nrounds == 0 || nnewfixedvars > 0 || nnewaggrvars > 0 )
2569 {
2570 /* get constraint handler data */
2571 assert(SCIPconshdlrGetData(conshdlr) != NULL);
2572 eventhdlr = SCIPconshdlrGetData(conshdlr)->eventhdlr;
2573 assert(eventhdlr != NULL);
2574
2576
2577 /* check each constraint */
2578 for( c = 0; c < nconss; ++c )
2579 {
2580 SCIP_CONSDATA* consdata;
2581 SCIP_CONS* cons;
2583 SCIP_Bool success;
2584
2585 assert(conss != NULL);
2586 assert(conss[c] != NULL);
2587 cons = conss[c];
2588 consdata = SCIPconsGetData(cons);
2589
2590 assert(consdata != NULL);
2591 assert(consdata->nvars >= 0);
2592 assert(consdata->nvars <= consdata->maxvars);
2594
2595 /* perform one presolving round */
2596 SCIP_CALL( presolRoundCardinality(scip, cons, consdata, eventhdlr, &cutoff, &success,
2597 ndelconss, nupgdconss, nfixedvars, &nremovedvars) );
2598
2599 if( cutoff )
2600 {
2601 SCIPdebugMsg(scip, "presolving detected cutoff.\n");
2603 return SCIP_OKAY;
2604 }
2605
2606 if( success )
2608 }
2609 }
2610 (*nchgcoefs) += nremovedvars;
2611
2612 SCIPdebug( SCIPdebugMsg(scip, "presolving fixed %d variables, removed %d variables, deleted %d constraints, "
2613 "and upgraded %d constraints.\n", *nfixedvars - oldnfixedvars, nremovedvars, *ndelconss - oldndelconss,
2614 *nupgdconss - oldnupgdconss); )
2615
2616 return SCIP_OKAY;
2617}
2618
2619/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
2620static
2621SCIP_DECL_CONSINITLP(consInitlpCardinality)
2622{ /*lint --e{715}*/
2624
2625 assert(scip != NULL);
2626 assert(conshdlr != NULL);
2627
2628 /* checking for initial rows for cardinality constraints */
2629 SCIP_CALL( initsepaBoundInequalityFromCardinality(scip, conshdlr, conss, nconss, NULL, FALSE, NULL, &cutoff) );
2630 assert(!cutoff);
2631
2632 return SCIP_OKAY;
2633}
2634
2635/** separation method of constraint handler for LP solutions */
2636static
2637SCIP_DECL_CONSSEPALP(consSepalpCardinality)
2638{ /*lint --e{715}*/
2639 assert(scip != NULL);
2640 assert(conshdlr != NULL);
2641 assert(conss != NULL);
2642 assert(result != NULL);
2643
2644 SCIP_CALL( separateCardinality(scip, conshdlr, NULL, nconss, conss, result) );
2645
2646 return SCIP_OKAY;
2647}
2648
2649/** separation method of constraint handler for arbitrary primal solutions */
2650static
2651SCIP_DECL_CONSSEPASOL(consSepasolCardinality)
2652{ /*lint --e{715}*/
2653 assert(scip != NULL);
2654 assert(conshdlr != NULL);
2655 assert(conss != NULL);
2656 assert(result != NULL);
2657
2658 SCIP_CALL( separateCardinality(scip, conshdlr, sol, nconss, conss, result) );
2659
2660 return SCIP_OKAY;
2661}
2662
2663/** constraint enforcing method of constraint handler for LP solutions */
2664static
2665SCIP_DECL_CONSENFOLP(consEnfolpCardinality)
2666{ /*lint --e{715}*/
2667 assert(scip != NULL);
2668 assert(conshdlr != NULL);
2669 assert(conss != NULL);
2670 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2671 assert(result != NULL);
2672
2673 SCIP_CALL( enforceCardinality(scip, conshdlr, NULL, nconss, conss, result) );
2674
2675 return SCIP_OKAY;
2676}
2677
2678/** constraint enforcing method of constraint handler for relaxation solutions */
2679static
2680SCIP_DECL_CONSENFORELAX(consEnforelaxCardinality)
2681{ /*lint --e{715}*/
2682 assert( scip != NULL );
2683 assert( conshdlr != NULL );
2684 assert( conss != NULL );
2685 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2686 assert( result != NULL );
2687
2688 SCIP_CALL( enforceCardinality(scip, conshdlr, sol, nconss, conss, result) );
2689
2690 return SCIP_OKAY;
2691}
2692
2693/** constraint enforcing method of constraint handler for pseudo solutions */
2694static
2695SCIP_DECL_CONSENFOPS(consEnfopsCardinality)
2696{ /*lint --e{715}*/
2697 assert(scip != NULL);
2698 assert(conshdlr != NULL);
2699 assert(conss != NULL);
2700 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2701 assert(result != NULL);
2702
2703 SCIP_CALL( enforceCardinality(scip, conshdlr, NULL, nconss, conss, result) );
2704
2705 return SCIP_OKAY;
2706}
2707
2708/** feasibility check method of constraint handler for integral solutions
2709 *
2710 * We simply check whether more variables than allowed are nonzero in the given solution.
2711 */
2712static
2713SCIP_DECL_CONSCHECK(consCheckCardinality)
2714{ /*lint --e{715}*/
2715 int c;
2716
2717 assert(scip != NULL);
2718 assert(conshdlr != NULL);
2719 assert(conss != NULL);
2720 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2721 assert(result != NULL);
2722
2723 /* check each constraint */
2724 for( c = 0; c < nconss; ++c )
2725 {
2726 SCIP_CONSDATA* consdata;
2727 int cardval;
2728 int j;
2729 int cnt;
2730
2731 cnt = 0;
2732 assert(conss[c] != NULL);
2733 consdata = SCIPconsGetData(conss[c]);
2734 assert(consdata != NULL);
2735 cardval = consdata->cardval;
2736 SCIPdebugMsg(scip, "Checking cardinality constraint <%s>.\n", SCIPconsGetName(conss[c]));
2737
2738 /* check all variables */
2739 for( j = 0; j < consdata->nvars; ++j )
2740 {
2741 /* if variable is nonzero */
2742 if( !SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->vars[j])) )
2743 {
2744 ++cnt;
2745
2746 /* if more variables than allowed are nonzero */
2747 if( cnt > cardval )
2748 {
2749 SCIP_CALL( SCIPresetConsAge(scip, conss[c]) );
2751
2752 if( printreason )
2753 {
2754 int l;
2755
2756 SCIP_CALL( SCIPprintCons(scip, conss[c], NULL) );
2757 SCIPinfoMessage(scip, NULL, ";\nviolation: ");
2758
2759 for( l = 0; l < consdata->nvars; ++l )
2760 {
2761 /* if variable is nonzero */
2762 if( !SCIPisFeasZero(scip, SCIPgetSolVal(scip, sol, consdata->vars[l])) )
2763 {
2764 SCIPinfoMessage(scip, NULL, "<%s> = %.15g ",
2765 SCIPvarGetName(consdata->vars[l]), SCIPgetSolVal(scip, sol, consdata->vars[l]));
2766 }
2767 }
2768 SCIPinfoMessage(scip, NULL, "\n");
2769 }
2770 if( sol != NULL )
2772 return SCIP_OKAY;
2773 }
2774 }
2775 }
2776 }
2778
2779 return SCIP_OKAY;
2780}
2781
2782/** domain propagation method of constraint handler */
2783static
2784SCIP_DECL_CONSPROP(consPropCardinality)
2785{ /*lint --e{715}*/
2786 int nchgdomain = 0;
2787 int c;
2788
2789 assert(scip != NULL);
2790 assert(conshdlr != NULL);
2791 assert(conss != NULL);
2792 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2793 assert(result != NULL);
2795
2797
2798 /* check each constraint */
2799 for( c = 0; c < nconss; ++c )
2800 {
2801 SCIP_CONS* cons;
2802 SCIP_CONSDATA* consdata;
2804
2806 assert(conss[c] != NULL);
2807 cons = conss[c];
2808 consdata = SCIPconsGetData(cons);
2809 assert(consdata != NULL);
2810 SCIPdebugMsg(scip, "Propagating cardinality constraint <%s>.\n", SCIPconsGetName(cons) );
2811
2813 SCIP_CALL( propCardinality(scip, cons, consdata, &cutoff, &nchgdomain) );
2814 if( cutoff )
2815 {
2817 return SCIP_OKAY;
2818 }
2819 }
2820 SCIPdebugMsg(scip, "Propagated %d domains.\n", nchgdomain);
2821 if( nchgdomain > 0 )
2823
2824 return SCIP_OKAY;
2825}
2826
2827/** variable rounding lock method of constraint handler
2828 *
2829 * Let lb and ub be the lower and upper bounds of a
2830 * variable. Preprocessing usually makes sure that lb <= 0 <= ub.
2831 *
2832 * - If lb < 0 then rounding down may violate the constraint.
2833 * - If ub > 0 then rounding up may violated the constraint.
2834 * - If lb > 0 or ub < 0 then the rhs of the constraint can be updated and the variable
2835 * can be removed from the constraint. Thus, we do not have to deal with it here.
2836 * - If lb == 0 then rounding down does not violate the constraint.
2837 * - If ub == 0 then rounding up does not violate the constraint.
2838 */
2839static
2840SCIP_DECL_CONSLOCK(consLockCardinality)
2841{
2842 SCIP_CONSDATA* consdata;
2843 SCIP_VAR** vars;
2844 int nvars;
2845 SCIP_VAR** indvars;
2846 int j;
2847
2848 assert(scip != NULL);
2849 assert(conshdlr != NULL);
2850 assert(cons != NULL);
2851 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2852 assert(locktype == SCIP_LOCKTYPE_MODEL);
2853
2854 consdata = SCIPconsGetData(cons);
2855 assert(consdata != NULL);
2856
2857 SCIPdebugMsg(scip, "Locking constraint <%s>.\n", SCIPconsGetName(cons));
2858
2859 vars = consdata->vars;
2860 indvars = consdata->indvars;
2861 nvars = consdata->nvars;
2862 assert(vars != NULL);
2863
2864 for( j = 0; j < nvars; ++j )
2865 {
2866 SCIP_VAR* var;
2867 SCIP_VAR* indvar;
2868 var = vars[j];
2869 indvar = indvars[j];
2870
2871 /* if lower bound is negative, rounding down may violate constraint */
2873 {
2874 SCIP_CALL( SCIPaddVarLocksType(scip, var, locktype, nlockspos, nlocksneg) );
2875 }
2876
2877 /* additionally: if upper bound is positive, rounding up may violate constraint */
2879 {
2880 SCIP_CALL( SCIPaddVarLocksType(scip, var, locktype, nlocksneg, nlockspos) );
2881 }
2882
2883 /* add lock on indicator variable in both directions; @todo write constraint handler to handle down locks */
2884 SCIP_CALL( SCIPaddVarLocksType(scip, indvar, locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
2885 }
2886
2887 return SCIP_OKAY;
2888}
2889
2890/** constraint display method of constraint handler */
2891static
2892SCIP_DECL_CONSPRINT(consPrintCardinality)
2893{ /*lint --e{715}*/
2894 SCIP_CONSDATA* consdata;
2895 int j;
2896
2897 assert(scip != NULL);
2898 assert(conshdlr != NULL);
2899 assert(cons != NULL);
2900 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2901
2902 consdata = SCIPconsGetData(cons);
2903 assert(consdata != NULL);
2904
2905 for( j = 0; j < consdata->nvars; ++j )
2906 {
2907 if( j > 0 )
2908 SCIPinfoMessage(scip, file, ", ");
2909 SCIP_CALL( SCIPwriteVarName(scip, file, consdata->vars[j], FALSE) );
2910
2911 if( consdata->indvars[j] != NULL )
2912 {
2913 SCIPinfoMessage(scip, file, " [");
2914 SCIP_CALL( SCIPwriteVarName(scip, file, consdata->indvars[j], FALSE) );
2915 SCIPinfoMessage(scip, file, "]");
2916 }
2917
2918 if( consdata->weights == NULL )
2919 SCIPinfoMessage(scip, file, " (%d)", j+1);
2920 else
2921 SCIPinfoMessage(scip, file, " (%3.2f)", consdata->weights[j]);
2922 }
2923 SCIPinfoMessage(scip, file, " <= %d", consdata->cardval);
2924
2925 return SCIP_OKAY;
2926}
2927
2928/** constraint copying method of constraint handler */
2929static
2930SCIP_DECL_CONSCOPY(consCopyCardinality)
2931{ /*lint --e{715}*/
2932 SCIP_CONSDATA* sourceconsdata;
2933 SCIP_VAR** sourcevars;
2934 SCIP_VAR** targetvars;
2935 SCIP_VAR** sourceindvars;
2936 SCIP_VAR** targetindvars;
2937 SCIP_Real* sourceweights;
2938 SCIP_Real* targetweights;
2939 const char* consname;
2940 int nvars;
2941 int v;
2942
2943 assert(scip != NULL);
2944 assert(sourcescip != NULL);
2945 assert(sourcecons != NULL);
2946 assert(SCIPisTransformed(sourcescip));
2947 assert(strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(sourcecons)), CONSHDLR_NAME) == 0);
2948
2949 *valid = TRUE;
2950
2951 if( name != NULL )
2952 consname = name;
2953 else
2954 consname = SCIPconsGetName(sourcecons);
2955
2956 SCIPdebugMsg(scip, "Copying cardinality constraint <%s> ...\n", consname);
2957
2958 sourceconsdata = SCIPconsGetData(sourcecons);
2959 assert(sourceconsdata != NULL);
2960
2961 /* get variables and weights of the source constraint */
2962 nvars = sourceconsdata->nvars;
2963
2964 if( nvars == 0 )
2965 return SCIP_OKAY;
2966
2967 sourcevars = sourceconsdata->vars;
2968 assert(sourcevars != NULL);
2969 sourceindvars = sourceconsdata->indvars;
2970 assert(sourceindvars != NULL);
2971 sourceweights = sourceconsdata->weights;
2972 assert(sourceweights != NULL);
2973
2974 /* duplicate variable array */
2975 SCIP_CALL( SCIPallocBufferArray(sourcescip, &targetvars, nvars) );
2976 SCIP_CALL( SCIPallocBufferArray(sourcescip, &targetindvars, nvars) );
2977 SCIP_CALL( SCIPduplicateBufferArray(sourcescip, &targetweights, sourceweights, nvars) );
2978
2979 /* get copied variables in target SCIP */
2980 for( v = 0; v < nvars && *valid; ++v )
2981 {
2982 assert(sourcevars[v] != NULL);
2983 assert(sourceindvars[v] != NULL);
2984
2985 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[v], &(targetvars[v]), varmap, consmap, global, valid) );
2986 if( *valid )
2987 {
2988 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourceindvars[v], &(targetindvars[v]), varmap, consmap, global, valid) );
2989 }
2990 }
2991
2992 /* only create the target constraint, if all variables could be copied */
2993 if( *valid )
2994 {
2995 SCIP_CALL( SCIPcreateConsCardinality(scip, cons, consname, nvars, targetvars, sourceconsdata->cardval, targetindvars,
2996 targetweights, initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
2997 }
2998
2999 /* free buffer array */
3000 SCIPfreeBufferArray(sourcescip, &targetweights);
3001 SCIPfreeBufferArray(sourcescip, &targetindvars);
3002 SCIPfreeBufferArray(sourcescip, &targetvars);
3003
3004 return SCIP_OKAY;
3005}
3006
3007/** constraint parsing method of constraint handler */
3008static
3009SCIP_DECL_CONSPARSE(consParseCardinality)
3010{ /*lint --e{715}*/
3011 SCIP_VAR* var;
3012 SCIP_VAR* indvar;
3013 SCIP_Real weight;
3014 int cardval;
3015 const char* s;
3016 char* t;
3017
3018 assert(scip != NULL);
3019 assert(conshdlr != NULL);
3020 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
3021 assert(cons != NULL);
3022 assert(success != NULL);
3023
3024 *success = TRUE;
3025 s = str;
3026
3027 /* create empty cardinality constraint */
3028 SCIP_CALL( SCIPcreateConsCardinality(scip, cons, name, 0, NULL, 0, NULL, NULL, initial, separate, enforce, check, propagate, local, dynamic, removable, stickingatnode) );
3029
3030 /* loop through string */
3031 while( *s != '\0' )
3032 {
3033 /* parse variable name */
3034 SCIP_CALL( SCIPparseVarName(scip, s, &var, &t) );
3035
3036 if( var == NULL )
3037 {
3038 t = strchr(t, '<');
3039
3040 if( t != NULL )
3041 s = t;
3042
3043 break;
3044 }
3045
3046 /* skip until beginning of indicator variable or weight */
3047 while( *t != '\0' && *t != '(' && *t != '[' )
3048 ++t;
3049
3050 if( *t == '\0' )
3051 {
3052 SCIPerrorMessage("Syntax error: expected opening '[' or '(' at input: %s\n", s);
3053 *success = FALSE;
3054 break;
3055 }
3056
3057 s = t;
3058
3059 /* parse indicator variable */
3060 indvar = NULL;
3061 if( *s == '[' )
3062 {
3063 ++s;
3064 SCIP_CALL( SCIPparseVarName(scip, s, &indvar, &t) );
3065
3066 if( indvar == NULL )
3067 {
3068 SCIPerrorMessage("Syntax error: expected indicator variable name at input: %s\n", s);
3069 *success = FALSE;
3070 break;
3071 }
3072 s = t;
3073
3074 /* skip ']' */
3075 if( *s != ']' )
3076 {
3077 SCIPerrorMessage("Syntax error: expected closing ']' at input: %s\n", s);
3078 *success = FALSE;
3079 break;
3080 }
3081 ++s;
3082
3083 /* skip white space */
3084 SCIP_CALL( SCIPskipSpace((char**)&s) );
3085 }
3086
3087 /* skip '(' */
3088 if( *s != '(' )
3089 {
3090 SCIPerrorMessage("Syntax error: expected opening '(' at input: %s\n", s);
3091 *success = FALSE;
3092 break;
3093 }
3094 ++s;
3095
3096 /* find weight */
3097 weight = strtod(s, &t);
3098
3099 if( t == NULL )
3100 {
3101 SCIPerrorMessage("Syntax error during parsing of the weight: %s\n", s);
3102 *success = FALSE;
3103 break;
3104 }
3105
3106 s = t;
3107
3108 /* skip until ending of weight */
3109 t = strchr(t, ')');
3110
3111 if( t == NULL )
3112 {
3113 SCIPerrorMessage("Syntax error: expected closing ')' at input %s\n", s);
3114 *success = FALSE;
3115 break;
3116 }
3117
3118 s = t;
3119
3120 /* skip ')' */
3121 ++s;
3122
3123 /* skip white space */
3124 SCIP_CALL( SCIPskipSpace((char**)&s) );
3125
3126 /* skip ',' */
3127 if( *s == ',' )
3128 ++s;
3129
3130 /* add variable */
3131 SCIP_CALL( SCIPaddVarCardinality(scip, *cons, var, indvar, weight) );
3132 }
3133
3134 /* check if there is a '<=' */
3135 if( *success && *s == '<' && *(s+1) == '=' )
3136 {
3137 s = s + 2;
3138
3139 /* skip white space */
3140 SCIP_CALL( SCIPskipSpace((char**)&s) );
3141
3142 cardval = (int)strtod(s, &t);
3143
3144 if( t == NULL )
3145 {
3146 SCIPerrorMessage("Syntax error during parsing of the cardinality restriction value: %s\n", s);
3147 *success = FALSE;
3148 }
3149 else
3150 SCIP_CALL( SCIPchgCardvalCardinality(scip, *cons, cardval) );
3151 }
3152
3153 if( !*success )
3154 SCIP_CALL( SCIPreleaseCons(scip, cons) );
3155
3156 return SCIP_OKAY;
3157}
3158
3159/** constraint method of constraint handler which returns the variables (if possible) */
3160static
3161SCIP_DECL_CONSGETVARS(consGetVarsCardinality)
3162{ /*lint --e{715}*/
3163 SCIP_CONSDATA* consdata;
3164
3165 consdata = SCIPconsGetData(cons);
3166 assert(consdata != NULL);
3167
3168 if( varssize < 2 * consdata->nvars )
3169 (*success) = FALSE;
3170 else
3171 {
3172 int v;
3173 int cnt = 0;
3174
3175 assert(vars != NULL);
3176
3177 for (v = 0; v < consdata->nvars; ++v)
3178 {
3179 vars[cnt++] = consdata->vars[v];
3180 vars[cnt++] = consdata->indvars[v];
3181 }
3182 (*success) = TRUE;
3183 }
3184
3185 return SCIP_OKAY;
3186}
3187
3188/** constraint method of constraint handler which returns the number of variables (if possible) */
3189static
3190SCIP_DECL_CONSGETNVARS(consGetNVarsCardinality)
3191{ /*lint --e{715}*/
3192 SCIP_CONSDATA* consdata;
3193
3194 consdata = SCIPconsGetData(cons);
3195 assert(consdata != NULL);
3196
3197 (*nvars) = 2 * consdata->nvars;
3198 (*success) = TRUE;
3199
3200 return SCIP_OKAY;
3201}
3202
3203/** constraint handler method which returns the permutation symmetry detection graph of a constraint */
3204static
3205SCIP_DECL_CONSGETPERMSYMGRAPH(consGetPermsymGraphCardinality)
3206{ /*lint --e{715}*/
3207 SCIP_CONSDATA* consdata;
3208 SCIP_VAR** vars;
3209 SCIP_Real* vals;
3210 SCIP_Real constant;
3211 SCIP_Real rhs;
3212 int consnodeidx;
3213 int pairnodeidx;
3214 int nodeidx;
3215 int nconsvars;
3216 int nlocvars;
3217 int nvars;
3218 int i;
3219
3220 consdata = SCIPconsGetData(cons);
3221 assert(consdata != NULL);
3222 assert(graph != NULL);
3223
3224 nconsvars = consdata->nvars;
3225 rhs = (SCIP_Real) consdata->cardval;
3226
3227 /* add node for constraint */
3228 SCIP_CALL( SCIPaddSymgraphConsnode(scip, graph, cons, -SCIPinfinity(scip), rhs, &consnodeidx) );
3229
3230 /* create nodes and edges for each variable */
3234
3235 for( i = 0; i < nconsvars; ++i )
3236 {
3237 /* connect each variable and its indicator variable with an intermediate node, which is connected with consnode */
3238 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_CARD_TUPLE , &pairnodeidx) );
3239
3240 /* connect variable with pair node*/
3241 vars[0] = consdata->vars[i];
3242 vals[0] = 1.0;
3243 nlocvars = 1;
3244 constant = 0.0;
3245
3247 &nlocvars, &constant, SCIPisTransformed(scip)) );
3248
3249 /* check whether variable is (multi-)aggregated or negated */
3250 if( nlocvars > 1 || !SCIPisEQ(scip, vals[0], 1.0) || !SCIPisZero(scip, constant) )
3251 {
3252 /* encode aggregation by a sum-expression */
3253 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &nodeidx) ); /*lint !e641*/
3254
3255 /* we do not need to take weights of variables into account;
3256 * they are only used to sort variables within the constraint */
3257 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, pairnodeidx, nodeidx, FALSE, 0.0) );
3258
3259 /* add nodes and edges for variables in aggregation */
3260 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, nodeidx, vars, vals, nlocvars, constant) );
3261 }
3262 else if( nlocvars == 1 )
3263 {
3264 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, vars[0]);
3265
3266 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, pairnodeidx, nodeidx, FALSE, 0.0) );
3267 }
3268
3269 /* connect indicator variable with pair node*/
3270 vars[0] = consdata->indvars[i];
3271 vals[0] = 1.0;
3272 nlocvars = 1;
3273 constant = 0.0;
3274
3276 &nlocvars, &constant, SCIPisTransformed(scip)) );
3277
3278 /* check whether variable is (multi-)aggregated or negated */
3279 if( nlocvars > 1 || !SCIPisEQ(scip, vals[0], 1.0) || !SCIPisZero(scip, constant) )
3280 {
3281 /* encode aggregation by a sum-expression */
3282 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &nodeidx) ); /*lint !e641*/
3283
3284 /* we do not need to take weights of variables into account;
3285 * they are only used to sort variables within the constraint */
3286 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, pairnodeidx, nodeidx, FALSE, 0.0) );
3287
3288 /* add nodes and edges for variables in aggregation */
3289 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, nodeidx, vars, vals, nlocvars, constant) );
3290 }
3291 else if( nlocvars == 1 )
3292 {
3293 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, vars[0]);
3294
3295 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, pairnodeidx, nodeidx, FALSE, 0.0) );
3296 }
3297 }
3298
3299 SCIPfreeBufferArray(scip, &vals);
3301
3302 assert(success != NULL);
3303 *success = TRUE;
3304
3305 return SCIP_OKAY;
3306}
3307
3308/** constraint handler method which returns the signed permutation symmetry detection graph of a constraint */
3309static
3310SCIP_DECL_CONSGETSIGNEDPERMSYMGRAPH(consGetSignedPermsymGraphCardinality)
3311{ /*lint --e{715}*/
3312 SCIP_CONSDATA* consdata;
3313 SCIP_VAR** vars;
3314 SCIP_Real* vals;
3315 SCIP_Real constant;
3316 SCIP_Real rhs;
3317 int consnodeidx;
3318 int pairnodeidx;
3319 int nodeidx;
3320 int nconsvars;
3321 int nlocvars;
3322 int nvars;
3323 int i;
3324
3325 consdata = SCIPconsGetData(cons);
3326 assert(consdata != NULL);
3327 assert(graph != NULL);
3328
3329 nconsvars = consdata->nvars;
3330 rhs = (SCIP_Real) consdata->cardval;
3331
3332 /* add node for constraint */
3333 SCIP_CALL( SCIPaddSymgraphConsnode(scip, graph, cons, -SCIPinfinity(scip), rhs, &consnodeidx) );
3334
3335 /* create nodes and edges for each variable */
3339
3340 for( i = 0; i < nconsvars; ++i )
3341 {
3342 /* connect each variable and its indicator variable with an intermediate node, which is connected with consnode */
3343 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_CARD_TUPLE , &pairnodeidx) );
3344
3345 vars[0] = consdata->vars[i];
3346 vals[0] = 1.0;
3347 nlocvars = 1;
3348 constant = 0.0;
3349
3350 /* use SYM_SYMTYPE_PERM here to NOT center variable domains at 0, as the latter might not preserve
3351 * cardinality constraints */
3353 &nlocvars, &constant, SCIPisTransformed(scip)) );
3354
3355 /* check whether variable is (multi-) aggregated or negated */
3356 if( nlocvars > 1 || !SCIPisEQ(scip, vals[0], 1.0) || !SCIPisZero(scip, constant) )
3357 {
3358 int sumnodeidx;
3359 int j;
3360
3361 /* encode aggregation by a sum-expression */
3362 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &sumnodeidx) ); /*lint !e641*/
3363
3364 /* we do not need to take weights of variables into account;
3365 * they are only used to sort variables within the constraint */
3366 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, pairnodeidx, sumnodeidx, FALSE, 0.0) );
3367
3368 /* add nodes and edges for variables in aggregation, do not add edges to negated variables
3369 * since this might not necessarily be a symmetry of the cardinality constraint; therefore,
3370 * do not use SCIPaddSymgraphVarAggregation() */
3371 for( j = 0; j < nlocvars; ++j )
3372 {
3373 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, vars[j]);
3374 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, sumnodeidx, nodeidx, TRUE, vals[j]) );
3375 }
3376
3377 /* possibly add node for constant */
3378 if( ! SCIPisZero(scip, constant) )
3379 {
3380 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, constant, &nodeidx) );
3381
3382 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, sumnodeidx, nodeidx, FALSE, 0.0) );
3383 }
3384 }
3385 else if( nlocvars == 1 )
3386 {
3387 SCIP_Bool allownegation = FALSE;
3388
3389 /* a negation is allowed if it is centered around 0 */
3393 allownegation = TRUE;
3394
3395 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, vars[0]);
3396 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, pairnodeidx, nodeidx, TRUE, 1.0) );
3397
3398 nodeidx = SCIPgetSymgraphNegatedVarnodeidx(scip, graph, vars[0]);
3399 if( allownegation )
3400 {
3401 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, pairnodeidx, nodeidx, TRUE, 1.0) );
3402 }
3403 else
3404 {
3405 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, pairnodeidx, nodeidx, FALSE, 0.0) );
3406 }
3407 }
3408
3409 /* connect indicator variable with pair node, do not add edges to negated variables since negating
3410 * might not preserve the cardinality requirement
3411 */
3412 vars[0] = consdata->indvars[i];
3413 vals[0] = 1.0;
3414 nlocvars = 1;
3415 constant = 0.0;
3416
3418 &nlocvars, &constant, SCIPisTransformed(scip)) );
3419
3420 /* check whether variable is (multi-)aggregated or negated */
3421 if( nlocvars > 1 || !SCIPisEQ(scip, vals[0], 1.0) || !SCIPisZero(scip, constant) )
3422 {
3423 /* encode aggregation by a sum-expression */
3424 SCIP_CALL( SCIPaddSymgraphOpnode(scip, graph, (int) SYM_CONSOPTYPE_SUM, &nodeidx) ); /*lint !e641*/
3425
3426 /* we do not need to take weights of variables into account;
3427 * they are only used to sort variables within the constraint */
3428 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, pairnodeidx, nodeidx, FALSE, 0.0) );
3429
3430 /* add nodes and edges for variables in aggregation */
3431 SCIP_CALL( SCIPaddSymgraphVarAggregation(scip, graph, nodeidx, vars, vals, nlocvars, constant) );
3432 }
3433 else if( nlocvars == 1 )
3434 {
3435 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, vars[0]);
3436
3437 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, pairnodeidx, nodeidx, FALSE, 0.0) );
3438 }
3439 }
3440
3441 SCIPfreeBufferArray(scip, &vals);
3443
3444 assert(success != NULL);
3445 *success = TRUE;
3446
3447 return SCIP_OKAY;
3448}
3449
3450/* ---------------- Callback methods of event handler ---------------- */
3451
3452/* exec the event handler
3453 *
3454 * update the number of variables fixed to be nonzero
3455 * update the bound constraints
3456 */
3457static
3458SCIP_DECL_EVENTEXEC(eventExecCardinality)
3459{
3460 SCIP_EVENTTYPE eventtype;
3461 SCIP_CONSDATA* consdata;
3462 SCIP_Real oldbound;
3463 SCIP_Real newbound;
3464 SCIP_VAR* var;
3465
3466 assert(eventhdlr != NULL);
3467 assert(eventdata != NULL);
3468 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0);
3469 assert(event != NULL);
3470
3471 consdata = eventdata->consdata;
3472 assert(consdata != NULL);
3473 assert(0 <= consdata->ntreatnonzeros && consdata->ntreatnonzeros <= consdata->nvars);
3474 assert(consdata->eventdatascurrent != NULL);
3475 assert(consdata->eventvarscurrent != NULL);
3476
3477 var = SCIPeventGetVar(event);
3478 assert(var != NULL);
3479 oldbound = SCIPeventGetOldbound(event);
3480 newbound = SCIPeventGetNewbound(event);
3481 eventtype = SCIPeventGetType(event);
3482
3483#ifdef SCIP_DEBUG
3484 if( ( eventdata->varmarked && var == eventdata->var) || ( eventdata->indvarmarked && var == eventdata->indvar) )
3485 {
3486 int i;
3487
3488 for( i = 0; i < consdata->neventdatascurrent; ++i )
3489 {
3490 if( var == consdata->eventvarscurrent[i] )
3491 {
3492 break;
3493 }
3494 }
3495 assert(i < consdata->neventdatascurrent);
3496 }
3497#endif
3498
3499 if( eventtype & SCIP_EVENTTYPE_GBDCHANGED )
3500 {
3501 if( eventtype == SCIP_EVENTTYPE_GLBCHANGED )
3502 {
3503 /* global lower bound is not negative anymore -> remove down lock */
3504 if ( SCIPisFeasNegative(scip, oldbound) && ! SCIPisFeasNegative(scip, newbound) )
3505 SCIP_CALL( SCIPunlockVarCons(scip, var, consdata->cons, TRUE, FALSE) );
3506 /* global lower bound turned negative -> add down lock */
3507 else if ( ! SCIPisFeasNegative(scip, oldbound) && SCIPisFeasNegative(scip, newbound) )
3508 SCIP_CALL( SCIPlockVarCons(scip, var, consdata->cons, TRUE, FALSE) );
3509
3510 return SCIP_OKAY;
3511 }
3512 if( eventtype == SCIP_EVENTTYPE_GUBCHANGED )
3513 {
3514 /* global upper bound is not positive anymore -> remove up lock */
3515 if ( SCIPisFeasPositive(scip, oldbound) && ! SCIPisFeasPositive(scip, newbound) )
3516 SCIP_CALL( SCIPunlockVarCons(scip, var, consdata->cons, FALSE, TRUE) );
3517 /* global upper bound turned positive -> add up lock */
3518 else if ( ! SCIPisFeasPositive(scip, oldbound) && SCIPisFeasPositive(scip, newbound) )
3519 SCIP_CALL( SCIPlockVarCons(scip, var, consdata->cons, FALSE, TRUE) );
3520
3521 return SCIP_OKAY;
3522 }
3523 }
3524
3525 /* if variable is an indicator variable */
3526 if( var == eventdata->indvar )
3527 {
3529 assert(consdata->cons != NULL);
3530
3531 if( eventtype == SCIP_EVENTTYPE_LBTIGHTENED )
3532 ++(consdata->ntreatnonzeros);
3533 else if( eventtype == SCIP_EVENTTYPE_LBRELAXED )
3534 --(consdata->ntreatnonzeros);
3535 else if( eventtype == SCIP_EVENTTYPE_UBTIGHTENED && ! eventdata->indvarmarked )
3536 {
3537 assert(oldbound == 1.0 && newbound == 0.0 );
3538
3539 /* save event data for propagation */
3540 consdata->eventdatascurrent[consdata->neventdatascurrent] = eventdata;
3541 consdata->eventvarscurrent[consdata->neventdatascurrent] = var;
3542 ++consdata->neventdatascurrent;
3543 eventdata->indvarmarked = TRUE;
3544 assert(consdata->neventdatascurrent <= 4 * consdata->maxvars);
3545 assert(var == eventdata->indvar );
3546 }
3547 assert(0 <= consdata->ntreatnonzeros && consdata->ntreatnonzeros <= consdata->nvars);
3548 }
3549
3550 /* if variable is an implied variable,
3551 * notice that the case consdata->var = consdata->indvar is possible */
3552 if( var == eventdata->var && ! eventdata->varmarked )
3553 {
3554 if( eventtype == SCIP_EVENTTYPE_LBTIGHTENED )
3555 {
3556 /* if variable is now fixed to be nonzero */
3557 if( !SCIPisFeasPositive(scip, oldbound) && SCIPisFeasPositive(scip, newbound) )
3558 {
3559 /* save event data for propagation */
3560 consdata->eventdatascurrent[consdata->neventdatascurrent] = eventdata;
3561 consdata->eventvarscurrent[consdata->neventdatascurrent] = var;
3562 ++consdata->neventdatascurrent;
3563 eventdata->varmarked = TRUE;
3564 assert(consdata->neventdatascurrent <= 4 * consdata->maxvars );
3565 assert(var == eventdata->var );
3566 }
3567 }
3568 else if( eventtype == SCIP_EVENTTYPE_UBTIGHTENED )
3569 {
3570 /* if variable is now fixed to be nonzero */
3571 if( !SCIPisFeasNegative(scip, oldbound) && SCIPisFeasNegative(scip, newbound) )
3572 {
3573 /* save event data for propagation */
3574 consdata->eventdatascurrent[consdata->neventdatascurrent] = eventdata;
3575 consdata->eventvarscurrent[consdata->neventdatascurrent] = var;
3576 ++consdata->neventdatascurrent;
3577 eventdata->varmarked = TRUE;
3578 assert(consdata->neventdatascurrent <= 4 * consdata->maxvars );
3579 assert(var == eventdata->var);
3580 }
3581 }
3582 }
3583 assert(0 <= consdata->ntreatnonzeros && consdata->ntreatnonzeros <= consdata->nvars);
3584
3585 SCIPdebugMsg(scip, "event exec cons <%s>: changed %s bound of variable <%s> from %g to %g (ntreatnonzeros: %d).\n",
3586 SCIPconsGetName(consdata->cons), eventtype & (SCIP_EVENTTYPE_UBTIGHTENED | SCIP_EVENTTYPE_GUBCHANGED) ? "upper" : "lower", SCIPvarGetName(SCIPeventGetVar(event)),
3587 oldbound, newbound, consdata->ntreatnonzeros);
3588
3589 return SCIP_OKAY;
3590}
3591
3592/* ---------------- Constraint specific interface methods ---------------- */
3593
3594/** creates the handler for cardinality constraints and includes it in SCIP */
3596 SCIP* scip /**< SCIP data structure */
3597 )
3598{
3599 SCIP_CONSHDLRDATA* conshdlrdata;
3600 SCIP_CONSHDLR* conshdlr;
3601
3602 /* create constraint handler data */
3603 SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
3604 conshdlrdata->eventhdlr = NULL;
3605 conshdlrdata->varhash = NULL;
3606
3607 /* create event handler for bound change events */
3609 eventExecCardinality, NULL) );
3610 if( conshdlrdata->eventhdlr == NULL )
3611 {
3612 SCIPerrorMessage("event handler for cardinality constraints not found.\n");
3613 return SCIP_PLUGINNOTFOUND;
3614 }
3615
3616 /* include constraint handler */
3619 consEnfolpCardinality, consEnfopsCardinality, consCheckCardinality, consLockCardinality, conshdlrdata) );
3620 assert(conshdlr != NULL);
3621
3622 /* set non-fundamental callbacks via specific setter functions */
3623 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyCardinality, consCopyCardinality) );
3624 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteCardinality) );
3625 SCIP_CALL( SCIPsetConshdlrExitsol(scip, conshdlr, consExitsolCardinality) );
3626 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeCardinality) );
3627 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsCardinality) );
3628 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsCardinality) );
3629 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpCardinality) );
3630 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseCardinality) );
3632 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintCardinality) );
3633 SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropCardinality, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
3635 /*SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropCardinality) ); @todo: implement repropagation */
3636 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpCardinality, consSepasolCardinality, CONSHDLR_SEPAFREQ,
3638 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransCardinality) );
3639 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxCardinality) );
3640 SCIP_CALL( SCIPsetConshdlrGetPermsymGraph(scip, conshdlr, consGetPermsymGraphCardinality) );
3641 SCIP_CALL( SCIPsetConshdlrGetSignedPermsymGraph(scip, conshdlr, consGetSignedPermsymGraphCardinality) );
3642
3643 /* add cardinality constraint handler parameters */
3644 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/branchbalanced",
3645 "whether to use balanced instead of unbalanced branching",
3646 &conshdlrdata->branchbalanced, TRUE, DEFAULT_BRANCHBALANCED, NULL, NULL) );
3647
3648 SCIP_CALL( SCIPaddIntParam(scip, "constraints/" CONSHDLR_NAME "/balanceddepth",
3649 "maximum depth for using balanced branching (-1: no limit)",
3650 &conshdlrdata->balanceddepth, TRUE, DEFAULT_BALANCEDDEPTH, -1, INT_MAX, NULL, NULL) );
3651
3652 SCIP_CALL( SCIPaddRealParam(scip, "constraints/" CONSHDLR_NAME "/balancedcutoff",
3653 "determines that balanced branching is only used if the branching cut off value "
3654 "w.r.t. the current LP solution is greater than a given value",
3655 &conshdlrdata->balancedcutoff, TRUE, DEFAULT_BALANCEDCUTOFF, 0.01, SCIP_REAL_MAX, NULL, NULL) );
3656
3657 return SCIP_OKAY;
3658}
3659
3660/** creates and captures a cardinality constraint
3661 *
3662 * We set the constraint to not be modifable. If the weights are non
3663 * NULL, the variables are ordered according to these weights (in
3664 * ascending order).
3665 *
3666 * @note the constraint gets captured, hence at one point you have to release it using the method \ref SCIPreleaseCons()
3667 */
3669 SCIP* scip, /**< SCIP data structure */
3670 SCIP_CONS** cons, /**< pointer to hold the created constraint */
3671 const char* name, /**< name of constraint */
3672 int nvars, /**< number of variables in the constraint */
3673 SCIP_VAR** vars, /**< array with variables of constraint entries */
3674 int cardval, /**< number of variables allowed to be nonzero */
3675 SCIP_VAR** indvars, /**< indicator variables indicating which variables may be treated as nonzero
3676 * in cardinality constraint, or NULL if new indicator variables should be
3677 * introduced automatically */
3678 SCIP_Real* weights, /**< weights determining the variable order, or NULL if variables should be
3679 * ordered in the same way they were added to the constraint */
3680 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
3681 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
3682 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
3683 * Usually set to TRUE. */
3684 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
3685 * TRUE for model constraints, FALSE for additional, redundant constraints. */
3686 SCIP_Bool check, /**< should the constraint be checked for feasibility?
3687 * TRUE for model constraints, FALSE for additional, redundant constraints. */
3688 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
3689 * Usually set to TRUE. */
3690 SCIP_Bool local, /**< is constraint only valid locally?
3691 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
3692 SCIP_Bool dynamic, /**< is constraint subject to aging?
3693 * Usually set to FALSE. Set to TRUE for own cuts which
3694 * are separated as constraints. */
3695 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
3696 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
3697 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
3698 * if it may be moved to a more global node?
3699 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
3700 )
3701{
3702 SCIP_CONSHDLRDATA* conshdlrdata;
3703 SCIP_CONSHDLR* conshdlr;
3704 SCIP_CONSDATA* consdata;
3705 SCIP_Bool modifiable;
3706 SCIP_Bool transformed;
3707 int v;
3708
3709 modifiable = FALSE;
3710
3711#ifndef NDEBUG
3712 /* Check that the weights are sensible (not nan or inf); although not strictly needed, such values are likely a mistake. */
3713 if ( nvars > 0 && weights != NULL )
3714 {
3715 for (v = 0; v < nvars; ++v)
3716 assert( SCIPisFinite(weights[v]) );
3717 }
3718#endif
3719
3720 /* find the cardinality constraint handler */
3721 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
3722 if( conshdlr == NULL )
3723 {
3724 SCIPerrorMessage("<%s> constraint handler not found\n", CONSHDLR_NAME);
3725 return SCIP_PLUGINNOTFOUND;
3726 }
3727
3728 /* check whether indicator variables are binary */
3729 if( indvars != NULL )
3730 {
3731 for( v = 0; v < nvars; ++v )
3732 {
3733 if( !SCIPvarIsBinary(indvars[v]) )
3734 {
3735 SCIPerrorMessage("indicator <%s> is not binary\n", SCIPvarGetName(indvars[v]));
3736 return SCIP_INVALIDDATA;
3737 }
3738 }
3739 }
3740
3741 /* get constraint handler data */
3742 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3743 assert(conshdlrdata != NULL);
3744
3745 /* are we in the transformed problem? */
3746 transformed = SCIPgetStage(scip) >= SCIP_STAGE_TRANSFORMED;
3747
3748 /* create constraint data */
3749 SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) );
3750 consdata->cons = NULL;
3751 consdata->vars = NULL;
3752 consdata->indvars = NULL;
3753 consdata->eventdatas = NULL;
3754 consdata->nvars = nvars;
3755 consdata->cardval = cardval;
3756 consdata->maxvars = nvars;
3757 consdata->rowub = NULL;
3758 consdata->rowlb = NULL;
3759 consdata->eventdatascurrent = NULL;
3760 consdata->eventvarscurrent = NULL;
3761 consdata->neventdatascurrent = 0;
3762 consdata->ntreatnonzeros = transformed ? 0 : -1;
3763 consdata->weights = NULL;
3764
3765 if( nvars > 0 )
3766 {
3767 /* duplicate memory for implied variables */
3768 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->vars, vars, nvars) );
3769
3770 /* create indicator variables if not present */
3771 if( indvars != NULL )
3772 {
3773 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->indvars, indvars, nvars) );
3774 }
3775 else
3776 {
3777 if( conshdlrdata->varhash == NULL )
3778 {
3779 /* set up hash map */
3780 SCIP_CALL( SCIPhashmapCreate(&conshdlrdata->varhash, SCIPblkmem(scip), SCIPgetNTotalVars(scip)) );
3781 }
3782
3783 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->indvars, nvars) );
3784 for( v = 0; v < nvars; ++v )
3785 {
3786 SCIP_VAR* implvar;
3787
3788 implvar = vars[v];
3789 assert(implvar != NULL);
3790
3791 /* check whether an indicator variable already exists for implied variable */
3792 if( SCIPhashmapExists(conshdlrdata->varhash, implvar) )
3793 {
3794 assert((SCIP_VAR*) SCIPhashmapGetImage(conshdlrdata->varhash, implvar) != NULL);
3795 consdata->indvars[v] = (SCIP_VAR*) SCIPhashmapGetImage(conshdlrdata->varhash, implvar);
3796 }
3797 else
3798 {
3799 /* if implied variable is binary, then it is not necessary to create an indicator variable */
3800 if( SCIPvarIsBinary(implvar) )
3801 consdata->indvars[v] = implvar;
3802 else
3803 {
3804 char varname[SCIP_MAXSTRLEN];
3805 SCIP_VAR* var;
3806
3807 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "ind_%s", SCIPvarGetName(vars[v]));
3808 SCIP_CALL( SCIPcreateVar(scip, &var, varname, 0.0, 1.0, 0.0, SCIP_VARTYPE_BINARY, FALSE, FALSE,
3809 NULL, NULL, NULL, NULL, NULL) );
3811 consdata->indvars[v] = var;
3813 }
3814
3815 /* insert implied variable to hash map */
3816 SCIP_CALL( SCIPhashmapInsert(conshdlrdata->varhash, implvar, (void*) consdata->indvars[v]) );/*lint !e571*/
3817 assert(consdata->indvars[v] == (SCIP_VAR*) SCIPhashmapGetImage(conshdlrdata->varhash, implvar));
3818 assert(SCIPhashmapExists(conshdlrdata->varhash, implvar));
3819 }
3820 }
3821 }
3822
3823 /* allocate block memory */
3824 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eventdatascurrent, 4*nvars) );/*lint !e647*/
3825 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eventvarscurrent, 4*nvars) );/*lint !e647*/
3826 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->eventdatas, nvars) );
3827
3828 /* check weights */
3829 if( weights != NULL )
3830 {
3831 /* store weights */
3832 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->weights, weights, nvars) );
3833
3834 /* sort variables - ascending order */
3835 SCIPsortRealPtrPtr(consdata->weights, (void**)consdata->vars, (void**)consdata->indvars, nvars);
3836 }
3837 }
3838 else
3839 {
3840 assert(weights == NULL);
3841 }
3842
3843 /* create cardinality constraint */
3844 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
3845 local, modifiable, dynamic, removable, stickingatnode) );
3846
3847 consdata->cons = *cons;
3848 assert(consdata->cons != NULL);
3849
3850 /* replace original variables by transformed variables in transformed constraint, add locks, and catch events */
3851 for( v = nvars - 1; v >= 0; --v )
3852 {
3853 /* always use transformed variables in transformed constraints */
3854 if( transformed )
3855 {
3856 SCIP_CALL( SCIPgetTransformedVar(scip, consdata->vars[v], &(consdata->vars[v])) );
3857 SCIP_CALL( SCIPgetTransformedVar(scip, consdata->indvars[v], &(consdata->indvars[v])) );
3858 }
3859 assert(consdata->vars[v] != NULL);
3860 assert(consdata->indvars[v] != NULL);
3861 assert(transformed == SCIPvarIsTransformed(consdata->vars[v]));
3862 assert(transformed == SCIPvarIsTransformed(consdata->indvars[v]));
3863
3864 /* handle the new variable */
3865 SCIP_CALL( handleNewVariableCardinality(scip, *cons, consdata, conshdlrdata, consdata->vars[v],
3866 consdata->indvars[v], v, transformed, &consdata->eventdatas[v]) );
3867 assert(! transformed || consdata->eventdatas[v] != NULL);
3868 }
3869
3870 return SCIP_OKAY;
3871}
3872
3873/** creates and captures a cardinality constraint with all constraint flags set to their default values.
3874 *
3875 * @warning Do NOT set the constraint to be modifiable manually, because this might lead
3876 * to wrong results as the variable array will not be re-sorted
3877 *
3878 * @note the constraint gets captured, hence at one point you have to release it using the method \ref SCIPreleaseCons()
3879 */
3881 SCIP* scip, /**< SCIP data structure */
3882 SCIP_CONS** cons, /**< pointer to hold the created constraint */
3883 const char* name, /**< name of constraint */
3884 int nvars, /**< number of variables in the constraint */
3885 SCIP_VAR** vars, /**< array with variables of constraint entries */
3886 int cardval, /**< number of variables allowed to be nonzero */
3887 SCIP_VAR** indvars, /**< indicator variables indicating which variables may be treated as nonzero
3888 * in cardinality constraint, or NULL if new indicator variables should be
3889 * introduced automatically */
3890 SCIP_Real* weights /**< weights determining the variable order, or NULL if variables should be
3891 * ordered in the same way they were added to the constraint */
3892 )
3893{
3894 SCIP_CALL( SCIPcreateConsCardinality(scip, cons, name, nvars, vars, cardval, indvars, weights, TRUE, TRUE, TRUE, TRUE,
3895 TRUE, FALSE, FALSE, FALSE, FALSE) );
3896
3897 return SCIP_OKAY;
3898}
3899
3900/** changes cardinality value of cardinality constraint (i.e., right hand side of cardinality constraint) */
3902 SCIP* scip, /**< SCIP data structure */
3903 SCIP_CONS* cons, /**< pointer to hold the created constraint */
3904 int cardval /**< number of variables allowed to be nonzero */
3905 )
3906{
3907 SCIP_CONSDATA* consdata;
3908
3909 assert(scip != NULL);
3910 assert(cons != NULL);
3911
3912 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
3913 {
3914 SCIPerrorMessage("constraint is not a cardinality constraint.\n");
3915 return SCIP_INVALIDDATA;
3916 }
3917
3918 consdata = SCIPconsGetData(cons);
3919 assert(consdata != NULL);
3920
3921 SCIPdebugMsg(scip, "modify right hand side of cardinality constraint from <%i> to <%i>\n", consdata->cardval, cardval);
3922
3923 /* create constraint data */
3924 consdata->cardval = cardval;
3925
3926 return SCIP_OKAY;
3927}
3928
3929/** adds variable to cardinality constraint, the position is determined by the given weight */
3931 SCIP* scip, /**< SCIP data structure */
3932 SCIP_CONS* cons, /**< constraint */
3933 SCIP_VAR* var, /**< variable to add to the constraint */
3934 SCIP_VAR* indvar, /**< indicator variable indicating whether variable may be treated as nonzero
3935 * in cardinality constraint (or NULL if this variable should be created
3936 * automatically) */
3937 SCIP_Real weight /**< weight determining position of variable */
3938 )
3939{
3940 SCIP_CONSHDLRDATA* conshdlrdata;
3941 SCIP_CONSHDLR* conshdlr;
3942
3943 assert(scip != NULL);
3944 assert(var != NULL);
3945 assert(cons != NULL);
3946
3947 SCIPdebugMsg(scip, "adding variable <%s> to constraint <%s> with weight %g\n", SCIPvarGetName(var),
3948 SCIPconsGetName(cons), weight);
3949
3950 conshdlr = SCIPconsGetHdlr(cons);
3951 assert(conshdlr != NULL);
3952 if( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
3953 {
3954 SCIPerrorMessage("constraint is not a cardinality constraint.\n");
3955 return SCIP_INVALIDDATA;
3956 }
3957
3958 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3959 assert(conshdlrdata != NULL);
3960
3961 SCIP_CALL( addVarCardinality(scip, cons, conshdlrdata, var, indvar, weight) );
3962
3963 return SCIP_OKAY;
3964}
3965
3966/** appends variable to cardinality constraint */
3968 SCIP* scip, /**< SCIP data structure */
3969 SCIP_CONS* cons, /**< constraint */
3970 SCIP_VAR* var, /**< variable to add to the constraint */
3971 SCIP_VAR* indvar /**< indicator variable indicating whether variable may be treated as nonzero
3972 * in cardinality constraint (or NULL if this variable should be created
3973 * automatically) */
3974 )
3975{
3976 SCIP_CONSHDLRDATA* conshdlrdata;
3977 SCIP_CONSHDLR* conshdlr;
3978
3979 assert(scip != NULL);
3980 assert(var != NULL);
3981 assert(cons != NULL);
3982
3983 SCIPdebugMsg(scip, "appending variable <%s> to constraint <%s>\n", SCIPvarGetName(var), SCIPconsGetName(cons));
3984
3985 conshdlr = SCIPconsGetHdlr(cons);
3986 assert(conshdlr != NULL);
3987 if( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) != 0 )
3988 {
3989 SCIPerrorMessage("constraint is not a cardinality constraint.\n");
3990 return SCIP_INVALIDDATA;
3991 }
3992
3993 conshdlrdata = SCIPconshdlrGetData(conshdlr);
3994 assert(conshdlrdata != NULL);
3995
3996 SCIP_CALL( appendVarCardinality(scip, cons, conshdlrdata, var, indvar) );
3997
3998 return SCIP_OKAY;
3999}
4000
4001/** gets number of variables in cardinality constraint */
4003 SCIP* scip, /**< SCIP data structure */
4004 SCIP_CONS* cons /**< constraint */
4005 )
4006{
4007 SCIP_CONSDATA* consdata;
4008
4009 assert(scip != NULL);
4010 assert(cons != NULL);
4011
4012 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
4013 {
4014 SCIPerrorMessage("constraint is not a cardinality constraint.\n");
4015 SCIPABORT();
4016 return -1; /*lint !e527*/
4017 }
4018
4019 consdata = SCIPconsGetData(cons);
4020 assert(consdata != NULL);
4021
4022 return consdata->nvars;
4023}
4024
4025/** gets array of variables in cardinality constraint */
4027 SCIP* scip, /**< SCIP data structure */
4028 SCIP_CONS* cons /**< constraint data */
4029 )
4030{
4031 SCIP_CONSDATA* consdata;
4032
4033 assert(scip != NULL);
4034 assert(cons != NULL);
4035
4036 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
4037 {
4038 SCIPerrorMessage("constraint is not a cardinality constraint.\n");
4039 SCIPABORT();
4040 return NULL; /*lint !e527*/
4041 }
4042
4043 consdata = SCIPconsGetData(cons);
4044 assert(consdata != NULL);
4045
4046 return consdata->vars;
4047}
4048
4049/** gets cardinality value of cardinality constraint (i.e., right hand side of cardinality constraint) */
4051 SCIP* scip, /**< SCIP data structure */
4052 SCIP_CONS* cons /**< constraint data */
4053 )
4054{
4055 SCIP_CONSDATA* consdata;
4056
4057 assert(scip != NULL);
4058 assert(cons != NULL);
4059
4060 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
4061 {
4062 SCIPerrorMessage("constraint is not a cardinality constraint.\n");
4063 return -1; /*lint !e527*/
4064 }
4065
4066 consdata = SCIPconsGetData(cons);
4067 assert(consdata != NULL);
4068
4069 return consdata->cardval;
4070}
4071
4072/** gets array of weights in cardinality constraint (or NULL if not existent) */
4074 SCIP* scip, /**< SCIP data structure */
4075 SCIP_CONS* cons /**< constraint data */
4076 )
4077{
4078 SCIP_CONSDATA* consdata;
4079
4080 assert(scip != NULL);
4081 assert(cons != NULL);
4082
4083 if( strcmp(SCIPconshdlrGetName(SCIPconsGetHdlr(cons)), CONSHDLR_NAME) != 0 )
4084 {
4085 SCIPerrorMessage("constraint is not a cardinality constraint.\n");
4086 SCIPABORT();
4087 return NULL; /*lint !e527*/
4088 }
4089
4090 consdata = SCIPconsGetData(cons);
4091 assert(consdata != NULL);
4092
4093 return consdata->weights;
4094}
#define EVENTHDLR_NAME
SCIP_VAR * w
#define EVENTHDLR_DESC
#define CONSHDLR_NEEDSCONS
Definition cons_and.c:97
#define CONSHDLR_SEPAFREQ
Definition cons_and.c:90
#define CONSHDLR_CHECKPRIORITY
Definition cons_and.c:89
#define CONSHDLR_DESC
Definition cons_and.c:86
#define CONSHDLR_PROP_TIMING
Definition cons_and.c:100
#define CONSHDLR_MAXPREROUNDS
Definition cons_and.c:94
#define CONSHDLR_SEPAPRIORITY
Definition cons_and.c:87
#define CONSHDLR_PROPFREQ
Definition cons_and.c:91
#define CONSHDLR_PRESOLTIMING
Definition cons_and.c:99
#define CONSHDLR_EAGERFREQ
Definition cons_and.c:92
#define CONSHDLR_ENFOPRIORITY
Definition cons_and.c:88
#define CONSHDLR_DELAYSEPA
Definition cons_and.c:95
#define CONSHDLR_NAME
Definition cons_and.c:85
#define CONSHDLR_DELAYPROP
Definition cons_and.c:96
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:255
#define SCIP_MAXSTRLEN
Definition def.h:276
#define SCIP_Longint
Definition def.h:148
#define SCIP_REAL_MAX
Definition def.h:165
#define SCIP_Bool
Definition def.h:98
#define MIN(x, y)
Definition def.h:231
#define SCIP_Real
Definition def.h:163
#define TRUE
Definition def.h:100
#define FALSE
Definition def.h:101
#define MAX(x, y)
Definition def.h:227
#define SCIP_LONGINT_FORMAT
Definition def.h:155
#define SCIPABORT()
Definition def.h:334
#define REALABS(x)
Definition def.h:189
#define SCIP_CALL(x)
Definition def.h:362
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:884
void SCIPupdateSolConsViolation(SCIP *scip, SCIP_SOL *sol, SCIP_Real absviol, SCIP_Real relviol)
Definition scip_sol.c:453
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:4019
SCIP_RETCODE SCIPsetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var, SCIP_Real val)
Definition scip_sol.c:1571
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition scip_sol.c:1765
SCIP_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:23844
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition var.c:23479
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:23387
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition var.c:24269
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition var.c:23431
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:24143
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:23268
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:23807
int SCIPvarGetMultaggrNVars(SCIP_VAR *var)
Definition var.c:23795
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:24235
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:24121
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:23819
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