Scippy

SCIP

Solving Constraint Integer Programs

cons_orbitope_full.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file cons_orbitope_full.c
26 * @ingroup DEFPLUGINS_CONS
27 * @brief constraint handler for full orbitope constraints w.r.t. the full symmetric group
28 * @author Timo Berthold
29 * @author Marc Pfetsch
30 * @author Christopher Hojny
31 *
32 * The type of constraints of this constraint handler is described in cons_orbitope_full.h.
33 * When creating the constraint, users can decide whether it is a constraint defining the model
34 * or "just" use to handle symmetries. In the latter case, symmetry reductions are only performed
35 * by the constraint handler if strong dual reductions are permitted.
36 *
37 * The details of the method implemented here are described in the following papers.
38 *
39 * Orbitopal fixing for the full (sub-)orbitope and application to the Unit Commitment Problem@n
40 * Pascale Bendotti, Pierre Fouilhoux, and Cecile Rottner,@n
41 * Optimization Online: http://www.optimization-online.org/DB_HTML/2017/10/6301.html
42 *
43 * Two linear time propagation algorithms for full orbitopes are described in this paper, a static
44 * version and a dynamic one. While the static version uses a fixed variable order, the dynamic
45 * version determines the variable order during the solving process via branching descisions.
46 * We only implemented the static version, because constraints should define the model and should
47 * not be changed during the solving process. Instead, a dynamic version of orbitopal fixing has
48 * been implemented as a routine in prop_symmetry.c.
49 *
50 * Polytopes associated with symmetry handling@n
51 * Christopher Hojny and Marc E. Pfetsch,@n
52 * Math. Program. (2018)
53 *
54 * In this paper, a linear time separation algorithm for orbisacks (full orbitopes with two columnes)
55 * is described. We use this algorithm for every pair of adjacent columns within the orbitope.
56 */
57
58/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
59
61#include "scip/cons_orbisack.h"
63#include "scip/cons_setppc.h"
64#include "scip/pub_cons.h"
65#include "scip/pub_message.h"
66#include "scip/pub_var.h"
67#include "scip/scip.h"
68#include "scip/scip_branch.h"
69#include "scip/scip_conflict.h"
70#include "scip/scip_cons.h"
71#include "scip/scip_copy.h"
72#include "scip/scip_cut.h"
73#include "scip/scip_general.h"
74#include "scip/scip_lp.h"
75#include "scip/scip_mem.h"
76#include "scip/scip_message.h"
77#include "scip/scip_numerics.h"
78#include "scip/scip_param.h"
79#include "scip/scip_prob.h"
80#include "scip/scip_probing.h"
81#include "scip/scip_sol.h"
82#include "scip/scip_var.h"
83#include "scip/symmetry.h"
85
86/* constraint handler properties */
87#define CONSHDLR_NAME "orbitope_full"
88#define CONSHDLR_DESC "symmetry breaking constraint handler relying on full orbitopes"
89#define CONSHDLR_SEPAPRIORITY +40100 /**< priority of the constraint handler for separation */
90#define CONSHDLR_ENFOPRIORITY -1005200 /**< priority of the constraint handler for constraint enforcing */
91#define CONSHDLR_CHECKPRIORITY -1005200 /**< priority of the constraint handler for checking feasibility */
92#define CONSHDLR_SEPAFREQ -1 /**< frequency for separating cuts; zero means to separate only in the root node */
93#define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
94#define CONSHDLR_EAGERFREQ -1 /**< frequency for using all instead of only the useful constraints in separation,
95 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
96#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
97#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
98#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
99#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
100
101#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler */
102#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_MEDIUM /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
103
104#define DEFAULT_FORCECONSCOPY FALSE /**< whether orbitope constraints should be forced to be copied to sub SCIPs */
105
106/*
107 * Data structures
108 */
109
110/** constraint handler data */
111struct SCIP_ConshdlrData
112{
113 SCIP_Bool forceconscopy; /**< whether orbitope constraints should be forced to be copied to sub SCIPs */
114};
115
116/** constraint data for orbitope constraints */
117struct SCIP_ConsData
118{
119 SCIP_VAR*** vars; /**< matrix of variables on which the symmetry acts */
120 int nrows; /**< number of rows */
121 int ncols; /**< number of columns*/
122 SCIP_Bool resolveprop; /**< should propagation be resolved? */
123 SCIP_Bool ismodelcons; /**< whether the orbitope is a model constraint */
124};
125
126
127/*
128 * Local methods
129 */
130
131/** frees an orbitope constraint data */
132static
134 SCIP* scip, /**< SCIP data structure */
135 SCIP_CONSDATA** consdata /**< pointer to orbitope constraint data */
136 )
137{
138 int i;
139 int j;
140 int nrows;
141 int ncols;
142
143 assert( consdata != NULL );
144 assert( *consdata != NULL );
145
146 nrows = (*consdata)->nrows;
147 ncols = (*consdata)->ncols;
148 for (i = 0; i < nrows; ++i)
149 {
150 /* release variables in vars array */
151 for (j = 0; j < ncols; ++j)
152 {
153 assert( (*consdata)->vars[i] != NULL );
154 SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->vars[i][j]) );
155 }
156
157 SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->vars[i]), ncols); /*lint !e866*/
158 }
159
160 SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->vars), nrows);
161
162 SCIPfreeBlockMemory(scip, consdata);
163
164 return SCIP_OKAY;
165}
166
167
168/** creates orbitope constraint data */
169static
171 SCIP* scip, /**< SCIP data structure */
172 SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
173 SCIP_VAR*** vars, /**< variables array, must have size nrows x ncols*/
174 int nrows, /**< number of rows */
175 int ncols, /**< number of columns */
176 SCIP_Bool resolveprop, /**< should propagation be resolved? */
177 SCIP_Bool ismodelcons /**< whether the orbitope is a model constraint */
178 )
179{
180 int i;
181 int j;
182
183 assert(consdata != NULL);
184
185 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
186
187 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->vars, nrows) );
188
189 for (i = 0; i < nrows; ++i)
190 {
191 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars[i], vars[i], ncols) ); /*lint !e866*/
192 }
193
194 (*consdata)->nrows = nrows;
195 (*consdata)->ncols = ncols;
196 (*consdata)->resolveprop = resolveprop;
197 (*consdata)->ismodelcons = ismodelcons;
198
199 /* get transformed variables, if we are in the transformed problem */
200 if ( SCIPisTransformed(scip) )
201 {
202 for (i = 0; i < nrows; ++i)
203 {
204 /* make sure that no variable gets multiaggregated (cannot be handled by cons_orbitope, since one cannot easily
205 * eliminate single variables from an orbitope constraint).
206 */
207 for (j = 0; j < ncols; ++j)
208 {
209 SCIP_CALL( SCIPgetTransformedVar(scip, (*consdata)->vars[i][j], &(*consdata)->vars[i][j]) );
210 SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->vars[i][j]) );
211 }
212 }
213 }
214
215 /* capture vars contained in vars array */
216 for (i = 0; i < nrows; ++i)
217 {
218 for (j = 0; j < ncols; ++j)
219 {
220 assert( (*consdata)->vars[i][j] != NULL );
221 SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[i][j]) );
222 }
223 }
224
225 return SCIP_OKAY;
226}
227
228
229/** Compute lexicographically minimal face of the hypercube w.r.t. some coordinate fixing */
230static
232 SCIP_VAR*** vars, /**< variable matrix */
233 int** lexminfixes, /**< fixings characterzing lex-min face */
234 int* minfixedrowlexmin, /**< index of minimum fixed row for each column or NULL (if in prop) */
235 SCIP_Bool* infeasible, /**< pointer to store whether infeasibility has been detected or NULL (if in resprop) */
236 int nrows, /**< number of rows in vars */
237 int ncols, /**< number of columns in vars */
238 SCIP_Bool resprop /**< whether we are in resprop (TRUE) or prop (FALSE) */
239 )
240{
241 int i;
242 int j;
243
244 *infeasible = FALSE;
245
246 assert( vars != NULL );
247 assert( lexminfixes != NULL );
248 assert( !resprop || minfixedrowlexmin != NULL );
249 assert( nrows > 0 );
250 assert( ncols > 0 );
251 assert( infeasible != NULL );
252
253 /* iterate over columns in reverse order and find the lexicographically minimal face
254 * of the hypercube containing lexminfixes
255 */
256 for (j = ncols - 2; j >= 0; --j)
257 {
258 int maxdiscriminating;
259 int minfixed = -1;
260
261 maxdiscriminating = nrows;
262
263 /* fix free entries in column j to the corresponding value in column j + 1 and collect some information */
264 for (i = 0; i < nrows; ++i)
265 {
266 /* is row i j-discriminating? */
267 if ( minfixed == -1 && lexminfixes[i][j] != 0 && lexminfixes[i][j + 1] != 1 )
268 {
269 assert( lexminfixes[i][j + 1] == 0 );
270
271 maxdiscriminating = i;
272 }
273
274 /* is row i j-fixed? */
275 if ( minfixed == -1 && lexminfixes[i][j] != lexminfixes[i][j + 1] && lexminfixes[i][j] != 2 )
276 {
277 assert( lexminfixes[i][j + 1] != 2 );
278
279 minfixed = i;
280
281 /* detect infeasibility */
282 if ( maxdiscriminating > minfixed )
283 {
284 *infeasible = TRUE;
285
286 return SCIP_OKAY;
287 }
288 }
289 }
290
291 /* ensure that column j is lexicographically not smaller than column j + 1 */
292 for (i = 0; i < nrows; ++i)
293 {
294 if ( lexminfixes[i][j] == 2 )
295 {
296 if ( i < maxdiscriminating || minfixed == -1 )
297 lexminfixes[i][j] = lexminfixes[i][j + 1];
298 else if ( i == maxdiscriminating )
299 lexminfixes[i][j] = 1;
300 else
301 lexminfixes[i][j] = 0;
302 }
303 }
304
305 if ( resprop )
306 {
307 assert( minfixedrowlexmin != NULL );
308
309 /* store minimum fixed row */
310 if ( minfixed == -1 )
311 minfixedrowlexmin[j] = nrows - 1;
312 else
313 minfixedrowlexmin[j] = minfixed;
314
315 /* columns 1, ..., n-2 are contained in two columns (take the minimum) and
316 * the minimum fixed row of column n-1 is determined by column n-2 */
317 if ( minfixedrowlexmin[j + 1] < minfixedrowlexmin[j] )
318 minfixedrowlexmin[j + 1] = minfixedrowlexmin[j];
319 }
320 }
321
322 return SCIP_OKAY;
323}
324
325
326/** Compute lexicographically maximal face of the hypercube w.r.t. some coordinate fixing */
327static
329 SCIP_VAR*** vars, /**< variable matrix */
330 int** lexmaxfixes, /**< fixings characterzing lex-max face */
331 int* minfixedrowlexmax, /**< index of minimum fixed row for each column or NULL (if in prop) */
332 SCIP_Bool* infeasible, /**< pointer to store whether infeasibility has been detected or NULL (if in resprop) */
333 int nrows, /**< number of rows in vars */
334 int ncols, /**< number of columns in vars */
335 SCIP_Bool resprop /**< whether we are in resprop (TRUE) or prop (FALSE) */
336 )
337{
338 int i;
339 int j;
340
341 *infeasible = FALSE;
342
343 assert( vars != NULL );
344 assert( lexmaxfixes != NULL );
345 assert( !resprop || minfixedrowlexmax != NULL );
346 assert( nrows > 0 );
347 assert( ncols > 0 );
348 assert( infeasible != NULL );
349
350 for (j = 1; j < ncols; ++j)
351 {
352 int maxdiscriminating;
353 int minfixed = -1;
354
355 maxdiscriminating = nrows;
356
357 /* fix free entries in column j to the corresponding value in column j - 1 and collect some information */
358 for (i = 0; i < nrows; ++i)
359 {
360 /* is row i j-discriminating? */
361 if ( minfixed == -1 && lexmaxfixes[i][j - 1] != 0 && lexmaxfixes[i][j] != 1 )
362 {
363 assert( lexmaxfixes[i][j - 1] == 1 );
364
365 maxdiscriminating = i;
366 }
367
368 /* is row i j-fixed? */
369 if ( minfixed == -1 && lexmaxfixes[i][j - 1] != lexmaxfixes[i][j] && lexmaxfixes[i][j] != 2 )
370 {
371 assert( lexmaxfixes[i][j - 1] != 2 );
372
373 minfixed = i;
374
375 /* detect infeasibility */
376 if ( maxdiscriminating > minfixed )
377 {
378 *infeasible = TRUE;
379
380 return SCIP_OKAY;
381 }
382 }
383 }
384
385 /* ensure that column j is lexicographically not greater than column j - 1 */
386 for (i = 0; i < nrows; ++i)
387 {
388 if ( lexmaxfixes[i][j] == 2 )
389 {
390 if ( i < maxdiscriminating || minfixed == -1 )
391 lexmaxfixes[i][j] = lexmaxfixes[i][j - 1];
392 else if ( i == maxdiscriminating )
393 lexmaxfixes[i][j] = 0;
394 else
395 lexmaxfixes[i][j] = 1;
396 }
397 }
398
399 if ( resprop )
400 {
401 assert( minfixedrowlexmax != NULL );
402
403 /* store minimum fixed row */
404 if ( minfixed == -1 )
405 minfixedrowlexmax[j] = nrows - 1;
406 else
407 minfixedrowlexmax[j] = minfixed;
408
409 /* columns 1, ..., n-2 are contained in two columns (take the minimum) and
410 * the minimum fixed row of column 0 is determined by column 1 */
411 if ( minfixedrowlexmax[j - 1] < minfixedrowlexmax[j] )
412 minfixedrowlexmax[j - 1] = minfixedrowlexmax[j];
413 }
414 }
415
416 return SCIP_OKAY;
417}
418
419
420/** propagation method for a single full orbitope constraint */
421static
423 SCIP* scip, /**< SCIP data structure */
424 SCIP_CONS* cons, /**< constraint to be processed */
425 SCIP_Bool* infeasible, /**< pointer to store TRUE, if the node can be cut off */
426 int* nfixedvars /**< pointer to add up the number of found domain reductions */
427 )
428{
429 SCIP_CONSDATA* consdata;
430 SCIP_VAR*** vars;
431 int** lexminfixes;
432 int** lexmaxfixes;
433 int i;
434 int j;
435 int nrows;
436 int ncols;
437
438 assert( scip != NULL );
439 assert( cons != NULL );
440 assert( infeasible != NULL );
441 assert( nfixedvars != NULL );
442
443 consdata = SCIPconsGetData(cons);
444 assert( consdata != NULL );
445
446 *nfixedvars = 0;
447 *infeasible = FALSE;
448
449 /* if the constraint is not a model constraint, check whether symmetry reductions are permitted */
450 if ( !consdata->ismodelcons && !SCIPallowStrongDualReds(scip) )
451 return SCIP_OKAY;
452
453 assert( consdata->nrows > 0 );
454 assert( consdata->ncols > 0 );
455 assert( consdata->vars != NULL );
456
457 nrows = consdata->nrows;
458 ncols = consdata->ncols;
459 vars = consdata->vars;
460
461 /* Initialize lexicographically minimal matrix by fixed entries at the current node.
462 * Free entries in the last column are set to 0.
463 */
464 SCIP_CALL( SCIPallocBufferArray(scip, &lexminfixes, nrows) );
465 for (i = 0; i < nrows; ++i)
466 {
467 SCIP_CALL( SCIPallocBufferArray(scip, &lexminfixes[i], ncols) ); /*lint !e866*/
468 }
469
470 for (i = 0; i < nrows; ++i)
471 {
472 for (j = 0; j < ncols; ++j)
473 {
474 if ( SCIPvarGetLbLocal(vars[i][j]) > 0.5 )
475 lexminfixes[i][j] = 1;
476 else if ( SCIPvarGetUbLocal(vars[i][j]) < 0.5 || j == ncols - 1 )
477 lexminfixes[i][j] = 0;
478 else
479 lexminfixes[i][j] = 2;
480 }
481 }
482
483 /* find lexicographically minimal face of hypercube containing lexmin fixes */
484 SCIP_CALL( findLexMinFace(vars, lexminfixes, NULL, infeasible, nrows, ncols, FALSE) );
485
486 if ( *infeasible == TRUE )
487 goto FREELEXMIN;
488
489 /* Initialize lexicographically maximal matrix by fixed entries at the current node.
490 * Free entries in the first column are set to 1.
491 */
492 SCIP_CALL( SCIPallocBufferArray(scip, &lexmaxfixes, nrows) );
493 for (i = 0; i < nrows; ++i)
494 {
495 SCIP_CALL( SCIPallocBufferArray(scip, &lexmaxfixes[i], ncols) ); /*lint !e866*/
496 }
497
498 for (i = 0; i < nrows; ++i)
499 {
500 for (j = 0; j < ncols; ++j)
501 {
502 if ( SCIPvarGetUbLocal(vars[i][j]) < 0.5 )
503 lexmaxfixes[i][j] = 0;
504 else if ( SCIPvarGetLbLocal(vars[i][j]) > 0.5 || j == 0 )
505 lexmaxfixes[i][j] = 1;
506 else
507 lexmaxfixes[i][j] = 2;
508 }
509 }
510
511 /* find lexicographically maximal face of hypercube containing lexmax fixes */
512 SCIP_CALL( findLexMaxFace(vars, lexmaxfixes, NULL, infeasible, nrows, ncols, FALSE) );
513
514 if ( *infeasible )
515 goto FREELEXMAX;
516
517 /* Find for each column j the minimal row in which lexminfixes and lexmaxfixes differ. Fix all entries above this
518 * row to the corresponding value in lexminfixes (or lexmaxfixes).
519 */
520 for (j = 0; j < ncols; ++j)
521 {
522 for (i = 0; i < nrows; ++i)
523 {
524 if ( lexminfixes[i][j] != lexmaxfixes[i][j] )
525 break;
526
527 if ( SCIPvarGetLbLocal(vars[i][j]) < 0.5 && SCIPvarGetUbLocal(vars[i][j]) > 0.5 )
528 {
529 SCIP_Bool success;
530
531 SCIP_CALL( SCIPinferBinvarCons(scip, vars[i][j], (SCIP_Bool) lexminfixes[i][j],
532 cons, 0, infeasible, &success) );
533
534 if ( success )
535 *nfixedvars += 1;
536 }
537 }
538 }
539
540 FREELEXMAX:
541 for (i = nrows - 1; i >= 0; --i)
542 SCIPfreeBufferArray(scip, &lexmaxfixes[i]);
543 SCIPfreeBufferArray(scip, &lexmaxfixes);
544
545 FREELEXMIN:
546 for (i = nrows - 1; i >= 0; --i)
547 SCIPfreeBufferArray(scip, &lexminfixes[i]);
548 SCIPfreeBufferArray(scip, &lexminfixes);
549
550 return SCIP_OKAY;
551}
552
553
554/** Propagation conflict resolving method of propagator
555 *
556 * In this function we use that all variable reductions that can be found by the propagation algorithm
557 * are only due to the fixed variables that are in or above the minimum fixed row of each pair of adjacent
558 * columns of the lexmin and lexmax matrices.
559 *
560 * Since the storage of an integer is not enough to store the complete information about the fixing,
561 * we have to use the linear time algorithm for finding the lexmin and lexmax
562 * matrices and determine from this the minimum fixed rows.
563 */
564static
566 SCIP* scip, /**< SCIP data structure */
567 SCIP_CONSHDLR* conshdlr, /**< constraint handler of the corresponding constraint */
568 SCIP_CONS* cons, /**< constraint that inferred the bound change */
569 int inferinfo, /**< inference information */
570 SCIP_BDCHGIDX* bdchgidx, /**< bound change index (time stamp of bound change), or NULL for current time */
571 SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
572 )
573{ /*lint --e{715}*/
574 SCIP_CONSDATA* consdata;
575 SCIP_VAR*** vars;
576 int** lexminfixes;
577 int** lexmaxfixes;
578 int* minfixedrowlexmin;
579 int* minfixedrowlexmax;
580 int i;
581 int j;
582 int nrows;
583 int ncols;
584 SCIP_Bool terminate;
585
586 *result = SCIP_DIDNOTFIND;
587
588 assert( scip != NULL );
589 assert( conshdlr != NULL );
590 assert( cons != NULL );
591 assert( result != NULL );
592
593 consdata = SCIPconsGetData(cons);
594 assert( consdata != NULL );
595 assert( consdata->nrows > 0 );
596 assert( consdata->ncols > 0 );
597 assert( consdata->vars != NULL );
598
599 nrows = consdata->nrows;
600 ncols = consdata->ncols;
601 vars = consdata->vars;
602
603 assert( inferinfo <= consdata->nrows );
604
605 /* Initialize lexicographically minimal matrix by fixed entries at the current node.
606 * Free entries in the last column are set to 0.
607 */
608 SCIP_CALL( SCIPallocBufferArray(scip, &lexminfixes, nrows) );
609 for (i = 0; i < nrows; ++i)
610 {
611 SCIP_CALL( SCIPallocBufferArray(scip, &lexminfixes[i], ncols) ); /*lint !e866*/
612 }
613
614 /* store minimum fixed row for each column */
615 SCIP_CALL( SCIPallocBufferArray(scip, &minfixedrowlexmin, ncols) );
616 minfixedrowlexmin[ncols - 1] = -1;
617
618 for (i = 0; i < nrows; ++i)
619 {
620 for (j = 0; j < ncols; ++j)
621 {
622 if ( SCIPgetVarLbAtIndex(scip, vars[i][j], bdchgidx, FALSE) > 0.5 )
623 lexminfixes[i][j] = 1;
624 else if ( SCIPgetVarUbAtIndex(scip, vars[i][j], bdchgidx, FALSE) < 0.5 || j == ncols - 1 )
625 lexminfixes[i][j] = 0;
626 else
627 lexminfixes[i][j] = 2;
628 }
629 }
630
631 /* find lexicographically minimal face of hypercube containing lexmin fixes */
632 SCIP_CALL( findLexMinFace(vars, lexminfixes, minfixedrowlexmin, &terminate, nrows, ncols, TRUE) );
633
634 if ( terminate )
635 goto FREELEXMIN;
636
637 /* Initialize lexicographically maximal matrix by fixed entries at the current node.
638 * Free entries in the first column are set to 1.
639 */
640 SCIP_CALL( SCIPallocBufferArray(scip, &lexmaxfixes, nrows) );
641 for (i = 0; i < nrows; ++i)
642 {
643 SCIP_CALL( SCIPallocBufferArray(scip, &lexmaxfixes[i], ncols) ); /*lint !e866*/
644 }
645
646 /* store minimum fixed row for each column */
647 SCIP_CALL( SCIPallocBufferArray(scip, &minfixedrowlexmax, ncols) );
648 minfixedrowlexmax[0] = -1;
649
650 for (i = 0; i < nrows; ++i)
651 {
652 for (j = 0; j < ncols; ++j)
653 {
654 if ( SCIPgetVarUbAtIndex(scip, vars[i][j], bdchgidx, FALSE) < 0.5 )
655 lexmaxfixes[i][j] = 0;
656 else if ( SCIPgetVarLbAtIndex(scip, vars[i][j], bdchgidx, FALSE) > 0.5 || j == 0 )
657 lexmaxfixes[i][j] = 1;
658 else
659 lexmaxfixes[i][j] = 2;
660 }
661 }
662
663 /* find lexicographically maximal face of hypercube containing lexmax fixes */
664 SCIP_CALL( findLexMaxFace(vars, lexmaxfixes, minfixedrowlexmax, &terminate, nrows, ncols, TRUE) );
665
666 if ( terminate )
667 goto FREELEXMAX;
668
669 /* Find for each column j the minimal row in which lexminfixes and lexmaxfixes differ. Fix all entries above this
670 * row to the corresponding value in lexminfixes (or lexmaxfixes).
671 */
672 for (j = 0; j < ncols; ++j)
673 {
674 int ub = MAX(minfixedrowlexmin[j], minfixedrowlexmax[j]);
675
676 for (i = 0; i <= ub; ++i)
677 {
678 if ( SCIPgetVarLbAtIndex(scip, vars[i][j], bdchgidx, FALSE) > 0.5 ||
679 SCIPgetVarUbAtIndex(scip, vars[i][j], bdchgidx, FALSE) < 0.5 )
680 {
681 SCIP_CALL( SCIPaddConflictBinvar(scip, vars[i][j]) );
682 *result = SCIP_SUCCESS;
683 }
684 }
685 }
686
687 FREELEXMAX:
688 SCIPfreeBufferArray(scip, &minfixedrowlexmax);
689 for (i = nrows - 1; i >= 0; --i)
690 SCIPfreeBufferArray(scip, &lexmaxfixes[i]);
691 SCIPfreeBufferArray(scip, &lexmaxfixes);
692
693 FREELEXMIN:
694 SCIPfreeBufferArray(scip, &minfixedrowlexmin);
695 for (i = nrows - 1; i >= 0; --i)
696 SCIPfreeBufferArray(scip, &lexminfixes[i]);
697 SCIPfreeBufferArray(scip, &lexminfixes);
698
699 return SCIP_OKAY;
700}
701
702
703/** check full orbitope solution for feasibility */
704static
706 SCIP* scip, /**< SCIP data structure */
707 SCIP_CONS* cons, /**< constraint to process */
708 SCIP_SOL* sol, /**< solution to be checked */
709 SCIP_Bool printreason, /**< whether reason for infeasibility should be printed */
710 SCIP_Bool* feasible /**< memory address to store whether solution is feasible */
711 )
712{
713 SCIP_CONSDATA* consdata;
714 SCIP_VAR*** vars;
715 SCIP_VAR** vars1;
716 SCIP_VAR** vars2;
717 int nrows;
718 int ncols;
719 int j;
720 int i;
721
722 assert( scip != NULL );
723 assert( cons != NULL );
724 assert( feasible != NULL );
725
726 consdata = SCIPconsGetData(cons);
727
728 assert( consdata != NULL );
729 assert( consdata->vars != NULL );
730 assert( consdata->nrows > 0 );
731 assert( consdata->ncols > 0 );
732 assert( ! consdata->ismodelcons ); /* non-model constraints are never checked */
733
734 vars = consdata->vars;
735 nrows = consdata->nrows;
736 ncols = consdata->ncols;
737
738 SCIP_CALL( SCIPallocBufferArray(scip, &vars1, nrows) );
739 SCIP_CALL( SCIPallocBufferArray(scip, &vars2, nrows) );
740
741 /* iterate over adjacent columns of orbitope and check whether the first column in this
742 * column pair is lexicographically not smaller than the second column in the pair */
743 *feasible = TRUE;
744 for (j = 1; j < ncols && *feasible; ++j)
745 {
746 for (i = 0; i < nrows; ++i)
747 {
748 vars1[i] = vars[i][j - 1];
749 vars2[i] = vars[i][j];
750 }
751
752 SCIP_CALL( SCIPcheckSolutionOrbisack(scip, sol, vars1, vars2, nrows, printreason, feasible) );
753 }
754
755 SCIPfreeBufferArray(scip, &vars2);
756 SCIPfreeBufferArray(scip, &vars1);
757
758 return SCIP_OKAY;
759}
760
761
762/** separate orbisack cover inequalities */
763static
765 SCIP* scip, /**< SCIP data structure */
766 SCIP_CONS* cons, /**< constraint to process */
767 SCIP_SOL* sol, /**< solution to separate (NULL for the LP solution) */
768 int* ngen, /**< pointer to store number of generated cuts */
769 SCIP_Bool* infeasible /**< pointer to store whether infeasibility has been detected */
770 )
771{
772 SCIP_CONSDATA* consdata;
773 SCIP_VAR*** vars;
774 int nrows;
775 int ncols;
776 int i;
777 int j;
778 SCIP_Real rhs = 0.0;
779 SCIP_Real lhs = 0.0;
780 SCIP_Real* coeffs1;
781 SCIP_Real* coeffs2;
782
783 assert( scip != NULL );
784 assert( cons != NULL );
785 assert( ngen != NULL );
786 assert( infeasible != NULL );
787
788 *ngen = 0;
789 *infeasible = FALSE;
790
791 /* get basic data */
792 consdata = SCIPconsGetData(cons);
793 assert( consdata != NULL );
794
795 vars = consdata->vars;
796 nrows = consdata->nrows;
797 ncols = consdata->ncols;
798
799 /* allocate memory for cover inequalities */
800 SCIP_CALL( SCIPallocBufferArray(scip, &coeffs1, nrows) );
801 SCIP_CALL( SCIPallocBufferArray(scip, &coeffs2, nrows) );
802
803 /* separate orbisack cover inequalities for adjacent columns */
804 for (j = 0; j < ncols - 1 && ! *infeasible; ++j)
805 {
806 SCIP_Real rowval;
807
808 for (i = 0; i < nrows; ++i)
809 {
810 rowval = SCIPgetSolVal(scip, sol, vars[i][j + 1]) - SCIPgetSolVal(scip, sol, vars[i][j]);
811
812 /* check whether cover inequality is violated */
813 if ( SCIPisEfficacious(scip, rowval + lhs - rhs) )
814 {
815 SCIP_ROW* row;
816 int k;
817
818 /* set coefficients for current inequality */
819 coeffs1[i] = -1.0;
820 coeffs2[i] = 1.0;
821
822 /* add violated orbisack cover inequality */
823 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, "orbisackcover", -SCIPinfinity(scip), rhs,
824 FALSE, FALSE, TRUE) );
826
827 for (k = 0; k <= i; ++k)
828 {
829 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[k][j], coeffs1[k]) );
830 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[k][j + 1], coeffs2[k]) );
831 }
833
834 SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
835#ifdef SCIP_DEBUG
837#endif
838 SCIP_CALL( SCIPreleaseRow(scip, &row) );
839
840 ++(*ngen);
841 if ( *infeasible )
842 break;
843
844 /* reset coefficients for next inequality */
845 coeffs1[i] = 0.0;
846 coeffs2[i] = 0.0;
847 }
848
849 /* add argmax( 1 - vals[i][0], vals[i][1] ) as coefficient and ensure that both vars1[0] and vars2[0] are
850 * contained in the LIFTED cover inequality */
851 rowval = SCIPgetSolVal(scip, sol, vars[i][j]) + SCIPgetSolVal(scip, sol, vars[i][j + 1]);
852 if ( SCIPisEfficacious(scip, 1.0 - rowval) )
853 {
854 coeffs1[i] = -1.0;
855 coeffs2[i] = 0.0;
856 lhs -= SCIPgetSolVal(scip, sol, vars[i][j]);
857
858 /* apply lifting? */
859 if ( i == 0 )
860 {
861 coeffs2[i] = 1.0;
862 lhs += SCIPgetSolVal(scip, sol, vars[i][j + 1]);
863 }
864 }
865 else
866 {
867 coeffs1[i] = 0.0;
868 coeffs2[i] = 1.0;
869 lhs += SCIPgetSolVal(scip, sol, vars[i][j]);
870 rhs += 1.0;
871
872 /* apply lifting? */
873 if ( i == 0 )
874 {
875 coeffs1[i] = -1.0;
876 lhs -= SCIPgetSolVal(scip, sol, vars[i][j]);
877 rhs -= 1.0;
878 }
879 }
880 }
881 }
882
883 SCIPfreeBufferArray(scip, &coeffs1);
884 SCIPfreeBufferArray(scip, &coeffs2);
885
886 return SCIP_OKAY;
887}
888
889
890/** separate or enforce constraints */
891static
893 SCIP* scip, /**< SCIP data structure */
894 SCIP_CONSHDLR* conshdlr, /**< constraint handler */
895 SCIP_CONS** conss, /**< constraints to process */
896 int nconss, /**< number of constraints */
897 int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
898 SCIP_SOL* sol, /**< solution to separate (NULL for the LP solution) */
899 SCIP_RESULT* result, /**< pointer to store the result (should be initialized) */
900 SCIP_Bool enforce /**< whether we enforce orbitope constraints */
901 )
902{
903 SCIP_Bool infeasible = FALSE;
904 int ncuts = 0;
905 int c;
906
907 assert( scip != NULL );
908 assert( conshdlr != NULL );
909 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
910 assert( result != NULL );
911
912 /* loop through constraints */
913 for (c = 0; c < nconss && ! infeasible; c++)
914 {
915 SCIP_CONSDATA* consdata;
916 int nconscuts = 0;
917
918 assert( conss[c] != NULL );
919
920 /* get data of constraint */
921 consdata = SCIPconsGetData(conss[c]);
922 assert( consdata != NULL );
923
924 /* skip non-model constraints if strong dual reductions are not permitted */
925 if ( !consdata->ismodelcons && !SCIPallowStrongDualReds(scip) )
926 continue;
927
928 /* do not enforce non-model constraints */
929 if ( enforce && !consdata->ismodelcons )
930 continue;
931
932 SCIP_CALL( separateCoversOrbisack(scip, conss[c], sol, &nconscuts, &infeasible) );
933 ncuts += nconscuts;
934
935 /* stop after the useful constraints if we found cuts */
936 if ( c >= nusefulconss && ncuts > 0 )
937 break;
938 }
939
940 if ( infeasible )
941 {
942 SCIPdebugMsg(scip, "Infeasible node.\n");
943 *result = SCIP_CUTOFF;
944 }
945 else if ( ncuts > 0 )
946 {
947 SCIPdebugMsg(scip, "Separated %dinequalities.\n", ncuts);
948 *result = SCIP_SEPARATED;
949 }
950 else
951 {
952 SCIPdebugMsg(scip, "No violated inequality found during separation.\n");
953 }
954
955 return SCIP_OKAY;
956}
957
958
959/** check whether all variables in an orbitope constraint are fixed */
960static
962 SCIP* scip, /**< SCIP data structure */
963 SCIP_CONS* cons, /**< constraint to be processed */
964 SCIP_Bool* redundant /**< pointer to store whether constraint is redundant (contains no active vars) */
965 )
966{
967 SCIP_CONSDATA* consdata;
968 SCIP_VAR*** vars;
969 int i;
970 int j;
971 int nrows;
972 int ncols;
973
974 assert( scip != NULL );
975 assert( cons != NULL );
976 assert( redundant != NULL );
977
978 *redundant = FALSE;
979
980 consdata = SCIPconsGetData(cons);
981 assert( consdata != NULL );
982 assert( consdata->vars != NULL );
983 assert( consdata->nrows > 0 );
984 assert( consdata->ncols > 0 );
985
986 vars = consdata->vars;
987 nrows = consdata->nrows;
988 ncols = consdata->ncols;
989
990 /* check whether there exists an active variable in the orbitope */
991 for (i = 0; i < nrows; ++i)
992 {
993 for (j = 0; j < ncols; ++j)
994 {
995 if ( SCIPvarIsActive(vars[i][j]) )
996 return SCIP_OKAY;
997 }
998 }
999 *redundant = TRUE;
1000
1001 return SCIP_OKAY;
1002}
1003
1004
1005/** replace aggregated variables by active variables */
1006static
1008 SCIP* scip, /**< SCIP data structure */
1009 SCIP_CONS* cons /**< constraint to be processed */
1010 )
1011{
1012 SCIP_CONSDATA* consdata;
1013 SCIP_VAR*** vars;
1014 int i;
1015 int j;
1016 int nrows;
1017 int ncols;
1018
1019 assert( scip != NULL );
1020 assert( cons != NULL );
1021
1022 consdata = SCIPconsGetData(cons);
1023 assert( consdata != NULL );
1024 assert( consdata->vars != NULL );
1025 assert( consdata->nrows > 0 );
1026 assert( consdata->ncols > 0 );
1027
1028 vars = consdata->vars;
1029 nrows = consdata->nrows;
1030 ncols = consdata->ncols;
1031
1032 /* check whether there exists an aggregated variable in the orbitope */
1033 for (i = 0; i < nrows; ++i)
1034 {
1035 for (j = 0; j < ncols; ++j)
1036 {
1037 SCIP_VAR* var;
1038 SCIP_Bool negated;
1039
1040 assert( SCIPvarGetStatus(vars[i][j]) != SCIP_VARSTATUS_MULTAGGR ); /* variables are marked as not to be multi-aggregated */
1041
1042 SCIP_CALL( SCIPgetBinvarRepresentative(scip, vars[i][j], &var, &negated) );
1043 SCIP_UNUSED( negated );
1045 if ( var != vars[i][j] )
1046 {
1047 SCIP_CALL( SCIPreleaseVar(scip, &vars[i][j]) );
1048 vars[i][j] = var;
1049 SCIP_CALL( SCIPcaptureVar(scip, var) );
1050 }
1051 }
1052 }
1053
1054 return SCIP_OKAY;
1055}
1056
1057
1058/*
1059 * Callback methods of constraint handler
1060 */
1061
1062/** copy method for constraint handler plugins (called when SCIP copies plugins) */
1063static
1064SCIP_DECL_CONSHDLRCOPY(conshdlrCopyOrbitopeFull)
1065{ /*lint --e{715}*/
1066 assert(scip != NULL);
1067 assert(conshdlr != NULL);
1068 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
1069 assert(valid != NULL);
1070
1071 /* call inclusion method of constraint handler */
1073
1074 *valid = TRUE;
1075
1076 return SCIP_OKAY;
1077}
1078
1079/** frees constraint handler */
1080static
1081SCIP_DECL_CONSFREE(consFreeOrbitopeFull)
1082{ /*lint --e{715}*/
1083 SCIP_CONSHDLRDATA* conshdlrdata;
1084
1085 assert( scip != 0 );
1086 assert( conshdlr != 0 );
1087 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
1088
1089 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1090 assert( conshdlrdata != NULL );
1091
1092 SCIPfreeBlockMemory(scip, &conshdlrdata);
1093
1094 return SCIP_OKAY;
1095}
1096
1097/** frees specific constraint data */
1098static
1099SCIP_DECL_CONSDELETE(consDeleteOrbitopeFull)
1100{ /*lint --e{715}*/
1101 assert(conshdlr != NULL);
1102 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
1103
1104 SCIP_CALL( consdataFree(scip, consdata) );
1105
1106 return SCIP_OKAY;
1107}
1108
1109/** transforms constraint data into data belonging to the transformed problem */
1110static
1111SCIP_DECL_CONSTRANS(consTransOrbitopeFull)
1112{ /*lint --e{715}*/
1113 SCIP_CONSDATA* sourcedata;
1114 SCIP_CONSDATA* targetdata;
1115
1116 assert(conshdlr != NULL);
1117 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
1119 assert(sourcecons != NULL);
1120 assert(targetcons != NULL);
1121
1122 sourcedata = SCIPconsGetData(sourcecons);
1123 assert(sourcedata != NULL);
1124
1125 /* create linear constraint data for target constraint */
1126 SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->vars, sourcedata->nrows, sourcedata->ncols,
1127 sourcedata->resolveprop, sourcedata->ismodelcons) );
1128
1129 /* create target constraint */
1130 SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
1131 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
1132 SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
1133 SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
1134 SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
1135
1136 return SCIP_OKAY;
1137}
1138
1139/** separation method of constraint handler for LP solutions */
1140static
1141SCIP_DECL_CONSSEPALP(consSepalpOrbitopeFull)
1142{ /*lint --e{715}*/
1143 assert( scip != NULL );
1144 assert( result != NULL );
1145
1146 SCIPdebugMsg(scip, "Separation of full orbitope constraint handler <%s> for LP solution.\n",
1147 SCIPconshdlrGetName(conshdlr));
1148
1149 *result = SCIP_DIDNOTRUN;
1150
1151 /* if solution is integer, skip separation */
1152 if ( SCIPgetNLPBranchCands(scip) <= 0 )
1153 return SCIP_OKAY;
1154
1155 *result = SCIP_DIDNOTFIND;
1156
1157 /* separate constraints */
1158 SCIP_CALL( separateConstraints(scip, conshdlr, conss, nconss, nusefulconss, NULL, result, FALSE) );
1159
1160 return SCIP_OKAY;
1161}
1162
1163/** separation method of constraint handler for arbitrary primal solutions */
1164static
1165SCIP_DECL_CONSSEPASOL(consSepasolOrbitopeFull)
1166{ /*lint --e{715}*/
1167 assert( scip != NULL );
1168 assert( result != NULL );
1169
1170 SCIPdebugMsg(scip, "Separation of full orbitope constraint handler <%s> for primal solution.\n",
1171 SCIPconshdlrGetName(conshdlr));
1172
1173 *result = SCIP_DIDNOTFIND;
1174
1175 /* separate constraints */
1176 SCIP_CALL( separateConstraints(scip, conshdlr, conss, nconss, nusefulconss, sol, result, FALSE) );
1177
1178 return SCIP_OKAY;
1179}
1180
1181/** constraint enforcing method of constraint handler for LP solutions */
1182static
1183SCIP_DECL_CONSENFOLP(consEnfolpOrbitopeFull)
1184{ /*lint --e{715}*/
1185 assert( scip != NULL );
1186 assert( result != NULL );
1187
1188 /* we have a negative priority, so we should come after the integrality conshdlr */
1189 assert( SCIPgetNLPBranchCands(scip) == 0 );
1190
1191 SCIPdebugMsg(scip, "Enforcement for full orbitope constraint handler <%s> for LP solution.\n",
1192 SCIPconshdlrGetName(conshdlr));
1193
1194 *result = SCIP_FEASIBLE;
1195
1196 /* separate constraints */
1197 SCIP_CALL( separateConstraints(scip, conshdlr, conss, nconss, nusefulconss, NULL, result, TRUE) );
1198
1199 return SCIP_OKAY;
1200}
1201
1202/** constraint enforcing method of constraint handler for relaxation solutions */
1203static
1204SCIP_DECL_CONSENFORELAX(consEnforelaxOrbitopeFull)
1205{ /*lint --e{715}*/
1206 assert( result != NULL );
1207 assert( scip != NULL );
1208
1209 SCIPdebugMsg(scip, "Enforcement for full orbitope constraint handler <%s> for relaxation solution.\n",
1210 SCIPconshdlrGetName(conshdlr));
1211
1212 *result = SCIP_FEASIBLE;
1213
1214 /* separate constraints */
1215 SCIP_CALL( separateConstraints(scip, conshdlr, conss, nconss, nusefulconss, sol, result, TRUE) );
1216
1217 return SCIP_OKAY;
1218}
1219
1220/** constraint enforcing method of constraint handler for pseudo solutions */
1221static
1222SCIP_DECL_CONSENFOPS(consEnfopsOrbitopeFull)
1223{ /*lint --e{715}*/
1224 int c;
1225
1226 assert( scip != NULL );
1227 assert( conshdlr != NULL );
1228 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
1229 assert( result != NULL );
1230
1231 *result = SCIP_FEASIBLE;
1232 if ( objinfeasible || solinfeasible )
1233 return SCIP_OKAY;
1234
1235 /* loop through constraints */
1236 for (c = 0; c < nconss && *result == SCIP_FEASIBLE; ++c)
1237 {
1238 SCIP_CONSDATA* consdata;
1239 SCIP_Bool feasible;
1240
1241 /* get data of constraint */
1242 assert( conss[c] != NULL );
1243 consdata = SCIPconsGetData(conss[c]);
1244 assert( consdata != NULL );
1245
1246 /* do not enforce non-model constraints */
1247 if ( !consdata->ismodelcons )
1248 continue;
1249
1250 SCIP_CALL( checkFullOrbitopeSolution(scip, conss[c], NULL, FALSE, &feasible) );
1251
1252 if ( ! feasible )
1253 *result = SCIP_INFEASIBLE;
1254 }
1255
1256 return SCIP_OKAY;
1257}
1258
1259
1260/** feasibility check method of constraint handler for integral solutions */
1261static
1262SCIP_DECL_CONSCHECK(consCheckOrbitopeFull)
1263{ /*lint --e{715}*/
1264 int c;
1265
1266 assert( scip != NULL );
1267 assert( conshdlr != NULL );
1268 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
1269 assert( result != NULL );
1270
1271 *result = SCIP_FEASIBLE;
1272
1273 /* loop through constraints */
1274 for( c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c )
1275 {
1276 SCIP_CONSDATA* consdata;
1277 SCIP_Bool feasible;
1278
1279 assert( conss[c] != 0 );
1280 consdata = SCIPconsGetData(conss[c]);
1281 assert( consdata != NULL );
1282
1283 /* do not check non-model constraints */
1284 if ( !consdata->ismodelcons )
1285 continue;
1286
1287 SCIP_CALL( checkFullOrbitopeSolution(scip, conss[c], sol, printreason, &feasible) );
1288
1289 if ( ! feasible )
1290 *result = SCIP_INFEASIBLE;
1291 }
1292
1293 if( *result == SCIP_FEASIBLE )
1294 {
1295 SCIPdebugMsg(scip, "Solution is feasible.\n");
1296 }
1297 else
1298 {
1299 SCIPdebugMsg(scip, "Solution is infeasible.\n");
1300 }
1301
1302 return SCIP_OKAY;
1303}
1304
1305
1306/** domain propagation method of constraint handler */
1307static
1308SCIP_DECL_CONSPROP(consPropOrbitopeFull)
1309{ /*lint --e{715}*/
1310 SCIP_Bool infeasible = FALSE;
1311 int nfixedvars = 0;
1312 int c;
1313
1314 assert( scip != NULL );
1315 assert( conshdlr != NULL );
1316 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
1317 assert( result != NULL );
1318
1319 *result = SCIP_DIDNOTRUN;
1320
1321 /* propagate all useful constraints */
1322 for (c = 0; c < nusefulconss && !infeasible; ++c)
1323 {
1324 int nfixed;
1325 assert( conss[c] != 0 );
1326
1327 SCIPdebugMsg(scip, "Propagation of full orbitope constraint <%s> ...\n", SCIPconsGetName(conss[c]));
1328
1329 SCIP_CALL( propagateCons(scip, conss[c], &infeasible, &nfixed) );
1330 nfixedvars += nfixed;
1331 }
1332
1333 /* return the correct result */
1334 if ( infeasible )
1335 {
1336 *result = SCIP_CUTOFF;
1337 SCIPdebugMsg(scip, "Propagation via orbitopal fixing proved node to be infeasible.\n");
1338 }
1339 else if ( nfixedvars > 0 )
1340 {
1341 *result = SCIP_REDUCEDDOM;
1342 SCIPdebugMsg(scip, "Propagated %d variables via orbitopal fixing.\n", nfixedvars);
1343 }
1344 else if ( nusefulconss > 0 )
1345 {
1346 *result = SCIP_DIDNOTFIND;
1347 SCIPdebugMsg(scip, "Propagation via orbitopal fixing did not find anything.\n");
1348 }
1349
1350 return SCIP_OKAY;
1351}
1352
1353
1354/** presolving method of constraint handler */
1355static
1356SCIP_DECL_CONSPRESOL(consPresolOrbitopeFull)
1357{ /*lint --e{715}*/
1358 SCIP_Bool infeasible = FALSE;
1359 int noldfixedvars;
1360 int c;
1361 SCIP_Bool redundant;
1362
1363 assert( scip != NULL );
1364 assert( conshdlr != NULL );
1365 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
1366 assert( result != NULL );
1367
1368 *result = SCIP_DIDNOTRUN;
1369 noldfixedvars = *nfixedvars;
1370
1371 /* propagate all useful constraints
1372 *
1373 * @todo use an event handler to only propagate if a variable in the orbitope has been fixed
1374 */
1375 for (c = 0; c < nconss && !infeasible; ++c)
1376 {
1377 int nfixed = 0;
1378
1379 assert( conss[c] != 0 );
1380
1381 SCIPdebugMsg(scip, "Presolving of full orbitope constraint <%s> ...\n", SCIPconsGetName(conss[c]));
1382
1383 /* first propagate */
1384 SCIP_CALL( propagateCons(scip, conss[c], &infeasible, &nfixed) );
1385 *nfixedvars += nfixed;
1386
1387 if ( ! infeasible )
1388 {
1389 SCIP_CALL( checkRedundantCons(scip, conss[c], &redundant) );
1390
1391 if ( redundant )
1392 {
1393 SCIPdebugMsg(scip, "Full orbitope constraint <%s> is redundant: it does not contain active variables\n",
1394 SCIPconsGetName(conss[c]));
1395 SCIP_CALL( SCIPdelCons(scip, conss[c]) );
1396 assert( ! SCIPconsIsActive(conss[c]) );
1397 (*ndelconss)++;
1398 continue;
1399 }
1400 }
1401 }
1402
1403 if ( infeasible )
1404 {
1405 *result = SCIP_CUTOFF;
1406 SCIPdebugMsg(scip, "Presolving detected infeasibility.\n");
1407 }
1408 else if ( *nfixedvars > noldfixedvars )
1409 {
1410 *result = SCIP_SUCCESS;
1411 }
1412 else if ( nconss > 0 )
1413 {
1414 *result = SCIP_DIDNOTFIND;
1415 SCIPdebugMsg(scip, "Presolving via orbitopal fixing did not find anything.\n");
1416 }
1417
1418 return SCIP_OKAY;
1419}
1420
1421
1422/** propagation conflict resolving method of constraint handler */
1423static
1424SCIP_DECL_CONSRESPROP(consRespropOrbitopeFull)
1425{ /*lint --e{715}*/
1426 assert( scip != NULL );
1427 assert( cons != NULL );
1428 assert( infervar != NULL );
1429 assert( bdchgidx != NULL );
1430 assert( result != NULL );
1431
1432 SCIP_CALL( resolvePropagationFullOrbitope(scip, conshdlr, cons, inferinfo, bdchgidx, result) );
1433
1434 return SCIP_OKAY;
1435}
1436
1437
1438/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
1439static
1440SCIP_DECL_CONSEXITPRE(consExitpreOrbitopeFull)
1441{
1442 int c;
1443
1444 assert( scip != NULL );
1445 assert( conshdlr != NULL );
1446 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
1447
1448 for (c = 0; c < nconss; ++c)
1449 {
1450 /* replace aggregated variables by active variables */
1452 }
1453 return SCIP_OKAY;
1454}
1455
1456
1457/** variable rounding lock method of constraint handler */
1458static
1459SCIP_DECL_CONSLOCK(consLockOrbitopeFull)
1460{ /*lint --e{715}*/
1461 SCIP_CONSDATA* consdata;
1462 SCIP_VAR*** vars;
1463 int i;
1464 int j;
1465 int nrows;
1466 int ncols;
1467
1468 assert( scip != NULL );
1469 assert( conshdlr != NULL );
1470 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
1471 assert( cons != NULL );
1472 assert( locktype == SCIP_LOCKTYPE_MODEL );
1473
1474 consdata = SCIPconsGetData(cons);
1475 assert( consdata != NULL );
1476 assert( consdata->nrows > 0 );
1477 assert( consdata->ncols > 0 );
1478 assert( consdata->vars != NULL );
1479
1480 SCIPdebugMsg(scip, "Locking method for full orbitope constraint handler\n");
1481
1482 nrows = consdata->nrows;
1483 ncols = consdata->ncols;
1484 vars = consdata->vars;
1485
1486 /* add up locks and down locks on each variable */
1487 for (i = 0; i < nrows; ++i)
1488 {
1489 for (j = 0; j < ncols; ++j)
1490 {
1491 SCIP_CALL( SCIPaddVarLocksType(scip, vars[i][j], locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
1492 }
1493 }
1494
1495 return SCIP_OKAY;
1496}
1497
1498
1499/** constraint display method of constraint handler */
1500static
1501SCIP_DECL_CONSPRINT(consPrintOrbitopeFull)
1502{
1503 SCIP_CONSDATA* consdata;
1504 SCIP_VAR*** vars;
1505 int i;
1506 int j;
1507 int nrows;
1508 int ncols;
1509
1510 assert( scip != NULL );
1511 assert( conshdlr != NULL );
1512 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
1513 assert( cons != NULL );
1514
1515 consdata = SCIPconsGetData(cons);
1516 assert( consdata != NULL );
1517 assert( consdata->nrows > 0 );
1518 assert( consdata->ncols > 0 );
1519 assert( consdata->vars != NULL );
1520
1521 nrows = consdata->nrows;
1522 ncols = consdata->ncols;
1523 vars = consdata->vars;
1524
1525 SCIPdebugMsg(scip, "Printing method for full orbitope constraint handler\n");
1526
1527 SCIPinfoMessage(scip, file, "fullOrbitope(");
1528
1529 for (i = 0; i < nrows; ++i)
1530 {
1531 for (j = 0; j < ncols; ++j)
1532 {
1533 if ( j > 0 )
1534 SCIPinfoMessage(scip, file, ",");
1535 SCIP_CALL( SCIPwriteVarName(scip, file, vars[i][j], TRUE) );
1536 }
1537 if ( i < nrows - 1 )
1538 SCIPinfoMessage(scip, file, ".");
1539 }
1540 SCIPinfoMessage(scip, file, ")");
1541
1542 return SCIP_OKAY;
1543}
1544
1545
1546/** constraint copying method of constraint handler */
1547static
1548SCIP_DECL_CONSCOPY(consCopyOrbitopeFull)
1549{
1550 SCIP_CONSHDLRDATA* conshdlrdata;
1551 SCIP_CONSDATA* sourcedata;
1552 SCIP_VAR*** sourcevars;
1553 SCIP_VAR*** vars;
1554 int nrows;
1555 int ncols;
1556 int i;
1557 int k;
1558 int j;
1559
1560 assert( scip != NULL );
1561 assert( cons != NULL );
1562 assert( sourcescip != NULL );
1563 assert( sourceconshdlr != NULL );
1564 assert( strcmp(SCIPconshdlrGetName(sourceconshdlr), CONSHDLR_NAME) == 0 );
1565 assert( sourcecons != NULL );
1566 assert( varmap != NULL );
1567 assert( valid != NULL );
1568
1569 *valid = TRUE;
1570
1571 SCIPdebugMsg(scip, "Copying method for full orbitope constraint handler.\n");
1572
1573 sourcedata = SCIPconsGetData(sourcecons);
1574 assert( sourcedata != NULL );
1575 assert( sourcedata->nrows > 0 );
1576 assert( sourcedata->ncols > 0 );
1577 assert( sourcedata->vars != NULL );
1578
1579 conshdlrdata = SCIPconshdlrGetData(sourceconshdlr);
1580 assert( conshdlrdata != NULL );
1581
1582 /* do not copy non-model constraints */
1583 if ( !sourcedata->ismodelcons && !conshdlrdata->forceconscopy )
1584 {
1585 *valid = FALSE;
1586
1587 return SCIP_OKAY;
1588 }
1589
1590 nrows = sourcedata->nrows;
1591 ncols = sourcedata->ncols;
1592 sourcevars = sourcedata->vars;
1593
1594 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nrows) );
1595 for (i = 0; i < nrows && *valid; ++i)
1596 {
1597 SCIP_CALL( SCIPallocBufferArray(scip, &(vars[i]), ncols) ); /*lint !e866*/
1598
1599 for (j = 0; j < ncols && *valid; ++j)
1600 {
1601 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[i][j], &(vars[i][j]), varmap, consmap, global, valid) );
1602 assert( !(*valid) || vars[i][j] != NULL );
1603 }
1604 }
1605
1606 /* only create the target constraint, if all variables could be copied */
1607 if ( *valid )
1608 {
1609 /* create copied constraint */
1610 if ( name == NULL )
1611 name = SCIPconsGetName(sourcecons);
1612
1613 SCIP_CALL( SCIPcreateConsOrbitopeFull(scip, cons, name, vars, nrows, ncols,
1614 sourcedata->resolveprop, sourcedata->ismodelcons,
1615 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
1616 }
1617
1618 /* free space; only up to row i if copying failed */
1619 assert( 0 <= i && i <= nrows );
1620 for (k = i - 1; k >= 0; --k)
1621 SCIPfreeBufferArray(scip, &vars[k]);
1622 SCIPfreeBufferArray(scip, &vars);
1623
1624 return SCIP_OKAY;
1625}
1626
1627
1628/** constraint parsing method of constraint handler */
1629static
1630SCIP_DECL_CONSPARSE(consParseOrbitopeFull)
1631{ /*lint --e{715}*/
1632 const char* s;
1633 char* endptr;
1634 SCIP_VAR*** vars;
1635 SCIP_VAR* var;
1636 int nrows;
1637 int maxnrows;
1638 int ncols;
1639 int maxncols;
1640 int k;
1641 int j;
1642
1643 assert( success != NULL );
1644
1645 *success = TRUE;
1646 s = str;
1647
1648 /* skip white space */
1649 SCIP_CALL( SCIPskipSpace((char**)&s) );
1650
1651 if( strncmp(s, "fullOrbitope(", 13) != 0 )
1652 {
1653 SCIPerrorMessage("Syntax error - expected \"fullOrbitope(\": %s\n", s);
1654 *success = FALSE;
1655 return SCIP_OKAY;
1656 }
1657 s += 13;
1658
1659 /* loop through string */
1660 nrows = 0;
1661 ncols = 0;
1662 maxnrows = 10;
1663 maxncols = 10;
1664
1665 SCIP_CALL( SCIPallocBufferArray(scip, &vars, maxnrows) );
1666
1667 j = 0;
1668 do
1669 {
1670 /* parse variable name */
1671 SCIP_CALL( SCIPparseVarName(scip, s, &var, &endptr) );
1672
1673 if( var == NULL )
1674 {
1675 endptr = strchr(endptr, ')');
1676
1677 if( endptr == NULL || j > 0 )
1678 {
1679 SCIPerrorMessage("not enough variables.\n");
1680 *success = FALSE;
1681 }
1682
1683 break;
1684 }
1685
1686 s = endptr;
1687 assert( s != NULL );
1688
1689 /* skip white space */
1690 SCIP_CALL( SCIPskipSpace((char**)&s) );
1691
1692 /* begin new row if required */
1693 if( j == 0 )
1694 {
1695 ++nrows;
1696
1697 if( nrows > maxnrows )
1698 {
1699 maxnrows = SCIPcalcMemGrowSize(scip, nrows);
1700 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, maxnrows) );
1701 assert( nrows <= maxnrows );
1702 }
1703
1704 SCIP_CALL( SCIPallocBufferArray(scip, &(vars[nrows-1]), nrows == 1 ? maxncols : ncols) ); /*lint !e866*/
1705 }
1706
1707 /* determine number of columns */
1708 if( nrows == 1 )
1709 {
1710 ncols = j + 1;
1711
1712 if( *s == '.' || *s == ')' )
1713 SCIP_CALL( SCIPreallocBufferArray(scip, &(vars[nrows-1]), ncols) ); /*lint !e866*/
1714 else if( ncols > maxncols )
1715 {
1716 maxncols = SCIPcalcMemGrowSize(scip, ncols);
1717 SCIP_CALL( SCIPreallocBufferArray(scip, &(vars[nrows-1]), maxncols) ); /*lint !e866*/
1718 assert( ncols <= maxncols );
1719 }
1720 }
1721 else if( ( j < ncols-1 ) == ( *s == '.' || *s == ')' ) )
1722 {
1723 SCIPerrorMessage("variables per row do not match.\n");
1724 *success = FALSE;
1725 break;
1726 }
1727
1728 vars[nrows-1][j] = var;
1729
1730 if( *s == '.' )
1731 j = 0;
1732 else
1733 ++j;
1734
1735 /* skip ',' or '.' */
1736 if( *s == ',' || *s == '.' )
1737 ++s;
1738 }
1739 while( *s != ')' );
1740
1741 if( *success )
1742 {
1743 SCIP_CALL( SCIPcreateConsOrbitopeFull(scip, cons, name, vars, nrows, ncols, TRUE, TRUE,
1744 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
1745 }
1746
1747 for( k = nrows - 1; k >= 0; --k )
1748 SCIPfreeBufferArray(scip, &vars[k]);
1749 SCIPfreeBufferArray(scip, &vars);
1750
1751 return SCIP_OKAY;
1752}
1753
1754
1755/** constraint method of constraint handler which returns the variables (if possible) */
1756static
1757SCIP_DECL_CONSGETVARS(consGetVarsOrbitopeFull)
1758{ /*lint --e{715}*/
1759 SCIP_CONSDATA* consdata;
1760
1761 assert( cons != NULL );
1762 assert( success != NULL );
1763 assert( vars != NULL );
1764
1765 consdata = SCIPconsGetData(cons);
1766 assert( consdata != NULL );
1767
1768 if ( varssize < consdata->ncols * consdata->nrows )
1769 *success = FALSE;
1770 else
1771 {
1772 int cnt = 0;
1773 int i;
1774 int j;
1775
1776 for (i = 0; i < consdata->nrows; ++i)
1777 {
1778 for (j = 0; j < consdata->ncols; ++j)
1779 vars[cnt++] = consdata->vars[i][j];
1780 }
1781 *success = TRUE;
1782 }
1783
1784 return SCIP_OKAY;
1785}
1786
1787
1788/** constraint method of constraint handler which returns the number of variables (if possible) */
1789static
1790SCIP_DECL_CONSGETNVARS(consGetNVarsOrbitopeFull)
1791{ /*lint --e{715}*/
1792 SCIP_CONSDATA* consdata;
1793
1794 assert( cons != NULL );
1795
1796 consdata = SCIPconsGetData(cons);
1797 assert( consdata != NULL );
1798
1799 *nvars = consdata->ncols * consdata->nrows;
1800 *success = TRUE;
1801
1802 return SCIP_OKAY;
1803}
1804
1805
1806/*
1807 * constraint specific interface methods
1808 */
1809
1810/** creates the handler for orbitope constraints and includes it in SCIP */
1812 SCIP* scip /**< SCIP data structure */
1813 )
1814{
1815 SCIP_CONSHDLRDATA* conshdlrdata;
1816 SCIP_CONSHDLR* conshdlr;
1817
1818 /* create orbitope constraint handler data */
1819 SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
1820
1821 /* include constraint handler */
1825 consEnfolpOrbitopeFull, consEnfopsOrbitopeFull, consCheckOrbitopeFull, consLockOrbitopeFull,
1826 conshdlrdata) );
1827 assert(conshdlr != NULL);
1828
1829 /* set non-fundamental callbacks via specific setter functions */
1830 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyOrbitopeFull, consCopyOrbitopeFull) );
1831 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeOrbitopeFull) );
1832 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteOrbitopeFull) );
1833 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsOrbitopeFull) );
1834 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsOrbitopeFull) );
1835 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseOrbitopeFull) );
1836 SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolOrbitopeFull,
1838 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintOrbitopeFull) );
1839 SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropOrbitopeFull, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
1841 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropOrbitopeFull) );
1842 SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreOrbitopeFull) );
1843 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpOrbitopeFull, consSepasolOrbitopeFull, CONSHDLR_SEPAFREQ,
1845 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransOrbitopeFull) );
1846 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxOrbitopeFull) );
1847
1848 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forceconscopy",
1849 "Whether orbitope constraints should be forced to be copied to sub SCIPs.",
1850 &conshdlrdata->forceconscopy, TRUE, DEFAULT_FORCECONSCOPY, NULL, NULL) );
1851
1852 return SCIP_OKAY;
1853}
1854
1855
1856/** creates and captures a full orbitope constraint
1857 *
1858 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
1859 */
1861 SCIP* scip, /**< SCIP data structure */
1862 SCIP_CONS** cons, /**< pointer to hold the created constraint */
1863 const char* name, /**< name of constraint */
1864 SCIP_VAR*** vars, /**< matrix of variables on which the symmetry acts */
1865 int nrows, /**< number of set partitioning/packing constraints <=> p */
1866 int ncols, /**< number of symmetric variable blocks <=> q */
1867 SCIP_Bool resolveprop, /**< should propagation be resolved? */
1868 SCIP_Bool ismodelcons, /**< whether the orbitope is a model constraint */
1869 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
1870 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1871 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
1872 * Usually set to TRUE. */
1873 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
1874 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1875 SCIP_Bool check, /**< should the constraint be checked for feasibility?
1876 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1877 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
1878 * Usually set to TRUE. */
1879 SCIP_Bool local, /**< is constraint only valid locally?
1880 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1881 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
1882 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
1883 * adds coefficients to this constraint. */
1884 SCIP_Bool dynamic, /**< is constraint subject to aging?
1885 * Usually set to FALSE. Set to TRUE for own cuts which
1886 * are separated as constraints. */
1887 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
1888 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
1889 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
1890 * if it may be moved to a more global node?
1891 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
1892 )
1893{
1894 SCIP_CONSHDLR* conshdlr;
1895 SCIP_CONSDATA* consdata;
1896
1897 /* find the orbitope constraint handler */
1898 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
1899 if ( conshdlr == NULL )
1900 {
1901 SCIPerrorMessage("full orbitope constraint handler not found\n");
1902 return SCIP_PLUGINNOTFOUND;
1903 }
1904
1905 assert( nrows > 0 );
1906 assert( ncols > 0 );
1907
1908 /* run some checks */
1909#ifndef NDEBUG
1910 {
1911 SCIP_Real obj;
1912 int i;
1913 int j;
1914 for (i = 0; i < nrows; ++i)
1915 {
1916 /* initialize obj to infinity */
1917 obj = SCIPinfinity(scip);
1918 for (j = 0; j < ncols; ++j)
1919 {
1920 SCIP_Bool fixedZero;
1921 SCIP_VAR* var;
1922
1923 var = vars[i][j];
1924 assert(var != NULL);
1925
1926 if ( SCIPvarIsNegated(var) )
1927 var = SCIPvarGetNegatedVar(var);
1928
1929 /* all variables need to be binary */
1930 assert( SCIPvarIsBinary(var) );
1931
1932 /* fixed variables have obj = 0; for variables fixed to 0, we assume that there is no
1933 problem (but we cannot always check it, e.g., when in the original problem
1934 variables were fixed and this problem was copied.) */
1935 fixedZero = ( SCIPisZero(scip, SCIPvarGetLbGlobal(var)) && SCIPisZero(scip, SCIPvarGetUbGlobal(var)) );
1936
1937 /* @todo adapt correctness of the following check for sub-scips */
1938 if ( SCIPgetSubscipDepth(scip) == 0 )
1939 {
1940 /* check whether all variables in a row have the same objective */
1941 if ( ! fixedZero && SCIPisInfinity(scip, obj) )
1942 obj = SCIPvarGetObj(var);
1943 else
1944 {
1945 assert( fixedZero || ! SCIPvarIsActive(var) || SCIPisEQ(scip, obj, SCIPvarGetObj(var)) );
1946 }
1947 }
1948 }
1949 }
1950 }
1951#endif
1952
1953 /* create constraint data */
1954 SCIP_CALL( consdataCreate(scip, &consdata, vars, nrows, ncols, resolveprop, ismodelcons) );
1955
1956 /* create constraint */
1957 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
1958 local, modifiable, dynamic, removable, stickingatnode) );
1959
1960 return SCIP_OKAY;
1961}
1962
1963/** creates and captures a full orbitope constraint in its most basic variant, i. e., with all constraint flags set to
1964 * their default values, which can be set afterwards using SCIPsetConsFLAGNAME()
1965 *
1966 * @see SCIPcreateConsOrbitopeFull() for the default constraint flag configuration
1967 *
1968 * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
1969 */
1971 SCIP* scip, /**< SCIP data structure */
1972 SCIP_CONS** cons, /**< pointer to hold the created constraint */
1973 const char* name, /**< name of constraint */
1974 SCIP_VAR*** vars, /**< matrix of variables on which the symmetry acts */
1975 int nrows, /**< number of set partitioning/packing constraints <=> p */
1976 int ncols, /**< number of symmetric variable blocks <=> q */
1977 SCIP_Bool resolveprop, /**< should propagation be resolved? */
1978 SCIP_Bool ismodelcons /**< whether the orbitope is a model constraint */
1979 )
1980{
1981 SCIP_CALL( SCIPcreateConsOrbitopeFull(scip, cons, name, vars, nrows, ncols,
1982 resolveprop, ismodelcons, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
1983
1984 return SCIP_OKAY;
1985}
constraint handler for orbisack constraints
static SCIP_RETCODE checkRedundantCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *redundant)
#define CONSHDLR_NEEDSCONS
#define CONSHDLR_SEPAFREQ
static SCIP_RETCODE checkFullOrbitopeSolution(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool printreason, SCIP_Bool *feasible)
#define CONSHDLR_CHECKPRIORITY
#define CONSHDLR_DESC
static SCIP_RETCODE separateConstraints(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_RESULT *result, SCIP_Bool enforce)
#define CONSHDLR_PROP_TIMING
#define DEFAULT_FORCECONSCOPY
#define CONSHDLR_MAXPREROUNDS
static SCIP_DECL_CONSLOCK(consLockOrbitopeFull)
#define CONSHDLR_SEPAPRIORITY
static SCIP_RETCODE propagateCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *infeasible, int *nfixedvars)
static SCIP_DECL_CONSPRESOL(consPresolOrbitopeFull)
static SCIP_DECL_CONSENFORELAX(consEnforelaxOrbitopeFull)
static SCIP_RETCODE resolvePropagationFullOrbitope(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int inferinfo, SCIP_BDCHGIDX *bdchgidx, SCIP_RESULT *result)
static SCIP_DECL_CONSPRINT(consPrintOrbitopeFull)
static SCIP_DECL_CONSENFOPS(consEnfopsOrbitopeFull)
static SCIP_DECL_CONSCOPY(consCopyOrbitopeFull)
static SCIP_DECL_CONSGETNVARS(consGetNVarsOrbitopeFull)
static SCIP_DECL_CONSCHECK(consCheckOrbitopeFull)
static SCIP_RETCODE findLexMaxFace(SCIP_VAR ***vars, int **lexmaxfixes, int *minfixedrowlexmax, SCIP_Bool *infeasible, int nrows, int ncols, SCIP_Bool resprop)
static SCIP_DECL_CONSSEPALP(consSepalpOrbitopeFull)
static SCIP_DECL_CONSEXITPRE(consExitpreOrbitopeFull)
static SCIP_DECL_CONSENFOLP(consEnfolpOrbitopeFull)
static SCIP_DECL_CONSTRANS(consTransOrbitopeFull)
#define CONSHDLR_PROPFREQ
static SCIP_RETCODE separateCoversOrbisack(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, int *ngen, SCIP_Bool *infeasible)
static SCIP_DECL_CONSSEPASOL(consSepasolOrbitopeFull)
static SCIP_DECL_CONSPARSE(consParseOrbitopeFull)
#define CONSHDLR_PRESOLTIMING
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata)
#define CONSHDLR_EAGERFREQ
#define CONSHDLR_ENFOPRIORITY
static SCIP_DECL_CONSPROP(consPropOrbitopeFull)
static SCIP_RETCODE findLexMinFace(SCIP_VAR ***vars, int **lexminfixes, int *minfixedrowlexmin, SCIP_Bool *infeasible, int nrows, int ncols, SCIP_Bool resprop)
#define CONSHDLR_DELAYSEPA
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_VAR ***vars, int nrows, int ncols, SCIP_Bool resolveprop, SCIP_Bool ismodelcons)
#define CONSHDLR_NAME
static SCIP_DECL_CONSRESPROP(consRespropOrbitopeFull)
static SCIP_RETCODE replaceAggregatedVarsOrbitopeFull(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_CONSFREE(consFreeOrbitopeFull)
static SCIP_DECL_CONSGETVARS(consGetVarsOrbitopeFull)
#define CONSHDLR_DELAYPROP
static SCIP_DECL_CONSDELETE(consDeleteOrbitopeFull)
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyOrbitopeFull)
constraint handler for full orbitope constraints w.r.t. the full symmetric group
Constraint handler for the set partitioning / packing / covering constraints .
#define NULL
Definition: def.h:248
#define SCIP_UNUSED(x)
Definition: def.h:409
#define SCIP_Bool
Definition: def.h:91
#define SCIP_Real
Definition: def.h:156
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:220
#define SCIP_CALL(x)
Definition: def.h:355
SCIP_RETCODE SCIPcheckSolutionOrbisack(SCIP *scip, SCIP_SOL *sol, SCIP_VAR **vars1, SCIP_VAR **vars2, int nrows, SCIP_Bool printreason, SCIP_Bool *feasible)
SCIP_RETCODE SCIPcreateConsBasicOrbitopeFull(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR ***vars, int nrows, int ncols, SCIP_Bool resolveprop, SCIP_Bool ismodelcons)
SCIP_RETCODE SCIPcreateConsOrbitopeFull(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR ***vars, int nrows, int ncols, SCIP_Bool resolveprop, SCIP_Bool ismodelcons, 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 SCIPincludeConshdlrOrbitopeFull(SCIP *scip)
int SCIPgetSubscipDepth(SCIP *scip)
Definition: scip_copy.c:2588
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)
Definition: scip_general.c:647
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:444
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3420
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:208
#define SCIPdebugMsg
Definition: scip_message.h:78
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
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip_branch.c:436
SCIP_RETCODE SCIPaddConflictBinvar(SCIP *scip, SCIP_VAR *var)
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip_cons.c:808
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:540
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:831
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition: scip_cons.c:235
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip_cons.c:281
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip_cons.c:181
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:578
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:372
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip_cons.c:323
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4316
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip_cons.c:516
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:347
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:940
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4336
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:601
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip_cons.c:647
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:854
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip_cons.c:785
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8419
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8648
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8558
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8588
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8578
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8450
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip_cons.c:997
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8608
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8628
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8389
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8638
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8668
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8568
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8658
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip_cut.c:135
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:225
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:139
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:128
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:111
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:105
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1581
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 SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1604
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_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1765
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
Definition: var.c:23868
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:23642
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:23478
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition: var.c:23386
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:24268
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:23900
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip_var.c:728
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:24142
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:5118
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:2872
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1887
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:24234
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition: var.c:23443
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:24120
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:11057
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:2736
SCIP_RETCODE SCIPinferBinvarCons(SCIP *scip, SCIP_VAR *var, SCIP_Bool fixedval, SCIP_CONS *infercons, int inferinfo, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:7412
SCIP_RETCODE SCIPwriteVarName(SCIP *scip, FILE *file, SCIP_VAR *var, SCIP_Bool type)
Definition: scip_var.c:361
SCIP_RETCODE SCIPgetBinvarRepresentative(SCIP *scip, SCIP_VAR *var, SCIP_VAR **repvar, SCIP_Bool *negated)
Definition: scip_var.c:2236
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip_var.c:2078
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1853
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition: scip_var.c:10984
SCIP_RETCODE SCIPskipSpace(char **s)
Definition: misc.c:10816
memory allocation routines
public methods for managing constraints
public methods for message output
#define SCIPerrorMessage
Definition: pub_message.h:64
public methods for problem variables
SCIP callable library.
public methods for branching rule plugins and branching
public methods for conflict handler plugins and conflict analysis
public methods for constraint handler plugins and constraints
public methods for problem copies
public methods for cuts and aggregation rows
general public methods
public methods for the LP relaxation, rows and columns
public methods for memory management
public methods for message handling
public methods for numerical tolerances
public methods for SCIP parameter handling
public methods for global and local (sub)problems
public methods for the probing mode
public methods for solutions
public methods for SCIP variables
static SCIP_RETCODE separate(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_RESULT *result)
Main separation function.
Definition: sepa_flower.c:1221
methods for handling symmetries
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:64
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:65
@ 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_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_PLUGINNOTFOUND
Definition: type_retcode.h:54
@ SCIP_OKAY
Definition: type_retcode.h:42
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_STAGE_TRANSFORMING
Definition: type_set.h:46
type definitions for symmetry computations
@ SCIP_VARSTATUS_FIXED
Definition: type_var.h:54
@ SCIP_VARSTATUS_MULTAGGR
Definition: type_var.h:56
@ SCIP_VARSTATUS_NEGATED
Definition: type_var.h:57
@ SCIP_LOCKTYPE_MODEL
Definition: type_var.h:141