SCIP Doxygen Documentation
Loading...
Searching...
No Matches
cons_symresack.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_symresack.c
26 * @ingroup DEFPLUGINS_CONS
27 * @brief constraint handler for symresack constraints
28 * @author Christopher Hojny
29 * @author Jasper van Doornmalen
30 *
31 * The type of constraints of this constraint handler is described in cons_symresack.h.
32 *
33 * The details of the method implemented here are described in the following papers:
34 *
35 * Fundamental Domains for Integer Programs with Symmetries@n
36 * Eric J. Friedman,@n
37 * Combinatorial Optimization, volume 4616 of LNCS, 146-153 (2007)
38 *
39 * This paper describes an inequality to handle symmetries of a single permutation. This
40 * so-called FD-inequality is the basic for the propagation routine of our implementation.
41 *
42 * Polytopes Associated with Symmetry Handling@n
43 * Christopher Hojny and Marc E. Pfetsch,@n
44 * Mathematical Programming 175, No. 1, 197-240, 2019
45 *
46 * This paper describes an almost linear time separation routine for so-called cover
47 * inequalities of symresacks. A slight modification of this algorithm allows for a linear
48 * running time, which is used in this implementation.
49 *
50 * Packing, Partitioning, and Covering Symresacks@n
51 * Christopher Hojny,@n
52 * (2020), available at https://doi.org/10.1016/j.dam.2020.03.002
53 * Discrete Applied Mathematics, volume 283, 689-717 (2020)
54 *
55 * This paper introduces linearly many inequalities with ternary coefficients that suffice to
56 * characterize the binary points contained in a packing and partitioning symresack completely.
57 */
58
59/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
60
62#include "scip/cons_orbisack.h"
63#include "scip/cons_setppc.h"
64#include "scip/cons_symresack.h"
65#include "scip/pub_cons.h"
66#include "scip/pub_message.h"
67#include "scip/pub_misc.h"
68#include "scip/pub_var.h"
69#include "scip/scip.h"
70#include "scip/scip_branch.h"
71#include "scip/scip_conflict.h"
72#include "scip/scip_cons.h"
73#include "scip/scip_cut.h"
74#include "scip/scip_general.h"
75#include "scip/scip_lp.h"
76#include "scip/scip_mem.h"
77#include "scip/scip_message.h"
78#include "scip/scip_numerics.h"
79#include "scip/scip_param.h"
80#include "scip/scip_prob.h"
81#include "scip/scip_sol.h"
82#include "scip/scip_var.h"
83
84
85/* constraint handler properties */
86#define CONSHDLR_NAME "symresack"
87#define CONSHDLR_DESC "symmetry breaking constraint handler relying on symresacks"
88#define CONSHDLR_SEPAPRIORITY +40100 /**< priority of the constraint handler for separation */
89#define CONSHDLR_ENFOPRIORITY -1005200 /**< priority of the constraint handler for constraint enforcing */
90#define CONSHDLR_CHECKPRIORITY -1005200 /**< priority of the constraint handler for checking feasibility */
91#define CONSHDLR_SEPAFREQ 5 /**< frequency for separating cuts; zero means to separate only in the root node */
92#define CONSHDLR_PROPFREQ 5 /**< frequency for propagating domains; zero means only preprocessing propagation */
93#define CONSHDLR_EAGERFREQ -1 /**< frequency for using all instead of only the useful constraints in separation,
94 * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
95#define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
96#define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
97#define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
98#define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
99
100#define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
101#define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_EXHAUSTIVE
102
103#define DEFAULT_PPSYMRESACK TRUE /**< whether we allow upgrading to packing/partitioning symresacks */
104#define DEFAULT_CHECKMONOTONICITY TRUE /**< check whether permutation is monotone when upgrading to packing/partitioning symresacks */
105#define DEFAULT_FORCECONSCOPY FALSE /**< whether symresack constraints should be forced to be copied to sub SCIPs */
106
107/* Constants to store fixings */
108#define FIXED0 1 /* When a variable is fixed to 0. */
109#define FIXED1 2 /* When a variable is fixed to 1. */
110#define UNFIXED 3 /* When a variable is neither fixed to 0 or to 1. */
111#define NOINIT 0 /* A dummy entry for non-initialized variables.
112 * Must have value 0 because of SCIPallocCleanBufferArray. */
113/* A macro for checking if a variable was fixed during a bound change */
114#define ISFIXED(scip, x, bdchgidx) (SCIPgetVarUbAtIndex(scip, x, bdchgidx, FALSE) - SCIPgetVarLbAtIndex(scip, x, bdchgidx, FALSE) < 0.5)
115
116
117
118/*
119 * Data structures
120 */
121
122/** constraint handler data */
123struct SCIP_ConshdlrData
124{
125 SCIP_Bool checkppsymresack; /**< whether we allow upgrading to packing/partitioning symresacks */
126 SCIP_Bool checkmonotonicity; /**< check whether permutation is monotone when upgrading to packing/partitioning symresacks */
127 int maxnvars; /**< maximal number of variables in a symresack constraint */
128 SCIP_Bool forceconscopy; /**< whether symresack constraints should be forced to be copied to sub SCIPs */
129};
130
131
132/** constraint data for symresack constraints */
133struct SCIP_ConsData
134{
135 SCIP_VAR** vars; /**< variables */
136 int nvars; /**< number of variables */
137 int* perm; /**< permutation associated to the symresack */
138 int* invperm; /**< inverse permutation */
139 SCIP_Bool ppupgrade; /**< whether constraint is upgraded to packing/partitioning symresack */
140 SCIP_Bool ismodelcons; /**< whether the symresack is a model constraint */
141#ifdef SCIP_DEBUG
142 int debugcnt; /**< counter to store number of added cover inequalities */
143#endif
144
145 /* data for upgraded symresack constraints */
146 int ncycles; /**< number of cycles in permutation */
147 int** cycledecomposition; /**< cycle decomposition */
148 int ndescentpoints; /**< number of descent points in perm (only used if perm is not monotone) */
149 int* descentpoints; /**< descent points in perm (only used if perm is not monotone) */
150};
151
152
153/*
154 * Local methods
155 */
156
157/** frees a symresack constraint data */
158static
160 SCIP* scip, /**< SCIP data structure */
161 SCIP_CONSDATA** consdata /**< pointer to symresack constraint data */
162 )
163{
164 int nvars;
165 int i;
166
167 assert( consdata != NULL );
168 assert( *consdata != NULL );
169
170 nvars = (*consdata)->nvars;
171
172 if ( nvars == 0 )
173 {
174 assert( (*consdata)->vars == NULL );
175 assert( (*consdata)->perm == NULL );
176 assert( (*consdata)->invperm == NULL );
177 assert( (*consdata)->ncycles == 0 );
178 assert( (*consdata)->cycledecomposition == NULL );
179
180 SCIPfreeBlockMemory(scip, consdata);
181
182 return SCIP_OKAY;
183 }
184
185 if ( (*consdata)->ndescentpoints > 0 )
186 {
187 assert( (*consdata)->descentpoints != NULL );
188
189 SCIPfreeBlockMemoryArray(scip, &((*consdata)->descentpoints), (*consdata)->ndescentpoints);
190 }
191
192 if ( (*consdata)->ppupgrade )
193 {
194 for (i = 0; i < (*consdata)->ncycles; ++i)
195 {
196 SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->cycledecomposition[i]), nvars + 1);
197 }
198 SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->cycledecomposition), (*consdata)->ncycles);
199 }
200
201 SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->invperm), nvars);
202 SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->perm), nvars);
203
204 for (i = 0; i < nvars; ++i)
205 {
206 SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->vars[i]) );
207 }
208 SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->vars), nvars);
209
210 SCIPfreeBlockMemory(scip, consdata);
211
212 return SCIP_OKAY;
213}
214
215
216/** check whether constraint can be upgraded to packing/partitioning symresack */
217static
219 SCIP* scip, /**< SCIP data structure */
220 SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
221 int* perm, /**< permutation */
222 SCIP_VAR** vars, /**< variables affected by permutation */
223 int nvars, /**< length of permutation */
224 SCIP_Bool checkmonotonicity, /**< check whether permutation is monotone */
225 SCIP_Bool* upgrade /**< pointer to store whether upgrade was successful */
226 )
227{
228 SCIP_Bool* covered;
229 SCIP_Bool descent;
230 SCIP_CONSHDLR* setppcconshdlr;
231 SCIP_CONS** setppcconss;
232 SCIP_VAR* var;
233 SCIP_Bool terminated = FALSE;
234 int** cycledecomposition;
235 int* indicesincycle;
236 int nsetppcconss;
237 int curcycle;
238 int maxcyclelength;
239 int ncycles = 0;
240 int c;
241 int i;
242 int j;
243 int ndescentpoints = 0;
244 int* descentpoints;
245
246 assert( scip != NULL );
247 assert( perm != NULL );
248 assert( vars != NULL );
249 assert( nvars > 0 );
250 assert( upgrade != NULL );
251
252 *upgrade = FALSE;
253
255
256 for (i = 0; i < nvars; ++i)
257 covered[i] = FALSE;
258
259 /* get number of cycles in permutation */
260 for (i = 0; i < nvars; ++i)
261 {
262 /* skip checked indices */
263 if ( covered[i] )
264 continue;
265
266 ++ncycles;
267 j = i;
268 descent = FALSE;
269
270 do
271 {
272 covered[j] = TRUE;
273
274 if ( perm[j] < j )
275 {
276 ++ndescentpoints;
277
278 if ( ! descent )
279 descent = TRUE;
280 else if ( checkmonotonicity )
281 break;
282 }
283
284 j = perm[j];
285 }
286 while ( j != i );
287
288 /* if cycle is not monotone and we require the cycle to be monotone */
289 if ( j != i )
290 {
291 assert( checkmonotonicity );
292 SCIPfreeBufferArray(scip, &covered);
293
294 return SCIP_OKAY;
295 }
296 }
297 assert( ncycles <= nvars / 2 );
298
299 /* check for packing/partitioning type */
300 for (i = 0; i < nvars; ++i)
301 covered[i] = FALSE;
302
303 /* compute cycle decomposition: row i stores in entry 0 the length of the cycle,
304 * the remaining entries are the coordinates in the cycle;
305 * store descent points as well if permutation is not monotone */
306 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &cycledecomposition, ncycles) );
307 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &descentpoints, ndescentpoints) );
308 for (i = 0; i < ncycles; ++i)
309 {
310 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &cycledecomposition[i], nvars + 1) );
311 }
312
313 curcycle = 0;
314 maxcyclelength = 0;
315 c = 0;
316 for (i = 0; i < nvars; ++i)
317 {
318 int cyclelength = 0;
319
320 /* skip checked indices */
321 if ( covered[i] )
322 continue;
323
324 j = i;
325 do
326 {
327 if ( perm[j] < j )
328 descentpoints[c++] = j;
329
330 covered[j] = TRUE;
331 cycledecomposition[curcycle][++cyclelength] = j;
332 j = perm[j];
333 }
334 while ( j != i );
335
336 cycledecomposition[curcycle][0] = cyclelength;
337 ++curcycle;
338
339 if ( maxcyclelength < cyclelength )
340 maxcyclelength = cyclelength;
341 }
342 assert( c == ndescentpoints );
343
344 /* permutation can be upgraded -> check whether the symresack is of packing/partitioning type */
345 setppcconshdlr = SCIPfindConshdlr(scip, "setppc");
346 if ( setppcconshdlr == NULL )
347 {
348 SCIPerrorMessage("Setppc constraint handler not found.\n");
349 return SCIP_PLUGINNOTFOUND;
350 }
351 setppcconss = SCIPconshdlrGetConss(setppcconshdlr);
352 nsetppcconss = SCIPconshdlrGetNConss(setppcconshdlr);
353
354 /* Check whether each cycle of the symresack is contained in a set packing/partitioning constraint.
355 * To this end, we have to guarantee that all affected variables are not negated since permutations
356 * are given w.r.t. original variables. */
357 *upgrade = TRUE;
358
359 SCIP_CALL( SCIPallocBufferArray(scip, &indicesincycle, maxcyclelength) );
360
361 for (i = 0; i < ncycles && *upgrade && ! terminated; ++i)
362 {
363 int cyclelength;
364
365 /* get indices of variables in current cycle */
366 for (j = 0; j < cycledecomposition[i][0]; ++ j)
367 {
368 var = vars[cycledecomposition[i][j + 1]];
369
370 if ( SCIPvarIsNegated(var) )
371 {
372 terminated = TRUE;
373 break;
374 }
375
376 indicesincycle[j] = SCIPvarGetProbindex(var);
377 }
378
379 cyclelength = cycledecomposition[i][0];
380
381 /* iterate over constraints
382 *
383 * @todo Improve the check by sorting the constraints in the setppcconss array
384 * by type and number of contained variables. */
385 for (c = 0; c < nsetppcconss; ++c)
386 {
387 int nsetppcvars;
388 SCIP_VAR** setppcvars;
389 int varidx;
390 int nfound = 0;
391 int k;
392
393 /* check type */
394 if ( SCIPgetTypeSetppc(scip, setppcconss[c]) == SCIP_SETPPCTYPE_COVERING )
395 continue;
397
398 /* get set packing/partitioning variables */
399 nsetppcvars = SCIPgetNVarsSetppc(scip, setppcconss[c]);
400
401 /* skip empty constraints (might not have been removed by presolving yet) */
402 if ( nsetppcvars == 0 )
403 continue;
404 assert( nsetppcvars > 0 );
405
406 setppcvars = SCIPgetVarsSetppc(scip, setppcconss[c]);
407 assert( setppcvars != NULL );
408
409 /* check whether all variables of the cycle are contained in setppc constraint */
410 for (j = 0; j < nsetppcvars && nfound < cyclelength; ++j)
411 {
412 var = setppcvars[j];
413
414 if ( SCIPvarIsNegated(var) )
415 continue;
416
418
419 for (k = 0; k < cyclelength; ++k)
420 {
421 if ( varidx == indicesincycle[k] )
422 {
423 ++nfound;
424 break;
425 }
426 }
427 }
428 assert( nfound <= cyclelength );
429
430 if ( nfound == cyclelength )
431 break;
432 }
433
434 /* row is not contained in a set packing/partitioning constraint */
435 if ( c >= nsetppcconss )
436 *upgrade = FALSE;
437 }
438
439 if ( *upgrade )
440 {
441 (*consdata)->ncycles = ncycles;
442 (*consdata)->cycledecomposition = cycledecomposition;
443 (*consdata)->ndescentpoints = ndescentpoints;
444 (*consdata)->descentpoints = descentpoints;
445 SCIPdebugMsg(scip, "added monotone PP symresack.\n");
446
447 SCIPfreeBufferArray(scip, &indicesincycle);
448 SCIPfreeBufferArray(scip, &covered);
449 }
450 else
451 {
452 SCIPfreeBlockMemoryArray(scip, &descentpoints, ndescentpoints);
453 SCIPfreeBufferArray(scip, &indicesincycle);
454 SCIPfreeBufferArray(scip, &covered);
455 for (i = 0; i < ncycles; ++i)
456 {
457 SCIPfreeBlockMemoryArray(scip, &cycledecomposition[i], nvars + 1);
458 }
459 SCIPfreeBlockMemoryArray(scip, &cycledecomposition, ncycles);
460 }
461
462 return SCIP_OKAY;
463}
464
465
466/** creates symresack constraint data
467 *
468 * If the input data contains non-binary variables or fixed
469 * points, we delete these variables in a preprocessing step.
470 */
471static
473 SCIP* scip, /**< SCIP data structure */
474 SCIP_CONSHDLR* conshdlr, /**< symresack constraint handler */
475 SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
476 SCIP_VAR*const* inputvars, /**< input variables of the constraint handler */
477 int inputnvars, /**< input number of variables of the constraint handler*/
478 int* inputperm, /**< input permutation of the constraint handler */
479 SCIP_Bool ismodelcons /**< whether the symresack is a model constraint */
480 )
481{
482 SCIP_CONSHDLRDATA* conshdlrdata;
483 SCIP_VAR** vars;
484 SCIP_Bool upgrade;
485 int* indexcorrection;
486 int* invperm;
487 int* perm;
488 int naffectedvariables;
489 int i;
490 int j = 0;
491
492 assert( consdata != NULL );
493 assert( conshdlr != NULL );
494
496
497 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
498
499#ifdef SCIP_DEBUG
500 (*consdata)->debugcnt = 0;
501#endif
502
503 (*consdata)->ndescentpoints = 0;
504 (*consdata)->descentpoints = NULL;
505 (*consdata)->ismodelcons = ismodelcons;
506
507 /* count the number of binary variables which are affected by the permutation */
508 SCIP_CALL( SCIPallocBufferArray(scip, &indexcorrection, inputnvars) );
509 indexcorrection[0] = -1;
510 for (i = 0; i < inputnvars; ++i)
511 {
512 if ( inputperm[i] != i && SCIPvarIsBinary(inputvars[i]) )
513 {
514 if ( i == 0 )
515 indexcorrection[i] = 0;
516 else
517 indexcorrection[i] = indexcorrection[i - 1] + 1;
518 }
519 else
520 {
521 if ( i > 0 )
522 indexcorrection[i] = indexcorrection[i - 1];
523 }
524 }
525 naffectedvariables = indexcorrection[inputnvars - 1] + 1;
526
527 (*consdata)->nvars = naffectedvariables;
528
529 /* Stop if we detect that the permutation fixes each binary point. */
530 if ( naffectedvariables == 0 )
531 {
532 SCIPfreeBufferArrayNull(scip, &indexcorrection);
533
534 (*consdata)->vars = NULL;
535 (*consdata)->perm = NULL;
536 (*consdata)->invperm = NULL;
537 (*consdata)->ppupgrade = FALSE;
538 (*consdata)->ncycles = 0;
539 (*consdata)->cycledecomposition = NULL;
540 return SCIP_OKAY;
541 }
542
543 /* remove fixed points from permutation representation */
544 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &vars, naffectedvariables) );
545 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &perm, naffectedvariables) );
546 for (i = 0; i < inputnvars; ++i)
547 {
548 if ( i == 0 )
549 {
550 if ( indexcorrection[i] > -1 )
551 {
552 vars[j] = inputvars[i];
553 perm[j++] = indexcorrection[inputperm[i]];
554 }
555 }
556 else
557 {
558 if ( indexcorrection[i] > indexcorrection[i - 1] )
559 {
560 vars[j] = inputvars[i];
561 perm[j++] = indexcorrection[inputperm[i]];
562 }
563 }
564 }
565 SCIPfreeBufferArrayNull(scip, &indexcorrection);
566
567 (*consdata)->vars = vars;
568 (*consdata)->perm = perm;
569
570 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &invperm, naffectedvariables) );
571 for (i = 0; i < naffectedvariables; ++i)
572 {
573 SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[i]) );
574 invperm[perm[i]] = i;
575 }
576 (*consdata)->invperm = invperm;
577
578 /* check for upgrade to packing/partitioning symresacks*/
579 conshdlrdata = SCIPconshdlrGetData(conshdlr);
580 upgrade = FALSE;
581 if ( conshdlrdata->checkppsymresack )
582 {
583 SCIP_CALL( packingUpgrade(scip, consdata, perm, vars, naffectedvariables, conshdlrdata->checkmonotonicity, &upgrade) );
584 }
585
586 (*consdata)->ppupgrade = upgrade;
587
588 /* get transformed variables, if we are in the transformed problem */
589 if ( SCIPisTransformed(scip) )
590 {
591 /* Make sure that all variables cannot be multiaggregated (cannot be handled by cons_symresack, since one cannot
592 * easily eliminate single variables from a symresack constraint. */
593 for (i = 0; i < naffectedvariables; ++i)
594 {
595 SCIP_CALL( SCIPgetTransformedVar(scip, (*consdata)->vars[i], &(*consdata)->vars[i]) );
596 SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->vars[i]) );
597 }
598 }
599
600 return SCIP_OKAY;
601}
602
603
604/** generate initial LP cut
605 *
606 * We generate the ordering inequality for the pair \f$(1, \gamma^{-1}(1))\f$, i.e.,
607 * the inequality \f$-x_{1} + x_{\gamma^{-1}(1)} \leq 0\f$. This inequality is valid,
608 * because we guaranteed in a preprocessing step that all variables are binary.
609 *
610 * Furthermore, we add facet inequalities of packing/partitioning symresacks if
611 * we deal with packing/partitioning symresacks.
612 */
613static
615 SCIP* scip, /**< SCIP pointer */
616 SCIP_CONS* cons, /**< constraint */
617 SCIP_Bool checkmonotonicity, /**< has it been checked whether permutation is monotone for packing/partitioning symresacks? */
618 SCIP_Bool* infeasible /**< pointer to store whether we detected infeasibility */
619 )
620{
621 SCIP_CONSDATA* consdata;
622 SCIP_VAR** vars;
623 SCIP_ROW* row;
624 int nvars;
625#ifdef SCIP_DEBUG
626 char name[SCIP_MAXSTRLEN];
627#endif
628 int i;
629 int j;
630 int k;
631
632 assert( scip != NULL );
633 assert( cons != NULL );
634 assert( infeasible != NULL );
635
636 *infeasible = FALSE;
637
638 consdata = SCIPconsGetData(cons);
639 assert( consdata != NULL );
640
641 nvars = consdata->nvars;
642
643 /* avoid stupid problems */
644 if ( nvars <= 1 )
645 return SCIP_OKAY;
646
647 assert( consdata->vars != NULL );
648 vars = consdata->vars;
649
650 /* there are no fixed points */
651 assert( consdata->invperm[0] != 0 );
652
653 /* add ordering inequality */
654#ifdef SCIP_DEBUG
655 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "symresack_init_%s", SCIPconsGetName(cons));
656 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), 0.0, FALSE, FALSE, TRUE) );
657#else
658 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, "", -SCIPinfinity(scip), 0.0, FALSE, FALSE, TRUE) );
659#endif
660 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[0], -1.0) );
661 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[consdata->invperm[0]], 1.0) );
662
663 SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
664
665 SCIP_CALL( SCIPreleaseRow(scip, &row) );
666
667 /* check whether we have a packing/partioning symresack */
668 if ( consdata->ppupgrade && ! *infeasible )
669 {
670 if ( checkmonotonicity )
671 {
672 SCIP_VAR** varsincons;
673 SCIP_Real* coeffs;
674 int** cycledecomposition;
675 int ncycles;
676 int nvarsincons;
677 int nvarsincycle;
678 int firstelemincycle;
679
680 ncycles = consdata->ncycles;
681 cycledecomposition = consdata->cycledecomposition;
682
683 SCIP_CALL( SCIPallocBufferArray(scip, &varsincons, nvars) );
685
686 coeffs[0] = 1.0;
687
688 /* add packing/partitioning symresack constraints */
689 for (i = 0; i < ncycles; ++i)
690 {
691 assert( cycledecomposition[i][0] > 0 );
692
693 nvarsincycle = cycledecomposition[i][0];
694 varsincons[0] = vars[cycledecomposition[i][nvarsincycle]];
695 firstelemincycle = cycledecomposition[i][1];
696
697 assert( firstelemincycle == consdata->perm[cycledecomposition[i][nvarsincycle]] );
698
699 nvarsincons = 1;
700
701 /* add variables of other cycles to the constraint */
702 for (j = 0; j < i; ++j)
703 {
704 nvarsincycle = cycledecomposition[j][0];
705 for (k = 1; k <= nvarsincycle; ++k)
706 {
707 if ( cycledecomposition[j][k] < firstelemincycle )
708 {
709 varsincons[nvarsincons] = vars[cycledecomposition[j][k]];
710 coeffs[nvarsincons++] = -1.0;
711 }
712 else
713 continue;
714 }
715 }
716
717#ifdef SCIP_DEBUG
718 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "ppSymresack_%d_%s", i, SCIPconsGetName(cons));
719 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), 0.0, FALSE, FALSE, TRUE) );
720#else
721 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, "", -SCIPinfinity(scip), 0.0, FALSE, FALSE, TRUE) );
722#endif
723 SCIP_CALL( SCIPaddVarsToRow(scip, row, nvarsincons, varsincons, coeffs) );
724
725 SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
726 SCIP_CALL( SCIPreleaseRow(scip, &row) );
727
728 if ( *infeasible )
729 break;
730 }
731
732 SCIPfreeBufferArray(scip, &coeffs);
733 SCIPfreeBufferArray(scip, &varsincons);
734 }
735 else
736 {
737 SCIP_Real* coeffs;
738 SCIP_VAR** varsincons;
739 int* imgdescentpoints;
740 int* descentpoints;
741 int* perm;
742 int ndescentpoints;
743 int lastascent = 0;
744 int newlastascent = 0;
745 int nvarsincons = 1;
746
747 descentpoints = consdata->descentpoints;
748 ndescentpoints = consdata->ndescentpoints;
749 perm = consdata->perm;
750
751 assert( descentpoints != NULL );
752 assert( ndescentpoints > 0 );
753 assert( perm != NULL );
754 assert( vars != NULL );
755 assert( nvars > 0 );
756
757 SCIP_CALL( SCIPallocBufferArray(scip, &imgdescentpoints, ndescentpoints) );
758
759 /* get images of descentpoints */
760 for (j = 0; j < ndescentpoints; ++j)
761 imgdescentpoints[j] = perm[descentpoints[j]];
762
763 /* sort descent points increasingly w.r.t. the corresponding image */
764 SCIPsortIntInt(imgdescentpoints, descentpoints, ndescentpoints);
765
766 /* iteratively generate coefficient vector: the first entry is the descent point j and the remaining entries
767 * are the corresponding ascent points less than perm[j]
768 */
771 coeffs[0] = 1.0;
772 for (j = 0; j < ndescentpoints; ++j)
773 {
774 varsincons[0] = vars[descentpoints[j]];
775 for (i = lastascent; i < imgdescentpoints[j]; ++i)
776 {
777 if ( perm[i] > i )
778 {
779 coeffs[nvarsincons] = -1.0;
780 varsincons[nvarsincons++] = vars[i];
781 newlastascent = i;
782 }
783 }
784 lastascent = newlastascent;
785
786#ifdef SCIP_DEBUG
787 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "ppSymresack_%d_%s", j, SCIPconsGetName(cons));
788 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), 0.0, FALSE, FALSE, TRUE) );
789#else
790 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, "", -SCIPinfinity(scip), 0.0, FALSE, FALSE, TRUE) );
791#endif
792 SCIP_CALL( SCIPaddVarsToRow(scip, row, nvarsincons, varsincons, coeffs) );
793
794 SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
795 SCIP_CALL( SCIPreleaseRow(scip, &row) );
796
797 if ( *infeasible )
798 break;
799 }
800
801 SCIPfreeBufferArray(scip, &varsincons);
802 SCIPfreeBufferArray(scip, &coeffs);
803 SCIPfreeBufferArray(scip, &imgdescentpoints);
804 }
805 }
806
807 return SCIP_OKAY;
808}
809
810
811/** Determines if a vector with additional fixings could exist that is lexicographically larger than its image.
812 *
813 * Given a vector of variables, a permutation, and a set of additional (virtual) fixings.
814 * If a vector adhering to the local variable bounds (local fixings) and to the virtual fixings exists,
815 * then infeasible is FALSE, otherwise TRUE.
816 */
817static
819 SCIP* scip, /**< SCIP pointer */
820 SCIP_VAR** vars, /**< array of variables affected by permutation */
821 int* invperm, /**< inverse of permutation */
822 int nvars, /**< number of variables */
823 int start, /**< at which position to start (assuming previous positions are equal) */
824 int* tempfixings, /**< array with at entry i the virtual fixing of variable vars[i] */
825 int* tempfixentries, /**< the entries i that are virtually fixed until numfixentriesinit */
826 int numfixentriesinit, /**< the number of virtually fixed entries */
827 SCIP_Bool* infeasible, /**< pointer to store whether infeasibility is detected in these fixings */
828 int* infeasibleentry /**< pointer to store at which entry a (0, 1) pattern is found */
829 )
830{
831 SCIP_VAR* var1;
832 SCIP_VAR* var2;
833 int var1fix;
834 int var2fix;
835
836 int i;
837 int numfixentries;
838
839 /* avoid trivial problems */
840 if ( nvars < 2 )
841 return SCIP_OKAY;
842
843 assert( scip != NULL );
844 assert( vars != NULL );
845 assert( invperm != NULL );
846 assert( tempfixings != NULL );
847 assert( tempfixentries != NULL );
848 assert( infeasible != NULL );
849
850 /* A counter for how many virtual fixings we have. */
851 numfixentries = numfixentriesinit;
852
853 *infeasible = FALSE;
854
855 for (i = start; i < nvars; ++i)
856 {
857 /* there are no fixed points */
858 assert( invperm[i] != i );
859
860 /* get variables of first and second column */
861 var1 = vars[i];
862 var2 = vars[invperm[i]];
863
864 assert( var1 != NULL );
865 assert( var2 != NULL );
866
867 /* Get virtual fixing of variable in left column */
868 var1fix = tempfixings[i];
869 if ( var1fix == NOINIT )
870 {
871 if ( SCIPvarGetUbLocal(var1) < 0.5 )
872 {
873 var1fix = FIXED0;
874 assert( SCIPvarGetLbLocal(var1) <= 0.5 );
875 }
876 else if ( SCIPvarGetLbLocal(var1) > 0.5 )
877 var1fix = FIXED1;
878 else
879 var1fix = UNFIXED;
880 }
881 assert( var1fix != NOINIT );
882
883 /* Get virtual fixing of variable in right column */
884 var2fix = tempfixings[invperm[i]];
885 if ( var2fix == NOINIT )
886 {
887 if ( SCIPvarGetUbLocal(var2) < 0.5 )
888 {
889 var2fix = FIXED0;
890 assert( SCIPvarGetLbLocal(var2) <= 0.5 );
891 }
892 else if ( SCIPvarGetLbLocal(var2) > 0.5 )
893 var2fix = FIXED1;
894 else
895 var2fix = UNFIXED;
896 }
897 assert( var2fix != NOINIT );
898
899 /* Encounter one of (_, _), (_, 0), (1, _), (1, 0). In all cases (1, 0) can be constructed. Thus feasible. */
900 if ( var1fix != FIXED0 && var2fix != FIXED1 )
901 break;
902 /* Encounter (0, 1). Infeasible. */
903 else if ( var1fix == FIXED0 && var2fix == FIXED1 )
904 {
905 *infeasible = TRUE;
906 *infeasibleentry = i;
907 break;
908 }
909 /* Encounter (0, _). Virtually fix var2 to 0. */
910 else if ( var1fix == FIXED0 && var2fix == UNFIXED )
911 {
912 tempfixings[invperm[i]] = FIXED0;
913 /* Mark that we have fixed invperm[i]. */
914 tempfixentries[numfixentries++] = invperm[i];
915 }
916 /* Encounter (_, 1). Virtually fix var1 to 1. */
917 else if(var1fix == UNFIXED && var2fix == FIXED1 )
918 {
919 tempfixings[i] = FIXED0;
920 /* Mark that we have fixed invperm[i]. */
921 tempfixentries[numfixentries++] = i;
922 }
923 /* Remaining cases are (0, 0) and (1, 1). In both cases: continue. */
924 }
925
926 /* Undo virtual fixings made in this function */
927 for (i = numfixentriesinit; i < numfixentries; ++i)
928 {
929 tempfixings[tempfixentries[i]] = NOINIT;
930 tempfixentries[i] = 0;
931 }
932
933 return SCIP_OKAY;
934}
935
936
937/** perform propagation of symresack constraint */
938static
940 SCIP* scip, /**< SCIP pointer */
941 SCIP_CONS* cons, /**< constraint to be propagated */
942 SCIP_Bool* infeasible, /**< pointer to store whether it was detected that the node is infeasible */
943 int* ngen /**< pointer to store number of generated bound strengthenings */
944 )
945{
946 SCIP_CONSDATA* consdata;
947 SCIP_VAR** vars;
948 int* invperm;
949 int nvars;
950 int i;
951 int r;
952 SCIP_VAR* var1;
953 SCIP_VAR* var2;
954 int var1fix;
955 int var2fix;
956 SCIP_Bool tightened;
957 SCIP_Bool peekinfeasible;
958 int peekinfeasibleentry;
959 int* tempfixings;
960 int* tempfixentries;
961
962 assert( scip != NULL );
963 assert( cons != NULL );
964 assert( infeasible != NULL );
965 assert( ngen != NULL );
966
967 SCIPdebugMsg(scip, "Propagating variables of constraint <%s>.\n", SCIPconsGetName(cons));
968
969 *ngen = 0;
970 *infeasible = FALSE;
971
972 /* get data of constraint */
973 consdata = SCIPconsGetData(cons);
974 assert( consdata != NULL );
975 nvars = consdata->nvars;
976
977 /* avoid trivial problems */
978 if ( nvars < 2 )
979 return SCIP_OKAY;
980
981 assert( consdata->vars != NULL );
982 assert( consdata->invperm != NULL );
983 vars = consdata->vars;
984 invperm = consdata->invperm;
985
986 /* loop through all variables */
987 for (i = 0; i < nvars; ++i)
988 {
989 /* there are no fixed points */
990 assert( invperm[i] != i );
991
992 /* get variables of first and second column */
993 var1 = vars[i];
994 var2 = vars[invperm[i]];
995 assert( var1 != NULL );
996 assert( var2 != NULL );
997
998 /* Get the fixing status of the left column variable var1 */
999 if ( SCIPvarGetUbLocal(var1) < 0.5 )
1000 {
1001 var1fix = FIXED0;
1002 assert( SCIPvarGetLbLocal(var1) <= 0.5 );
1003 }
1004 else if ( SCIPvarGetLbLocal(var1) > 0.5 )
1005 var1fix = FIXED1;
1006 else
1007 var1fix = UNFIXED;
1008
1009 /* Get the fixing status of the right column variable var2 */
1010 if ( SCIPvarGetUbLocal(var2) < 0.5 )
1011 {
1012 var2fix = FIXED0;
1013 assert( SCIPvarGetLbLocal(var2) <= 0.5 );
1014 }
1015 else if ( SCIPvarGetLbLocal(var2) > 0.5 )
1016 var2fix = FIXED1;
1017 else
1018 var2fix = UNFIXED;
1019
1020 /* Encounter one of (_, _), (_, 0), (1, _), (1, 0). Check if (1, 1) or (0, 0) are possible, otherwise fix. */
1021 if ( var1fix != FIXED0 && var2fix != FIXED1 )
1022 {
1023 assert( SCIPvarGetUbLocal(var1) > 0.5 );
1024 assert( SCIPvarGetLbLocal(var2) < 0.5 );
1025
1026 SCIPdebugMsg(scip, "Check variable pair (%d,%d).\n", i, invperm[i]);
1027 SCIPdebugMsg(scip, " -> node is feasible (could set pair to (1,0) and every earlier pair is constant).\n");
1028
1029 if ( var1fix == UNFIXED || var2fix == UNFIXED )
1030 {
1031 /* Create arrays tempfixings and tempfixentries to store virtual fixings. */
1032 SCIP_CALL( SCIPallocCleanBufferArray(scip, &tempfixings, nvars) );
1033 SCIP_CALL( SCIPallocCleanBufferArray(scip, &tempfixentries, nvars) );
1034
1035 if ( var1fix == UNFIXED )
1036 {
1037 assert( SCIPvarGetLbLocal(var1) < 0.5 );
1038
1039 /* Peek whether a lexicographical larger-or-equal vector can be created with var1 fixed to 0 */
1040 SCIPdebugMsg(scip, " -> First entry is not fixed. Check if 0 is feasible.\n");
1041 tempfixings[i] = FIXED0;
1042 tempfixentries[0] = i;
1043 SCIP_CALL( checkFeasible(scip, vars, invperm, nvars, i, tempfixings, tempfixentries, 1,
1044 &peekinfeasible, &peekinfeasibleentry) );
1045
1046 if ( peekinfeasible )
1047 {
1048 /* No feasible vector exists with var1 set to 0, so it must be a 1-fixing. */
1049 SCIPdebugMsg(scip, " -> First entry is not fixed. 0 is not feasible. Fixing to 1.\n");
1050 SCIP_CALL( SCIPinferVarLbCons(scip, var1, 1.0, cons, i + nvars * peekinfeasibleentry,
1051 FALSE, infeasible, &tightened) ); /*lint !e713*/
1052 assert( ! *infeasible );
1053
1054 if ( tightened )
1055 ++(*ngen);
1056 }
1057
1058 tempfixings[i] = NOINIT;
1059 tempfixentries[0] = 0;
1060 }
1061
1062 if ( var2fix == UNFIXED )
1063 {
1064 assert( SCIPvarGetUbLocal(var2) > 0.5 );
1065
1066 /* Peek whether a lexicographical larger-or-equal vector can be created with var2 fixed to 1 */
1067 SCIPdebugMsg(scip, " -> Second entry is not fixed. Check if 1 is feasible.\n");
1068 tempfixings[invperm[i]] = FIXED1;
1069 tempfixentries[0] = invperm[i];
1070 SCIP_CALL( checkFeasible(scip, vars, invperm, nvars, i, tempfixings, tempfixentries, 1,
1071 &peekinfeasible, &peekinfeasibleentry) );
1072
1073 if ( peekinfeasible )
1074 {
1075 /* No feasible vector exists with var2 set to 1, so it must be a 1-fixing. */
1076 SCIPdebugMsg(scip, " -> Second entry is not fixed. 1 is not feasible. Fixing to 0.\n");
1077 SCIP_CALL( SCIPinferVarUbCons(scip, var2, 0.0, cons, i + nvars * peekinfeasibleentry,
1078 FALSE, infeasible, &tightened) ); /*lint !e713*/
1079 assert( ! *infeasible );
1080
1081 if ( tightened )
1082 ++(*ngen);
1083 }
1084
1085 tempfixings[invperm[i]] = NOINIT;
1086 tempfixentries[0] = 0;
1087 }
1088
1089 SCIPfreeCleanBufferArray(scip, &tempfixentries);
1090 SCIPfreeCleanBufferArray(scip, &tempfixings);
1091 }
1092
1093 /* Can stop here, because this row can become (1, 0). Therefore all next rows can take arbitrary values. */
1094 break;
1095 }
1096 /* Encounter (0, 1): If first part of variable pair fixed to 0 and second part is fixed to 1 */
1097 else if ( var1fix == FIXED0 && var2fix == FIXED1 )
1098 {
1099 SCIPdebugMsg(scip, "Check variable pair (%d,%d).\n", i, invperm[i]);
1100
1101 SCIPdebugMsg(scip, " -> node infeasible (pair was fixed to (0,1) but there was no pair of type (1,0) before) ---> lexicographical order violated, infeasible.\n");
1102
1103 /* perform conflict analysis */
1105 {
1107
1108 for (r = 0; r <= i; ++r)
1109 {
1110 /* there are no fixed points */
1111 assert( invperm[r] != r );
1112
1114 SCIP_CALL( SCIPaddConflictBinvar(scip, vars[invperm[r]]) );
1115 }
1116
1118 }
1119
1120 *infeasible = TRUE;
1121 break;
1122 }
1123 /* Encounter (0, _): Fix second part to 0 */
1124 else if ( var1fix == FIXED0 && var2fix != FIXED0 )
1125 {
1126 assert( SCIPvarGetUbLocal(var1) < 0.5 );
1127 assert( SCIPvarGetLbLocal(var2) < 0.5 );
1128 assert( SCIPvarGetUbLocal(var2) > 0.5 );
1129
1130 SCIPdebugMsg(scip, "Check variable pair (%d,%d).\n", i, invperm[i]);
1131
1132 assert( SCIPvarGetLbLocal(var2) < 0.5 );
1133 SCIP_CALL( SCIPinferVarUbCons(scip, var2, 0.0, cons, i, FALSE, infeasible, &tightened) ); /*lint !e713*/
1134 assert( ! *infeasible );
1135
1136 if ( tightened )
1137 ++(*ngen);
1138 }
1139 /* Encounter (_, 1): fix first part to 1 */
1140 else if ( var1fix != FIXED1 && var2fix == FIXED1 )
1141 {
1142 assert( SCIPvarGetLbLocal(var1) < 0.5 );
1143 assert( SCIPvarGetUbLocal(var1) > 0.5 );
1144 assert( SCIPvarGetLbLocal(var2) > 0.5 );
1145
1146 SCIPdebugMsg(scip, "Check variable pair (%d,%d).\n", i, invperm[i]);
1147
1148 assert( SCIPvarGetUbLocal(var1) > 0.5 );
1149 SCIP_CALL( SCIPinferVarLbCons(scip, var1, 1.0, cons, i, FALSE, infeasible, &tightened) ); /*lint !e713*/
1150 assert( ! *infeasible );
1151
1152 if ( tightened )
1153 ++(*ngen);
1154 }
1155 /* Remaining cases are (0, 0) and (1, 1). In these cases we can continue! */
1156 }
1157
1158 return SCIP_OKAY;
1159}
1160
1161
1162/** add symresack cover inequality */
1163static
1165 SCIP* scip, /**< SCIP pointer */
1166 SCIP_CONS* cons, /**< constraint */
1167 int nvars, /**< number of variables */
1168 SCIP_VAR** vars, /**< variables */
1169 int* coeffs, /**< coefficient vector of inequality to be added */
1170 SCIP_Real rhs, /**< right-hand side of inequality to be added */
1171 SCIP_Bool* infeasible /**< pointer to store whether we detected infeasibility */
1172 )
1173{
1174 SCIP_ROW* row;
1175 int i;
1176#ifdef SCIP_DEBUG
1177 SCIP_CONSDATA* consdata;
1178 char name[SCIP_MAXSTRLEN];
1179#endif
1180
1181 assert( scip != NULL );
1182 assert( cons != NULL );
1183 assert( nvars > 0 );
1184 assert( vars != NULL );
1185 assert( coeffs != NULL );
1186 assert( infeasible != NULL );
1187
1188 *infeasible = FALSE;
1189
1190#ifdef SCIP_DEBUG
1191 consdata = SCIPconsGetData(cons);
1192 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "symresack_cover_%s_%d", SCIPconsGetName(cons), consdata->debugcnt);
1193 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), rhs, FALSE, FALSE, TRUE) );
1194 ++consdata->debugcnt;
1195#else
1196 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, "", -SCIPinfinity(scip), rhs, FALSE, FALSE, TRUE) );
1197#endif
1199
1200 for (i = 0; i < nvars; ++i)
1201 {
1202 if ( coeffs[i] == 1 || coeffs[i] == -1 )
1203 {
1204 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[i], (SCIP_Real) coeffs[i]) );
1205 }
1206 }
1208 SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
1209 SCIP_CALL( SCIPreleaseRow(scip, &row) );
1210
1211 return SCIP_OKAY;
1212}
1213
1214
1215/** Maximize a linear function on a "strict" symresack,
1216 * that is a symresack where we do not allow the solution x = gamma(x).
1217 */
1218static
1220 SCIP* scip, /**< SCIP pointer */
1221 int nvars, /**< number of variables in symresack */
1222 SCIP_Real* objective, /**< the objective vector */
1223 int* perm, /**< the permutation (without fixed points) as an array */
1224 int* invperm, /**< the inverse permutation as an array */
1225 int* maxcrit, /**< pointer to the critical entry where optimality is found at */
1226 SCIP_Real* maxsoluval /**< pointer to store the optimal objective value */
1227 )
1228{
1229 /* The maximal objective in every iteration. */
1230 SCIP_Real tmpobj;
1231 /* The new value of componentobj when combining two components. */
1232 SCIP_Real tmpnewcompobj;
1233 /* helperobj is the sum of all positive objective-sums for all components. */
1234 SCIP_Real helperobj = 0.0;
1235
1236 int crit;
1237 int critinv;
1238 int i;
1239
1240 /* For every vertex of degree < 2 we maintain componentends and componentobj. */
1241 int* componentends;
1242 SCIP_Real* componentobj;
1243
1244 assert( scip != NULL );
1245 assert( nvars > 0 );
1246 assert( objective != NULL );
1247 assert( perm != NULL );
1248 assert( invperm != NULL );
1249 assert( maxcrit != NULL );
1250 assert( maxsoluval != NULL );
1251
1252 /* The current best known critical entry and objective */
1253 *maxcrit = -1;
1254 *maxsoluval = -SCIP_DEFAULT_INFINITY;
1255
1256 SCIP_CALL( SCIPallocBufferArray(scip, &componentends, nvars) );
1257 SCIP_CALL( SCIPallocBufferArray(scip, &componentobj, nvars) );
1258
1259 /* Initialization: Every entry is a component in the graph,
1260 * having the corresponding objective
1261 */
1262 for (i = 0; i < nvars; ++i)
1263 {
1264 componentends[i] = i;
1265 componentobj[i] = objective[i];
1266 if ( SCIPisGT(scip, objective[i], 0.0) )
1267 helperobj += objective[i];
1268 }
1269
1270 /* Iterate over all critical rows, and of the graph maintain the components on the vertices of degree < 2. */
1271 for (crit = 0; crit < nvars; ++crit)
1272 {
1273 critinv = invperm[crit];
1274
1275 /* Do not allow fixed points. */
1276 assert( crit != critinv );
1277
1278 /* If the other end of the component of crit is critinv, then crit cannot be a critical entry. */
1279 if ( componentends[crit] == critinv )
1280 continue;
1281
1282 /* Compute objective for crit as critical entry. Update if it is better than the best found objective */
1283 tmpobj = helperobj;
1284 if ( SCIPisLT(scip, componentobj[crit], 0.0) )
1285 tmpobj += componentobj[crit];
1286 if ( SCIPisGT(scip, componentobj[critinv], 0.0) )
1287 tmpobj -= componentobj[critinv];
1288 if ( SCIPisGT(scip, tmpobj, *maxsoluval) )
1289 {
1290 *maxsoluval = tmpobj;
1291 *maxcrit = crit;
1292 }
1293
1294 /* Update helperobj */
1295 tmpnewcompobj = componentobj[crit] + componentobj[critinv];
1296 if ( SCIPisGT(scip, componentobj[crit], 0.0) )
1297 helperobj -= componentobj[crit];
1298 if ( SCIPisGT(scip, componentobj[critinv], 0.0) )
1299 helperobj -= componentobj[critinv];
1300 if ( SCIPisGT(scip, tmpnewcompobj, 0.0) )
1301 helperobj += tmpnewcompobj;
1302
1303 /* Update the objective of a component */
1304 componentobj[componentends[crit]] = tmpnewcompobj;
1305 componentobj[componentends[critinv]] = tmpnewcompobj;
1306
1307 /* Connect the endpoints of the newly created path */
1308 if ( componentends[crit] == crit )
1309 {
1310 componentends[crit] = componentends[critinv];
1311 componentends[componentends[critinv]] = crit;
1312 }
1313 else
1314 {
1315 componentends[componentends[crit]] = componentends[critinv];
1316 componentends[componentends[critinv]] = componentends[crit];
1317 }
1318
1319 /* Early termination criterion. helperobj is upper bound to tmpobj for every next iteration,
1320 * so if helperobj <= maxsoluval then we can terminate earlier.
1321 */
1322 if ( SCIPisGE(scip, *maxsoluval, helperobj) )
1323 break;
1324 }
1325
1326 /* It is always possible to make the first entry critical. */
1327 assert( *maxcrit >= 0 );
1328
1329 SCIPfreeBufferArray(scip, &componentobj);
1330 SCIPfreeBufferArray(scip, &componentends);
1331
1332 return SCIP_OKAY;
1333}
1334
1335
1336/** For a symresack, determine a maximizer for optimizing linear function
1337 * over a symresack, where the critical entry is fixed.
1338 */
1339static
1341 SCIP* scip, /**< SCIP pointer */
1342 int nvars, /**< number of variables in symresack */
1343 SCIP_Real* objective, /**< the objective vector */
1344 int* perm, /**< the permutation (without fixed points) as an array */
1345 int* invperm, /**< the inverse permutation as an array */
1346 int crit, /**< critical entry where optimality is found at */
1347 int* maxsolu /**< pointer to the optimal objective array */
1348 )
1349{
1350 /* Compute to which components all entries belong. */
1351 int* entrycomponent;
1352 SCIP_Real* componentobjective;
1353
1354 int i;
1355 int c;
1356
1357 assert( scip != NULL );
1358 assert( nvars > 0 );
1359 assert( objective != NULL );
1360 assert( perm != NULL );
1361 assert( invperm != NULL );
1362 assert( maxsolu != NULL );
1363 assert( crit >= 0 );
1364 assert( crit <= nvars );
1365
1366 SCIP_CALL( SCIPallocBufferArray(scip, &entrycomponent, nvars) );
1367 SCIP_CALL( SCIPallocBufferArray(scip, &componentobjective, nvars) );
1368
1369 /* Initially: Everything forms its own component */
1370 for (i = 0; i < nvars; ++i)
1371 {
1372 entrycomponent[i] = i;
1373 componentobjective[i] = objective[i];
1374 }
1375 for (i = 0; i < crit; ++i)
1376 {
1377 /* The graph with arcs {i, invperm[i]} if i < c is a collection of paths, cycles and singletons.
1378 * Label the vertices to the lowest entry in the component, and store the value of that in this component.
1379 * Every inner while-loop labels one new vertex per iteration, and a vertex is relabeled exactly once.
1380 */
1381 if ( entrycomponent[i] < i )
1382 {
1383 /* This entry is already included in a component. */
1384 continue;
1385 }
1386
1387 /* Follow the path forward: Take edges {c, invperm[c]} until c >= crit, or a cycle is found. */
1388 c = i;
1389 while( c < crit )
1390 {
1391 /* c < crit, so edge {c, invperm[c]} exists. Label invperm[c] as part of component of i */
1392 c = invperm[c];
1393
1394 /* Stop if we find a cycle. */
1395 if ( entrycomponent[c] != c )
1396 break;
1397
1398 entrycomponent[c] = i;
1399 componentobjective[i] += objective[c];
1400 }
1401
1402 /* Follow the path backward: Take edges {c, perm[c]} until perm[c] >= crit, or a cycle is found. */
1403 c = perm[i];
1404 while( c < crit )
1405 {
1406 /* c < crit, so edge {c, invperm[c]} exists. Label c as part of component of i */
1407
1408 /* Stop if we find a cycle. */
1409 if ( entrycomponent[c] != c )
1410 break;
1411
1412 entrycomponent[c] = i;
1413 componentobjective[i] += objective[c];
1414 /* For next iteration: We do another step back */
1415 c = perm[c];
1416 }
1417 }
1418
1419 /* Now fill the objective vector.
1420 * For the component containing crit, set the value to 1.
1421 * For the component contraining invperm[crit], set the value to 0.
1422 * For the other components, set the value to 1 if the objective sum is positive.
1423 * Otherwise to 0.
1424 */
1425 for (i = 0; i < nvars; ++i)
1426 {
1427 if ( entrycomponent[i] == entrycomponent[crit] )
1428 maxsolu[i] = 1;
1429 else if ( entrycomponent[i] == entrycomponent[invperm[crit]] )
1430 maxsolu[i] = 0;
1431 else if ( SCIPisGT(scip, componentobjective[entrycomponent[i]], 0.0) )
1432 maxsolu[i] = 1;
1433 else
1434 maxsolu[i] = 0;
1435 }
1436
1437 SCIPfreeBufferArray(scip, &componentobjective);
1438 SCIPfreeBufferArray(scip, &entrycomponent);
1439
1440 return SCIP_OKAY;
1441}
1442
1443
1444/** separate symresack cover inequalities
1445 *
1446 * We currently do NOT enter cuts into the pool.
1447 */
1448static
1450 SCIP* scip, /**< SCIP pointer */
1451 SCIP_CONS* cons, /**< constraint */
1452 const SCIP_CONSDATA* consdata, /**< constraint data */
1453 SCIP_Real* vals, /**< solution values of variables */
1454 int* ngen, /**< pointer to store the number of separated covers */
1455 SCIP_Bool* infeasible /**< pointer to store whether we detected infeasibility */
1456 )
1457{
1458 SCIP_Real constobjective;
1459 SCIP_Real* sepaobjective;
1460 SCIP_Real maxsoluobj = 0.0;
1461 int* maxsolu;
1462 int* invperm;
1463 int* perm;
1464 int nvars;
1465 int maxcrit;
1466 int i;
1467
1468 *infeasible = FALSE;
1469 *ngen = 0;
1470
1471 assert( scip != NULL );
1472 assert( consdata != NULL );
1473
1474 /* we do not have to take care of trivial constraints */
1475 if ( consdata->nvars < 2 )
1476 return SCIP_OKAY;
1477
1478 assert( consdata->vars != NULL );
1479 assert( consdata->perm != NULL );
1480 assert( consdata->invperm != NULL );
1481 assert( infeasible != NULL );
1482 assert( ngen != NULL );
1483
1484 nvars = consdata->nvars;
1485 perm = consdata->perm;
1486 invperm = consdata->invperm;
1487
1488 /* initialize objective */
1489 SCIP_CALL( SCIPallocBufferArray(scip, &sepaobjective, nvars) );
1490
1491 constobjective = 1.0; /* constant part of separation objective */
1492 for (i = 0; i < nvars; ++i)
1493 {
1494 if ( i < perm[i] )
1495 sepaobjective[i] = - vals[i];
1496 else
1497 {
1498 sepaobjective[i] = 1.0 - vals[i];
1499 constobjective += vals[i] - 1.0;
1500 }
1501 }
1502
1503 /* allocate memory for temporary and global solution */
1505
1506 /* Find critical row of a maximally violated cover */
1507 SCIP_CALL( maximizeObjectiveSymresackStrict(scip, nvars, sepaobjective, perm, invperm, &maxcrit, &maxsoluobj) );
1508 assert( maxcrit >= 0 );
1509 SCIPdebugMsg(scip, "Critical row %d found; Computing maximally violated cover.\n", maxcrit);
1510 SCIP_CALL( maximizeObjectiveSymresackCriticalEntry(scip, nvars, sepaobjective, perm, invperm, maxcrit, maxsolu) );
1511
1512 /* Add constant to maxsoluobj to get the real objective */
1513 maxsoluobj += constobjective;
1514
1515 /* Check whether the separation objective is positive, i.e., a violated cover was found. */
1516 if ( SCIPisEfficacious(scip, maxsoluobj) )
1517 {
1518 /* Now add the cut. Reuse array maxsolu as coefficient vector for the constraint. */
1519 SCIP_Real rhs = -1.0;
1520 for (i = 0; i < nvars; ++i)
1521 {
1522 if ( i < perm[i] )
1523 maxsolu[i] = -maxsolu[i];
1524 else
1525 {
1526 if ( maxsolu[i] == 0 )
1527 rhs += 1.0;
1528 maxsolu[i] = 1 - maxsolu[i];
1529 }
1530 }
1531
1532 /* add cover inequality */
1533 SCIP_CALL( addSymresackInequality(scip, cons, nvars, consdata->vars, maxsolu, rhs, infeasible) );
1534
1535 if ( ! *infeasible )
1536 ++(*ngen);
1537 }
1538
1539 SCIPfreeBufferArrayNull(scip, &maxsolu);
1540 SCIPfreeBufferArrayNull(scip, &sepaobjective);
1541
1542 return SCIP_OKAY;
1543}
1544
1545
1546/** check whether solution is feasible for symresacks */
1547static
1549 SCIP* scip, /**< SCIP pointer */
1550 SCIP_CONS* cons, /**< constrained for which we check the solution */
1551 SCIP_SOL* sol, /**< solution to be checked */
1552 SCIP_RESULT* result, /**< pointer to store whether we detected infeasibility */
1553 SCIP_Bool printreason /**< whether reason for infeasibility should be printed */
1554 )
1555{
1556 SCIP_CONSDATA* consdata;
1557 SCIP_VAR** vars;
1558 int* invperm;
1559 int nvars;
1560 int i;
1561
1562 assert( cons != NULL );
1563 consdata = SCIPconsGetData(cons);
1564 assert( consdata != NULL);
1565
1566 /* we do not have to take care of trivial constraints */
1567 if ( consdata->nvars < 2 )
1568 return SCIP_OKAY;
1569
1570 assert( consdata->vars != NULL );
1571 assert( consdata->invperm != NULL );
1572
1573 SCIPdebugMsg(scip, "Check method for symresack constraint <%s> (%d rows) ...\n", SCIPconsGetName(cons), consdata->nvars);
1574
1575 nvars = consdata->nvars;
1576 vars = consdata->vars;
1577 invperm = consdata->invperm;
1578
1579 /* detect first non-constant pair of variables */
1580 for (i = 0; i < nvars; ++i)
1581 {
1582 SCIP_Real solval;
1583 int val1;
1584 int val2;
1585
1586 /* there are no fixed points */
1587 assert( invperm[i] != i );
1588
1589 /* get value of variable i and its inverse */
1590 solval = SCIPgetSolVal(scip, sol, vars[i]);
1591 assert( SCIPisFeasIntegral(scip, solval) );
1592 if ( solval > 0.5 )
1593 val1 = 1;
1594 else
1595 val1 = 0;
1596
1597 solval = SCIPgetSolVal(scip, sol, vars[invperm[i]]);
1598 assert( SCIPisFeasIntegral(scip, solval) );
1599 if ( solval > 0.5 )
1600 val2 = 1;
1601 else
1602 val2 = 0;
1603
1604 /* if we detected a constant pair */
1605 if ( val1 == val2 )
1606 continue;
1607 /* pair is (1,0) --> lexicographically maximal */
1608 else if ( val1 > val2 )
1609 break;
1610
1611 /* pair is (0,1) --> solution is infeasible */
1612 assert( val2 > val1 );
1613 SCIPdebugMsg(scip, "Solution is infeasible.\n");
1615
1616 if ( printreason )
1617 SCIPinfoMessage(scip, NULL, "First non-constant pair (%d, %d) of variables has pattern (0,1).\n", i, invperm[i]);
1618
1619 break;
1620 }
1621
1622 return SCIP_OKAY;
1623}
1624
1625
1626/** Upgrade symresack constraints to orbisacks */
1627static
1629 SCIP* scip, /**< SCIP pointer */
1630 SCIP_CONS** cons, /**< pointer to hold the created constraint */
1631 const char* name, /**< name of constraint */
1632 int* perm, /**< permutation */
1633 SCIP_VAR** inputvars, /**< permuted variables array */
1634 int nvars, /**< size of perm array */
1635 SCIP_Bool* upgrade, /**< whether constraint was upgraded */
1636 SCIP_Bool ismodelcons, /**< whether the symresack is a model constraint */
1637 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
1638 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1639 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
1640 * Usually set to TRUE. */
1641 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
1642 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1643 SCIP_Bool check, /**< should the constraint be checked for feasibility?
1644 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1645 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
1646 * Usually set to TRUE. */
1647 SCIP_Bool local, /**< is constraint only valid locally?
1648 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1649 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
1650 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
1651 * adds coefficients to this constraint. */
1652 SCIP_Bool dynamic, /**< is constraint subject to aging?
1653 * Usually set to FALSE. Set to TRUE for own cuts which
1654 * are separated as constraints. */
1655 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
1656 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
1657 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
1658 * if it may be moved to a more global node?
1659 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
1660 )
1661{
1662 SCIP_CONSHDLR* conshdlr;
1663 SCIP_VAR** vars1;
1664 SCIP_VAR** vars2;
1665 int nrows = 0;
1666 int i;
1667
1668 assert( scip != NULL );
1669 assert( perm != NULL );
1670 assert( nvars > 0 );
1671 assert( inputvars != NULL );
1672 assert( upgrade != NULL );
1673
1674 *upgrade = TRUE;
1675
1676 /* check whether orbisack conshdlr is available */
1677 conshdlr = SCIPfindConshdlr(scip, "orbisack");
1678 if ( conshdlr == NULL )
1679 {
1680 *upgrade = FALSE;
1681 SCIPdebugMsg(scip, "Cannot check whether symresack constraint can be upgraded to orbisack constraint. ");
1682 SCIPdebugMsg(scip, "---> Orbisack constraint handler not found.\n");
1683
1684 return SCIP_OKAY;
1685 }
1686
1689
1690 /* check whether permutation is a composition of 2-cycles */
1691 for (i = 0; i < nvars; ++i)
1692 {
1693 /* ignore non-binary variables */
1694 if ( ! SCIPvarIsBinary(inputvars[i]) )
1695 continue;
1696
1697 if ( perm[perm[i]] != i )
1698 {
1699 *upgrade = FALSE;
1700 break;
1701 }
1702
1703 if ( perm[i] > i )
1704 {
1705 vars1[nrows] = inputvars[i];
1706 vars2[nrows++] = inputvars[perm[i]];
1707
1708 assert( nrows <= nvars );
1709 }
1710 }
1711
1712 /* if permutation can be upgraded to an orbisack */
1713 if ( nrows == 0 )
1714 *upgrade = FALSE;
1715 else if ( *upgrade )
1716 {
1717 SCIP_CALL( SCIPcreateConsOrbisack(scip, cons, name, vars1, vars2, nrows, FALSE, FALSE, ismodelcons,
1718 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
1719 }
1720
1721 SCIPfreeBufferArray(scip, &vars2);
1722 SCIPfreeBufferArray(scip, &vars1);
1723
1724 return SCIP_OKAY;
1725}
1726
1727
1728/** creates a symmetry breaking constraint
1729 *
1730 * Depending on the given permutation, either an orbisack or symresack constraint
1731 * is created.
1734 SCIP* scip, /**< SCIP data structure */
1735 SCIP_CONS** cons, /**< pointer to hold the created constraint */
1736 const char* name, /**< name of constraint */
1737 int* perm, /**< permutation */
1738 SCIP_VAR** vars, /**< variables */
1739 int nvars, /**< number of variables in vars array */
1740 SCIP_Bool ismodelcons, /**< whether the added constraint is a model constraint */
1741 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
1742 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1743 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
1744 * Usually set to TRUE. */
1745 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
1746 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1747 SCIP_Bool check, /**< should the constraint be checked for feasibility?
1748 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1749 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
1750 * Usually set to TRUE. */
1751 SCIP_Bool local, /**< is constraint only valid locally?
1752 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1753 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
1754 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
1755 * adds coefficients to this constraint. */
1756 SCIP_Bool dynamic, /**< is constraint subject to aging?
1757 * Usually set to FALSE. Set to TRUE for own cuts which
1758 * are separated as constraints. */
1759 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
1760 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
1761 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
1762 * if it may be moved to a more global node?
1763 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
1764 )
1765{
1766 SCIP_Bool upgrade = FALSE;
1767
1768 assert( scip != NULL );
1769 assert( cons != NULL );
1770 assert( perm != NULL );
1771 assert( vars != NULL );
1772 assert( nvars > 0 );
1773
1774 SCIP_CALL( orbisackUpgrade(scip, cons, name, perm, vars, nvars, &upgrade, ismodelcons,
1775 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
1776
1777 if ( ! upgrade )
1778 {
1779 SCIP_CALL( SCIPcreateConsSymresack(scip, cons, name, perm, vars, nvars, ismodelcons,
1780 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
1781 }
1782
1783 return SCIP_OKAY;
1784}
1785
1786
1787/** replace aggregated variables by active variables */
1788static
1790 SCIP* scip, /**< SCIP data structure */
1791 SCIP_CONS* cons /**< constraint to be processed */
1792 )
1793{
1794 SCIP_CONSDATA* consdata;
1795 SCIP_VAR** vars;
1796 int nvars;
1797 int i;
1798
1799 assert( scip != NULL );
1800 assert( cons != NULL );
1801
1802 /* get data of constraint */
1803 consdata = SCIPconsGetData(cons);
1804 assert( consdata != NULL );
1805 assert( consdata->vars != NULL );
1806
1807 nvars = consdata->nvars;
1808 vars = consdata->vars;
1809
1810 /* loop through all variables */
1811 for (i = 0; i < nvars; ++i)
1812 {
1813 SCIP_VAR* var;
1814 SCIP_Bool negated;
1815
1816 assert( SCIPvarGetStatus(vars[i]) != SCIP_VARSTATUS_MULTAGGR ); /* variables are marked as not to be multi-aggregated */
1817
1819 SCIP_UNUSED( negated );
1821 if ( var != vars[i] )
1822 {
1823 if ( consdata->perm[i] > i )
1824 {
1826 }
1827 else
1828 {
1830 }
1832
1833 vars[i] = var;
1834 if ( consdata->perm[i] > i )
1835 {
1837 }
1838 else
1839 {
1841 }
1843 }
1844 }
1845
1846 return SCIP_OKAY;
1847}
1848
1849
1850/*--------------------------------------------------------------------------------------------
1851 *--------------------------------- SCIP functions -------------------------------------------
1852 *--------------------------------------------------------------------------------------------*/
1853
1854/** copy method for constraint handler plugins (called when SCIP copies plugins) */
1855static
1856SCIP_DECL_CONSHDLRCOPY(conshdlrCopySymresack)
1857{ /*lint --e{715}*/
1858 assert(scip != NULL);
1859 assert(conshdlr != NULL);
1860
1862
1863 /* call inclusion method of constraint handler */
1865
1866 *valid = TRUE;
1867
1868 return SCIP_OKAY;
1869}
1870
1871
1872/** frees specific constraint data */
1873static
1874SCIP_DECL_CONSDELETE(consDeleteSymresack)
1875{ /*lint --e{715}*/
1876 assert( scip != NULL );
1877 assert( conshdlr != NULL );
1878 assert( consdata != NULL );
1879
1881
1882 SCIP_CALL( consdataFree(scip, consdata) );
1883
1884 return SCIP_OKAY;
1885}
1886
1887
1888/** frees constraint handler */
1889static
1890SCIP_DECL_CONSFREE(consFreeSymresack)
1891{ /*lint --e{715}*/
1892 SCIP_CONSHDLRDATA* conshdlrdata;
1893
1894 assert( scip != NULL );
1895 assert( conshdlr != NULL );
1896
1898
1899 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1900 assert( conshdlrdata != NULL );
1901
1902 SCIPfreeBlockMemory(scip, &conshdlrdata);
1903
1904 return SCIP_OKAY;
1905}
1906
1907
1908/** transforms constraint data into data belonging to the transformed problem */
1909static
1910SCIP_DECL_CONSTRANS(consTransSymresack)
1911{
1912 SCIP_CONSDATA* sourcedata;
1913 SCIP_CONSDATA* consdata = NULL;
1914 int nvars;
1915 int i;
1916
1917 assert( scip != NULL );
1918 assert( conshdlr != NULL );
1919 assert( sourcecons != NULL );
1920 assert( targetcons != NULL );
1921
1923
1924 SCIPdebugMsg(scip, "Transforming constraint.\n");
1925
1926 /* get data of original constraint */
1927 sourcedata = SCIPconsGetData(sourcecons);
1928 assert( sourcedata != NULL);
1929
1930 /* constraint might be empty and not deleted if no presolving took place */
1931 assert( sourcedata->nvars == 0 || sourcedata->vars != NULL );
1932 assert( sourcedata->nvars == 0 || sourcedata->perm != NULL );
1933 assert( sourcedata->nvars == 0 || sourcedata->invperm != NULL );
1934#ifndef NDEBUG
1935 if ( sourcedata->ppupgrade )
1936 {
1937 assert( sourcedata->nvars > 0 );
1938 assert( sourcedata->ncycles != 0 );
1939 assert( sourcedata->cycledecomposition != NULL );
1940 for (i = 0; i < sourcedata->ncycles; ++i)
1941 {
1942 assert( sourcedata->cycledecomposition[i] != NULL );
1943 assert( sourcedata->cycledecomposition[i][0] != 0 );
1944 }
1945 }
1946#endif
1947
1948 /* create transformed constraint data
1949 *
1950 * do NOT call consdataCreate() again to avoid doing the packing-upgrade check twice
1951 */
1952 nvars = sourcedata->nvars;
1953
1954 SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) );
1955
1956 consdata->vars = NULL;
1957 consdata->nvars = nvars;
1958 consdata->perm = NULL;
1959 consdata->invperm = NULL;
1960 consdata->ppupgrade = sourcedata->ppupgrade;
1961 consdata->ismodelcons = sourcedata->ismodelcons;
1962#ifdef SCIP_DEBUG
1963 consdata->debugcnt = 0;
1964#endif
1965 consdata->ncycles = 0;
1966 consdata->cycledecomposition = NULL;
1967 consdata->ndescentpoints = 0;
1968 consdata->descentpoints = NULL;
1969
1970 if ( nvars > 0 )
1971 {
1972 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->vars, nvars) );
1973 SCIP_CALL( SCIPgetTransformedVars(scip, nvars, sourcedata->vars, consdata->vars) );
1974 for (i = 0; i < nvars; ++i)
1975 {
1976 SCIP_CALL( SCIPcaptureVar(scip, consdata->vars[i]) );
1977 }
1978
1979 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->perm, sourcedata->perm, nvars) );
1980 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->invperm, sourcedata->invperm, nvars) );
1981
1982 if ( sourcedata->ppupgrade )
1983 {
1984 consdata->ncycles = sourcedata->ncycles;
1985 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->cycledecomposition, sourcedata->cycledecomposition, sourcedata->ncycles) );
1986 for (i = 0; i < sourcedata->ncycles; ++i)
1987 {
1988 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->cycledecomposition[i], sourcedata->cycledecomposition[i], nvars + 1) ); /*lint !e866*/
1989 }
1990
1991 consdata->ndescentpoints = sourcedata->ndescentpoints;
1992 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->descentpoints, sourcedata->descentpoints, sourcedata->ndescentpoints) );
1993 }
1994
1995 /* Make sure that all variables cannot be multiaggregated (this cannot be handled by cons_symresack, since one cannot
1996 * easily eliminate single variables from a symresack constraint).
1997 *
1998 * We need to call this again to ensure that multiaggregation is forbidden also if the constraint was part
1999 * of the original problem.
2000 */
2001 for (i = 0; i < sourcedata->nvars; ++i)
2002 {
2003 SCIP_CALL( SCIPgetTransformedVar(scip, consdata->vars[i], &consdata->vars[i]) );
2004 SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, consdata->vars[i]) );
2005 }
2006 }
2007
2008 /* create transformed constraint */
2009 SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, consdata,
2010 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons),
2011 SCIPconsIsEnforced(sourcecons), SCIPconsIsChecked(sourcecons),
2012 SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
2013 SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons),
2014 SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
2015
2016 return SCIP_OKAY;
2017}
2018
2019
2020/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
2021static
2022SCIP_DECL_CONSINITLP(consInitlpSymresack)
2023{
2024 int c;
2025 SCIP_CONSHDLRDATA* conshdlrdata;
2026
2027 assert( infeasible != NULL );
2028 *infeasible = FALSE;
2029
2030 assert( scip != NULL );
2031 assert( conshdlr != NULL );
2032
2034
2035 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2036 assert( conshdlrdata != NULL );
2037
2038 /* loop through constraints */
2039 for (c = 0; c < nconss; ++c)
2040 {
2041 assert( conss[c] != NULL );
2042
2043 SCIPdebugMsg(scip, "Generating initial symresack cut for constraint <%s> ...\n", SCIPconsGetName(conss[c]));
2044
2045 SCIP_CALL( initLP(scip, conss[c], conshdlrdata->checkmonotonicity, infeasible) );
2046 if ( *infeasible )
2047 break;
2048 }
2049 SCIPdebugMsg(scip, "Generated initial symresack cuts.\n");
2050
2051 return SCIP_OKAY;
2052}
2053
2054
2055/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
2056static
2057SCIP_DECL_CONSINITSOL(consInitsolSymresack)
2058{
2059 SCIP_CONSHDLRDATA* conshdlrdata;
2060 int c;
2061
2062 assert( scip != NULL );
2063 assert( conshdlr != NULL );
2064
2066
2067 /* determine maximum number of vars in a symresack constraint */
2068 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2069 assert( conshdlrdata != NULL );
2070
2071 conshdlrdata->maxnvars = 0;
2072
2073 /* loop through constraints */
2074 for (c = 0; c < nconss; ++c)
2075 {
2076 SCIP_CONSDATA* consdata;
2077
2078 assert( conss[c] != NULL );
2079
2080 consdata = SCIPconsGetData(conss[c]);
2081 assert( consdata != NULL );
2082
2083 /* update conshdlrdata if necessary */
2084 if ( consdata->nvars > conshdlrdata->maxnvars )
2085 conshdlrdata->maxnvars = consdata->nvars;
2086 }
2087
2088 return SCIP_OKAY;
2089}
2090
2091
2092/** separation method of constraint handler for LP solution */
2093static
2094SCIP_DECL_CONSSEPALP(consSepalpSymresack)
2095{ /*lint --e{715}*/
2096 SCIP_CONSHDLRDATA* conshdlrdata;
2097 SCIP_CONSDATA* consdata;
2098 SCIP_Real* vals;
2099 int maxnvars;
2100 int c;
2101
2102 assert( scip != NULL );
2103 assert( conshdlr != NULL );
2104 assert( result != NULL );
2105
2107
2108 SCIPdebugMsg(scip, "Separation method for symresack constraints\n");
2109
2111
2112 /* if solution is not integer */
2113 if ( SCIPgetNLPBranchCands(scip) == 0 )
2114 return SCIP_OKAY;
2115
2116 if ( nconss == 0 )
2117 return SCIP_OKAY;
2118
2119 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2120 assert( conshdlrdata != NULL );
2121
2122 maxnvars = conshdlrdata->maxnvars;
2123 assert( maxnvars > 0 );
2124
2125 SCIP_CALL( SCIPallocBufferArray(scip, &vals, maxnvars) );
2126
2127 /* loop through constraints */
2128 for (c = 0; c < nconss; ++c)
2129 {
2130 SCIP_Bool infeasible = FALSE;
2131 int ngen = 0;
2132
2133 SCIPdebugMsg(scip, "Separating symresack constraint <%s> ...\n", SCIPconsGetName(conss[c]));
2134
2135 /* get data of constraint */
2136 assert( conss[c] != NULL );
2137 consdata = SCIPconsGetData(conss[c]);
2138
2139 if ( consdata->nvars == 0 )
2140 continue;
2141
2142 /* get solution */
2143 assert( consdata->nvars <= maxnvars );
2144 SCIP_CALL( SCIPgetSolVals(scip, NULL, consdata->nvars, consdata->vars, vals) );
2145 SCIP_CALL( separateSymresackCovers(scip, conss[c], consdata, vals, &ngen, &infeasible) );
2146
2147 if ( infeasible )
2148 {
2150 SCIPfreeBufferArray(scip, &vals);
2151
2152 return SCIP_OKAY;
2153 }
2154
2155 if ( ngen > 0 )
2157
2158 if ( *result == SCIP_DIDNOTRUN )
2160 }
2161 SCIPfreeBufferArray(scip, &vals);
2162
2163 return SCIP_OKAY;
2164}
2165
2166
2167/** separation method of constraint handler for arbitrary primal solution */
2168static
2169SCIP_DECL_CONSSEPASOL(consSepasolSymresack)
2170{ /*lint --e{715}*/
2171 SCIP_CONSHDLRDATA* conshdlrdata;
2172 SCIP_CONSDATA* consdata;
2173 SCIP_Real* vals;
2174 int maxnvars;
2175 int c;
2176
2177 assert( scip != NULL );
2178 assert( conshdlr != NULL );
2179 assert( result != NULL );
2180
2182
2183 SCIPdebugMsg(scip, "Separation method for symresack constraints\n");
2184
2186
2187 if ( nconss == 0 )
2188 return SCIP_OKAY;
2189
2190 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2191 assert( conshdlrdata != NULL );
2192
2193 maxnvars = conshdlrdata->maxnvars;
2194 assert( maxnvars > 0 );
2195
2196 SCIP_CALL( SCIPallocBufferArray(scip, &vals, maxnvars) );
2197
2198 /* loop through constraints */
2199 for (c = 0; c < nconss; ++c)
2200 {
2201 SCIP_Bool infeasible = FALSE;
2202 int ngen = 0;
2203
2204 SCIPdebugMsg(scip, "Separating symresack constraint <%s> ...\n", SCIPconsGetName(conss[c]));
2205
2206 /* get data of constraint */
2207 assert( conss[c] != NULL );
2208 consdata = SCIPconsGetData(conss[c]);
2209
2210 if ( consdata->nvars == 0 )
2211 continue;
2212
2213 /* get solution */
2214 assert( consdata->nvars <= maxnvars );
2215 SCIP_CALL( SCIPgetSolVals(scip, sol, consdata->nvars, consdata->vars, vals) );
2216 SCIP_CALL( separateSymresackCovers(scip, conss[c], consdata, vals, &ngen, &infeasible) );
2217
2218 if ( infeasible )
2219 {
2221 SCIPfreeBufferArray(scip, &vals);
2222
2223 return SCIP_OKAY;
2224 }
2225
2226 if ( ngen > 0 )
2228
2229 if ( *result == SCIP_DIDNOTRUN )
2231 }
2232 SCIPfreeBufferArray(scip, &vals);
2233
2234 return SCIP_OKAY;
2235}
2236
2237
2238/** constraint enforcing method of constraint handler for LP solutions.
2239 *
2240 * To check feasibility, we separate cover inequalities.
2241 *
2242 * @pre It is assumed that the solution is integral (this can be ensured by appropriate priorities).
2243 */
2244static
2245SCIP_DECL_CONSENFOLP(consEnfolpSymresack)
2246{ /*lint --e{715}*/
2247 SCIP_CONSDATA* consdata;
2248 int c;
2249
2250 assert( scip != NULL );
2251 assert( conshdlr != NULL );
2252 assert( result != NULL );
2253
2255
2256 SCIPdebugMsg(scip, "Enforcing method for symresack constraints (lp solutions) ...\n");
2257
2258 /* we have a negative priority, so we should come after the integrality conshdlr. */
2260
2262
2263 if ( nconss > 0 )
2264 {
2265 SCIP_CONSHDLRDATA* conshdlrdata;
2266 SCIP_Real* vals;
2267 int maxnvars;
2268
2269 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2270 assert( conshdlrdata != NULL );
2271
2272 maxnvars = conshdlrdata->maxnvars;
2273 assert( maxnvars > 0 );
2274
2275 SCIP_CALL( SCIPallocBufferArray(scip, &vals, maxnvars) );
2276
2277 /* loop through constraints */
2278 for (c = 0; c < nconss; ++c)
2279 {
2280 SCIP_Bool infeasible = FALSE;
2281 int ngen = 0;
2282
2283 SCIPdebugMsg(scip, "Enforcing symresack constraint <%s> ...\n", SCIPconsGetName(conss[c]));
2284
2285 /* get data of constraint */
2286 assert( conss[c] != NULL );
2287 consdata = SCIPconsGetData(conss[c]);
2288 assert( consdata != NULL );
2289
2290 /* do not enforce non-model constraints */
2291 if ( !consdata->ismodelcons )
2292 continue;
2293
2294 if ( consdata->nvars == 0 )
2295 continue;
2296
2297 /* get solution */
2298 assert( consdata->nvars <= maxnvars );
2299 SCIP_CALL( SCIPgetSolVals(scip, NULL, consdata->nvars, consdata->vars, vals) );
2300 SCIP_CALL( separateSymresackCovers(scip, conss[c], consdata, vals, &ngen, &infeasible) );
2301
2302 if ( infeasible )
2303 {
2305 SCIPfreeBufferArray(scip, &vals);
2306
2307 return SCIP_OKAY;
2308 }
2309
2310 /* SCIPdebugMsg(scip, "Generated symresack inequalities for <%s>: %d\n", SCIPconsGetName(conss[c]), ngen); */
2311
2312 if ( ngen > 0 )
2314 }
2315 SCIPfreeBufferArray(scip, &vals);
2316 }
2317
2318 return SCIP_OKAY;
2319}
2320
2321
2322/** constraint enforcing method of constraint handler for pseudo solutions */
2323static
2324SCIP_DECL_CONSENFOPS(consEnfopsSymresack)
2325{ /*lint --e{715}*/
2326 SCIP_CONSDATA* consdata;
2327 int c;
2328
2329 assert( scip != NULL );
2330 assert( conshdlr != NULL );
2331 assert( result != NULL );
2332
2334
2335 SCIPdebugMsg(scip, "Enforcing method for symresack constraints (pseudo solutions) ...\n");
2336
2338
2339 if ( objinfeasible || solinfeasible )
2340 return SCIP_OKAY;
2341
2342 /* loop through constraints */
2343 for (c = 0; c < nconss; ++c)
2344 {
2345 consdata = SCIPconsGetData(conss[c]);
2346 assert( consdata != NULL );
2347
2348 /* do not enforce non-model constraints */
2349 if ( !consdata->ismodelcons )
2350 continue;
2351
2353
2354 if ( *result == SCIP_INFEASIBLE )
2355 break;
2356 }
2357
2358 return SCIP_OKAY;
2359}
2360
2361
2362/** constraint enforcing method of constraint handler for relaxation solutions
2363 *
2364 * To check feasibility, we separate cover inequalities.
2365 *
2366 */
2367static
2368SCIP_DECL_CONSENFORELAX(consEnforelaxSymresack)
2369{ /*lint --e{715}*/
2370 SCIP_CONSDATA* consdata;
2371 int c;
2372
2373 assert( scip != NULL );
2374 assert( conshdlr != NULL );
2375 assert( result != NULL );
2376
2378
2379 SCIPdebugMsg(scip, "Enforcing method for symresack constraints (relaxation solutions) ...\n");
2380
2381 /* we have a negative priority, so we should come after the integrality conshdlr. */
2383
2385
2386 if ( nconss > 0 )
2387 {
2388 SCIP_CONSHDLRDATA* conshdlrdata;
2389 SCIP_Real* vals;
2390 int maxnvars;
2391
2392 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2393 assert( conshdlrdata != NULL );
2394
2395 maxnvars = conshdlrdata->maxnvars;
2396 assert( maxnvars > 0 );
2397
2398 SCIP_CALL( SCIPallocBufferArray(scip, &vals, maxnvars) );
2399
2400 /* loop through constraints */
2401 for (c = 0; c < nconss; ++c)
2402 {
2403 SCIP_Bool infeasible = FALSE;
2404 int ngen = 0;
2405
2406 SCIPdebugMsg(scip, "Enforcing symresack constraint <%s> ...\n", SCIPconsGetName(conss[c]));
2407
2408 /* get data of constraint */
2409 assert( conss[c] != NULL );
2410 consdata = SCIPconsGetData(conss[c]);
2411 assert( consdata != NULL );
2412
2413 /* do not enforce non-model constraints */
2414 if ( !consdata->ismodelcons )
2415 continue;
2416
2417 if ( consdata->nvars == 0 )
2418 continue;
2419
2420 /* get solution */
2421 assert( consdata->nvars <= maxnvars );
2422 SCIP_CALL( SCIPgetSolVals(scip, sol, consdata->nvars, consdata->vars, vals) );
2423 SCIP_CALL( separateSymresackCovers(scip, conss[c], consdata, vals, &ngen, &infeasible) );
2424
2425 if ( infeasible )
2426 {
2428 SCIPfreeBufferArray(scip, &vals);
2429
2430 return SCIP_OKAY;
2431 }
2432
2433 if ( ngen > 0 )
2435 }
2436 SCIPfreeBufferArray(scip, &vals);
2437 }
2438
2439 return SCIP_OKAY;
2440}
2441
2442
2443/** feasibility check method of constraint handler for integral solutions */
2444static
2445SCIP_DECL_CONSCHECK(consCheckSymresack)
2446{ /*lint --e{715}*/
2447 SCIP_CONSDATA* consdata;
2448 int c;
2449
2450 assert( scip != NULL );
2451 assert( conshdlr != NULL );
2452 assert( result != NULL );
2453
2455
2457
2458 /* loop through constraints */
2459 for (c = 0; c < nconss; ++c)
2460 {
2461 consdata = SCIPconsGetData(conss[c]);
2462 assert( consdata != NULL );
2463
2464 /* do not check non-model constraints */
2465 if ( !consdata->ismodelcons )
2466 continue;
2467
2468 SCIP_CALL( checkSymresackSolution(scip, conss[c], sol, result, printreason) );
2469
2470 if ( *result == SCIP_INFEASIBLE )
2471 break;
2472 }
2473
2474 if ( *result == SCIP_FEASIBLE )
2475 SCIPdebugMsg(scip, "Solution is feasible.\n");
2476
2477 return SCIP_OKAY;
2478}
2479
2480
2481/** domain propagation method of constraint handler */
2482static
2483SCIP_DECL_CONSPROP(consPropSymresack)
2484{ /*lint --e{715}*/
2485 int c;
2486 SCIP_Bool success = FALSE;
2487
2488 assert( scip != NULL );
2489 assert( conshdlr != NULL );
2490 assert( result != NULL );
2491
2493
2495
2496 SCIPdebugMsg(scip, "Propagation method of symresack constraint handler.\n");
2497
2498 /* loop through constraints */
2499 for (c = 0; c < nconss; ++c)
2500 {
2501 SCIP_Bool infeasible = FALSE;
2502 int ngen = 0;
2503
2504 assert( conss[c] != NULL );
2505
2506 SCIP_CALL( propVariables(scip, conss[c], &infeasible, &ngen) );
2507
2508 if ( infeasible )
2509 {
2511 return SCIP_OKAY;
2512 }
2513
2514 success = success || ( ngen > 0 );
2515
2517 }
2518
2519 if ( success )
2520 {
2522 return SCIP_OKAY;
2523 }
2524
2525 return SCIP_OKAY;
2526}
2527
2528
2529/** presolving method of constraint handler */
2530static
2531SCIP_DECL_CONSPRESOL(consPresolSymresack)
2532{ /*lint --e{715}*/
2533 int c;
2534 SCIP_Bool success = FALSE;
2535 int oldndelconss;
2536
2537 assert( scip != NULL );
2538 assert( conshdlr != NULL );
2539 assert( result != NULL );
2540
2542
2543 oldndelconss = *ndelconss;
2544
2545 SCIPdebugMsg(scip, "Presolving method of symresack constraint handler. Propagating symresack inequalities.\n");
2547
2548 /* loop through constraints */
2549 for (c = 0; c < nconss; ++c)
2550 {
2551 SCIP_Bool infeasible = FALSE;
2552 SCIP_CONSDATA* consdata;
2553 int ngen = 0;
2554
2555 assert( conss[c] != NULL );
2556
2557 consdata = SCIPconsGetData(conss[c]);
2558 assert( consdata != NULL );
2559
2560 /* avoid trivial problems */
2561 if ( consdata->nvars == 0 )
2562 {
2563 SCIP_CALL( SCIPdelCons(scip, conss[c]) );
2564 (*ndelconss)++;
2565 }
2566 else
2567 {
2568 SCIP_CALL( propVariables(scip, conss[c], &infeasible, &ngen) );
2569 }
2570
2571 if ( infeasible )
2572 {
2574 break;
2575 }
2576
2577 if ( ngen > 0 )
2578 {
2579 *nfixedvars += ngen;
2580 success = TRUE;
2581 }
2582
2584 }
2585
2586 if ( *ndelconss > oldndelconss || success )
2588
2589 return SCIP_OKAY;
2590}
2591
2592
2593/** Propagation resolution for conflict analysis */
2594static
2595SCIP_DECL_CONSRESPROP(consRespropSymresack)
2596{ /*lint --e{715}*/
2597 SCIP_CONSDATA* consdata;
2598 SCIP_VAR** vars;
2599 int* perm;
2600 int* invperm;
2601 int nvars;
2602 int i;
2603 int varrow;
2604 int infrow;
2605
2606 assert( scip != NULL );
2607 assert( conshdlr != NULL );
2608 assert( cons != NULL );
2609 assert( infervar != NULL );
2610 assert( bdchgidx != NULL );
2611 assert( result != NULL );
2612
2614
2615 SCIPdebugMsg(scip, "Propagation resolution method of symresack constraint handler.\n");
2616
2618
2619 consdata = SCIPconsGetData(cons);
2620 assert( consdata != NULL );
2621
2622 /* we do not have to take care of trivial constraints */
2623 if ( consdata->nvars < 2 )
2624 return SCIP_OKAY;
2625
2626 assert( consdata->vars != NULL );
2627 assert( consdata->invperm != NULL );
2628
2629 vars = consdata->vars;
2630 nvars = consdata->nvars;
2631 perm = consdata->perm;
2632 invperm = consdata->invperm;
2633
2634 /* inferinfo == varrow + infrow * nvars.
2635 * infrow is 0 if the fixing is not caused by a lookahead.
2636 */
2637 varrow = inferinfo % nvars;
2638 infrow = inferinfo / nvars;
2639
2640 assert( varrow >= 0 );
2641 assert( varrow < nvars );
2642 assert( infrow >= 0 );
2643 assert( infrow < nvars );
2644 assert( vars[varrow] == infervar || vars[invperm[varrow]] == infervar );
2645
2646 /* Up to entry varrow the vectors x and perm[x] are equal. */
2647 for (i = 0; i < varrow; ++i)
2648 {
2649 /* Conflict caused by bounds of x[i] and perm(x)[i] = x[invperm[i]]. */
2650
2651 /* No fixed points in the permutation. */
2652 assert( i != invperm[i] );
2653
2654 /* Up to entry varrow the vectors x and perm[x] are fixed to the same value. */
2655 assert( ISFIXED(scip, vars[i], bdchgidx) );
2656 assert( ISFIXED(scip, vars[invperm[i]], bdchgidx) );
2658 SCIPgetVarUbAtIndex(scip, vars[invperm[i]], bdchgidx, FALSE)) < 0.5 );
2660 SCIPgetVarLbAtIndex(scip, vars[invperm[i]], bdchgidx, FALSE)) < 0.5 );
2661
2662 /* At iteration i the vars x[i] and x[invperm[i]] are fixed.
2663 * So only new information is received if i < perm[i] (i.e. there is no j < i with j = invperm[i])
2664 * Or if invperm[i] > i.
2665 */
2666 if ( i < perm[i] )
2667 {
2668 assert( vars[i] != infervar );
2669 SCIP_CALL( SCIPaddConflictUb(scip, vars[i], bdchgidx) );
2670 SCIP_CALL( SCIPaddConflictLb(scip, vars[i], bdchgidx) );
2671 }
2672 if ( invperm[i] > i )
2673 {
2674 assert( vars[invperm[i]] != infervar );
2675 SCIP_CALL( SCIPaddConflictUb(scip, vars[invperm[i]], bdchgidx) );
2676 SCIP_CALL( SCIPaddConflictLb(scip, vars[invperm[i]], bdchgidx) );
2677 }
2678 }
2679
2680 /* Case distinction: Fixing due to propagation or due to lookahead */
2681 if ( infrow > 0 )
2682 {
2683 /* The fixing of infervar is caused by a lookahead (checkFeasible)
2684 * Up to row "varrow" the entries x[i] and perm(x)[i] are forced to be equal
2685 * If x[varrow] = perm(x)[varrow] is assumed, then until infrow we find x[i] = perm(x)[i] ( = x[invperm[i]] )
2686 * and (x[infrow], perm(x)[infrow]) = (0, 1).
2687 */
2688
2689 /* Everything after varrow to infrow is forced to a constant, and row infrow is (0, 1) */
2690 for (i = varrow + 1; i <= infrow; ++i)
2691 {
2692 /* Conflict caused by bounds of x[i] and perm(x)[i] = x[invperm[i]]. */
2693
2694 /* No fixed points in the permutation. */
2695 assert( i != invperm[i] );
2696
2697 /* The fixing are applied 'virtually', i.e. if varrow is considered constant, then fixings will follow.
2698 * Thus, between entries varrow and infrow of vectorx x and gamma(x) the entries do not have to be fixed.
2699 * For conflict analysis, only the fixed entries matter.
2700 */
2701 if ( ( i < perm[i] || i == invperm[varrow] ) && ISFIXED(scip, vars[i], bdchgidx) )
2702 {
2703 assert( vars[i] != infervar );
2704 SCIP_CALL( SCIPaddConflictUb(scip, vars[i], bdchgidx) );
2705 SCIP_CALL( SCIPaddConflictLb(scip, vars[i], bdchgidx) );
2706 }
2707 if ( ( invperm[i] > i || invperm[i] == varrow ) && ISFIXED(scip, vars[invperm[i]], bdchgidx) )
2708 {
2709 assert( vars[invperm[i]] != infervar );
2710 SCIP_CALL( SCIPaddConflictUb(scip, vars[invperm[i]], bdchgidx) );
2711 SCIP_CALL( SCIPaddConflictLb(scip, vars[invperm[i]], bdchgidx) );
2712 }
2713 }
2714 }
2715 else
2716 {
2717 /* This is not a fixing caused by lookahead (checkFeasible),
2718 * so row "varrow" was (0, _) or (_, 1) and for i < varrow x[i] = perm(x)[i].
2719 */
2720 if ( boundtype == SCIP_BOUNDTYPE_LOWER )
2721 {
2722 /* Changed the lower bound of infervar to 1. That means that this fixing is due to (_, 1) */
2723 assert( infervar == vars[varrow] );
2724 assert( ISFIXED(scip, vars[invperm[varrow]], bdchgidx) );
2725
2726 if ( invperm[varrow] > varrow )
2727 {
2728 SCIP_CALL( SCIPaddConflictUb(scip, vars[invperm[varrow]], bdchgidx) );
2729 SCIP_CALL( SCIPaddConflictLb(scip, vars[invperm[varrow]], bdchgidx) );
2730 }
2731 }
2732 else
2733 {
2734 /* Changed the lower bound of infervar to 0. That means that this fixing is due to (0, _) */
2735 assert( infervar == vars[invperm[varrow]] );
2736 assert( ISFIXED(scip, vars[varrow], bdchgidx) );
2737
2738 if ( varrow < perm[varrow] )
2739 {
2740 SCIP_CALL( SCIPaddConflictUb(scip, vars[varrow], bdchgidx) );
2741 SCIP_CALL( SCIPaddConflictLb(scip, vars[varrow], bdchgidx) );
2742 }
2743 }
2744 }
2745
2747
2748 return SCIP_OKAY;
2749}
2750
2751
2752/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
2753static
2754SCIP_DECL_CONSEXITPRE(consExitpreSymresack)
2755{
2756 int c;
2757
2758 assert( scip != NULL );
2759 assert( conshdlr != NULL );
2760
2762
2763 for (c = 0; c < nconss; ++c)
2764 {
2765 /* replace aggregated variables by active variables */
2767 }
2768 return SCIP_OKAY;
2769}
2770
2771
2772/** lock variables
2773 *
2774 * We assume we have only one global (void) constraint and lock all binary variables
2775 * which do not correspond to fixed points of the permutation.
2776 *
2777 * - Symresack constraints may get violated if the variables with a negative coefficient
2778 * in the FD inequality are rounded down, we therefor call
2779 * SCIPaddVarLocksType(..., nlockspos, nlocksneg).
2780 * - Symresack constraints may get violated if the variables with a positive coefficient
2781 * in the FD inequality are rounded up, we therefor call
2782 * SCIPaddVarLocksType(..., nlocksneg, nlockspo ).
2783 */
2784static
2785SCIP_DECL_CONSLOCK(consLockSymresack)
2786{ /*lint --e{715}*/
2787 SCIP_CONSDATA* consdata;
2788 SCIP_VAR** vars;
2789 int* perm;
2790 int nvars;
2791 int i;
2792
2793 assert( scip != NULL );
2794 assert( conshdlr != NULL );
2795 assert( cons != NULL );
2796
2798
2799 SCIPdebugMsg(scip, "Locking method for symresack constraint handler.\n");
2800
2801 /* get data of original constraint */
2802 consdata = SCIPconsGetData(cons);
2803 assert( consdata != NULL );
2804
2805 /* we do not have to take care of trivial constraints */
2806 if ( consdata->nvars < 2 )
2807 return SCIP_OKAY;
2808
2809 assert( consdata->vars != NULL );
2810 assert( consdata->perm != NULL );
2811
2812 nvars = consdata->nvars;
2813 vars = consdata->vars;
2814 perm = consdata->perm;
2815
2816 for (i = 0; i < nvars; ++i)
2817 {
2818 /* due to clean-up in consdataCreate, there are no fixed points */
2819 assert( perm[i] != i );
2820
2821 if ( perm[i] > i )
2822 {
2823 SCIP_CALL( SCIPaddVarLocksType(scip, vars[i], locktype, nlockspos, nlocksneg) );
2824 }
2825 else
2826 {
2827 SCIP_CALL( SCIPaddVarLocksType(scip, vars[i], locktype, nlocksneg, nlockspos) );
2828 }
2829 }
2830
2831 return SCIP_OKAY;
2832}
2833
2834
2835/** constraint copying method of constraint handler */
2836static
2837SCIP_DECL_CONSCOPY(consCopySymresack)
2838{
2839 SCIP_CONSHDLRDATA* conshdlrdata;
2840 SCIP_CONSDATA* sourcedata;
2841 SCIP_VAR** sourcevars;
2842 SCIP_VAR** vars;
2843 int nvars;
2844 int i;
2845
2846 assert( scip != NULL );
2847 assert( cons != NULL );
2848 assert( sourcescip != NULL );
2849 assert( sourceconshdlr != NULL );
2850 assert( sourcecons != NULL );
2851 assert( varmap != NULL );
2852 assert( valid != NULL );
2853
2855
2856 *valid = TRUE;
2857
2858 SCIPdebugMsg(scip, "Copying method for symresack constraint handler.\n");
2859
2860 sourcedata = SCIPconsGetData(sourcecons);
2861 assert( sourcedata != NULL );
2862 assert( sourcedata->vars != NULL );
2863 assert( sourcedata->perm != NULL );
2864 assert( sourcedata->nvars > 0 );
2865
2866 conshdlrdata = SCIPconshdlrGetData(sourceconshdlr);
2867 assert( conshdlrdata != NULL );
2868
2869 /* do not copy non-model constraints */
2870 if ( !sourcedata->ismodelcons && !conshdlrdata->forceconscopy )
2871 {
2872 *valid = FALSE;
2873
2874 return SCIP_OKAY;
2875 }
2876
2877 sourcevars = sourcedata->vars;
2878 nvars = sourcedata->nvars;
2879
2881
2882 for (i = 0; i < nvars && *valid; ++i)
2883 {
2884 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[i], &(vars[i]), varmap, consmap, global, valid) );
2885 assert( !(*valid) || vars[i] != NULL );
2886 }
2887
2888 /* only create the target constraint, if all variables could be copied */
2889 if ( *valid )
2890 {
2891 /* create copied constraint */
2892 if ( name == NULL )
2893 name = SCIPconsGetName(sourcecons);
2894
2895 SCIP_CALL( SCIPcreateConsSymresack(scip, cons, name, sourcedata->perm, vars, nvars, sourcedata->ismodelcons,
2896 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
2897 }
2898
2900
2901 return SCIP_OKAY;
2902}
2903
2904
2905/** constraint parsing method of constraint handler */
2906static
2907SCIP_DECL_CONSPARSE(consParseSymresack)
2908{ /*lint --e{715}*/
2909 const char* s;
2910 char* endptr;
2911 SCIP_VAR** vars;
2912 SCIP_VAR* var;
2913 int* perm;
2914 int val;
2915 int nvars = 0;
2916 int cnt = 0;
2917 int nfoundpermidx = 0;
2918 int maxnvars = 128;
2919
2920 assert( success != NULL );
2921
2922 *success = TRUE;
2923 s = str;
2924
2925 /* skip white space */
2926 SCIP_CALL( SCIPskipSpace((char**)&s) );
2927
2928 if( strncmp(s, "symresack(", 10) != 0 )
2929 {
2930 SCIPerrorMessage("Syntax error - expected \"symresack(\", but got '%s'", s);
2931 *success = FALSE;
2932 return SCIP_OKAY;
2933 }
2934 s += 10;
2935
2936 /* loop through string */
2937 SCIP_CALL( SCIPallocBufferArray(scip, &vars, maxnvars) );
2938 SCIP_CALL( SCIPallocBufferArray(scip, &perm, maxnvars) );
2939
2940 do
2941 {
2942 if( cnt > 1 )
2943 {
2944 SCIPerrorMessage("expected two arrays, but got more\n");
2945 *success = FALSE;
2946 break;
2947 }
2948
2949 /* skip whitespace */
2950 SCIP_CALL( SCIPskipSpace((char**)&s) );
2951
2952 /* skip ',' */
2953 if( *s == ',' )
2954 ++s;
2955
2956 /* skip whitespace */
2957 SCIP_CALL( SCIPskipSpace((char**)&s) );
2958
2959 /* if we could not find starting indicator of array */
2960 if( *s != '[' )
2961 {
2962 SCIPerrorMessage("expected '[' to start new array\n");
2963 *success = FALSE;
2964 break;
2965 }
2966 ++s;
2967
2968 /* read array, cnt = 0: variables; cnt = 1: permutation*/
2969 if( cnt == 0 )
2970 {
2971 do
2972 {
2973 /* parse variable name */
2974 SCIP_CALL( SCIPparseVarName(scip, s, &var, &endptr) );
2975
2976 if( var == NULL )
2977 {
2978 endptr = strchr(endptr, ']');
2979
2980 if( endptr == NULL )
2981 {
2982 SCIPerrorMessage("closing ']' missing\n");
2983 *success = FALSE;
2984 }
2985 else
2986 s = endptr;
2987
2988 break;
2989 }
2990
2991 s = endptr;
2992 assert( s != NULL );
2993 ++nvars;
2994
2995 if( nvars > maxnvars )
2996 {
2997 maxnvars = SCIPcalcMemGrowSize(scip, nvars);
2998 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, maxnvars) );
2999 SCIP_CALL( SCIPreallocBufferArray(scip, &perm, maxnvars) );
3000 assert( nvars <= maxnvars );
3001 }
3002
3003 vars[nvars-1] = var;
3004
3005 /* skip white space */
3006 SCIP_CALL( SCIPskipSpace((char**)&s) );
3007
3008 /* skip ',' */
3009 if( *s == ',' )
3010 ++s;
3011 }
3012 while( *s != ']' );
3013 }
3014 else
3015 {
3016 do
3017 {
3018 /* skip whitespace */
3019 SCIP_CALL( SCIPskipSpace((char**)&s) );
3020
3021 /* parse integer value */
3022 if( !SCIPstrToIntValue(s, &val, &endptr) )
3023 {
3024 SCIPerrorMessage("could not extract int from string '%s'\n", str);
3025 *success = FALSE;
3026 break;
3027 }
3028
3029 s = endptr;
3030 assert( s != NULL );
3031 ++nfoundpermidx;
3032
3033 if( nfoundpermidx > nvars )
3034 {
3035 SCIPerrorMessage("permutation is longer than vars array\n");
3036 *success = FALSE;
3037 break;
3038 }
3039
3040 perm[nfoundpermidx-1] = val;
3041
3042 /* skip whitespace */
3043 SCIP_CALL( SCIPskipSpace((char**)&s) );
3044
3045 /* skip ',' */
3046 if( *s == ',' )
3047 ++s;
3048 }
3049 while( *s != ']' );
3050
3051 if( nfoundpermidx != nvars )
3052 {
3053 SCIPerrorMessage("length of permutation is not equal to number of given variables.\n");
3054 *success = FALSE;
3055 break;
3056 }
3057 }
3058
3059 if( !*success )
3060 break;
3061
3062 ++s;
3063 ++cnt;
3064 }
3065 while( *s != ')' );
3066
3067 if( *success && cnt < 2 )
3068 {
3069 SCIPerrorMessage("permutation is missing.\n");
3070 *success = FALSE;
3071 }
3072
3073 if( *success )
3074 SCIP_CALL( SCIPcreateConsBasicSymresack(scip, cons, name, perm, vars, nvars, TRUE) );
3075
3076 SCIPfreeBufferArray(scip, &perm);
3078
3079 return SCIP_OKAY;
3080}
3081
3082
3083/** constraint display method of constraint handler
3084 *
3085 * The constraint handler should output a representation of the constraint into the given text file.
3086 */
3087static
3088SCIP_DECL_CONSPRINT(consPrintSymresack)
3089{ /*lint --e{715}*/
3090 SCIP_CONSDATA* consdata;
3091 SCIP_VAR** vars;
3092 int* perm;
3093 int nvars;
3094 int i;
3095
3096 assert( scip != NULL );
3097 assert( conshdlr != NULL );
3098 assert( cons != NULL );
3099
3101
3102 consdata = SCIPconsGetData(cons);
3103 assert( consdata != NULL );
3104
3105 SCIPdebugMsg(scip, "Printing method for symresack constraint handler\n");
3106
3107 /* we do not have to take care of trivial constraints */
3108 if ( consdata->nvars < 2 )
3109 return SCIP_OKAY;
3110
3111 assert( consdata->vars != NULL );
3112 assert( consdata->perm != NULL );
3113
3114 vars = consdata->vars;
3115 nvars = consdata->nvars;
3116 perm = consdata->perm;
3117
3118 SCIPinfoMessage(scip, file, "symresack([");
3119 SCIP_CALL( SCIPwriteVarName(scip, file, vars[0], TRUE) );
3120
3121 for (i = 1; i < nvars; ++i)
3122 {
3123 SCIPinfoMessage(scip, file, ",");
3125 }
3126 SCIPinfoMessage(scip, file, "],[%d", perm[0]);
3127 for (i = 1; i < nvars; ++i)
3128 SCIPinfoMessage(scip, file, ",%d", perm[i]);
3129 SCIPinfoMessage(scip, file, "])");
3130
3131 return SCIP_OKAY;
3132}
3133
3134
3135/** constraint method of constraint handler which returns the variables (if possible) */
3136static
3137SCIP_DECL_CONSGETVARS(consGetVarsSymresack)
3138{ /*lint --e{715}*/
3139 SCIP_CONSDATA* consdata;
3140
3141 assert( cons != NULL );
3142 assert( success != NULL );
3143 assert( vars != NULL );
3144
3145 consdata = SCIPconsGetData(cons);
3146 assert( consdata != NULL );
3147
3148 if ( varssize < consdata->nvars )
3149 (*success) = FALSE;
3150 else
3151 {
3152 int cnt = 0;
3153 int i;
3154
3155 for (i = 0; i < consdata->nvars; ++i)
3156 vars[cnt++] = consdata->vars[i];
3157 (*success) = TRUE;
3158 }
3159
3160 return SCIP_OKAY;
3161}
3162
3163
3164/** constraint method of constraint handler which returns the number of variables (if possible) */
3165static
3166SCIP_DECL_CONSGETNVARS(consGetNVarsSymresack)
3167{ /*lint --e{715}*/
3168 SCIP_CONSDATA* consdata;
3169
3170 assert( cons != NULL );
3171 assert( success != NULL );
3172 assert( nvars != NULL );
3173
3174 consdata = SCIPconsGetData(cons);
3175 assert( consdata != NULL );
3176
3177 (*nvars) = consdata->nvars;
3178 (*success) = TRUE;
3179
3180 return SCIP_OKAY;
3181}
3182
3183
3184/** creates the handler for symresack constraints and includes it in SCIP */
3186 SCIP* scip /**< SCIP data structure */
3187 )
3188{
3189 SCIP_CONSHDLRDATA* conshdlrdata = NULL;
3190 SCIP_CONSHDLR* conshdlr;
3191
3192 SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
3193
3194 /* include constraint handler */
3197 consEnfolpSymresack, consEnfopsSymresack, consCheckSymresack, consLockSymresack,
3198 conshdlrdata) );
3199 assert( conshdlr != NULL );
3200
3201 /* set non-fundamental callbacks via specific setter functions */
3202 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopySymresack, consCopySymresack) );
3203 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxSymresack) );
3204 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeSymresack) );
3205 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteSymresack) );
3206 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsSymresack) );
3207 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsSymresack) );
3208 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseSymresack) );
3210 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintSymresack) );
3212 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropSymresack) );
3213 SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreSymresack) );
3214 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpSymresack, consSepasolSymresack, CONSHDLR_SEPAFREQ, CONSHDLR_SEPAPRIORITY, CONSHDLR_DELAYSEPA) );
3215 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransSymresack) );
3216 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpSymresack) );
3217 SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolSymresack) );
3218
3219 /* whether we allow upgrading to packing/partioning symresack constraints*/
3220 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/ppsymresack",
3221 "Upgrade symresack constraints to packing/partioning symresacks?",
3222 &conshdlrdata->checkppsymresack, TRUE, DEFAULT_PPSYMRESACK, NULL, NULL) );
3223
3224 /* whether we check for monotonicity of perm when upgrading to packing/partioning symresacks */
3225 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/checkmonotonicity",
3226 "Check whether permutation is monotone when upgrading to packing/partioning symresacks?",
3227 &conshdlrdata->checkmonotonicity, TRUE, DEFAULT_CHECKMONOTONICITY, NULL, NULL) );
3228
3229 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forceconscopy",
3230 "Whether symresack constraints should be forced to be copied to sub SCIPs.",
3231 &conshdlrdata->forceconscopy, TRUE, DEFAULT_FORCECONSCOPY, NULL, NULL) );
3232
3233 return SCIP_OKAY;
3234}
3235
3236
3237/*
3238 * constraint specific interface methods
3239 */
3240
3241/** creates and captures a symresack constraint
3242 *
3243 * In a presolving step, we check whether the permutation acts only on binary points. Otherwise, we eliminate
3244 * the non-binary variables from the permutation.
3245 *
3246 * @note The constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons().
3249 SCIP* scip, /**< SCIP data structure */
3250 SCIP_CONS** cons, /**< pointer to hold the created constraint */
3251 const char* name, /**< name of constraint */
3252 int* perm, /**< permutation */
3253 SCIP_VAR** vars, /**< variables */
3254 int nvars, /**< number of variables in vars array */
3255 SCIP_Bool ismodelcons, /**< whether the symresack is a model constraint */
3256 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
3257 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
3258 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
3259 * Usually set to TRUE. */
3260 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
3261 * TRUE for model constraints, FALSE for additional, redundant constraints. */
3262 SCIP_Bool check, /**< should the constraint be checked for feasibility?
3263 * TRUE for model constraints, FALSE for additional, redundant constraints. */
3264 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
3265 * Usually set to TRUE. */
3266 SCIP_Bool local, /**< is constraint only valid locally?
3267 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
3268 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
3269 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
3270 * adds coefficients to this constraint. */
3271 SCIP_Bool dynamic, /**< is constraint subject to aging?
3272 * Usually set to FALSE. Set to TRUE for own cuts which
3273 * are separated as constraints. */
3274 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
3275 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
3276 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
3277 * if it may be moved to a more global node?
3278 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
3279 )
3280{
3281 SCIP_CONSHDLR* conshdlr;
3282 SCIP_CONSDATA* consdata;
3283
3284 assert( cons != NULL );
3285 assert( nvars > 0 );
3286
3287 /* find the symresack constraint handler */
3288 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
3289 if ( conshdlr == NULL )
3290 {
3291 SCIPerrorMessage("Symresack constraint handler not found.\n");
3292 return SCIP_PLUGINNOTFOUND;
3293 }
3294
3295 /* create constraint data */
3296 SCIP_CALL( consdataCreate(scip, conshdlr, &consdata, vars, nvars, perm, ismodelcons) );
3297
3298 /* create constraint */
3299 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate && (! consdata->ppupgrade), enforce, check, propagate,
3300 local, modifiable, dynamic, removable, stickingatnode) );
3301
3302 return SCIP_OKAY;
3303}
3304
3305
3306/** creates and captures a symresack constraint
3307 * in its most basic variant, i.e., with all constraint flags set to their default values
3308 *
3309 * In a presolving step, we remove all fixed points and cycles that act on non-binary variables of the permutation
3310 *
3311 * @note The constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons().
3314 SCIP* scip, /**< SCIP data structure */
3315 SCIP_CONS** cons, /**< pointer to hold the created constraint */
3316 const char* name, /**< name of constraint */
3317 int* perm, /**< permutation */
3318 SCIP_VAR** vars, /**< variables */
3319 int nvars, /**< number of variables in vars array */
3320 SCIP_Bool ismodelcons /**< whether the symresack is a model constraint */
3321 )
3322{
3323 SCIP_CALL( SCIPcreateConsSymresack(scip, cons, name, perm, vars, nvars, ismodelcons,
3325
3326 return SCIP_OKAY;
3327}
#define CONSHDLR_NEEDSCONS
Definition cons_and.c:96
#define CONSHDLR_SEPAFREQ
Definition cons_and.c:89
#define CONSHDLR_CHECKPRIORITY
Definition cons_and.c:88
#define CONSHDLR_DESC
Definition cons_and.c:85
#define CONSHDLR_PROP_TIMING
Definition cons_and.c:99
#define CONSHDLR_MAXPREROUNDS
Definition cons_and.c:93
#define CONSHDLR_SEPAPRIORITY
Definition cons_and.c:86
#define CONSHDLR_PROPFREQ
Definition cons_and.c:90
#define CONSHDLR_PRESOLTIMING
Definition cons_and.c:98
#define CONSHDLR_EAGERFREQ
Definition cons_and.c:91
#define CONSHDLR_ENFOPRIORITY
Definition cons_and.c:87
#define CONSHDLR_DELAYSEPA
Definition cons_and.c:94
#define CONSHDLR_NAME
Definition cons_and.c:84
#define CONSHDLR_DELAYPROP
Definition cons_and.c:95
#define FIXED0
#define DEFAULT_FORCECONSCOPY
#define UNFIXED
#define FIXED1
constraint handler for orbisack constraints
Constraint handler for the set partitioning / packing / covering constraints .
#define NOINIT
#define ISFIXED(scip, x, bdchgidx)
static SCIP_RETCODE replaceAggregatedVarsSymresack(SCIP *scip, SCIP_CONS *cons)
#define DEFAULT_CHECKMONOTONICITY
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA **consdata, SCIP_VAR *const *inputvars, int inputnvars, int *inputperm, SCIP_Bool ismodelcons)
static SCIP_RETCODE propVariables(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *infeasible, int *ngen)
static SCIP_RETCODE initLP(SCIP *scip, SCIP_CONS *cons, SCIP_Bool checkmonotonicity, SCIP_Bool *infeasible)
static SCIP_RETCODE checkSymresackSolution(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_RESULT *result, SCIP_Bool printreason)
static SCIP_RETCODE checkFeasible(SCIP *scip, SCIP_VAR **vars, int *invperm, int nvars, int start, int *tempfixings, int *tempfixentries, int numfixentriesinit, SCIP_Bool *infeasible, int *infeasibleentry)
static SCIP_RETCODE maximizeObjectiveSymresackCriticalEntry(SCIP *scip, int nvars, SCIP_Real *objective, int *perm, int *invperm, int crit, int *maxsolu)
static SCIP_RETCODE separateSymresackCovers(SCIP *scip, SCIP_CONS *cons, const SCIP_CONSDATA *consdata, SCIP_Real *vals, int *ngen, SCIP_Bool *infeasible)
static SCIP_RETCODE addSymresackInequality(SCIP *scip, SCIP_CONS *cons, int nvars, SCIP_VAR **vars, int *coeffs, SCIP_Real rhs, SCIP_Bool *infeasible)
static SCIP_RETCODE packingUpgrade(SCIP *scip, SCIP_CONSDATA **consdata, int *perm, SCIP_VAR **vars, int nvars, SCIP_Bool checkmonotonicity, SCIP_Bool *upgrade)
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata)
#define DEFAULT_PPSYMRESACK
static SCIP_RETCODE maximizeObjectiveSymresackStrict(SCIP *scip, int nvars, SCIP_Real *objective, int *perm, int *invperm, int *maxcrit, SCIP_Real *maxsoluval)
static SCIP_RETCODE orbisackUpgrade(SCIP *scip, SCIP_CONS **cons, const char *name, int *perm, SCIP_VAR **inputvars, int nvars, SCIP_Bool *upgrade, 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)
constraint handler for symresack constraints
#define SCIP_DEFAULT_INFINITY
Definition def.h:172
#define NULL
Definition def.h:257
#define SCIP_MAXSTRLEN
Definition def.h:278
#define SCIP_UNUSED(x)
Definition def.h:418
#define SCIP_Bool
Definition def.h:100
#define SCIP_STRINGEQ(name, reference, retcode)
Definition def.h:454
#define SCIP_Real
Definition def.h:165
#define TRUE
Definition def.h:102
#define FALSE
Definition def.h:103
#define REALABS(x)
Definition def.h:191
#define SCIP_CALL(x)
Definition def.h:364
SCIP_RETCODE SCIPcreateSymbreakCons(SCIP *scip, SCIP_CONS **cons, const char *name, int *perm, SCIP_VAR **vars, int nvars, 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)
int SCIPgetNVarsSetppc(SCIP *scip, SCIP_CONS *cons)
SCIP_VAR ** SCIPgetVarsSetppc(SCIP *scip, SCIP_CONS *cons)
SCIP_SETPPCTYPE SCIPgetTypeSetppc(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPcreateConsOrbisack(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *const *vars1, SCIP_VAR *const *vars2, int nrows, SCIP_Bool ispporbisack, SCIP_Bool isparttype, 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 SCIPcreateConsBasicSymresack(SCIP *scip, SCIP_CONS **cons, const char *name, int *perm, SCIP_VAR **vars, int nvars, SCIP_Bool ismodelcons)
SCIP_RETCODE SCIPcreateConsSymresack(SCIP *scip, SCIP_CONS **cons, const char *name, int *perm, SCIP_VAR **vars, int nvars, 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_SETPPCTYPE_PARTITIONING
Definition cons_setppc.h:87
@ SCIP_SETPPCTYPE_COVERING
Definition cons_setppc.h:89
@ SCIP_SETPPCTYPE_PACKING
Definition cons_setppc.h:88
SCIP_RETCODE SCIPincludeConshdlrSymresack(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_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition scip_prob.c:3420
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
#define SCIPdebugMsg
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)
SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
SCIP_RETCODE SCIPaddConflictUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
SCIP_RETCODE SCIPaddConflictBinvar(SCIP *scip, SCIP_VAR *var)
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
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
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 SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:578
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:444
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4340
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:601
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:647
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr,)
Definition scip_cons.c:516
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition cons.c:4739
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_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition cons.c:8562
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition cons.c:8592
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_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition cons.c:8642
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition cons.c:8672
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition cons.c:8572
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition cons.c:8662
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
#define SCIPfreeCleanBufferArray(scip, ptr)
Definition scip_mem.h:146
#define SCIPallocCleanBufferArray(scip, ptr, num)
Definition scip_mem.h:142
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition scip_mem.h:110
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition scip_mem.h:126
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 SCIPfreeBufferArrayNull(scip, ptr)
Definition scip_mem.h:137
#define SCIPallocBlockMemory(scip, ptr)
Definition scip_mem.h:89
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition scip_mem.h:105
SCIP_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 SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition scip_lp.c:1508
SCIP_RETCODE SCIPaddVarsToRow(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition scip_lp.c:1672
SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition scip_sol.c:1844
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition scip_sol.c:1763
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition scip_var.c:5210
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition var.c:23674
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition var.c:23510
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition scip_var.c:2119
SCIP_VARSTATUS SCIPvarGetStatus(SCIP_VAR *var)
Definition var.c:23418
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition var.c:24300
SCIP_RETCODE SCIPinferVarUbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:7069
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition scip_var.c:728
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition scip_var.c:5118
SCIP_RETCODE SCIPunlockVarCons(SCIP *scip, SCIP_VAR *var, SCIP_CONS *cons, SCIP_Bool lockdown, SCIP_Bool lockup)
Definition scip_var.c:5296
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition scip_var.c:2872
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition var.c:23694
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition scip_var.c:1887
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition var.c:24266
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition var.c:23475
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition scip_var.c:11057
SCIP_RETCODE SCIPinferVarLbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition scip_var.c:6964
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition scip_var.c:2736
SCIP_RETCODE 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
void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
SCIP_Bool SCIPstrToIntValue(const char *str, int *value, char **endptr)
Definition misc.c:10924
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition misc.c:10827
SCIP_RETCODE SCIPskipSpace(char **s)
Definition misc.c:10816
return SCIP_OKAY
int c
static SCIP_SOL * sol
int r
assert(minobj< SCIPgetCutoffbound(scip))
int nvars
SCIP_VAR * var
static SCIP_Bool propagate
static SCIP_VAR ** vars
int ncycles
memory allocation routines
public methods for managing constraints
public methods for message output
#define SCIPerrorMessage
Definition pub_message.h:64
public data structures and miscellaneous methods
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 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 solutions
public methods for SCIP variables
static SCIP_RETCODE separate(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_RESULT *result)
Main separation function.
@ SCIP_CONFTYPE_PROPAGATION
#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_CONSINITSOL(x)
Definition type_cons.h:201
#define SCIP_DECL_CONSPRINT(x)
Definition type_cons.h:769
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition type_cons.h:64
#define SCIP_DECL_CONSSEPALP(x)
Definition type_cons.h:288
#define SCIP_DECL_CONSENFORELAX(x)
Definition type_cons.h:388
#define SCIP_DECL_CONSPROP(x)
Definition type_cons.h:506
#define SCIP_DECL_CONSGETNVARS(x)
Definition type_cons.h:885
#define SCIP_DECL_CONSRESPROP(x)
Definition type_cons.h:612
#define SCIP_DECL_CONSENFOPS(x)
Definition type_cons.h:431
#define SCIP_DECL_CONSPARSE(x)
Definition type_cons.h:845
#define SCIP_DECL_CONSTRANS(x)
Definition type_cons.h:239
#define SCIP_DECL_CONSPRESOL(x)
Definition type_cons.h:561
#define SCIP_DECL_CONSINITLP(x)
Definition type_cons.h:259
#define SCIP_DECL_CONSEXITPRE(x)
Definition type_cons.h:180
#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_CONSFREE(x)
Definition type_cons.h:116
#define SCIP_DECL_CONSSEPASOL(x)
Definition type_cons.h:320
struct SCIP_Row SCIP_ROW
Definition type_lp.h:105
@ SCIP_BOUNDTYPE_LOWER
Definition type_lp.h:57
@ 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
@ SCIP_INVALIDCALL
enum SCIP_Retcode SCIP_RETCODE
struct Scip SCIP
Definition type_scip.h:39
struct SCIP_Sol SCIP_SOL
Definition type_sol.h:57
struct SCIP_Var SCIP_VAR
Definition type_var.h:166
@ SCIP_VARSTATUS_FIXED
Definition type_var.h:54
@ SCIP_VARSTATUS_MULTAGGR
Definition type_var.h:56
@ SCIP_VARSTATUS_NEGATED
Definition type_var.h:57