Scippy

SCIP

Solving Constraint Integer Programs

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-2025 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file cons_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
254 SCIP_CALL( SCIPallocBufferArray(scip, &covered, nvars) );
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;
396 assert( SCIPgetTypeSetppc(scip, setppcconss[c]) == SCIP_SETPPCTYPE_PARTITIONING || SCIPgetTypeSetppc(scip, setppcconss[c]) == SCIP_SETPPCTYPE_PACKING );
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
417 varidx = SCIPvarGetProbindex(var);
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 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
495
496 SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
497
498#ifdef SCIP_DEBUG
499 (*consdata)->debugcnt = 0;
500#endif
501
502 (*consdata)->ndescentpoints = 0;
503 (*consdata)->descentpoints = NULL;
504 (*consdata)->ismodelcons = ismodelcons;
505
506 /* count the number of binary variables which are affected by the permutation */
507 SCIP_CALL( SCIPallocBufferArray(scip, &indexcorrection, inputnvars) );
508 indexcorrection[0] = -1;
509 for (i = 0; i < inputnvars; ++i)
510 {
511 if ( inputperm[i] != i && SCIPvarIsBinary(inputvars[i]) )
512 {
513 if ( i == 0 )
514 indexcorrection[i] = 0;
515 else
516 indexcorrection[i] = indexcorrection[i - 1] + 1;
517 }
518 else
519 {
520 if ( i > 0 )
521 indexcorrection[i] = indexcorrection[i - 1];
522 }
523 }
524 naffectedvariables = indexcorrection[inputnvars - 1] + 1;
525
526 (*consdata)->nvars = naffectedvariables;
527
528 /* Stop if we detect that the permutation fixes each binary point. */
529 if ( naffectedvariables == 0 )
530 {
531 SCIPfreeBufferArrayNull(scip, &indexcorrection);
532
533 (*consdata)->vars = NULL;
534 (*consdata)->perm = NULL;
535 (*consdata)->invperm = NULL;
536 (*consdata)->ppupgrade = FALSE;
537 (*consdata)->ncycles = 0;
538 (*consdata)->cycledecomposition = NULL;
539 return SCIP_OKAY;
540 }
541
542 /* remove fixed points from permutation representation */
543 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &vars, naffectedvariables) );
544 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &perm, naffectedvariables) );
545 for (i = 0; i < inputnvars; ++i)
546 {
547 if ( i == 0 )
548 {
549 if ( indexcorrection[i] > -1 )
550 {
551 vars[j] = inputvars[i];
552 perm[j++] = indexcorrection[inputperm[i]];
553 }
554 }
555 else
556 {
557 if ( indexcorrection[i] > indexcorrection[i - 1] )
558 {
559 vars[j] = inputvars[i];
560 perm[j++] = indexcorrection[inputperm[i]];
561 }
562 }
563 }
564 SCIPfreeBufferArrayNull(scip, &indexcorrection);
565
566 (*consdata)->vars = vars;
567 (*consdata)->perm = perm;
568
569 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &invperm, naffectedvariables) );
570 for (i = 0; i < naffectedvariables; ++i)
571 {
572 SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[i]) );
573 invperm[perm[i]] = i;
574 }
575 (*consdata)->invperm = invperm;
576
577 /* check for upgrade to packing/partitioning symresacks*/
578 conshdlrdata = SCIPconshdlrGetData(conshdlr);
579 upgrade = FALSE;
580 if ( conshdlrdata->checkppsymresack )
581 {
582 SCIP_CALL( packingUpgrade(scip, consdata, perm, vars, naffectedvariables, conshdlrdata->checkmonotonicity, &upgrade) );
583 }
584
585 (*consdata)->ppupgrade = upgrade;
586
587 /* get transformed variables, if we are in the transformed problem */
588 if ( SCIPisTransformed(scip) )
589 {
590 /* Make sure that all variables cannot be multiaggregated (cannot be handled by cons_symresack, since one cannot
591 * easily eliminate single variables from a symresack constraint. */
592 for (i = 0; i < naffectedvariables; ++i)
593 {
594 SCIP_CALL( SCIPgetTransformedVar(scip, (*consdata)->vars[i], &(*consdata)->vars[i]) );
595 SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->vars[i]) );
596 }
597 }
598
599 return SCIP_OKAY;
600}
601
602
603/** generate initial LP cut
604 *
605 * We generate the ordering inequality for the pair \f$(1, \gamma^{-1}(1))\f$, i.e.,
606 * the inequality \f$-x_{1} + x_{\gamma^{-1}(1)} \leq 0\f$. This inequality is valid,
607 * because we guaranteed in a preprocessing step that all variables are binary.
608 *
609 * Furthermore, we add facet inequalities of packing/partitioning symresacks if
610 * we deal with packing/partitioning symresacks.
611 */
612static
614 SCIP* scip, /**< SCIP pointer */
615 SCIP_CONS* cons, /**< constraint */
616 SCIP_Bool checkmonotonicity, /**< has it been checked whether permutation is monotone for packing/partitioning symresacks? */
617 SCIP_Bool* infeasible /**< pointer to store whether we detected infeasibility */
618 )
619{
620 SCIP_CONSDATA* consdata;
621 SCIP_VAR** vars;
622 SCIP_ROW* row;
623 int nvars;
624#ifdef SCIP_DEBUG
625 char name[SCIP_MAXSTRLEN];
626#endif
627 int i;
628 int j;
629 int k;
630
631 assert( scip != NULL );
632 assert( cons != NULL );
633 assert( infeasible != NULL );
634
635 *infeasible = FALSE;
636
637 consdata = SCIPconsGetData(cons);
638 assert( consdata != NULL );
639
640 nvars = consdata->nvars;
641
642 /* avoid stupid problems */
643 if ( nvars <= 1 )
644 return SCIP_OKAY;
645
646 assert( consdata->vars != NULL );
647 vars = consdata->vars;
648
649 /* there are no fixed points */
650 assert( consdata->invperm[0] != 0 );
651
652 /* add ordering inequality */
653#ifdef SCIP_DEBUG
654 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "symresack_init_%s", SCIPconsGetName(cons));
655 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), 0.0, FALSE, FALSE, TRUE) );
656#else
657 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, "", -SCIPinfinity(scip), 0.0, FALSE, FALSE, TRUE) );
658#endif
659 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[0], -1.0) );
660 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[consdata->invperm[0]], 1.0) );
661
662 SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
663
664 SCIP_CALL( SCIPreleaseRow(scip, &row) );
665
666 /* check whether we have a packing/partioning symresack */
667 if ( consdata->ppupgrade && ! *infeasible )
668 {
669 if ( checkmonotonicity )
670 {
671 SCIP_VAR** varsincons;
672 SCIP_Real* coeffs;
673 int** cycledecomposition;
674 int ncycles;
675 int nvarsincons;
676 int nvarsincycle;
677 int firstelemincycle;
678
679 ncycles = consdata->ncycles;
680 cycledecomposition = consdata->cycledecomposition;
681
682 SCIP_CALL( SCIPallocBufferArray(scip, &varsincons, nvars) );
683 SCIP_CALL( SCIPallocBufferArray(scip, &coeffs, nvars) );
684
685 coeffs[0] = 1.0;
686
687 /* add packing/partitioning symresack constraints */
688 for (i = 0; i < ncycles; ++i)
689 {
690 assert( cycledecomposition[i][0] > 0 );
691
692 nvarsincycle = cycledecomposition[i][0];
693 varsincons[0] = vars[cycledecomposition[i][nvarsincycle]];
694 firstelemincycle = cycledecomposition[i][1];
695
696 assert( firstelemincycle == consdata->perm[cycledecomposition[i][nvarsincycle]] );
697
698 nvarsincons = 1;
699
700 /* add variables of other cycles to the constraint */
701 for (j = 0; j < i; ++j)
702 {
703 nvarsincycle = cycledecomposition[j][0];
704 for (k = 1; k <= nvarsincycle; ++k)
705 {
706 if ( cycledecomposition[j][k] < firstelemincycle )
707 {
708 varsincons[nvarsincons] = vars[cycledecomposition[j][k]];
709 coeffs[nvarsincons++] = -1.0;
710 }
711 else
712 continue;
713 }
714 }
715
716#ifdef SCIP_DEBUG
717 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "ppSymresack_%d_%s", i, SCIPconsGetName(cons));
718 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), 0.0, FALSE, FALSE, TRUE) );
719#else
720 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, "", -SCIPinfinity(scip), 0.0, FALSE, FALSE, TRUE) );
721#endif
722 SCIP_CALL( SCIPaddVarsToRow(scip, row, nvarsincons, varsincons, coeffs) );
723
724 SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
725 SCIP_CALL( SCIPreleaseRow(scip, &row) );
726
727 if ( *infeasible )
728 break;
729 }
730
731 SCIPfreeBufferArray(scip, &coeffs);
732 SCIPfreeBufferArray(scip, &varsincons);
733 }
734 else
735 {
736 SCIP_Real* coeffs;
737 SCIP_VAR** varsincons;
738 int* imgdescentpoints;
739 int* descentpoints;
740 int* perm;
741 int ndescentpoints;
742 int lastascent = 0;
743 int newlastascent = 0;
744 int nvarsincons = 1;
745
746 descentpoints = consdata->descentpoints;
747 ndescentpoints = consdata->ndescentpoints;
748 perm = consdata->perm;
749
750 assert( descentpoints != NULL );
751 assert( ndescentpoints > 0 );
752 assert( perm != NULL );
753 assert( vars != NULL );
754 assert( nvars > 0 );
755
756 SCIP_CALL( SCIPallocBufferArray(scip, &imgdescentpoints, ndescentpoints) );
757
758 /* get images of descentpoints */
759 for (j = 0; j < ndescentpoints; ++j)
760 imgdescentpoints[j] = perm[descentpoints[j]];
761
762 /* sort descent points increasingly w.r.t. the corresponding image */
763 SCIPsortIntInt(imgdescentpoints, descentpoints, ndescentpoints);
764
765 /* iteratively generate coefficient vector: the first entry is the descent point j and the remaining entries
766 * are the corresponding ascent points less than perm[j]
767 */
768 SCIP_CALL( SCIPallocClearBufferArray(scip, &coeffs, nvars) );
769 SCIP_CALL( SCIPallocClearBufferArray(scip, &varsincons, nvars) );
770 coeffs[0] = 1.0;
771 for (j = 0; j < ndescentpoints; ++j)
772 {
773 varsincons[0] = vars[descentpoints[j]];
774 for (i = lastascent; i < imgdescentpoints[j]; ++i)
775 {
776 if ( perm[i] > i )
777 {
778 coeffs[nvarsincons] = -1.0;
779 varsincons[nvarsincons++] = vars[i];
780 newlastascent = i;
781 }
782 }
783 lastascent = newlastascent;
784
785#ifdef SCIP_DEBUG
786 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "ppSymresack_%d_%s", j, SCIPconsGetName(cons));
787 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), 0.0, FALSE, FALSE, TRUE) );
788#else
789 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, "", -SCIPinfinity(scip), 0.0, FALSE, FALSE, TRUE) );
790#endif
791 SCIP_CALL( SCIPaddVarsToRow(scip, row, nvarsincons, varsincons, coeffs) );
792
793 SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
794 SCIP_CALL( SCIPreleaseRow(scip, &row) );
795
796 if ( *infeasible )
797 break;
798 }
799
800 SCIPfreeBufferArray(scip, &varsincons);
801 SCIPfreeBufferArray(scip, &coeffs);
802 SCIPfreeBufferArray(scip, &imgdescentpoints);
803 }
804 }
805
806 return SCIP_OKAY;
807}
808
809
810/** Determines if a vector with additional fixings could exist that is lexicographically larger than its image.
811 *
812 * Given a vector of variables, a permutation, and a set of additional (virtual) fixings.
813 * If a vector adhering to the local variable bounds (local fixings) and to the virtual fixings exists,
814 * then infeasible is FALSE, otherwise TRUE.
815 */
816static
818 SCIP* scip, /**< SCIP pointer */
819 SCIP_VAR** vars, /**< array of variables affected by permutation */
820 int* invperm, /**< inverse of permutation */
821 int nvars, /**< number of variables */
822 int start, /**< at which position to start (assuming previous positions are equal) */
823 int* tempfixings, /**< array with at entry i the virtual fixing of variable vars[i] */
824 int* tempfixentries, /**< the entries i that are virtually fixed until numfixentriesinit */
825 int numfixentriesinit, /**< the number of virtually fixed entries */
826 SCIP_Bool* infeasible, /**< pointer to store whether infeasibility is detected in these fixings */
827 int* infeasibleentry /**< pointer to store at which entry a (0, 1) pattern is found */
828 )
829{
830 SCIP_VAR* var1;
831 SCIP_VAR* var2;
832 int var1fix;
833 int var2fix;
834
835 int i;
836 int numfixentries;
837
838 /* avoid trivial problems */
839 if ( nvars < 2 )
840 return SCIP_OKAY;
841
842 assert( scip != NULL );
843 assert( vars != NULL );
844 assert( invperm != NULL );
845 assert( tempfixings != NULL );
846 assert( tempfixentries != NULL );
847 assert( infeasible != NULL );
848
849 /* A counter for how many virtual fixings we have. */
850 numfixentries = numfixentriesinit;
851
852 *infeasible = FALSE;
853
854 for (i = start; i < nvars; ++i)
855 {
856 /* there are no fixed points */
857 assert( invperm[i] != i );
858
859 /* get variables of first and second column */
860 var1 = vars[i];
861 var2 = vars[invperm[i]];
862
863 assert( var1 != NULL );
864 assert( var2 != NULL );
865
866 /* Get virtual fixing of variable in left column */
867 var1fix = tempfixings[i];
868 if ( var1fix == NOINIT )
869 {
870 if ( SCIPvarGetUbLocal(var1) < 0.5 )
871 {
872 var1fix = FIXED0;
873 assert( SCIPvarGetLbLocal(var1) <= 0.5 );
874 }
875 else if ( SCIPvarGetLbLocal(var1) > 0.5 )
876 var1fix = FIXED1;
877 else
878 var1fix = UNFIXED;
879 }
880 assert( var1fix != NOINIT );
881
882 /* Get virtual fixing of variable in right column */
883 var2fix = tempfixings[invperm[i]];
884 if ( var2fix == NOINIT )
885 {
886 if ( SCIPvarGetUbLocal(var2) < 0.5 )
887 {
888 var2fix = FIXED0;
889 assert( SCIPvarGetLbLocal(var2) <= 0.5 );
890 }
891 else if ( SCIPvarGetLbLocal(var2) > 0.5 )
892 var2fix = FIXED1;
893 else
894 var2fix = UNFIXED;
895 }
896 assert( var2fix != NOINIT );
897
898 /* Encounter one of (_, _), (_, 0), (1, _), (1, 0). In all cases (1, 0) can be constructed. Thus feasible. */
899 if ( var1fix != FIXED0 && var2fix != FIXED1 )
900 break;
901 /* Encounter (0, 1). Infeasible. */
902 else if ( var1fix == FIXED0 && var2fix == FIXED1 )
903 {
904 *infeasible = TRUE;
905 *infeasibleentry = i;
906 break;
907 }
908 /* Encounter (0, _). Virtually fix var2 to 0. */
909 else if ( var1fix == FIXED0 && var2fix == UNFIXED )
910 {
911 tempfixings[invperm[i]] = FIXED0;
912 /* Mark that we have fixed invperm[i]. */
913 tempfixentries[numfixentries++] = invperm[i];
914 }
915 /* Encounter (_, 1). Virtually fix var1 to 1. */
916 else if(var1fix == UNFIXED && var2fix == FIXED1 )
917 {
918 tempfixings[i] = FIXED0;
919 /* Mark that we have fixed invperm[i]. */
920 tempfixentries[numfixentries++] = i;
921 }
922 /* Remaining cases are (0, 0) and (1, 1). In both cases: continue. */
923 }
924
925 /* Undo virtual fixings made in this function */
926 for (i = numfixentriesinit; i < numfixentries; ++i)
927 {
928 tempfixings[tempfixentries[i]] = NOINIT;
929 tempfixentries[i] = 0;
930 }
931
932 return SCIP_OKAY;
933}
934
935
936/** perform propagation of symresack constraint */
937static
939 SCIP* scip, /**< SCIP pointer */
940 SCIP_CONS* cons, /**< constraint to be propagated */
941 SCIP_Bool* infeasible, /**< pointer to store whether it was detected that the node is infeasible */
942 int* ngen /**< pointer to store number of generated bound strengthenings */
943 )
944{
945 SCIP_CONSDATA* consdata;
946 SCIP_VAR** vars;
947 int* invperm;
948 int nvars;
949 int i;
950 int r;
951 SCIP_VAR* var1;
952 SCIP_VAR* var2;
953 int var1fix;
954 int var2fix;
955 SCIP_Bool tightened;
956 SCIP_Bool peekinfeasible;
957 int peekinfeasibleentry;
958 int* tempfixings;
959 int* tempfixentries;
960
961 assert( scip != NULL );
962 assert( cons != NULL );
963 assert( infeasible != NULL );
964 assert( ngen != NULL );
965
966 SCIPdebugMsg(scip, "Propagating variables of constraint <%s>.\n", SCIPconsGetName(cons));
967
968 *ngen = 0;
969 *infeasible = FALSE;
970
971 /* get data of constraint */
972 consdata = SCIPconsGetData(cons);
973 assert( consdata != NULL );
974 nvars = consdata->nvars;
975
976 /* avoid trivial problems */
977 if ( nvars < 2 )
978 return SCIP_OKAY;
979
980 assert( consdata->vars != NULL );
981 assert( consdata->invperm != NULL );
982 vars = consdata->vars;
983 invperm = consdata->invperm;
984
985 /* loop through all variables */
986 for (i = 0; i < nvars; ++i)
987 {
988 /* there are no fixed points */
989 assert( invperm[i] != i );
990
991 /* get variables of first and second column */
992 var1 = vars[i];
993 var2 = vars[invperm[i]];
994 assert( var1 != NULL );
995 assert( var2 != NULL );
996
997 /* Get the fixing status of the left column variable var1 */
998 if ( SCIPvarGetUbLocal(var1) < 0.5 )
999 {
1000 var1fix = FIXED0;
1001 assert( SCIPvarGetLbLocal(var1) <= 0.5 );
1002 }
1003 else if ( SCIPvarGetLbLocal(var1) > 0.5 )
1004 var1fix = FIXED1;
1005 else
1006 var1fix = UNFIXED;
1007
1008 /* Get the fixing status of the right column variable var2 */
1009 if ( SCIPvarGetUbLocal(var2) < 0.5 )
1010 {
1011 var2fix = FIXED0;
1012 assert( SCIPvarGetLbLocal(var2) <= 0.5 );
1013 }
1014 else if ( SCIPvarGetLbLocal(var2) > 0.5 )
1015 var2fix = FIXED1;
1016 else
1017 var2fix = UNFIXED;
1018
1019 /* Encounter one of (_, _), (_, 0), (1, _), (1, 0). Check if (1, 1) or (0, 0) are possible, otherwise fix. */
1020 if ( var1fix != FIXED0 && var2fix != FIXED1 )
1021 {
1022 assert( SCIPvarGetUbLocal(var1) > 0.5 );
1023 assert( SCIPvarGetLbLocal(var2) < 0.5 );
1024
1025 SCIPdebugMsg(scip, "Check variable pair (%d,%d).\n", i, invperm[i]);
1026 SCIPdebugMsg(scip, " -> node is feasible (could set pair to (1,0) and every earlier pair is constant).\n");
1027
1028 if ( var1fix == UNFIXED || var2fix == UNFIXED )
1029 {
1030 /* Create arrays tempfixings and tempfixentries to store virtual fixings. */
1031 SCIP_CALL( SCIPallocCleanBufferArray(scip, &tempfixings, nvars) );
1032 SCIP_CALL( SCIPallocCleanBufferArray(scip, &tempfixentries, nvars) );
1033
1034 if ( var1fix == UNFIXED )
1035 {
1036 assert( SCIPvarGetLbLocal(var1) < 0.5 );
1037
1038 /* Peek whether a lexicographical larger-or-equal vector can be created with var1 fixed to 0 */
1039 SCIPdebugMsg(scip, " -> First entry is not fixed. Check if 0 is feasible.\n");
1040 tempfixings[i] = FIXED0;
1041 tempfixentries[0] = i;
1042 SCIP_CALL( checkFeasible(scip, vars, invperm, nvars, i, tempfixings, tempfixentries, 1,
1043 &peekinfeasible, &peekinfeasibleentry) );
1044
1045 if ( peekinfeasible )
1046 {
1047 /* No feasible vector exists with var1 set to 0, so it must be a 1-fixing. */
1048 SCIPdebugMsg(scip, " -> First entry is not fixed. 0 is not feasible. Fixing to 1.\n");
1049 SCIP_CALL( SCIPinferVarLbCons(scip, var1, 1.0, cons, i + nvars * peekinfeasibleentry,
1050 FALSE, infeasible, &tightened) ); /*lint !e713*/
1051 assert( ! *infeasible );
1052
1053 if ( tightened )
1054 ++(*ngen);
1055 }
1056
1057 tempfixings[i] = NOINIT;
1058 tempfixentries[0] = 0;
1059 }
1060
1061 if ( var2fix == UNFIXED )
1062 {
1063 assert( SCIPvarGetUbLocal(var2) > 0.5 );
1064
1065 /* Peek whether a lexicographical larger-or-equal vector can be created with var2 fixed to 1 */
1066 SCIPdebugMsg(scip, " -> Second entry is not fixed. Check if 1 is feasible.\n");
1067 tempfixings[invperm[i]] = FIXED1;
1068 tempfixentries[0] = invperm[i];
1069 SCIP_CALL( checkFeasible(scip, vars, invperm, nvars, i, tempfixings, tempfixentries, 1,
1070 &peekinfeasible, &peekinfeasibleentry) );
1071
1072 if ( peekinfeasible )
1073 {
1074 /* No feasible vector exists with var2 set to 1, so it must be a 1-fixing. */
1075 SCIPdebugMsg(scip, " -> Second entry is not fixed. 1 is not feasible. Fixing to 0.\n");
1076 SCIP_CALL( SCIPinferVarUbCons(scip, var2, 0.0, cons, i + nvars * peekinfeasibleentry,
1077 FALSE, infeasible, &tightened) ); /*lint !e713*/
1078 assert( ! *infeasible );
1079
1080 if ( tightened )
1081 ++(*ngen);
1082 }
1083
1084 tempfixings[invperm[i]] = NOINIT;
1085 tempfixentries[0] = 0;
1086 }
1087
1088 SCIPfreeCleanBufferArray(scip, &tempfixentries);
1089 SCIPfreeCleanBufferArray(scip, &tempfixings);
1090 }
1091
1092 /* Can stop here, because this row can become (1, 0). Therefore all next rows can take arbitrary values. */
1093 break;
1094 }
1095 /* Encounter (0, 1): If first part of variable pair fixed to 0 and second part is fixed to 1 */
1096 else if ( var1fix == FIXED0 && var2fix == FIXED1 )
1097 {
1098 SCIPdebugMsg(scip, "Check variable pair (%d,%d).\n", i, invperm[i]);
1099
1100 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");
1101
1102 /* perform conflict analysis */
1104 {
1106
1107 for (r = 0; r <= i; ++r)
1108 {
1109 /* there are no fixed points */
1110 assert( invperm[r] != r );
1111
1113 SCIP_CALL( SCIPaddConflictBinvar(scip, vars[invperm[r]]) );
1114 }
1115
1117 }
1118
1119 *infeasible = TRUE;
1120 break;
1121 }
1122 /* Encounter (0, _): Fix second part to 0 */
1123 else if ( var1fix == FIXED0 && var2fix != FIXED0 )
1124 {
1125 assert( SCIPvarGetUbLocal(var1) < 0.5 );
1126 assert( SCIPvarGetLbLocal(var2) < 0.5 );
1127 assert( SCIPvarGetUbLocal(var2) > 0.5 );
1128
1129 SCIPdebugMsg(scip, "Check variable pair (%d,%d).\n", i, invperm[i]);
1130
1131 assert( SCIPvarGetLbLocal(var2) < 0.5 );
1132 SCIP_CALL( SCIPinferVarUbCons(scip, var2, 0.0, cons, i, FALSE, infeasible, &tightened) ); /*lint !e713*/
1133 assert( ! *infeasible );
1134
1135 if ( tightened )
1136 ++(*ngen);
1137 }
1138 /* Encounter (_, 1): fix first part to 1 */
1139 else if ( var1fix != FIXED1 && var2fix == FIXED1 )
1140 {
1141 assert( SCIPvarGetLbLocal(var1) < 0.5 );
1142 assert( SCIPvarGetUbLocal(var1) > 0.5 );
1143 assert( SCIPvarGetLbLocal(var2) > 0.5 );
1144
1145 SCIPdebugMsg(scip, "Check variable pair (%d,%d).\n", i, invperm[i]);
1146
1147 assert( SCIPvarGetUbLocal(var1) > 0.5 );
1148 SCIP_CALL( SCIPinferVarLbCons(scip, var1, 1.0, cons, i, FALSE, infeasible, &tightened) ); /*lint !e713*/
1149 assert( ! *infeasible );
1150
1151 if ( tightened )
1152 ++(*ngen);
1153 }
1154 /* Remaining cases are (0, 0) and (1, 1). In these cases we can continue! */
1155 }
1156
1157 return SCIP_OKAY;
1158}
1159
1160
1161/** add symresack cover inequality */
1162static
1164 SCIP* scip, /**< SCIP pointer */
1165 SCIP_CONS* cons, /**< constraint */
1166 int nvars, /**< number of variables */
1167 SCIP_VAR** vars, /**< variables */
1168 int* coeffs, /**< coefficient vector of inequality to be added */
1169 SCIP_Real rhs, /**< right-hand side of inequality to be added */
1170 SCIP_Bool* infeasible /**< pointer to store whether we detected infeasibility */
1171 )
1172{
1173 SCIP_ROW* row;
1174 int i;
1175#ifdef SCIP_DEBUG
1176 SCIP_CONSDATA* consdata;
1177 char name[SCIP_MAXSTRLEN];
1178#endif
1179
1180 assert( scip != NULL );
1181 assert( cons != NULL );
1182 assert( nvars > 0 );
1183 assert( vars != NULL );
1184 assert( coeffs != NULL );
1185 assert( infeasible != NULL );
1186
1187 *infeasible = FALSE;
1188
1189#ifdef SCIP_DEBUG
1190 consdata = SCIPconsGetData(cons);
1191 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "symresack_cover_%s_%d", SCIPconsGetName(cons), consdata->debugcnt);
1192 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), rhs, FALSE, FALSE, TRUE) );
1193 ++consdata->debugcnt;
1194#else
1195 SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, "", -SCIPinfinity(scip), rhs, FALSE, FALSE, TRUE) );
1196#endif
1198
1199 for (i = 0; i < nvars; ++i)
1200 {
1201 if ( coeffs[i] == 1 || coeffs[i] == -1 )
1202 {
1203 SCIP_CALL( SCIPaddVarToRow(scip, row, vars[i], (SCIP_Real) coeffs[i]) );
1204 }
1205 }
1207 SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
1208 SCIP_CALL( SCIPreleaseRow(scip, &row) );
1209
1210 return SCIP_OKAY;
1211}
1212
1213
1214/** Maximize a linear function on a "strict" symresack,
1215 * that is a symresack where we do not allow the solution x = gamma(x).
1216 */
1217static
1219 SCIP* scip, /**< SCIP pointer */
1220 int nvars, /**< number of variables in symresack */
1221 SCIP_Real* objective, /**< the objective vector */
1222 int* perm, /**< the permutation (without fixed points) as an array */
1223 int* invperm, /**< the inverse permutation as an array */
1224 int* maxcrit, /**< pointer to the critical entry where optimality is found at */
1225 SCIP_Real* maxsoluval /**< pointer to store the optimal objective value */
1226 )
1227{
1228 /* The maximal objective in every iteration. */
1229 SCIP_Real tmpobj;
1230 /* The new value of componentobj when combining two components. */
1231 SCIP_Real tmpnewcompobj;
1232 /* helperobj is the sum of all positive objective-sums for all components. */
1233 SCIP_Real helperobj = 0.0;
1234
1235 int crit;
1236 int critinv;
1237 int i;
1238
1239 /* For every vertex of degree < 2 we maintain componentends and componentobj. */
1240 int* componentends;
1241 SCIP_Real* componentobj;
1242
1243 assert( scip != NULL );
1244 assert( nvars > 0 );
1245 assert( objective != NULL );
1246 assert( perm != NULL );
1247 assert( invperm != NULL );
1248 assert( maxcrit != NULL );
1249 assert( maxsoluval != NULL );
1250
1251 /* The current best known critical entry and objective */
1252 *maxcrit = -1;
1253 *maxsoluval = -SCIP_DEFAULT_INFINITY;
1254
1255 SCIP_CALL( SCIPallocBufferArray(scip, &componentends, nvars) );
1256 SCIP_CALL( SCIPallocBufferArray(scip, &componentobj, nvars) );
1257
1258 /* Initialization: Every entry is a component in the graph,
1259 * having the corresponding objective
1260 */
1261 for (i = 0; i < nvars; ++i)
1262 {
1263 componentends[i] = i;
1264 componentobj[i] = objective[i];
1265 if ( SCIPisGT(scip, objective[i], 0.0) )
1266 helperobj += objective[i];
1267 }
1268
1269 /* Iterate over all critical rows, and of the graph maintain the components on the vertices of degree < 2. */
1270 for (crit = 0; crit < nvars; ++crit)
1271 {
1272 critinv = invperm[crit];
1273
1274 /* Do not allow fixed points. */
1275 assert( crit != critinv );
1276
1277 /* If the other end of the component of crit is critinv, then crit cannot be a critical entry. */
1278 if ( componentends[crit] == critinv )
1279 continue;
1280
1281 /* Compute objective for crit as critical entry. Update if it is better than the best found objective */
1282 tmpobj = helperobj;
1283 if ( SCIPisLT(scip, componentobj[crit], 0.0) )
1284 tmpobj += componentobj[crit];
1285 if ( SCIPisGT(scip, componentobj[critinv], 0.0) )
1286 tmpobj -= componentobj[critinv];
1287 if ( SCIPisGT(scip, tmpobj, *maxsoluval) )
1288 {
1289 *maxsoluval = tmpobj;
1290 *maxcrit = crit;
1291 }
1292
1293 /* Update helperobj */
1294 tmpnewcompobj = componentobj[crit] + componentobj[critinv];
1295 if ( SCIPisGT(scip, componentobj[crit], 0.0) )
1296 helperobj -= componentobj[crit];
1297 if ( SCIPisGT(scip, componentobj[critinv], 0.0) )
1298 helperobj -= componentobj[critinv];
1299 if ( SCIPisGT(scip, tmpnewcompobj, 0.0) )
1300 helperobj += tmpnewcompobj;
1301
1302 /* Update the objective of a component */
1303 componentobj[componentends[crit]] = tmpnewcompobj;
1304 componentobj[componentends[critinv]] = tmpnewcompobj;
1305
1306 /* Connect the endpoints of the newly created path */
1307 if ( componentends[crit] == crit )
1308 {
1309 componentends[crit] = componentends[critinv];
1310 componentends[componentends[critinv]] = crit;
1311 }
1312 else
1313 {
1314 componentends[componentends[crit]] = componentends[critinv];
1315 componentends[componentends[critinv]] = componentends[crit];
1316 }
1317
1318 /* Early termination criterion. helperobj is upper bound to tmpobj for every next iteration,
1319 * so if helperobj <= maxsoluval then we can terminate earlier.
1320 */
1321 if ( SCIPisGE(scip, *maxsoluval, helperobj) )
1322 break;
1323 }
1324
1325 /* It is always possible to make the first entry critical. */
1326 assert( *maxcrit >= 0 );
1327
1328 SCIPfreeBufferArray(scip, &componentobj);
1329 SCIPfreeBufferArray(scip, &componentends);
1330
1331 return SCIP_OKAY;
1332}
1333
1334
1335/** For a symresack, determine a maximizer for optimizing linear function
1336 * over a symresack, where the critical entry is fixed.
1337 */
1338static
1340 SCIP* scip, /**< SCIP pointer */
1341 int nvars, /**< number of variables in symresack */
1342 SCIP_Real* objective, /**< the objective vector */
1343 int* perm, /**< the permutation (without fixed points) as an array */
1344 int* invperm, /**< the inverse permutation as an array */
1345 int crit, /**< critical entry where optimality is found at */
1346 int* maxsolu /**< pointer to the optimal objective array */
1347 )
1348{
1349 /* Compute to which components all entries belong. */
1350 int* entrycomponent;
1351 SCIP_Real* componentobjective;
1352
1353 int i;
1354 int c;
1355
1356 assert( scip != NULL );
1357 assert( nvars > 0 );
1358 assert( objective != NULL );
1359 assert( perm != NULL );
1360 assert( invperm != NULL );
1361 assert( maxsolu != NULL );
1362 assert( crit >= 0 );
1363 assert( crit <= nvars );
1364
1365 SCIP_CALL( SCIPallocBufferArray(scip, &entrycomponent, nvars) );
1366 SCIP_CALL( SCIPallocBufferArray(scip, &componentobjective, nvars) );
1367
1368 /* Initially: Everything forms its own component */
1369 for (i = 0; i < nvars; ++i)
1370 {
1371 entrycomponent[i] = i;
1372 componentobjective[i] = objective[i];
1373 }
1374 for (i = 0; i < crit; ++i)
1375 {
1376 /* The graph with arcs {i, invperm[i]} if i < c is a collection of paths, cycles and singletons.
1377 * Label the vertices to the lowest entry in the component, and store the value of that in this component.
1378 * Every inner while-loop labels one new vertex per iteration, and a vertex is relabeled exactly once.
1379 */
1380 if ( entrycomponent[i] < i )
1381 {
1382 /* This entry is already included in a component. */
1383 continue;
1384 }
1385
1386 /* Follow the path forward: Take edges {c, invperm[c]} until c >= crit, or a cycle is found. */
1387 c = i;
1388 while( c < crit )
1389 {
1390 /* c < crit, so edge {c, invperm[c]} exists. Label invperm[c] as part of component of i */
1391 c = invperm[c];
1392
1393 /* Stop if we find a cycle. */
1394 if ( entrycomponent[c] != c )
1395 break;
1396
1397 entrycomponent[c] = i;
1398 componentobjective[i] += objective[c];
1399 }
1400
1401 /* Follow the path backward: Take edges {c, perm[c]} until perm[c] >= crit, or a cycle is found. */
1402 c = perm[i];
1403 while( c < crit )
1404 {
1405 /* c < crit, so edge {c, invperm[c]} exists. Label c as part of component of i */
1406
1407 /* Stop if we find a cycle. */
1408 if ( entrycomponent[c] != c )
1409 break;
1410
1411 entrycomponent[c] = i;
1412 componentobjective[i] += objective[c];
1413 /* For next iteration: We do another step back */
1414 c = perm[c];
1415 }
1416 }
1417
1418 /* Now fill the objective vector.
1419 * For the component containing crit, set the value to 1.
1420 * For the component contraining invperm[crit], set the value to 0.
1421 * For the other components, set the value to 1 if the objective sum is positive.
1422 * Otherwise to 0.
1423 */
1424 for (i = 0; i < nvars; ++i)
1425 {
1426 if ( entrycomponent[i] == entrycomponent[crit] )
1427 maxsolu[i] = 1;
1428 else if ( entrycomponent[i] == entrycomponent[invperm[crit]] )
1429 maxsolu[i] = 0;
1430 else if ( SCIPisGT(scip, componentobjective[entrycomponent[i]], 0.0) )
1431 maxsolu[i] = 1;
1432 else
1433 maxsolu[i] = 0;
1434 }
1435
1436 SCIPfreeBufferArray(scip, &componentobjective);
1437 SCIPfreeBufferArray(scip, &entrycomponent);
1438
1439 return SCIP_OKAY;
1440}
1441
1442
1443/** separate symresack cover inequalities
1444 *
1445 * We currently do NOT enter cuts into the pool.
1446 */
1447static
1449 SCIP* scip, /**< SCIP pointer */
1450 SCIP_CONS* cons, /**< constraint */
1451 const SCIP_CONSDATA* consdata, /**< constraint data */
1452 SCIP_Real* vals, /**< solution values of variables */
1453 int* ngen, /**< pointer to store the number of separated covers */
1454 SCIP_Bool* infeasible /**< pointer to store whether we detected infeasibility */
1455 )
1456{
1457 SCIP_Real constobjective;
1458 SCIP_Real* sepaobjective;
1459 SCIP_Real maxsoluobj = 0.0;
1460 int* maxsolu;
1461 int* invperm;
1462 int* perm;
1463 int nvars;
1464 int maxcrit;
1465 int i;
1466
1467 *infeasible = FALSE;
1468 *ngen = 0;
1469
1470 assert( scip != NULL );
1471 assert( consdata != NULL );
1472
1473 /* we do not have to take care of trivial constraints */
1474 if ( consdata->nvars < 2 )
1475 return SCIP_OKAY;
1476
1477 assert( consdata->vars != NULL );
1478 assert( consdata->perm != NULL );
1479 assert( consdata->invperm != NULL );
1480 assert( infeasible != NULL );
1481 assert( ngen != NULL );
1482
1483 nvars = consdata->nvars;
1484 perm = consdata->perm;
1485 invperm = consdata->invperm;
1486
1487 /* initialize objective */
1488 SCIP_CALL( SCIPallocBufferArray(scip, &sepaobjective, nvars) );
1489
1490 constobjective = 1.0; /* constant part of separation objective */
1491 for (i = 0; i < nvars; ++i)
1492 {
1493 if ( i < perm[i] )
1494 sepaobjective[i] = - vals[i];
1495 else
1496 {
1497 sepaobjective[i] = 1.0 - vals[i];
1498 constobjective += vals[i] - 1.0;
1499 }
1500 }
1501
1502 /* allocate memory for temporary and global solution */
1503 SCIP_CALL( SCIPallocBufferArray(scip, &maxsolu, nvars) );
1504
1505 /* Find critical row of a maximally violated cover */
1506 SCIP_CALL( maximizeObjectiveSymresackStrict(scip, nvars, sepaobjective, perm, invperm, &maxcrit, &maxsoluobj) );
1507 assert( maxcrit >= 0 );
1508 SCIPdebugMsg(scip, "Critical row %d found; Computing maximally violated cover.\n", maxcrit);
1509 SCIP_CALL( maximizeObjectiveSymresackCriticalEntry(scip, nvars, sepaobjective, perm, invperm, maxcrit, maxsolu) );
1510
1511 /* Add constant to maxsoluobj to get the real objective */
1512 maxsoluobj += constobjective;
1513
1514 /* Check whether the separation objective is positive, i.e., a violated cover was found. */
1515 if ( SCIPisEfficacious(scip, maxsoluobj) )
1516 {
1517 /* Now add the cut. Reuse array maxsolu as coefficient vector for the constraint. */
1518 SCIP_Real rhs = -1.0;
1519 for (i = 0; i < nvars; ++i)
1520 {
1521 if ( i < perm[i] )
1522 maxsolu[i] = -maxsolu[i];
1523 else
1524 {
1525 if ( maxsolu[i] == 0 )
1526 rhs += 1.0;
1527 maxsolu[i] = 1 - maxsolu[i];
1528 }
1529 }
1530
1531 /* add cover inequality */
1532 SCIP_CALL( addSymresackInequality(scip, cons, nvars, consdata->vars, maxsolu, rhs, infeasible) );
1533
1534 if ( ! *infeasible )
1535 ++(*ngen);
1536 }
1537
1538 SCIPfreeBufferArrayNull(scip, &maxsolu);
1539 SCIPfreeBufferArrayNull(scip, &sepaobjective);
1540
1541 return SCIP_OKAY;
1542}
1543
1544
1545/** check whether solution is feasible for symresacks */
1546static
1548 SCIP* scip, /**< SCIP pointer */
1549 SCIP_CONS* cons, /**< constrained for which we check the solution */
1550 SCIP_SOL* sol, /**< solution to be checked */
1551 SCIP_RESULT* result, /**< pointer to store whether we detected infeasibility */
1552 SCIP_Bool printreason /**< whether reason for infeasibility should be printed */
1553 )
1554{
1555 SCIP_CONSDATA* consdata;
1556 SCIP_VAR** vars;
1557 int* invperm;
1558 int nvars;
1559 int i;
1560
1561 assert( cons != NULL );
1562 consdata = SCIPconsGetData(cons);
1563 assert( consdata != NULL);
1564
1565 /* we do not have to take care of trivial constraints */
1566 if ( consdata->nvars < 2 )
1567 return SCIP_OKAY;
1568
1569 assert( consdata->vars != NULL );
1570 assert( consdata->invperm != NULL );
1571
1572 SCIPdebugMsg(scip, "Check method for symresack constraint <%s> (%d rows) ...\n", SCIPconsGetName(cons), consdata->nvars);
1573
1574 nvars = consdata->nvars;
1575 vars = consdata->vars;
1576 invperm = consdata->invperm;
1577
1578 /* detect first non-constant pair of variables */
1579 for (i = 0; i < nvars; ++i)
1580 {
1581 SCIP_Real solval;
1582 int val1;
1583 int val2;
1584
1585 /* there are no fixed points */
1586 assert( invperm[i] != i );
1587
1588 /* get value of variable i and its inverse */
1589 solval = SCIPgetSolVal(scip, sol, vars[i]);
1590 assert( SCIPisFeasIntegral(scip, solval) );
1591 if ( solval > 0.5 )
1592 val1 = 1;
1593 else
1594 val1 = 0;
1595
1596 solval = SCIPgetSolVal(scip, sol, vars[invperm[i]]);
1597 assert( SCIPisFeasIntegral(scip, solval) );
1598 if ( solval > 0.5 )
1599 val2 = 1;
1600 else
1601 val2 = 0;
1602
1603 /* if we detected a constant pair */
1604 if ( val1 == val2 )
1605 continue;
1606 /* pair is (1,0) --> lexicographically maximal */
1607 else if ( val1 > val2 )
1608 break;
1609
1610 /* pair is (0,1) --> solution is infeasible */
1611 assert( val2 > val1 );
1612 SCIPdebugMsg(scip, "Solution is infeasible.\n");
1613 *result = SCIP_INFEASIBLE;
1614
1615 if ( printreason )
1616 SCIPinfoMessage(scip, NULL, "First non-constant pair (%d, %d) of variables has pattern (0,1).\n", i, invperm[i]);
1617
1618 break;
1619 }
1620
1621 return SCIP_OKAY;
1622}
1623
1624
1625/** Upgrade symresack constraints to orbisacks */
1626static
1628 SCIP* scip, /**< SCIP pointer */
1629 SCIP_CONS** cons, /**< pointer to hold the created constraint */
1630 const char* name, /**< name of constraint */
1631 int* perm, /**< permutation */
1632 SCIP_VAR** inputvars, /**< permuted variables array */
1633 int nvars, /**< size of perm array */
1634 SCIP_Bool* upgrade, /**< whether constraint was upgraded */
1635 SCIP_Bool ismodelcons, /**< whether the symresack is a model constraint */
1636 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
1637 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1638 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
1639 * Usually set to TRUE. */
1640 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
1641 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1642 SCIP_Bool check, /**< should the constraint be checked for feasibility?
1643 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1644 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
1645 * Usually set to TRUE. */
1646 SCIP_Bool local, /**< is constraint only valid locally?
1647 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1648 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
1649 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
1650 * adds coefficients to this constraint. */
1651 SCIP_Bool dynamic, /**< is constraint subject to aging?
1652 * Usually set to FALSE. Set to TRUE for own cuts which
1653 * are separated as constraints. */
1654 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
1655 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
1656 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
1657 * if it may be moved to a more global node?
1658 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
1659 )
1660{
1661 SCIP_CONSHDLR* conshdlr;
1662 SCIP_VAR** vars1;
1663 SCIP_VAR** vars2;
1664 int nrows = 0;
1665 int i;
1666
1667 assert( scip != NULL );
1668 assert( perm != NULL );
1669 assert( nvars > 0 );
1670 assert( inputvars != NULL );
1671 assert( upgrade != NULL );
1672
1673 *upgrade = TRUE;
1674
1675 /* check whether orbisack conshdlr is available */
1676 conshdlr = SCIPfindConshdlr(scip, "orbisack");
1677 if ( conshdlr == NULL )
1678 {
1679 *upgrade = FALSE;
1680 SCIPdebugMsg(scip, "Cannot check whether symresack constraint can be upgraded to orbisack constraint. ");
1681 SCIPdebugMsg(scip, "---> Orbisack constraint handler not found.\n");
1682
1683 return SCIP_OKAY;
1684 }
1685
1686 SCIP_CALL( SCIPallocBufferArray(scip, &vars1, nvars) );
1687 SCIP_CALL( SCIPallocBufferArray(scip, &vars2, nvars) );
1688
1689 /* check whether permutation is a composition of 2-cycles */
1690 for (i = 0; i < nvars; ++i)
1691 {
1692 /* ignore non-binary variables */
1693 if ( ! SCIPvarIsBinary(inputvars[i]) )
1694 continue;
1695
1696 if ( perm[perm[i]] != i )
1697 {
1698 *upgrade = FALSE;
1699 break;
1700 }
1701
1702 if ( perm[i] > i )
1703 {
1704 vars1[nrows] = inputvars[i];
1705 vars2[nrows++] = inputvars[perm[i]];
1706
1707 assert( nrows <= nvars );
1708 }
1709 }
1710
1711 /* if permutation can be upgraded to an orbisack */
1712 if ( nrows == 0 )
1713 *upgrade = FALSE;
1714 else if ( *upgrade )
1715 {
1716 SCIP_CALL( SCIPcreateConsOrbisack(scip, cons, name, vars1, vars2, nrows, FALSE, FALSE, ismodelcons,
1717 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
1718 }
1719
1720 SCIPfreeBufferArray(scip, &vars2);
1721 SCIPfreeBufferArray(scip, &vars1);
1722
1723 return SCIP_OKAY;
1724}
1725
1726
1727/** creates a symmetry breaking constraint
1728 *
1729 * Depending on the given permutation, either an orbisack or symresack constraint
1730 * is created.
1733 SCIP* scip, /**< SCIP data structure */
1734 SCIP_CONS** cons, /**< pointer to hold the created constraint */
1735 const char* name, /**< name of constraint */
1736 int* perm, /**< permutation */
1737 SCIP_VAR** vars, /**< variables */
1738 int nvars, /**< number of variables in vars array */
1739 SCIP_Bool ismodelcons, /**< whether the added constraint is a model constraint */
1740 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
1741 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1742 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
1743 * Usually set to TRUE. */
1744 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
1745 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1746 SCIP_Bool check, /**< should the constraint be checked for feasibility?
1747 * TRUE for model constraints, FALSE for additional, redundant constraints. */
1748 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
1749 * Usually set to TRUE. */
1750 SCIP_Bool local, /**< is constraint only valid locally?
1751 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1752 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
1753 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
1754 * adds coefficients to this constraint. */
1755 SCIP_Bool dynamic, /**< is constraint subject to aging?
1756 * Usually set to FALSE. Set to TRUE for own cuts which
1757 * are separated as constraints. */
1758 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
1759 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
1760 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
1761 * if it may be moved to a more global node?
1762 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
1763 )
1764{
1765 SCIP_Bool upgrade = FALSE;
1766
1767 assert( scip != NULL );
1768 assert( cons != NULL );
1769 assert( perm != NULL );
1770 assert( vars != NULL );
1771 assert( nvars > 0 );
1772
1773 SCIP_CALL( orbisackUpgrade(scip, cons, name, perm, vars, nvars, &upgrade, ismodelcons,
1774 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
1775
1776 if ( ! upgrade )
1777 {
1778 SCIP_CALL( SCIPcreateConsSymresack(scip, cons, name, perm, vars, nvars, ismodelcons,
1779 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
1780 }
1781
1782 return SCIP_OKAY;
1783}
1784
1785
1786/** replace aggregated variables by active variables */
1787static
1789 SCIP* scip, /**< SCIP data structure */
1790 SCIP_CONS* cons /**< constraint to be processed */
1791 )
1792{
1793 SCIP_CONSDATA* consdata;
1794 SCIP_VAR** vars;
1795 int nvars;
1796 int i;
1797
1798 assert( scip != NULL );
1799 assert( cons != NULL );
1800
1801 /* get data of constraint */
1802 consdata = SCIPconsGetData(cons);
1803 assert( consdata != NULL );
1804 assert( consdata->vars != NULL );
1805
1806 nvars = consdata->nvars;
1807 vars = consdata->vars;
1808
1809 /* loop through all variables */
1810 for (i = 0; i < nvars; ++i)
1811 {
1812 SCIP_VAR* var;
1813 SCIP_Bool negated;
1814
1815 assert( SCIPvarGetStatus(vars[i]) != SCIP_VARSTATUS_MULTAGGR ); /* variables are marked as not to be multi-aggregated */
1816
1817 SCIP_CALL( SCIPgetBinvarRepresentative(scip, vars[i], &var, &negated) );
1818 SCIP_UNUSED( negated );
1820 if ( var != vars[i] )
1821 {
1822 SCIP_CALL( SCIPreleaseVar(scip, &vars[i]) );
1823 vars[i] = var;
1824 SCIP_CALL( SCIPcaptureVar(scip, var) );
1825 }
1826 }
1827
1828 return SCIP_OKAY;
1829}
1830
1831
1832/*--------------------------------------------------------------------------------------------
1833 *--------------------------------- SCIP functions -------------------------------------------
1834 *--------------------------------------------------------------------------------------------*/
1835
1836/** copy method for constraint handler plugins (called when SCIP copies plugins) */
1837static
1838SCIP_DECL_CONSHDLRCOPY(conshdlrCopySymresack)
1839{ /*lint --e{715}*/
1840 assert(scip != NULL);
1841 assert(conshdlr != NULL);
1842 assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
1843
1844 /* call inclusion method of constraint handler */
1846
1847 *valid = TRUE;
1848
1849 return SCIP_OKAY;
1850}
1851
1852
1853/** frees specific constraint data */
1854static
1855SCIP_DECL_CONSDELETE(consDeleteSymresack)
1856{ /*lint --e{715}*/
1857 assert( scip != NULL );
1858 assert( conshdlr != NULL );
1859 assert( consdata != NULL );
1860 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
1861
1862 SCIP_CALL( consdataFree(scip, consdata) );
1863
1864 return SCIP_OKAY;
1865}
1866
1867
1868/** frees constraint handler */
1869static
1870SCIP_DECL_CONSFREE(consFreeSymresack)
1871{ /*lint --e{715}*/
1872 SCIP_CONSHDLRDATA* conshdlrdata;
1873
1874 assert( scip != NULL );
1875 assert( conshdlr != NULL );
1876 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
1877
1878 conshdlrdata = SCIPconshdlrGetData(conshdlr);
1879 assert( conshdlrdata != NULL );
1880
1881 SCIPfreeBlockMemory(scip, &conshdlrdata);
1882
1883 return SCIP_OKAY;
1884}
1885
1886
1887/** transforms constraint data into data belonging to the transformed problem */
1888static
1889SCIP_DECL_CONSTRANS(consTransSymresack)
1890{
1891 SCIP_CONSDATA* sourcedata;
1892 SCIP_CONSDATA* consdata = NULL;
1893 int nvars;
1894 int i;
1895
1896 assert( scip != NULL );
1897 assert( conshdlr != NULL );
1898 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
1899 assert( sourcecons != NULL );
1900 assert( targetcons != NULL );
1901
1902 SCIPdebugMsg(scip, "Transforming constraint.\n");
1903
1904 /* get data of original constraint */
1905 sourcedata = SCIPconsGetData(sourcecons);
1906 assert( sourcedata != NULL);
1907
1908 /* constraint might be empty and not deleted if no presolving took place */
1909 assert( sourcedata->nvars == 0 || sourcedata->vars != NULL );
1910 assert( sourcedata->nvars == 0 || sourcedata->perm != NULL );
1911 assert( sourcedata->nvars == 0 || sourcedata->invperm != NULL );
1912#ifndef NDEBUG
1913 if ( sourcedata->ppupgrade )
1914 {
1915 assert( sourcedata->nvars > 0 );
1916 assert( sourcedata->ncycles != 0 );
1917 assert( sourcedata->cycledecomposition != NULL );
1918 for (i = 0; i < sourcedata->ncycles; ++i)
1919 {
1920 assert( sourcedata->cycledecomposition[i] != NULL );
1921 assert( sourcedata->cycledecomposition[i][0] != 0 );
1922 }
1923 }
1924#endif
1925
1926 /* create transformed constraint data
1927 *
1928 * do NOT call consdataCreate() again to avoid doing the packing-upgrade check twice
1929 */
1930 nvars = sourcedata->nvars;
1931
1932 SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) );
1933
1934 consdata->vars = NULL;
1935 consdata->nvars = nvars;
1936 consdata->perm = NULL;
1937 consdata->invperm = NULL;
1938 consdata->ppupgrade = sourcedata->ppupgrade;
1939 consdata->ismodelcons = sourcedata->ismodelcons;
1940#ifdef SCIP_DEBUG
1941 consdata->debugcnt = 0;
1942#endif
1943 consdata->ncycles = 0;
1944 consdata->cycledecomposition = NULL;
1945 consdata->ndescentpoints = 0;
1946 consdata->descentpoints = NULL;
1947
1948 if ( nvars > 0 )
1949 {
1950 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->vars, nvars) );
1951 SCIP_CALL( SCIPgetTransformedVars(scip, nvars, sourcedata->vars, consdata->vars) );
1952 for (i = 0; i < nvars; ++i)
1953 {
1954 SCIP_CALL( SCIPcaptureVar(scip, consdata->vars[i]) );
1955 }
1956
1957 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->perm, sourcedata->perm, nvars) );
1958 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->invperm, sourcedata->invperm, nvars) );
1959
1960 if ( sourcedata->ppupgrade )
1961 {
1962 consdata->ncycles = sourcedata->ncycles;
1963 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->cycledecomposition, sourcedata->cycledecomposition, sourcedata->ncycles) );
1964 for (i = 0; i < sourcedata->ncycles; ++i)
1965 {
1966 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->cycledecomposition[i], sourcedata->cycledecomposition[i], nvars + 1) ); /*lint !e866*/
1967 }
1968
1969 consdata->ndescentpoints = sourcedata->ndescentpoints;
1970 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->descentpoints, sourcedata->descentpoints, sourcedata->ndescentpoints) );
1971 }
1972
1973 /* Make sure that all variables cannot be multiaggregated (this cannot be handled by cons_symresack, since one cannot
1974 * easily eliminate single variables from a symresack constraint).
1975 *
1976 * We need to call this again to ensure that multiaggregation is forbidden also if the constraint was part
1977 * of the original problem.
1978 */
1979 for (i = 0; i < sourcedata->nvars; ++i)
1980 {
1981 SCIP_CALL( SCIPgetTransformedVar(scip, consdata->vars[i], &consdata->vars[i]) );
1982 SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, consdata->vars[i]) );
1983 }
1984 }
1985
1986 /* create transformed constraint */
1987 SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, consdata,
1988 SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons),
1989 SCIPconsIsEnforced(sourcecons), SCIPconsIsChecked(sourcecons),
1990 SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
1991 SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons),
1992 SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
1993
1994 return SCIP_OKAY;
1995}
1996
1997
1998/** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
1999static
2000SCIP_DECL_CONSINITLP(consInitlpSymresack)
2001{
2002 int c;
2003 SCIP_CONSHDLRDATA* conshdlrdata;
2004
2005 assert( infeasible != NULL );
2006 *infeasible = FALSE;
2007
2008 assert( scip != NULL );
2009 assert( conshdlr != NULL );
2010 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2011
2012 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2013 assert( conshdlrdata != NULL );
2014
2015 /* loop through constraints */
2016 for (c = 0; c < nconss; ++c)
2017 {
2018 assert( conss[c] != NULL );
2019
2020 SCIPdebugMsg(scip, "Generating initial symresack cut for constraint <%s> ...\n", SCIPconsGetName(conss[c]));
2021
2022 SCIP_CALL( initLP(scip, conss[c], conshdlrdata->checkmonotonicity, infeasible) );
2023 if ( *infeasible )
2024 break;
2025 }
2026 SCIPdebugMsg(scip, "Generated initial symresack cuts.\n");
2027
2028 return SCIP_OKAY;
2029}
2030
2031
2032/** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
2033static
2034SCIP_DECL_CONSINITSOL(consInitsolSymresack)
2035{
2036 SCIP_CONSHDLRDATA* conshdlrdata;
2037 int c;
2038
2039 assert( scip != NULL );
2040 assert( conshdlr != NULL );
2041 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2042
2043 /* determine maximum number of vars in a symresack constraint */
2044 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2045 assert( conshdlrdata != NULL );
2046
2047 conshdlrdata->maxnvars = 0;
2048
2049 /* loop through constraints */
2050 for (c = 0; c < nconss; ++c)
2051 {
2052 SCIP_CONSDATA* consdata;
2053
2054 assert( conss[c] != NULL );
2055
2056 consdata = SCIPconsGetData(conss[c]);
2057 assert( consdata != NULL );
2058
2059 /* update conshdlrdata if necessary */
2060 if ( consdata->nvars > conshdlrdata->maxnvars )
2061 conshdlrdata->maxnvars = consdata->nvars;
2062 }
2063
2064 return SCIP_OKAY;
2065}
2066
2067
2068/** separation method of constraint handler for LP solution */
2069static
2070SCIP_DECL_CONSSEPALP(consSepalpSymresack)
2071{ /*lint --e{715}*/
2072 SCIP_CONSHDLRDATA* conshdlrdata;
2073 SCIP_CONSDATA* consdata;
2074 SCIP_Real* vals;
2075 int maxnvars;
2076 int c;
2077
2078 assert( scip != NULL );
2079 assert( conshdlr != NULL );
2080 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2081 assert( result != NULL );
2082
2083 SCIPdebugMsg(scip, "Separation method for symresack constraints\n");
2084
2085 *result = SCIP_DIDNOTRUN;
2086
2087 /* if solution is not integer */
2088 if ( SCIPgetNLPBranchCands(scip) == 0 )
2089 return SCIP_OKAY;
2090
2091 if ( nconss == 0 )
2092 return SCIP_OKAY;
2093
2094 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2095 assert( conshdlrdata != NULL );
2096
2097 maxnvars = conshdlrdata->maxnvars;
2098 assert( maxnvars > 0 );
2099
2100 SCIP_CALL( SCIPallocBufferArray(scip, &vals, maxnvars) );
2101
2102 /* loop through constraints */
2103 for (c = 0; c < nconss; ++c)
2104 {
2105 SCIP_Bool infeasible = FALSE;
2106 int ngen = 0;
2107
2108 SCIPdebugMsg(scip, "Separating symresack constraint <%s> ...\n", SCIPconsGetName(conss[c]));
2109
2110 /* get data of constraint */
2111 assert( conss[c] != NULL );
2112 consdata = SCIPconsGetData(conss[c]);
2113
2114 if ( consdata->nvars == 0 )
2115 continue;
2116
2117 /* get solution */
2118 assert( consdata->nvars <= maxnvars );
2119 SCIP_CALL( SCIPgetSolVals(scip, NULL, consdata->nvars, consdata->vars, vals) );
2120 SCIP_CALL( separateSymresackCovers(scip, conss[c], consdata, vals, &ngen, &infeasible) );
2121
2122 if ( infeasible )
2123 {
2124 *result = SCIP_CUTOFF;
2125 SCIPfreeBufferArray(scip, &vals);
2126
2127 return SCIP_OKAY;
2128 }
2129
2130 if ( ngen > 0 )
2131 *result = SCIP_SEPARATED;
2132
2133 if ( *result == SCIP_DIDNOTRUN )
2134 *result = SCIP_DIDNOTFIND;
2135 }
2136 SCIPfreeBufferArray(scip, &vals);
2137
2138 return SCIP_OKAY;
2139}
2140
2141
2142/** separation method of constraint handler for arbitrary primal solution */
2143static
2144SCIP_DECL_CONSSEPASOL(consSepasolSymresack)
2145{ /*lint --e{715}*/
2146 SCIP_CONSHDLRDATA* conshdlrdata;
2147 SCIP_CONSDATA* consdata;
2148 SCIP_Real* vals;
2149 int maxnvars;
2150 int c;
2151
2152 assert( scip != NULL );
2153 assert( conshdlr != NULL );
2154 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2155 assert( result != NULL );
2156
2157 SCIPdebugMsg(scip, "Separation method for symresack constraints\n");
2158
2159 *result = SCIP_DIDNOTRUN;
2160
2161 if ( nconss == 0 )
2162 return SCIP_OKAY;
2163
2164 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2165 assert( conshdlrdata != NULL );
2166
2167 maxnvars = conshdlrdata->maxnvars;
2168 assert( maxnvars > 0 );
2169
2170 SCIP_CALL( SCIPallocBufferArray(scip, &vals, maxnvars) );
2171
2172 /* loop through constraints */
2173 for (c = 0; c < nconss; ++c)
2174 {
2175 SCIP_Bool infeasible = FALSE;
2176 int ngen = 0;
2177
2178 SCIPdebugMsg(scip, "Separating symresack constraint <%s> ...\n", SCIPconsGetName(conss[c]));
2179
2180 /* get data of constraint */
2181 assert( conss[c] != NULL );
2182 consdata = SCIPconsGetData(conss[c]);
2183
2184 if ( consdata->nvars == 0 )
2185 continue;
2186
2187 /* get solution */
2188 assert( consdata->nvars <= maxnvars );
2189 SCIP_CALL( SCIPgetSolVals(scip, sol, consdata->nvars, consdata->vars, vals) );
2190 SCIP_CALL( separateSymresackCovers(scip, conss[c], consdata, vals, &ngen, &infeasible) );
2191
2192 if ( infeasible )
2193 {
2194 *result = SCIP_CUTOFF;
2195 SCIPfreeBufferArray(scip, &vals);
2196
2197 return SCIP_OKAY;
2198 }
2199
2200 if ( ngen > 0 )
2201 *result = SCIP_SEPARATED;
2202
2203 if ( *result == SCIP_DIDNOTRUN )
2204 *result = SCIP_DIDNOTFIND;
2205 }
2206 SCIPfreeBufferArray(scip, &vals);
2207
2208 return SCIP_OKAY;
2209}
2210
2211
2212/** constraint enforcing method of constraint handler for LP solutions.
2213 *
2214 * To check feasibility, we separate cover inequalities.
2215 *
2216 * @pre It is assumed that the solution is integral (this can be ensured by appropriate priorities).
2217 */
2218static
2219SCIP_DECL_CONSENFOLP(consEnfolpSymresack)
2220{ /*lint --e{715}*/
2221 SCIP_CONSDATA* consdata;
2222 int c;
2223
2224 assert( scip != NULL );
2225 assert( conshdlr != NULL );
2226 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2227 assert( result != NULL );
2228
2229 SCIPdebugMsg(scip, "Enforcing method for symresack constraints (lp solutions) ...\n");
2230
2231 /* we have a negative priority, so we should come after the integrality conshdlr. */
2232 assert( SCIPgetNLPBranchCands(scip) == 0 );
2233
2234 *result = SCIP_FEASIBLE;
2235
2236 if ( nconss > 0 )
2237 {
2238 SCIP_CONSHDLRDATA* conshdlrdata;
2239 SCIP_Real* vals;
2240 int maxnvars;
2241
2242 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2243 assert( conshdlrdata != NULL );
2244
2245 maxnvars = conshdlrdata->maxnvars;
2246 assert( maxnvars > 0 );
2247
2248 SCIP_CALL( SCIPallocBufferArray(scip, &vals, maxnvars) );
2249
2250 /* loop through constraints */
2251 for (c = 0; c < nconss; ++c)
2252 {
2253 SCIP_Bool infeasible = FALSE;
2254 int ngen = 0;
2255
2256 SCIPdebugMsg(scip, "Enforcing symresack constraint <%s> ...\n", SCIPconsGetName(conss[c]));
2257
2258 /* get data of constraint */
2259 assert( conss[c] != NULL );
2260 consdata = SCIPconsGetData(conss[c]);
2261 assert( consdata != NULL );
2262
2263 /* do not enforce non-model constraints */
2264 if ( !consdata->ismodelcons )
2265 continue;
2266
2267 if ( consdata->nvars == 0 )
2268 continue;
2269
2270 /* get solution */
2271 assert( consdata->nvars <= maxnvars );
2272 SCIP_CALL( SCIPgetSolVals(scip, NULL, consdata->nvars, consdata->vars, vals) );
2273 SCIP_CALL( separateSymresackCovers(scip, conss[c], consdata, vals, &ngen, &infeasible) );
2274
2275 if ( infeasible )
2276 {
2277 *result = SCIP_CUTOFF;
2278 SCIPfreeBufferArray(scip, &vals);
2279
2280 return SCIP_OKAY;
2281 }
2282
2283 /* SCIPdebugMsg(scip, "Generated symresack inequalities for <%s>: %d\n", SCIPconsGetName(conss[c]), ngen); */
2284
2285 if ( ngen > 0 )
2286 *result = SCIP_SEPARATED;
2287 }
2288 SCIPfreeBufferArray(scip, &vals);
2289 }
2290
2291 return SCIP_OKAY;
2292}
2293
2294
2295/** constraint enforcing method of constraint handler for pseudo solutions */
2296static
2297SCIP_DECL_CONSENFOPS(consEnfopsSymresack)
2298{ /*lint --e{715}*/
2299 SCIP_CONSDATA* consdata;
2300 int c;
2301
2302 assert( scip != NULL );
2303 assert( conshdlr != NULL );
2304 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2305 assert( result != NULL );
2306
2307 SCIPdebugMsg(scip, "Enforcing method for symresack constraints (pseudo solutions) ...\n");
2308
2309 *result = SCIP_FEASIBLE;
2310
2311 if ( objinfeasible || solinfeasible )
2312 return SCIP_OKAY;
2313
2314 /* loop through constraints */
2315 for (c = 0; c < nconss; ++c)
2316 {
2317 consdata = SCIPconsGetData(conss[c]);
2318 assert( consdata != NULL );
2319
2320 /* do not enforce non-model constraints */
2321 if ( !consdata->ismodelcons )
2322 continue;
2323
2324 SCIP_CALL( checkSymresackSolution(scip, conss[c], NULL, result, FALSE) );
2325
2326 if ( *result == SCIP_INFEASIBLE )
2327 break;
2328 }
2329
2330 return SCIP_OKAY;
2331}
2332
2333
2334/** constraint enforcing method of constraint handler for relaxation solutions
2335 *
2336 * To check feasibility, we separate cover inequalities.
2337 *
2338 */
2339static
2340SCIP_DECL_CONSENFORELAX(consEnforelaxSymresack)
2341{ /*lint --e{715}*/
2342 SCIP_CONSDATA* consdata;
2343 int c;
2344
2345 assert( scip != NULL );
2346 assert( conshdlr != NULL );
2347 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2348 assert( result != NULL );
2349
2350 SCIPdebugMsg(scip, "Enforcing method for symresack constraints (relaxation solutions) ...\n");
2351
2352 /* we have a negative priority, so we should come after the integrality conshdlr. */
2353 assert( SCIPgetNLPBranchCands(scip) == 0 );
2354
2355 *result = SCIP_FEASIBLE;
2356
2357 if ( nconss > 0 )
2358 {
2359 SCIP_CONSHDLRDATA* conshdlrdata;
2360 SCIP_Real* vals;
2361 int maxnvars;
2362
2363 conshdlrdata = SCIPconshdlrGetData(conshdlr);
2364 assert( conshdlrdata != NULL );
2365
2366 maxnvars = conshdlrdata->maxnvars;
2367 assert( maxnvars > 0 );
2368
2369 SCIP_CALL( SCIPallocBufferArray(scip, &vals, maxnvars) );
2370
2371 /* loop through constraints */
2372 for (c = 0; c < nconss; ++c)
2373 {
2374 SCIP_Bool infeasible = FALSE;
2375 int ngen = 0;
2376
2377 SCIPdebugMsg(scip, "Enforcing symresack constraint <%s> ...\n", SCIPconsGetName(conss[c]));
2378
2379 /* get data of constraint */
2380 assert( conss[c] != NULL );
2381 consdata = SCIPconsGetData(conss[c]);
2382 assert( consdata != NULL );
2383
2384 /* do not enforce non-model constraints */
2385 if ( !consdata->ismodelcons )
2386 continue;
2387
2388 if ( consdata->nvars == 0 )
2389 continue;
2390
2391 /* get solution */
2392 assert( consdata->nvars <= maxnvars );
2393 SCIP_CALL( SCIPgetSolVals(scip, sol, consdata->nvars, consdata->vars, vals) );
2394 SCIP_CALL( separateSymresackCovers(scip, conss[c], consdata, vals, &ngen, &infeasible) );
2395
2396 if ( infeasible )
2397 {
2398 *result = SCIP_CUTOFF;
2399 SCIPfreeBufferArray(scip, &vals);
2400
2401 return SCIP_OKAY;
2402 }
2403
2404 if ( ngen > 0 )
2405 *result = SCIP_SEPARATED;
2406 }
2407 SCIPfreeBufferArray(scip, &vals);
2408 }
2409
2410 return SCIP_OKAY;
2411}
2412
2413
2414/** feasibility check method of constraint handler for integral solutions */
2415static
2416SCIP_DECL_CONSCHECK(consCheckSymresack)
2417{ /*lint --e{715}*/
2418 SCIP_CONSDATA* consdata;
2419 int c;
2420
2421 assert( scip != NULL );
2422 assert( conshdlr != NULL );
2423 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2424 assert( result != NULL );
2425
2426 *result = SCIP_FEASIBLE;
2427
2428 /* loop through constraints */
2429 for (c = 0; c < nconss; ++c)
2430 {
2431 consdata = SCIPconsGetData(conss[c]);
2432 assert( consdata != NULL );
2433
2434 /* do not check non-model constraints */
2435 if ( !consdata->ismodelcons )
2436 continue;
2437
2438 SCIP_CALL( checkSymresackSolution(scip, conss[c], sol, result, printreason) );
2439
2440 if ( *result == SCIP_INFEASIBLE )
2441 break;
2442 }
2443
2444 if ( *result == SCIP_FEASIBLE )
2445 SCIPdebugMsg(scip, "Solution is feasible.\n");
2446
2447 return SCIP_OKAY;
2448}
2449
2450
2451/** domain propagation method of constraint handler */
2452static
2453SCIP_DECL_CONSPROP(consPropSymresack)
2454{ /*lint --e{715}*/
2455 int c;
2456 SCIP_Bool success = FALSE;
2457
2458 assert( scip != NULL );
2459 assert( conshdlr != NULL );
2460 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2461 assert( result != NULL );
2462
2463 *result = SCIP_DIDNOTRUN;
2464
2465 SCIPdebugMsg(scip, "Propagation method of symresack constraint handler.\n");
2466
2467 /* loop through constraints */
2468 for (c = 0; c < nconss; ++c)
2469 {
2470 SCIP_Bool infeasible = FALSE;
2471 int ngen = 0;
2472
2473 assert( conss[c] != NULL );
2474
2475 SCIP_CALL( propVariables(scip, conss[c], &infeasible, &ngen) );
2476
2477 if ( infeasible )
2478 {
2479 *result = SCIP_CUTOFF;
2480 return SCIP_OKAY;
2481 }
2482
2483 success = success || ( ngen > 0 );
2484
2485 *result = SCIP_DIDNOTFIND;
2486 }
2487
2488 if ( success )
2489 {
2490 *result = SCIP_REDUCEDDOM;
2491 return SCIP_OKAY;
2492 }
2493
2494 return SCIP_OKAY;
2495}
2496
2497
2498/** presolving method of constraint handler */
2499static
2500SCIP_DECL_CONSPRESOL(consPresolSymresack)
2501{ /*lint --e{715}*/
2502 int c;
2503 SCIP_Bool success = FALSE;
2504 int oldndelconss;
2505
2506 assert( scip != NULL );
2507 assert( conshdlr != NULL );
2508 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2509 assert( result != NULL );
2510
2511 oldndelconss = *ndelconss;
2512
2513 SCIPdebugMsg(scip, "Presolving method of symresack constraint handler. Propagating symresack inequalities.\n");
2514 *result = SCIP_DIDNOTRUN;
2515
2516 /* loop through constraints */
2517 for (c = 0; c < nconss; ++c)
2518 {
2519 SCIP_Bool infeasible = FALSE;
2520 SCIP_CONSDATA* consdata;
2521 int ngen = 0;
2522
2523 assert( conss[c] != NULL );
2524
2525 consdata = SCIPconsGetData(conss[c]);
2526 assert( consdata != NULL );
2527
2528 /* avoid trivial problems */
2529 if ( consdata->nvars == 0 )
2530 {
2531 SCIP_CALL( SCIPdelCons(scip, conss[c]) );
2532 (*ndelconss)++;
2533 }
2534 else
2535 {
2536 SCIP_CALL( propVariables(scip, conss[c], &infeasible, &ngen) );
2537 }
2538
2539 if ( infeasible )
2540 {
2541 *result = SCIP_CUTOFF;
2542 break;
2543 }
2544
2545 if ( ngen > 0 )
2546 {
2547 *nfixedvars += ngen;
2548 success = TRUE;
2549 }
2550
2551 *result = SCIP_DIDNOTFIND;
2552 }
2553
2554 if ( *ndelconss > oldndelconss || success )
2555 *result = SCIP_SUCCESS;
2556
2557 return SCIP_OKAY;
2558}
2559
2560
2561/** Propagation resolution for conflict analysis */
2562static
2563SCIP_DECL_CONSRESPROP(consRespropSymresack)
2564{ /*lint --e{715}*/
2565 SCIP_CONSDATA* consdata;
2566 SCIP_VAR** vars;
2567 int* perm;
2568 int* invperm;
2569 int nvars;
2570 int i;
2571 int varrow;
2572 int infrow;
2573
2574 assert( scip != NULL );
2575 assert( conshdlr != NULL );
2576 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2577 assert( cons != NULL );
2578 assert( infervar != NULL );
2579 assert( bdchgidx != NULL );
2580 assert( result != NULL );
2581
2582 SCIPdebugMsg(scip, "Propagation resolution method of symresack constraint handler.\n");
2583
2584 *result = SCIP_DIDNOTFIND;
2585
2586 consdata = SCIPconsGetData(cons);
2587 assert( consdata != NULL );
2588
2589 /* we do not have to take care of trivial constraints */
2590 if ( consdata->nvars < 2 )
2591 return SCIP_OKAY;
2592
2593 assert( consdata->vars != NULL );
2594 assert( consdata->invperm != NULL );
2595
2596 vars = consdata->vars;
2597 nvars = consdata->nvars;
2598 perm = consdata->perm;
2599 invperm = consdata->invperm;
2600
2601 /* inferinfo == varrow + infrow * nvars.
2602 * infrow is 0 if the fixing is not caused by a lookahead.
2603 */
2604 varrow = inferinfo % nvars;
2605 infrow = inferinfo / nvars;
2606
2607 assert( varrow >= 0 );
2608 assert( varrow < nvars );
2609 assert( infrow >= 0 );
2610 assert( infrow < nvars );
2611 assert( vars[varrow] == infervar || vars[invperm[varrow]] == infervar );
2612
2613 /* Up to entry varrow the vectors x and perm[x] are equal. */
2614 for (i = 0; i < varrow; ++i)
2615 {
2616 /* Conflict caused by bounds of x[i] and perm(x)[i] = x[invperm[i]]. */
2617
2618 /* No fixed points in the permutation. */
2619 assert( i != invperm[i] );
2620
2621 /* Up to entry varrow the vectors x and perm[x] are fixed to the same value. */
2622 assert( ISFIXED(scip, vars[i], bdchgidx) );
2623 assert( ISFIXED(scip, vars[invperm[i]], bdchgidx) );
2624 assert( REALABS(SCIPgetVarUbAtIndex(scip, vars[i], bdchgidx, FALSE) -
2625 SCIPgetVarUbAtIndex(scip, vars[invperm[i]], bdchgidx, FALSE)) < 0.5 );
2626 assert( REALABS(SCIPgetVarLbAtIndex(scip, vars[i], bdchgidx, FALSE) -
2627 SCIPgetVarLbAtIndex(scip, vars[invperm[i]], bdchgidx, FALSE)) < 0.5 );
2628
2629 /* At iteration i the vars x[i] and x[invperm[i]] are fixed.
2630 * So only new information is received if i < perm[i] (i.e. there is no j < i with j = invperm[i])
2631 * Or if invperm[i] > i.
2632 */
2633 if ( i < perm[i] )
2634 {
2635 assert( vars[i] != infervar );
2636 SCIP_CALL( SCIPaddConflictUb(scip, vars[i], bdchgidx) );
2637 SCIP_CALL( SCIPaddConflictLb(scip, vars[i], bdchgidx) );
2638 }
2639 if ( invperm[i] > i )
2640 {
2641 assert( vars[invperm[i]] != infervar );
2642 SCIP_CALL( SCIPaddConflictUb(scip, vars[invperm[i]], bdchgidx) );
2643 SCIP_CALL( SCIPaddConflictLb(scip, vars[invperm[i]], bdchgidx) );
2644 }
2645 }
2646
2647 /* Case distinction: Fixing due to propagation or due to lookahead */
2648 if ( infrow > 0 )
2649 {
2650 /* The fixing of infervar is caused by a lookahead (checkFeasible)
2651 * Up to row "varrow" the entries x[i] and perm(x)[i] are forced to be equal
2652 * If x[varrow] = perm(x)[varrow] is assumed, then until infrow we find x[i] = perm(x)[i] ( = x[invperm[i]] )
2653 * and (x[infrow], perm(x)[infrow]) = (0, 1).
2654 */
2655
2656 /* Everything after varrow to infrow is forced to a constant, and row infrow is (0, 1) */
2657 for (i = varrow + 1; i <= infrow; ++i)
2658 {
2659 /* Conflict caused by bounds of x[i] and perm(x)[i] = x[invperm[i]]. */
2660
2661 /* No fixed points in the permutation. */
2662 assert( i != invperm[i] );
2663
2664 /* The fixing are applied 'virtually', i.e. if varrow is considered constant, then fixings will follow.
2665 * Thus, between entries varrow and infrow of vectorx x and gamma(x) the entries do not have to be fixed.
2666 * For conflict analysis, only the fixed entries matter.
2667 */
2668 if ( ( i < perm[i] || i == invperm[varrow] ) && ISFIXED(scip, vars[i], bdchgidx) )
2669 {
2670 assert( vars[i] != infervar );
2671 SCIP_CALL( SCIPaddConflictUb(scip, vars[i], bdchgidx) );
2672 SCIP_CALL( SCIPaddConflictLb(scip, vars[i], bdchgidx) );
2673 }
2674 if ( ( invperm[i] > i || invperm[i] == varrow ) && ISFIXED(scip, vars[invperm[i]], bdchgidx) )
2675 {
2676 assert( vars[invperm[i]] != infervar );
2677 SCIP_CALL( SCIPaddConflictUb(scip, vars[invperm[i]], bdchgidx) );
2678 SCIP_CALL( SCIPaddConflictLb(scip, vars[invperm[i]], bdchgidx) );
2679 }
2680 }
2681 }
2682 else
2683 {
2684 /* This is not a fixing caused by lookahead (checkFeasible),
2685 * so row "varrow" was (0, _) or (_, 1) and for i < varrow x[i] = perm(x)[i].
2686 */
2687 if ( boundtype == SCIP_BOUNDTYPE_LOWER )
2688 {
2689 /* Changed the lower bound of infervar to 1. That means that this fixing is due to (_, 1) */
2690 assert( infervar == vars[varrow] );
2691 assert( ISFIXED(scip, vars[invperm[varrow]], bdchgidx) );
2692
2693 if ( invperm[varrow] > varrow )
2694 {
2695 SCIP_CALL( SCIPaddConflictUb(scip, vars[invperm[varrow]], bdchgidx) );
2696 SCIP_CALL( SCIPaddConflictLb(scip, vars[invperm[varrow]], bdchgidx) );
2697 }
2698 }
2699 else
2700 {
2701 /* Changed the lower bound of infervar to 0. That means that this fixing is due to (0, _) */
2702 assert( infervar == vars[invperm[varrow]] );
2703 assert( ISFIXED(scip, vars[varrow], bdchgidx) );
2704
2705 if ( varrow < perm[varrow] )
2706 {
2707 SCIP_CALL( SCIPaddConflictUb(scip, vars[varrow], bdchgidx) );
2708 SCIP_CALL( SCIPaddConflictLb(scip, vars[varrow], bdchgidx) );
2709 }
2710 }
2711 }
2712
2713 *result = SCIP_SUCCESS;
2714
2715 return SCIP_OKAY;
2716}
2717
2718
2719/** presolving deinitialization method of constraint handler (called after presolving has been finished) */
2720static
2721SCIP_DECL_CONSEXITPRE(consExitpreSymresack)
2722{
2723 int c;
2724
2725 assert( scip != NULL );
2726 assert( conshdlr != NULL );
2727 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2728
2729 for (c = 0; c < nconss; ++c)
2730 {
2731 /* replace aggregated variables by active variables */
2733 }
2734 return SCIP_OKAY;
2735}
2736
2737
2738/** lock variables
2739 *
2740 * We assume we have only one global (void) constraint and lock all binary variables
2741 * which do not correspond to fixed points of the permutation.
2742 *
2743 * - Symresack constraints may get violated if the variables with a negative coefficient
2744 * in the FD inequality are rounded down, we therefor call
2745 * SCIPaddVarLocksType(..., nlockspos, nlocksneg).
2746 * - Symresack constraints may get violated if the variables with a positive coefficient
2747 * in the FD inequality are rounded up, we therefor call
2748 * SCIPaddVarLocksType(..., nlocksneg, nlockspo ).
2749 */
2750static
2751SCIP_DECL_CONSLOCK(consLockSymresack)
2752{ /*lint --e{715}*/
2753 SCIP_CONSDATA* consdata;
2754 SCIP_VAR** vars;
2755 int* perm;
2756 int nvars;
2757 int i;
2758
2759 assert( scip != NULL );
2760 assert( conshdlr != NULL );
2761 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2762 assert( cons != NULL );
2763
2764 SCIPdebugMsg(scip, "Locking method for symresack constraint handler.\n");
2765
2766 /* get data of original constraint */
2767 consdata = SCIPconsGetData(cons);
2768 assert( consdata != NULL );
2769
2770 /* we do not have to take care of trivial constraints */
2771 if ( consdata->nvars < 2 )
2772 return SCIP_OKAY;
2773
2774 assert( consdata->vars != NULL );
2775 assert( consdata->perm != NULL );
2776
2777 nvars = consdata->nvars;
2778 vars = consdata->vars;
2779 perm = consdata->perm;
2780
2781 for (i = 0; i < nvars; ++i)
2782 {
2783 /* due to clean-up in consdataCreate, there are no fixed points */
2784 assert( perm[i] != i );
2785
2786 if ( perm[i] > i )
2787 {
2788 SCIP_CALL( SCIPaddVarLocksType(scip, vars[i], locktype, nlockspos, nlocksneg) );
2789 }
2790 else
2791 {
2792 SCIP_CALL( SCIPaddVarLocksType(scip, vars[i], locktype, nlocksneg, nlockspos) );
2793 }
2794 }
2795
2796 return SCIP_OKAY;
2797}
2798
2799
2800/** constraint copying method of constraint handler */
2801static
2802SCIP_DECL_CONSCOPY(consCopySymresack)
2803{
2804 SCIP_CONSHDLRDATA* conshdlrdata;
2805 SCIP_CONSDATA* sourcedata;
2806 SCIP_VAR** sourcevars;
2807 SCIP_VAR** vars;
2808 int nvars;
2809 int i;
2810
2811 assert( scip != NULL );
2812 assert( cons != NULL );
2813 assert( sourcescip != NULL );
2814 assert( sourceconshdlr != NULL );
2815 assert( strcmp(SCIPconshdlrGetName(sourceconshdlr), CONSHDLR_NAME) == 0 );
2816 assert( sourcecons != NULL );
2817 assert( varmap != NULL );
2818 assert( valid != NULL );
2819
2820 *valid = TRUE;
2821
2822 SCIPdebugMsg(scip, "Copying method for symresack constraint handler.\n");
2823
2824 sourcedata = SCIPconsGetData(sourcecons);
2825 assert( sourcedata != NULL );
2826 assert( sourcedata->vars != NULL );
2827 assert( sourcedata->perm != NULL );
2828 assert( sourcedata->nvars > 0 );
2829
2830 conshdlrdata = SCIPconshdlrGetData(sourceconshdlr);
2831 assert( conshdlrdata != NULL );
2832
2833 /* do not copy non-model constraints */
2834 if ( !sourcedata->ismodelcons && !conshdlrdata->forceconscopy )
2835 {
2836 *valid = FALSE;
2837
2838 return SCIP_OKAY;
2839 }
2840
2841 sourcevars = sourcedata->vars;
2842 nvars = sourcedata->nvars;
2843
2844 SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
2845
2846 for (i = 0; i < nvars && *valid; ++i)
2847 {
2848 SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[i], &(vars[i]), varmap, consmap, global, valid) );
2849 assert( !(*valid) || vars[i] != NULL );
2850 }
2851
2852 /* only create the target constraint, if all variables could be copied */
2853 if ( *valid )
2854 {
2855 /* create copied constraint */
2856 if ( name == NULL )
2857 name = SCIPconsGetName(sourcecons);
2858
2859 SCIP_CALL( SCIPcreateConsSymresack(scip, cons, name, sourcedata->perm, vars, nvars, sourcedata->ismodelcons,
2860 initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
2861 }
2862
2863 SCIPfreeBufferArray(scip, &vars);
2864
2865 return SCIP_OKAY;
2866}
2867
2868
2869/** constraint parsing method of constraint handler */
2870static
2871SCIP_DECL_CONSPARSE(consParseSymresack)
2872{ /*lint --e{715}*/
2873 const char* s;
2874 char* endptr;
2875 SCIP_VAR** vars;
2876 SCIP_VAR* var;
2877 int* perm;
2878 int val;
2879 int nvars = 0;
2880 int cnt = 0;
2881 int nfoundpermidx = 0;
2882 int maxnvars = 128;
2883
2884 assert( success != NULL );
2885
2886 *success = TRUE;
2887 s = str;
2888
2889 /* skip white space */
2890 SCIP_CALL( SCIPskipSpace((char**)&s) );
2891
2892 if( strncmp(s, "symresack(", 10) != 0 )
2893 {
2894 SCIPerrorMessage("Syntax error - expected \"symresack(\", but got '%s'", s);
2895 *success = FALSE;
2896 return SCIP_OKAY;
2897 }
2898 s += 10;
2899
2900 /* loop through string */
2901 SCIP_CALL( SCIPallocBufferArray(scip, &vars, maxnvars) );
2902 SCIP_CALL( SCIPallocBufferArray(scip, &perm, maxnvars) );
2903
2904 do
2905 {
2906 if( cnt > 1 )
2907 {
2908 SCIPerrorMessage("expected two arrays, but got more\n");
2909 *success = FALSE;
2910 break;
2911 }
2912
2913 /* skip whitespace */
2914 SCIP_CALL( SCIPskipSpace((char**)&s) );
2915
2916 /* skip ',' */
2917 if( *s == ',' )
2918 ++s;
2919
2920 /* skip whitespace */
2921 SCIP_CALL( SCIPskipSpace((char**)&s) );
2922
2923 /* if we could not find starting indicator of array */
2924 if( *s != '[' )
2925 {
2926 SCIPerrorMessage("expected '[' to start new array\n");
2927 *success = FALSE;
2928 break;
2929 }
2930 ++s;
2931
2932 /* read array, cnt = 0: variables; cnt = 1: permutation*/
2933 if( cnt == 0 )
2934 {
2935 do
2936 {
2937 /* parse variable name */
2938 SCIP_CALL( SCIPparseVarName(scip, s, &var, &endptr) );
2939
2940 if( var == NULL )
2941 {
2942 endptr = strchr(endptr, ']');
2943
2944 if( endptr == NULL )
2945 {
2946 SCIPerrorMessage("closing ']' missing\n");
2947 *success = FALSE;
2948 }
2949 else
2950 s = endptr;
2951
2952 break;
2953 }
2954
2955 s = endptr;
2956 assert( s != NULL );
2957 ++nvars;
2958
2959 if( nvars > maxnvars )
2960 {
2961 maxnvars = SCIPcalcMemGrowSize(scip, nvars);
2962 SCIP_CALL( SCIPreallocBufferArray(scip, &vars, maxnvars) );
2963 SCIP_CALL( SCIPreallocBufferArray(scip, &perm, maxnvars) );
2964 assert( nvars <= maxnvars );
2965 }
2966
2967 vars[nvars-1] = var;
2968
2969 /* skip white space */
2970 SCIP_CALL( SCIPskipSpace((char**)&s) );
2971
2972 /* skip ',' */
2973 if( *s == ',' )
2974 ++s;
2975 }
2976 while( *s != ']' );
2977 }
2978 else
2979 {
2980 do
2981 {
2982 /* skip whitespace */
2983 SCIP_CALL( SCIPskipSpace((char**)&s) );
2984
2985 /* parse integer value */
2986 if( !SCIPstrToIntValue(s, &val, &endptr) )
2987 {
2988 SCIPerrorMessage("could not extract int from string '%s'\n", str);
2989 *success = FALSE;
2990 break;
2991 }
2992
2993 s = endptr;
2994 assert( s != NULL );
2995 ++nfoundpermidx;
2996
2997 if( nfoundpermidx > nvars )
2998 {
2999 SCIPerrorMessage("permutation is longer than vars array\n");
3000 *success = FALSE;
3001 break;
3002 }
3003
3004 perm[nfoundpermidx-1] = val;
3005
3006 /* skip whitespace */
3007 SCIP_CALL( SCIPskipSpace((char**)&s) );
3008
3009 /* skip ',' */
3010 if( *s == ',' )
3011 ++s;
3012 }
3013 while( *s != ']' );
3014
3015 if( nfoundpermidx != nvars )
3016 {
3017 SCIPerrorMessage("length of permutation is not equal to number of given variables.\n");
3018 *success = FALSE;
3019 break;
3020 }
3021 }
3022
3023 if( !*success )
3024 break;
3025
3026 ++s;
3027 ++cnt;
3028 }
3029 while( *s != ')' );
3030
3031 if( *success && cnt < 2 )
3032 {
3033 SCIPerrorMessage("permutation is missing.\n");
3034 *success = FALSE;
3035 }
3036
3037 if( *success )
3038 SCIP_CALL( SCIPcreateConsBasicSymresack(scip, cons, name, perm, vars, nvars, TRUE) );
3039
3040 SCIPfreeBufferArray(scip, &perm);
3041 SCIPfreeBufferArray(scip, &vars);
3042
3043 return SCIP_OKAY;
3044}
3045
3046
3047/** constraint display method of constraint handler
3048 *
3049 * The constraint handler should output a representation of the constraint into the given text file.
3050 */
3051static
3052SCIP_DECL_CONSPRINT(consPrintSymresack)
3053{ /*lint --e{715}*/
3054 SCIP_CONSDATA* consdata;
3055 SCIP_VAR** vars;
3056 int* perm;
3057 int nvars;
3058 int i;
3059
3060 assert( scip != NULL );
3061 assert( conshdlr != NULL );
3062 assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
3063 assert( cons != NULL );
3064
3065 consdata = SCIPconsGetData(cons);
3066 assert( consdata != NULL );
3067
3068 SCIPdebugMsg(scip, "Printing method for symresack constraint handler\n");
3069
3070 /* we do not have to take care of trivial constraints */
3071 if ( consdata->nvars < 2 )
3072 return SCIP_OKAY;
3073
3074 assert( consdata->vars != NULL );
3075 assert( consdata->perm != NULL );
3076
3077 vars = consdata->vars;
3078 nvars = consdata->nvars;
3079 perm = consdata->perm;
3080
3081 SCIPinfoMessage(scip, file, "symresack([");
3082 SCIP_CALL( SCIPwriteVarName(scip, file, vars[0], TRUE) );
3083
3084 for (i = 1; i < nvars; ++i)
3085 {
3086 SCIPinfoMessage(scip, file, ",");
3087 SCIP_CALL( SCIPwriteVarName(scip, file, vars[i], TRUE) );
3088 }
3089 SCIPinfoMessage(scip, file, "],[%d", perm[0]);
3090 for (i = 1; i < nvars; ++i)
3091 SCIPinfoMessage(scip, file, ",%d", perm[i]);
3092 SCIPinfoMessage(scip, file, "])");
3093
3094 return SCIP_OKAY;
3095}
3096
3097
3098/** constraint method of constraint handler which returns the variables (if possible) */
3099static
3100SCIP_DECL_CONSGETVARS(consGetVarsSymresack)
3101{ /*lint --e{715}*/
3102 SCIP_CONSDATA* consdata;
3103
3104 assert( cons != NULL );
3105 assert( success != NULL );
3106 assert( vars != NULL );
3107
3108 consdata = SCIPconsGetData(cons);
3109 assert( consdata != NULL );
3110
3111 if ( varssize < consdata->nvars )
3112 (*success) = FALSE;
3113 else
3114 {
3115 int cnt = 0;
3116 int i;
3117
3118 for (i = 0; i < consdata->nvars; ++i)
3119 vars[cnt++] = consdata->vars[i];
3120 (*success) = TRUE;
3121 }
3122
3123 return SCIP_OKAY;
3124}
3125
3126
3127/** constraint method of constraint handler which returns the number of variables (if possible) */
3128static
3129SCIP_DECL_CONSGETNVARS(consGetNVarsSymresack)
3130{ /*lint --e{715}*/
3131 SCIP_CONSDATA* consdata;
3132
3133 assert( cons != NULL );
3134 assert( success != NULL );
3135 assert( nvars != NULL );
3136
3137 consdata = SCIPconsGetData(cons);
3138 assert( consdata != NULL );
3139
3140 (*nvars) = consdata->nvars;
3141 (*success) = TRUE;
3142
3143 return SCIP_OKAY;
3144}
3145
3146
3147/** creates the handler for symresack constraints and includes it in SCIP */
3149 SCIP* scip /**< SCIP data structure */
3150 )
3151{
3152 SCIP_CONSHDLRDATA* conshdlrdata = NULL;
3153 SCIP_CONSHDLR* conshdlr;
3154
3155 SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
3156
3157 /* include constraint handler */
3160 consEnfolpSymresack, consEnfopsSymresack, consCheckSymresack, consLockSymresack,
3161 conshdlrdata) );
3162 assert( conshdlr != NULL );
3163
3164 /* set non-fundamental callbacks via specific setter functions */
3165 SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopySymresack, consCopySymresack) );
3166 SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxSymresack) );
3167 SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeSymresack) );
3168 SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteSymresack) );
3169 SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsSymresack) );
3170 SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsSymresack) );
3171 SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseSymresack) );
3173 SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintSymresack) );
3175 SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropSymresack) );
3176 SCIP_CALL( SCIPsetConshdlrExitpre(scip, conshdlr, consExitpreSymresack) );
3177 SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpSymresack, consSepasolSymresack, CONSHDLR_SEPAFREQ, CONSHDLR_SEPAPRIORITY, CONSHDLR_DELAYSEPA) );
3178 SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransSymresack) );
3179 SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpSymresack) );
3180 SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolSymresack) );
3181
3182 /* whether we allow upgrading to packing/partioning symresack constraints*/
3183 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/ppsymresack",
3184 "Upgrade symresack constraints to packing/partioning symresacks?",
3185 &conshdlrdata->checkppsymresack, TRUE, DEFAULT_PPSYMRESACK, NULL, NULL) );
3186
3187 /* whether we check for monotonicity of perm when upgrading to packing/partioning symresacks */
3188 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/checkmonotonicity",
3189 "Check whether permutation is monotone when upgrading to packing/partioning symresacks?",
3190 &conshdlrdata->checkmonotonicity, TRUE, DEFAULT_CHECKMONOTONICITY, NULL, NULL) );
3191
3192 SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forceconscopy",
3193 "Whether symresack constraints should be forced to be copied to sub SCIPs.",
3194 &conshdlrdata->forceconscopy, TRUE, DEFAULT_FORCECONSCOPY, NULL, NULL) );
3195
3196 return SCIP_OKAY;
3197}
3198
3199
3200/*
3201 * constraint specific interface methods
3202 */
3203
3204/** creates and captures a symresack constraint
3205 *
3206 * In a presolving step, we check whether the permutation acts only on binary points. Otherwise, we eliminate
3207 * the non-binary variables from the permutation.
3208 *
3209 * @note The constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons().
3212 SCIP* scip, /**< SCIP data structure */
3213 SCIP_CONS** cons, /**< pointer to hold the created constraint */
3214 const char* name, /**< name of constraint */
3215 int* perm, /**< permutation */
3216 SCIP_VAR** vars, /**< variables */
3217 int nvars, /**< number of variables in vars array */
3218 SCIP_Bool ismodelcons, /**< whether the symresack is a model constraint */
3219 SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
3220 * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
3221 SCIP_Bool separate, /**< should the constraint be separated during LP processing?
3222 * Usually set to TRUE. */
3223 SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
3224 * TRUE for model constraints, FALSE for additional, redundant constraints. */
3225 SCIP_Bool check, /**< should the constraint be checked for feasibility?
3226 * TRUE for model constraints, FALSE for additional, redundant constraints. */
3227 SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
3228 * Usually set to TRUE. */
3229 SCIP_Bool local, /**< is constraint only valid locally?
3230 * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
3231 SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
3232 * Usually set to FALSE. In column generation applications, set to TRUE if pricing
3233 * adds coefficients to this constraint. */
3234 SCIP_Bool dynamic, /**< is constraint subject to aging?
3235 * Usually set to FALSE. Set to TRUE for own cuts which
3236 * are separated as constraints. */
3237 SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
3238 * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
3239 SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
3240 * if it may be moved to a more global node?
3241 * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
3242 )
3243{
3244 SCIP_CONSHDLR* conshdlr;
3245 SCIP_CONSDATA* consdata;
3246
3247 assert( cons != NULL );
3248 assert( nvars > 0 );
3249
3250 /* find the symresack constraint handler */
3251 conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
3252 if ( conshdlr == NULL )
3253 {
3254 SCIPerrorMessage("Symresack constraint handler not found.\n");
3255 return SCIP_PLUGINNOTFOUND;
3256 }
3257
3258 /* create constraint data */
3259 SCIP_CALL( consdataCreate(scip, conshdlr, &consdata, vars, nvars, perm, ismodelcons) );
3260
3261 /* create constraint */
3262 SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate && (! consdata->ppupgrade), enforce, check, propagate,
3263 local, modifiable, dynamic, removable, stickingatnode) );
3264
3265 return SCIP_OKAY;
3266}
3267
3268
3269/** creates and captures a symresack constraint
3270 * in its most basic variant, i.e., with all constraint flags set to their default values
3271 *
3272 * In a presolving step, we remove all fixed points and cycles that act on non-binary variables of the permutation
3273 *
3274 * @note The constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons().
3277 SCIP* scip, /**< SCIP data structure */
3278 SCIP_CONS** cons, /**< pointer to hold the created constraint */
3279 const char* name, /**< name of constraint */
3280 int* perm, /**< permutation */
3281 SCIP_VAR** vars, /**< variables */
3282 int nvars, /**< number of variables in vars array */
3283 SCIP_Bool ismodelcons /**< whether the symresack is a model constraint */
3284 )
3285{
3286 SCIP_CALL( SCIPcreateConsSymresack(scip, cons, name, perm, vars, nvars, ismodelcons,
3288
3289 return SCIP_OKAY;
3290}
SCIP_Real * r
Definition: circlepacking.c:59
constraint handler for orbisack constraints
Constraint handler for the set partitioning / packing / covering constraints .
#define CONSHDLR_NEEDSCONS
#define CONSHDLR_SEPAFREQ
static SCIP_DECL_CONSTRANS(consTransSymresack)
#define FIXED0
#define CONSHDLR_CHECKPRIORITY
#define CONSHDLR_DESC
static SCIP_DECL_CONSDELETE(consDeleteSymresack)
#define NOINIT
#define ISFIXED(scip, x, bdchgidx)
static SCIP_DECL_CONSINITSOL(consInitsolSymresack)
static SCIP_DECL_CONSPROP(consPropSymresack)
static SCIP_DECL_CONSGETVARS(consGetVarsSymresack)
#define CONSHDLR_PROP_TIMING
static SCIP_RETCODE replaceAggregatedVarsSymresack(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopySymresack)
static SCIP_DECL_CONSLOCK(consLockSymresack)
#define DEFAULT_FORCECONSCOPY
#define CONSHDLR_MAXPREROUNDS
#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_DECL_CONSENFOPS(consEnfopsSymresack)
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)
#define CONSHDLR_SEPAPRIORITY
#define UNFIXED
static SCIP_DECL_CONSENFOLP(consEnfolpSymresack)
static SCIP_RETCODE checkSymresackSolution(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_RESULT *result, SCIP_Bool printreason)
static SCIP_DECL_CONSCHECK(consCheckSymresack)
static SCIP_DECL_CONSENFORELAX(consEnforelaxSymresack)
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_DECL_CONSPRINT(consPrintSymresack)
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)
#define CONSHDLR_PROPFREQ
static SCIP_DECL_CONSPRESOL(consPresolSymresack)
static SCIP_DECL_CONSINITLP(consInitlpSymresack)
static SCIP_RETCODE addSymresackInequality(SCIP *scip, SCIP_CONS *cons, int nvars, SCIP_VAR **vars, int *coeffs, SCIP_Real rhs, SCIP_Bool *infeasible)
#define CONSHDLR_PRESOLTIMING
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)
static SCIP_DECL_CONSSEPALP(consSepalpSymresack)
static SCIP_DECL_CONSPARSE(consParseSymresack)
#define CONSHDLR_EAGERFREQ
static SCIP_DECL_CONSGETNVARS(consGetNVarsSymresack)
#define DEFAULT_PPSYMRESACK
static SCIP_RETCODE maximizeObjectiveSymresackStrict(SCIP *scip, int nvars, SCIP_Real *objective, int *perm, int *invperm, int *maxcrit, SCIP_Real *maxsoluval)
#define CONSHDLR_ENFOPRIORITY
static SCIP_DECL_CONSCOPY(consCopySymresack)
#define FIXED1
#define CONSHDLR_DELAYSEPA
static SCIP_DECL_CONSSEPASOL(consSepasolSymresack)
static SCIP_DECL_CONSFREE(consFreeSymresack)
#define CONSHDLR_NAME
static SCIP_DECL_CONSRESPROP(consRespropSymresack)
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)
#define CONSHDLR_DELAYPROP
static SCIP_DECL_CONSEXITPRE(consExitpreSymresack)
constraint handler for symresack constraints
#define SCIP_DEFAULT_INFINITY
Definition: def.h:163
#define NULL
Definition: def.h:248
#define SCIP_MAXSTRLEN
Definition: def.h:269
#define SCIP_UNUSED(x)
Definition: def.h:409
#define SCIP_Bool
Definition: def.h:91
#define SCIP_Real
Definition: def.h:156
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define REALABS(x)
Definition: def.h:182
#define SCIP_CALL(x)
Definition: def.h:355
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)
Definition: cons_setppc.c:9596
SCIP_VAR ** SCIPgetVarsSetppc(SCIP *scip, SCIP_CONS *cons)
Definition: cons_setppc.c:9619
SCIP_SETPPCTYPE SCIPgetTypeSetppc(SCIP *scip, SCIP_CONS *cons)
Definition: cons_setppc.c:9642
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)
Definition: scip_general.c:647
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:3420
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:208
#define SCIPdebugMsg
Definition: scip_message.h:78
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:57
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip_branch.c:436
SCIP_RETCODE 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 SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip_cons.c:808
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:540
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:831
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition: scip_cons.c:235
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip_cons.c:281
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip_cons.c:181
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:578
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:372
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip_cons.c:323
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4778
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4316
SCIP_RETCODE SCIPsetConshdlrExitpre(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSEXITPRE((*consexitpre)))
Definition: scip_cons.c:516
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:347
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:940
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip_cons.c:624
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
Definition: scip_cons.c:444
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4336
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:601
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip_cons.c:647
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:854
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4735
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip_cons.c:785
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8419
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8648
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8558
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8588
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8578
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip_cons.c:997
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8608
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8628
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8389
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8638
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8668
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8568
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8658
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip_cut.c:135
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:225
#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:1846
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1765
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_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:23642
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:23478
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:23386
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:24268
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_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:23662
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1887
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:24234
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition: var.c:23443
SCIP_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
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.
Definition: sepa_flower.c:1221
@ SCIP_CONFTYPE_PROPAGATION
Definition: type_conflict.h:62
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:64
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:65
@ 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
Definition: type_retcode.h:54
@ SCIP_OKAY
Definition: type_retcode.h:42
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
@ SCIP_VARSTATUS_FIXED
Definition: type_var.h:54
@ SCIP_VARSTATUS_MULTAGGR
Definition: type_var.h:56
@ SCIP_VARSTATUS_NEGATED
Definition: type_var.h:57