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