Scippy

    SCIP

    Solving Constraint Integer Programs

    symmetry_lexred.c
    Go to the documentation of this file.
    1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    2/* */
    3/* This file is part of the program and library */
    4/* SCIP --- Solving Constraint Integer Programs */
    5/* */
    6/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */
    7/* */
    8/* Licensed under the Apache License, Version 2.0 (the "License"); */
    9/* you may not use this file except in compliance with the License. */
    10/* You may obtain a copy of the License at */
    11/* */
    12/* http://www.apache.org/licenses/LICENSE-2.0 */
    13/* */
    14/* Unless required by applicable law or agreed to in writing, software */
    15/* distributed under the License is distributed on an "AS IS" BASIS, */
    16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
    17/* See the License for the specific language governing permissions and */
    18/* limitations under the License. */
    19/* */
    20/* You should have received a copy of the Apache-2.0 license */
    21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
    22/* */
    23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
    24
    25/**@file symmetry_lexred.c
    26 * @ingroup OTHER_CFILES
    27 * @brief methods for handling symmetries by dynamic lexicographic ordering reduction
    28 * @author Jasper van Doornmalen
    29 *
    30 * This implements lexicographic reduction, which generalizes symresack propagation to work for non-binary variable
    31 * domains, and is dynamified. Whereas static lexicographic reduction propagates that a vector \f$x\f$ is
    32 * lexicographically larger than its permuted counterpart (i.e., \f$x \succeq \gamma(x)\f$ with \f$\succeq\f$ being
    33 * standard elementwise lexicographic comparison), the dynamic variant determines the variable vector ordering
    34 * dynamically. Just as in orbital reduction (cf. symmetry_orbital.c), the variable order is chosen as the variables
    35 * branched on from the root node to the focus node.
    36 * Thus, in node \f$\beta\f$, we propagate \f$\sigma_\beta(x) \succeq \sigma_\beta(\gamma(x))\f$,
    37 * where \f$\sigma_\beta(\cdot)\f$ permutes and restricts the variable vector such that it corresponds to the branched
    38 * variables in the order from the rooted path to \f$\beta\f$.
    39 *
    40 * See Section 4.1 and Example 11 in [vD,H]:@n
    41 * J. van Doornmalen, C. Hojny, "A Unified Framework for Symmetry Handling", preprint, 2023,
    42 * https://doi.org/10.48550/arXiv.2211.01295.
    43 *
    44 * For dynamic lexicographic reduction, it is crucial that the vectors \f$\sigma_\beta(x)\f$ are the branching
    45 * variables up to node \f$\beta\f$ in the given order. Since SCIP can change the tree structure during solving
    46 * (re-writing history), we store the original branching decisions at the moment they are made. See event_shadowtree.c .
    47 */
    48
    49/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    50
    53#include "scip/pub_cons.h"
    54#include "scip/pub_message.h"
    55#include "scip/pub_var.h"
    56#include "scip/struct_var.h"
    57#include "scip/type_var.h"
    58#include "scip/scip.h"
    59#include "scip/scip_branch.h"
    60#include "scip/scip_conflict.h"
    61#include "scip/scip_cons.h"
    62#include "scip/scip_copy.h"
    63#include "scip/scip_cut.h"
    64#include "scip/scip_general.h"
    65#include "scip/scip_lp.h"
    66#include "scip/scip_mem.h"
    67#include "scip/scip_message.h"
    68#include "scip/scip_numerics.h"
    69#include "scip/scip_param.h"
    70#include "scip/scip_prob.h"
    71#include "scip/scip_probing.h"
    72#include "scip/scip_sol.h"
    73#include "scip/scip_var.h"
    74#include "scip/debug.h"
    75#include "scip/struct_scip.h"
    76#include "scip/struct_mem.h"
    77#include "scip/struct_tree.h"
    78#include "scip/symmetry.h"
    80#include <string.h>
    81
    82
    83/*
    84 * Data structures
    85 */
    86
    87
    88/** data per permutation for lexicographic reduction propagator */
    90{
    91 SCIP_Bool isdynamic; /**< whether permutation shall be propagated with dynamic variable order */
    92 SCIP_VAR** vars; /**< variables affected by permutation */
    93 int nvars; /**< number of variables */
    94 int* perm; /**< permutation for lexicographic reduction */
    95 int* invperm; /**< inverse permutation */
    96 SCIP_HASHMAP* varmap; /**< map of variables to indices in vars array */
    97 SYM_SYMTYPE symtype; /**< type of symmetries in perm */
    98 SCIP_Real* vardomaincenter; /**< array of centers of variable domains */
    99};
    100typedef struct LexRedPermData LEXDATA;
    101
    102
    103/** data for dynamic lexicographic reduction propagator */
    104struct SCIP_LexRedData
    105{
    106 SCIP_EVENTHDLR* shadowtreeeventhdlr;/**< eventhandler for the shadow tree data structure */
    107 SCIP_HASHMAP* symvarmap; /**< map of variables affected by some permutation handled by a LEXDATA */
    108 int nsymvars; /**< number of variables in symvarmap */
    109 LEXDATA** lexdatas; /**< array of pointers to individual LEXDATA's */
    110 int nlexdatas; /**< number of datas in array */
    111 int maxnlexdatas; /**< allocated datas array size */
    112 int nred; /**< total number of reductions */
    113 int ncutoff; /**< total number of cutoffs */
    114 SCIP_Bool hasdynamicperm; /**< whether there exists a permutation that is treated dynamically */
    115 SCIP_Bool treewarninggiven; /**< whether a warning is given for missing nodes in shadowtree */
    116};
    117
    118
    119/** to store branch-and-bound tree paths, (depth, index)-information per variable in rooted path */
    121{
    122 int nodedepth; /**< depth of var domain change */
    123 int index; /**< index of var domain change on node at depth */
    124};
    126
    127
    128/** auxiliary struct to pass branch-and-bound tree information to sort function */
    130{
    131 NODEDEPTHBRANCHINDEX* nodedepthbranchindices; /**< pointer to branch-and-bound tree information */
    132 SCIP_LEXREDDATA* masterdata; /**< pointer to global data for lexicographic reduction propagator */
    133 SCIP_VAR** vars; /**< pointer to variable array */
    134};
    136
    137
    138/*
    139 * Local methods
    140 */
    141
    142/** frees dynamic lexicographic reduction propagator data */
    143static
    145 SCIP* scip, /**< SCIP data structure */
    146 LEXDATA** lexdata /**< pointer to individual lexicographic reduction propagator datas */
    147 )
    148{
    149 SCIP_Bool issigned;
    150 int permlen;
    151 int i;
    152
    153 assert( scip != NULL );
    154 assert( lexdata != NULL );
    155 assert( (*lexdata) != NULL );
    156
    157 if ( (*lexdata)->symtype == SYM_SYMTYPE_SIGNPERM )
    158 {
    159 issigned = TRUE;
    160 permlen = 2 * (*lexdata)->nvars;
    161 }
    162 else
    163 {
    164 issigned = FALSE;
    165 permlen = (*lexdata)->nvars;
    166 }
    167
    168 if ( (*lexdata)->nvars > 0 )
    169 {
    170 assert( (*lexdata)->invperm != NULL );
    171 assert( (*lexdata)->perm != NULL );
    172 assert( (*lexdata)->vars != NULL );
    173
    174 /* free hashmap */
    175 if ( (*lexdata)->isdynamic )
    176 {
    177 assert( (*lexdata)->varmap != NULL );
    178 SCIPhashmapFree(&((*lexdata)->varmap));
    179 }
    180
    181 /* release variables */
    182 for (i = 0; i < (*lexdata)->nvars; ++i)
    183 {
    184 SCIP_CALL( SCIPreleaseVar(scip, &(*lexdata)->vars[i]) );
    185 }
    186
    187 SCIPfreeBlockMemoryArray(scip, &(*lexdata)->invperm, permlen);
    188 SCIPfreeBlockMemoryArray(scip, &(*lexdata)->perm, permlen);
    189 SCIPfreeBlockMemoryArray(scip, &(*lexdata)->vars, (*lexdata)->nvars);
    190
    191 if ( issigned )
    192 {
    193 SCIPfreeBlockMemoryArray(scip, &(*lexdata)->vardomaincenter, (*lexdata)->nvars);
    194 }
    195 else
    196 {
    197 assert( (*lexdata)->vardomaincenter == NULL );
    198 }
    199 }
    200#ifndef NDEBUG
    201 else
    202 {
    203 assert( (*lexdata)->nvars == 0 );
    204 assert( (*lexdata)->invperm == NULL );
    205 assert( (*lexdata)->vardomaincenter == NULL );
    206 assert( (*lexdata)->perm == NULL );
    207 assert( (*lexdata)->vars == NULL );
    208 assert( (*lexdata)->varmap == NULL );
    209 }
    210#endif
    211 SCIPfreeBlockMemory(scip, lexdata);
    212
    213 return SCIP_OKAY;
    214}
    215
    216
    217/** creates dynamic lexicographic reduction propagator data
    218 *
    219 * Fixed points are removed.
    220 */
    221static
    223 SCIP* scip, /**< SCIP data structure */
    224 SCIP_LEXREDDATA* masterdata, /**< pointer to global data for lexicographic reduction propagator */
    225 LEXDATA** lexdata, /**< pointer to store data for permutation to be added */
    226 SCIP_VAR*const* vars, /**< input variables of the lexicographic reduction propagator */
    227 int nvars, /**< input number of variables of the lexicographic reduction propagator */
    228 int* perm, /**< input permutation of the lexicographic reduction propagator */
    229 SYM_SYMTYPE symtype, /**< type of symmetries in perm */
    230 SCIP_Real* permvardomaincenter, /**< array containing center point for each variable domain */
    231 SCIP_Bool usedynamicorder, /**< whether a dynamic variable order shall be used */
    232 SCIP_Bool* success /**< to store whether the component is successfully added */
    233 )
    234{
    235 SCIP_VAR* var;
    236 SCIP_Bool issignedperm;
    237 int* indexcorrection;
    238 int naffectedvariables;
    239 int permlen;
    240 int i;
    241 int j;
    242
    243 assert( scip != NULL );
    244 assert( masterdata != NULL );
    245 assert( lexdata != NULL );
    246 assert( vars != NULL );
    247 assert( nvars >= 0 );
    248 assert( perm != NULL );
    249 assert( symtype == SYM_SYMTYPE_PERM || permvardomaincenter != NULL );
    250 assert( success != NULL );
    251 assert( SCIPisTransformed(scip) );
    252 assert( masterdata->shadowtreeeventhdlr != NULL );
    253
    254 *success = TRUE;
    255 issignedperm = symtype == SYM_SYMTYPE_PERM ? FALSE : TRUE;
    256
    257 /* initialize the data structures */
    259 (*lexdata)->symtype = symtype;
    260
    261 (*lexdata)->isdynamic = usedynamicorder;
    262
    263 /* remove fixed points */
    264 naffectedvariables = 0;
    265 SCIP_CALL( SCIPallocBufferArray(scip, &indexcorrection, nvars) );
    266 for (i = 0; i < nvars; ++i)
    267 {
    268 if ( perm[i] == i )
    269 indexcorrection[i] = -1; /* fixed points get an entry < 0 in the indexcorrection array */
    270 else
    271 indexcorrection[i] = naffectedvariables++;
    272 }
    273
    274 /* do nothing if reductions would be trivial */
    275 if ( naffectedvariables <= 0 )
    276 {
    277 assert( naffectedvariables == 0 );
    278 SCIPfreeBufferArray(scip, &indexcorrection);
    279
    280 *success = FALSE;
    281 SCIPfreeBlockMemory(scip, lexdata);
    282 return SCIP_OKAY;
    283 }
    284
    285 /* require that the shadowtree is active if dynamic propagation is used */
    286 if ( usedynamicorder )
    287 {
    288 masterdata->hasdynamicperm = TRUE;
    289
    290 SCIP_CALL( SCIPactivateShadowTree(scip, masterdata->shadowtreeeventhdlr) );
    291 }
    292
    293 /* initialize variable arrays */
    294 (*lexdata)->nvars = naffectedvariables;
    295 permlen = issignedperm ? 2 * (*lexdata)->nvars : (*lexdata)->nvars;
    296
    297 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*lexdata)->vars, (*lexdata)->nvars) );
    298 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*lexdata)->perm, permlen) );
    299 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*lexdata)->invperm, permlen) );
    300 if ( issignedperm )
    301 {
    302 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*lexdata)->vardomaincenter, (*lexdata)->nvars) );
    303 }
    304 else
    305 (*lexdata)->vardomaincenter = NULL;
    306
    307 /* determine the vars, perm, and centers */
    308 for (j = 0; j < nvars; ++j)
    309 {
    310 i = indexcorrection[j];
    311 if ( i < 0 )
    312 continue;
    313
    314 /* j is the original index, i is the relabeled index */
    315 (*lexdata)->vars[i] = vars[j];
    316
    317 if ( issignedperm )
    318 {
    319 if ( perm[j] >= nvars )
    320 {
    321 (*lexdata)->perm[i] = indexcorrection[perm[j] - nvars] + (*lexdata)->nvars;
    322 (*lexdata)->perm[i + (*lexdata)->nvars] = indexcorrection[perm[j] - nvars];
    323 assert( (*lexdata)->nvars <= (*lexdata)->perm[i] && (*lexdata)->perm[i] < 2 * (*lexdata)->nvars );
    324 }
    325 else
    326 {
    327 (*lexdata)->perm[i] = indexcorrection[perm[j]];
    328 (*lexdata)->perm[i + (*lexdata)->nvars] = indexcorrection[perm[j]] + (*lexdata)->nvars;
    329 }
    330 }
    331 else
    332 (*lexdata)->perm[i] = indexcorrection[perm[j]];
    333
    334 if ( issignedperm )
    335 (*lexdata)->vardomaincenter[i] = permvardomaincenter[j];
    336
    337 assert( perm[j] != j );
    338 assert( (*lexdata)->perm[i] != i );
    339 assert( (*lexdata)->perm[i] >= 0 );
    340 assert( (*lexdata)->perm[i] < permlen );
    341 }
    342
    343 /* determine invperm */
    344 for (i = 0; i < (*lexdata)->nvars; ++i)
    345 {
    346 if ( (*lexdata)->perm[i] >= (*lexdata)->nvars )
    347 {
    348 assert( issignedperm );
    349
    350 (*lexdata)->invperm[(*lexdata)->perm[i]] = i;
    351 (*lexdata)->invperm[(*lexdata)->perm[i] - (*lexdata)->nvars] = i + (*lexdata)->nvars;
    352 }
    353 else
    354 {
    355 (*lexdata)->invperm[(*lexdata)->perm[i]] = i;
    356
    357 if ( issignedperm )
    358 (*lexdata)->invperm[(*lexdata)->perm[i] + (*lexdata)->nvars] = i + (*lexdata)->nvars;
    359 }
    360 }
    361 SCIPfreeBufferArray(scip, &indexcorrection);
    362
    363 /* make sure that we deal with transformed variables and that variables cannot be multi-aggregated, and capture */
    364 for (i = 0; i < (*lexdata)->nvars; ++i)
    365 {
    366 assert( SCIPvarIsTransformed((*lexdata)->vars[i]) );
    367 SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*lexdata)->vars[i]) );
    368 SCIP_CALL( SCIPcaptureVar(scip, (*lexdata)->vars[i]) );
    369 }
    370
    371 /* create hashmap for all variables, both globally and just for this lexdata */
    372 assert( (masterdata->symvarmap == NULL) == (masterdata->nsymvars == 0) );
    373 if ( usedynamicorder )
    374 {
    375 if ( masterdata->symvarmap == NULL )
    376 {
    377 SCIP_CALL( SCIPhashmapCreate(&masterdata->symvarmap, SCIPblkmem(scip), (*lexdata)->nvars) );
    378 }
    379 assert( masterdata->symvarmap != NULL );
    380
    381 SCIP_CALL( SCIPhashmapCreate(&(*lexdata)->varmap, SCIPblkmem(scip), (*lexdata)->nvars) );
    382 assert( (*lexdata)->varmap != NULL );
    383
    384 for (i = 0; i < (*lexdata)->nvars; ++i)
    385 {
    386 var = (*lexdata)->vars[i];
    387 assert( var != NULL );
    388 assert( SCIPvarIsTransformed(var) );
    389
    390 /* the hashmap in lexdata maps to the index in the vars array */
    391 SCIP_CALL( SCIPhashmapInsertInt((*lexdata)->varmap, (void*) var, i) );
    392
    393 /* var already added to hashmap */
    394 if ( SCIPhashmapExists(masterdata->symvarmap, (void*) var) )
    395 continue;
    396
    397 /* the hashmap in symvarmap maps to a unique index */
    398 SCIP_CALL( SCIPhashmapInsertInt(masterdata->symvarmap, (void*) var, masterdata->nsymvars++) );
    399 }
    400 }
    401 else
    402 (*lexdata)->varmap = NULL;
    403
    404 return SCIP_OKAY;
    405}
    406
    407
    408/** comparator used in the getVarOrder() function, for sorting an array of NODEDEPTHBRANCHINDEX by depth, then by index
    409 *
    410 * @warning this function is only meant to be used in the getVarOrder() function
    411 *
    412 * @pre datapointer is populated with a VARARRAYNODEDEPTHBRANCHINDEX pointer
    413 * @pre the comparator is only called on entries with set (depth, index)-information
    414 * @pre the (depth, index)-informations are all different
    415 *
    416 * result:
    417 * 0: the same index is compared, so the (depth, index)-informations are the same
    418 * -1: the depth of ind1 is smaller than the depth of ind2, or it's equal and the index is smaller
    419 * 1: the depth of ind2 is smaller than the depth of ind1, or it's equal and the index is smaller
    420 */
    421static
    422SCIP_DECL_SORTINDCOMP(sortbynodedepthbranchindices)
    423{
    424 /* unpack the dataptr */
    425 VARARRAYNODEDEPTHBRANCHINDEX* vararraynodedepthbranchindices;
    428 SCIP_VAR** vars;
    429 NODEDEPTHBRANCHINDEX* index1;
    430 NODEDEPTHBRANCHINDEX* index2;
    431
    432 vararraynodedepthbranchindices = (VARARRAYNODEDEPTHBRANCHINDEX*) dataptr;
    433 nodedepthbranchindices = vararraynodedepthbranchindices->nodedepthbranchindices;
    434 masterdata = vararraynodedepthbranchindices->masterdata;
    435 vars = vararraynodedepthbranchindices->vars;
    436
    437 /* comparing the same element is an identity operation */
    438 if ( ind1 == ind2 )
    439 return 0;
    440
    441 /* sort by depth, then by index, in increasing order */
    442 index1 = &(nodedepthbranchindices[SCIPhashmapGetImageInt(masterdata->symvarmap, vars[ind1])]);
    443 index2 = &(nodedepthbranchindices[SCIPhashmapGetImageInt(masterdata->symvarmap, vars[ind2])]);
    444
    445 if ( index1->nodedepth < index2->nodedepth )
    446 return -1;
    447 if ( index1->nodedepth > index2->nodedepth )
    448 return 1;
    449 assert( index1->index != index2->index );
    450
    451 /* depth is the same, sort by index */
    452 if ( index1->index < index2->index )
    453 return -1;
    454 if ( index1->index > index2->index )
    455 return 1;
    456
    457 /* this may not happen, since all elements must be different */
    458 assert( index1->index == index2->index );
    459
    460 return 0;
    461}
    462
    463
    464/** return the index of a variable at a specific position of a variable order */
    465static
    467 int* varorder, /**< variable order (or NULL) */
    468 int pos /**< position for which index is returned */
    469 )
    470{
    471 assert( pos >= 0 );
    472
    473 if ( varorder == NULL )
    474 return pos;
    475 return varorder[pos];
    476}
    477
    478
    479/** gets the variable ordering based on the branching decisions at the node */
    480static
    482 SCIP* scip, /**< SCIP data structure */
    483 SCIP_LEXREDDATA* masterdata, /**< pointer to global data for lexicographic reduction propagator */
    484 LEXDATA* lexdata, /**< pointer to data for this permutation */
    485 NODEDEPTHBRANCHINDEX* nodedepthbranchindices, /**< array with (depth, index)-information per variable in rooted path to focus node */
    486 int nvarstotal, /**< length of that array */
    487 SCIP_VAR** branchvars, /**< array populated with variables branched on in the symvarmap hashset */
    488 int nbranchvars, /**< number of elements in branchvars array */
    489 int* varorder, /**< array to populate with variable order */
    490 int* nselvars, /**< pointer to number of variables in the ordering */
    491 int maxnselvars /**< maximal size of the number of selected variables */
    492 )
    493{
    494 SCIP_VAR** vars;
    495 int nvars;
    496 SCIP_VAR* var;
    497 int varindex;
    498 int i;
    499
    500 assert( scip != NULL );
    501 assert( masterdata != NULL );
    502 assert( lexdata != NULL );
    503 assert( nodedepthbranchindices != NULL );
    504 assert( nvarstotal >= 0 );
    505 assert( branchvars != NULL );
    506 assert( nbranchvars >= 0 );
    507 assert( varorder != NULL );
    508 assert( nselvars != NULL );
    509
    510 vars = lexdata->vars;
    511 assert( vars != NULL );
    512 nvars = lexdata->nvars;
    513 assert( nvars >= 0 );
    514
    515 /* first collect every variable that was branched on */
    516 *nselvars = 0;
    517
    518 if ( nvars < nbranchvars )
    519 {
    520 /* for permutations with small support, just check all support entries */
    521 for (i = 0; i < nvars; ++i)
    522 {
    523 var = vars[i];
    524 assert( var != NULL );
    525
    526 assert( SCIPhashmapExists(masterdata->symvarmap, (void*) var) );
    527 varindex = SCIPhashmapGetImageInt(masterdata->symvarmap, var);
    528 assert( varindex >= 0 );
    529 assert( varindex < masterdata->nsymvars );
    530
    531 assert( nodedepthbranchindices[varindex].nodedepth >= 0 );
    532
    533 /* skip variables that have not been used for branching */
    534 if ( nodedepthbranchindices[varindex].nodedepth <= 0 )
    535 continue;
    536
    537 /* add index i of branching variable */
    538 assert( i >= 0 );
    539 assert( i < nvars );
    540 assert( (*nselvars) < maxnselvars );
    541 varorder[(*nselvars)++] = i;
    542 }
    543 }
    544 else
    545 {
    546 /* for permutations where the support is larger than the number of branched vars, check for the branched vars */
    547 for (i = 0; i < nbranchvars; ++i)
    548 {
    549 var = branchvars[i];
    550 assert( var != NULL );
    551
    552#ifndef NDEBUG
    553 /* debugging: test if it is indeed a branched variable! */
    554 varindex = SCIPhashmapGetImageInt(masterdata->symvarmap, var);
    555 assert( varindex >= 0 );
    556 assert( varindex < masterdata->nsymvars );
    557 assert( nodedepthbranchindices[varindex].nodedepth > 0 );
    558#endif
    559
    560 /* get the variable index in the lexdata->vars array */
    561 varindex = SCIPhashmapGetImageInt(lexdata->varmap, (void*) var);
    562 assert( varindex == INT_MAX || (varindex >= 0 && varindex < lexdata->nvars) );
    563
    564 /* skip variables that are not permuted by the permutation */
    565 if ( varindex == INT_MAX )
    566 continue;
    567 assert( lexdata->vars[varindex] == var );
    568
    569 /* add index varindex of the branching variable */
    570 varorder[(*nselvars)++] = varindex;
    571 }
    572 }
    573
    574 if ( *nselvars > 1 )
    575 {
    576 /* sort the first n elements of varorder by depth, then by index, as indicated by nodedepthbranchindices. */
    577 VARARRAYNODEDEPTHBRANCHINDEX vararraynodedepthbranchindices;
    578 vararraynodedepthbranchindices.nodedepthbranchindices = nodedepthbranchindices;
    579 vararraynodedepthbranchindices.masterdata = masterdata;
    580 vararraynodedepthbranchindices.vars = vars;
    581 SCIPsortInd(varorder, sortbynodedepthbranchindices, (void*) &vararraynodedepthbranchindices, *nselvars);
    582 }
    583
    584 return SCIP_OKAY;
    585}
    586
    587
    588/** gerts local variable bounds or reads bound from peek data */
    589static
    591 SCIP_VAR* var1, /**< first variable in comparison */
    592 SCIP_VAR* var2, /**< second variable in comparison */
    593 SCIP_Bool peekmode, /**< whether function is called in peek mode */
    594 int varidx1, /**< index of var1 (or NULL) */
    595 int varidx2, /**< index of var2 (or NULL) */
    596 SCIP_Real* peeklbs, /**< lower bounds of variables in peek mode (or NULL) */
    597 SCIP_Real* peekubs, /**< upper bounds of variables in peek mode (or NULL) */
    598 SCIP_Bool* peekbdset, /**< whether peek bounds have been set (or NULL) */
    599 SCIP_Real* lb1, /**< pointer to store lower bound of var1 */
    600 SCIP_Real* ub1, /**< pointer to store upper bound of var1 */
    601 SCIP_Real* lb2, /**< pointer to store lower bound of var2 */
    602 SCIP_Real* ub2 /**< pointer to store upper bound of var2 */
    603 )
    604{
    605 assert( var1 != NULL );
    606 assert( var2 != NULL );
    607 assert( (!peekmode) || peeklbs != NULL );
    608 assert( (!peekmode) || peekubs != NULL );
    609 assert( (!peekmode) || peekbdset != NULL );
    610 assert( lb1 != NULL );
    611 assert( ub1 != NULL );
    612 assert( lb2 != NULL );
    613 assert( ub2 != NULL );
    614
    615 if ( peekmode && peekbdset[varidx1] )
    616 {
    617 *ub1 = peekubs[varidx1];
    618 *lb1 = peeklbs[varidx1];
    619 }
    620 else
    621 {
    622 *ub1 = SCIPvarGetUbLocal(var1);
    623 *lb1 = SCIPvarGetLbLocal(var1);
    624 }
    625 if ( peekmode && peekbdset[varidx2] )
    626 {
    627 *ub2 = peekubs[varidx2];
    628 *lb2 = peeklbs[varidx2];
    629 }
    630 else
    631 {
    632 *ub2 = SCIPvarGetUbLocal(var2);
    633 *lb2 = SCIPvarGetLbLocal(var2);
    634 }
    635
    636 return SCIP_OKAY;
    637}
    638
    639/** returns whether a shifted variable is always smaller than another shifted variable
    640 *
    641 * Shifts are always (var - shift).
    642 */
    643static
    645 SCIP* scip, /**< SCIP data structure */
    646 SCIP_VAR* var1, /**< first variable in comparison */
    647 SCIP_VAR* var2, /**< second variable in comparison */
    648 SCIP_Real shift1, /**< shift of var1 */
    649 SCIP_Real shift2, /**< shift of var2 */
    650 SCIP_Bool isnegated, /**< whether shift of var2 is negated */
    651 SCIP_Bool peekmode, /**< whether function is called in peek mode */
    652 int varidx1, /**< index of var1 (or NULL) */
    653 int varidx2, /**< index of var2 (or NULL) */
    654 SCIP_Real* peeklbs, /**< lower bounds of variables in peek mode (or NULL) */
    655 SCIP_Real* peekubs, /**< upper bounds of variables in peek mode (or NULL) */
    656 SCIP_Bool* peekbdset /**< whether peek bounds have been set (or NULL) */
    657 )
    658{
    659 SCIP_Real ub1;
    660 SCIP_Real ub2;
    661 SCIP_Real lb1;
    662 SCIP_Real lb2;
    663
    664 assert( scip != NULL );
    665 assert( var1 != NULL );
    666 assert( var2 != NULL );
    667 assert( (!peekmode) || peeklbs != NULL );
    668 assert( (!peekmode) || peekubs != NULL );
    669 assert( (!peekmode) || peekbdset != NULL );
    670
    671 SCIP_CALL_ABORT( getVarBounds(var1, var2, peekmode, varidx1, varidx2, peeklbs, peekubs, peekbdset,
    672 &lb1, &ub1, &lb2, &ub2) );
    673
    674 /* for negated variables, check: var1 - shift1 < shift2 - var2 */
    675 if ( isnegated && SCIPisLT(scip, ub1, shift1 + shift2 - ub2) )
    676 return TRUE;
    677
    678 /* for non-negated variables, check: var1 - center1 < var2 - center2 */
    679 if ( (!isnegated) && SCIPisLT(scip, ub1, shift1 - shift2 + lb2) )
    680 return TRUE;
    681
    682 return FALSE;
    683}
    684
    685
    686/** returns whether a shifted variable can be greater than another shifted variable
    687 *
    688 * Shifts are always (var - shift).
    689 */
    690static
    692 SCIP* scip, /**< SCIP data structure */
    693 SCIP_VAR* var1, /**< first variable in comparison */
    694 SCIP_VAR* var2, /**< second variable in comparison */
    695 SCIP_Real shift1, /**< shift of var1 */
    696 SCIP_Real shift2, /**< shift of var2 */
    697 SCIP_Bool isnegated, /**< whether shift of var2 is negated */
    698 SCIP_Bool peekmode, /**< whether function is called in peek mode */
    699 int varidx1, /**< index of var1 (or NULL) */
    700 int varidx2, /**< index of var2 (or NULL) */
    701 SCIP_Real* peeklbs, /**< lower bounds of variables in peek mode (or NULL) */
    702 SCIP_Real* peekubs, /**< upper bounds of variables in peek mode (or NULL) */
    703 SCIP_Bool* peekbdset /**< whether peek bounds have been set (or NULL) */
    704 )
    705{
    706 SCIP_Real ub1;
    707 SCIP_Real ub2;
    708 SCIP_Real lb1;
    709 SCIP_Real lb2;
    710
    711 assert( scip != NULL );
    712 assert( var1 != NULL );
    713 assert( var2 != NULL );
    714 assert( (!peekmode) || peeklbs != NULL );
    715 assert( (!peekmode) || peekubs != NULL );
    716 assert( (!peekmode) || peekbdset != NULL );
    717
    718 SCIP_CALL_ABORT( getVarBounds(var1, var2, peekmode, varidx1, varidx2, peeklbs, peekubs, peekbdset,
    719 &lb1, &ub1, &lb2, &ub2) );
    720
    721 /* for negated variables, check: var1 - shift1 > shift2 - var2 */
    722 if ( isnegated && SCIPisGT(scip, ub1, shift1 + shift2 - ub2) )
    723 return TRUE;
    724
    725 /* for non-negated variables, check: var1 - center1 > var2 - center2 */
    726 if ( (!isnegated) && SCIPisGT(scip, ub1, shift1 - shift2 + lb2) )
    727 return TRUE;
    728
    729 return FALSE;
    730}
    731
    732
    733/** propagates lower bound of first variable in relation x >= y for shifted variables */
    734static
    736 SCIP* scip, /**< SCIP data structure */
    737 SCIP_VAR* var1, /**< first variable in pair */
    738 SCIP_VAR* var2, /**< second variable in pair */
    739 SCIP_Real center1, /**< center of var1 (original var domain) */
    740 SCIP_Real center2, /**< center of var2 (original var domain) */
    741 SCIP_Bool isnegated, /**< whether var2 is negated by symmetry */
    742 SCIP_Bool* infeasible, /**< pointer to store whether infeasibility is found */
    743 int* nreductions, /**< pointer to store number of reductions */
    744 SCIP_Bool peekmode, /**< whether function is called in peek mode */
    745 int varidx1, /**< index of var1 (or NULL) */
    746 int varidx2, /**< index of var2 (or NULL) */
    747 SCIP_Real* peeklbs, /**< lower bounds of variables in peek mode (or NULL) */
    748 SCIP_Real* peekubs, /**< upper bounds of variables in peek mode (or NULL) */
    749 SCIP_Bool* peekbdset /**< whether peek bounds have been set (or NULL) */
    750 )
    751{
    752 SCIP_Real ub1;
    753 SCIP_Real ub2;
    754 SCIP_Real lb1;
    755 SCIP_Real lb2;
    756
    757 SCIP_Bool tighten = FALSE;
    758 SCIP_Real newbd;
    759
    760 assert( (!peekmode) || peeklbs != NULL );
    761 assert( (!peekmode) || peekubs != NULL );
    762 assert( (!peekmode) || peekbdset != NULL );
    763
    764 SCIP_CALL( getVarBounds(var1, var2, peekmode, varidx1, varidx2, peeklbs, peekubs, peekbdset,
    765 &lb1, &ub1, &lb2, &ub2) );
    766
    767 /* tighten domain of var1 to ensure that var1 - center1 >= isnegated * (var2 - center2 ) */
    768 if ( isnegated )
    769 {
    770 if ( SCIPisLT(scip, lb1 - center1, center2 - ub2) )
    771 {
    772 tighten = TRUE;
    773 newbd = center1 + center2 - ub2;
    774 }
    775 }
    776 else
    777 {
    778 if ( SCIPisLT(scip, lb1 - center1, lb2 - center2) )
    779 {
    780 tighten = TRUE;
    781 newbd = center1 + lb2 - center2;
    782 }
    783 }
    784
    785 if ( tighten )
    786 {
    787 /* in peek mode, only store updated bounds */
    788 if ( peekmode )
    789 {
    790 peeklbs[varidx1] = newbd; /*lint !e644*/
    791 peekubs[varidx1] = ub1;
    792 peekbdset[varidx1] = TRUE;
    793 }
    794 else
    795 {
    796 SCIP_CALL( SCIPtightenVarLb(scip, var1, newbd, TRUE, infeasible, &tighten) );
    797 if ( tighten )
    798 {
    799 SCIPdebugMessage("Restricting variable LB %12s to %5.2f\n", SCIPvarGetName(var1), newbd);
    800 *nreductions += 1;
    801 }
    802 else
    803 {
    804 SCIPdebugMessage("Restricting variable LB %12s to %5.2f (no success)\n",
    805 SCIPvarGetName(var1), newbd);
    806 }
    807 if ( *infeasible )
    808 {
    809 SCIPdebugMessage("Detected infeasibility restricting variable LB %12s to %5.2f\n",
    810 SCIPvarGetName(var1), newbd);
    811 return SCIP_OKAY;
    812 }
    813 }
    814 }
    815
    816 return SCIP_OKAY;
    817}
    818
    819
    820/** propagates upper bound of second variable in relation x >= y for shifted variables */
    821static
    823 SCIP* scip, /**< SCIP data structure */
    824 SCIP_VAR* var1, /**< first variable in pair */
    825 SCIP_VAR* var2, /**< second variable in pair */
    826 SCIP_Real center1, /**< center of var1 (original var domain) */
    827 SCIP_Real center2, /**< center of var2 (original var domain) */
    828 SCIP_Bool isnegated, /**< whether var2 is negated by symmetry */
    829 SCIP_Bool* infeasible, /**< pointer to store whether infeasibility is found */
    830 int* nreductions, /**< pointer to store number of reductions */
    831 SCIP_Bool peekmode, /**< whether function is called in peek mode */
    832 int varidx1, /**< index of var1 (or NULL) */
    833 int varidx2, /**< index of var2 (or NULL) */
    834 SCIP_Real* peeklbs, /**< lower bounds of variables in peek mode (or NULL) */
    835 SCIP_Real* peekubs, /**< upper bounds of variables in peek mode (or NULL) */
    836 SCIP_Bool* peekbdset /**< whether peek bounds have been set (or NULL) */
    837 )
    838{
    839 SCIP_Real ub1;
    840 SCIP_Real ub2;
    841 SCIP_Real lb1;
    842 SCIP_Real lb2;
    843
    844 SCIP_Bool tighten = FALSE;
    845 SCIP_Real newbd;
    846
    847 assert( scip != NULL );
    848 assert( var1 != NULL );
    849 assert( var2 != NULL );
    850 assert( infeasible != NULL );
    851 assert( nreductions != NULL );
    852 assert( (!peekmode) || peeklbs != NULL );
    853 assert( (!peekmode) || peekubs != NULL );
    854 assert( (!peekmode) || peekbdset != NULL );
    855
    856 SCIP_CALL( getVarBounds(var1, var2, peekmode, varidx1, varidx2, peeklbs, peekubs, peekbdset,
    857 &lb1, &ub1, &lb2, &ub2) );
    858
    859 /* tighten domain of var2 to ensure that var1 - center1 >= isnegated * (var2 - center2 ) */
    860 if ( isnegated )
    861 {
    862 if ( SCIPisLT(scip, ub1 - center1, center2 - lb2) )
    863 {
    864 tighten = TRUE;
    865 newbd = center1 + center2 - ub1;
    866 }
    867 }
    868 else
    869 {
    870 if ( SCIPisLT(scip, ub1 - center1, ub2 - center2) )
    871 {
    872 tighten = TRUE;
    873 newbd = center2 - center1 + ub1;
    874 }
    875 }
    876
    877 if ( tighten )
    878 {
    879 /* in peek mode, only store updated bounds */
    880 if ( peekmode )
    881 {
    882 if ( isnegated )
    883 {
    884 peeklbs[varidx2] = newbd; /*lint !e644*/
    885 peekubs[varidx2] = ub2;
    886 peekbdset[varidx2] = TRUE;
    887 }
    888 else
    889 {
    890 peeklbs[varidx2] = lb2;
    891 peekubs[varidx2] = newbd;
    892 peekbdset[varidx2] = TRUE;
    893 }
    894 }
    895 else
    896 {
    897 if ( isnegated )
    898 {
    899 SCIP_CALL( SCIPtightenVarLb(scip, var2, newbd, TRUE, infeasible, &tighten) );
    900 }
    901 else
    902 {
    903 SCIP_CALL( SCIPtightenVarUb(scip, var2, newbd, TRUE, infeasible, &tighten) );
    904 }
    905
    906 if ( tighten )
    907 {
    908 SCIPdebugMessage("Restricting variable %sB %12s to %5.2f\n",
    909 isnegated ? "L" : "U", SCIPvarGetName(var2), newbd);
    910 *nreductions += 1;
    911 }
    912 else
    913 {
    914 SCIPdebugMessage("Restricting variable %sB %12s to %5.2f (no success)\n",
    915 isnegated ? "L" : "U", SCIPvarGetName(var2), newbd);
    916 }
    917 if ( *infeasible )
    918 {
    919 SCIPdebugMessage("Detected infeasibility restricting variable %sB %12s to %5.2f\n",
    920 isnegated ? "L" : "U", SCIPvarGetName(var2), newbd);
    921 return SCIP_OKAY;
    922 }
    923 }
    924 }
    925
    926 return SCIP_OKAY;
    927}
    928
    929
    930/** propagates x - c >= c - x */
    931static
    933 SCIP* scip, /**< SCIP data structure */
    934 SCIP_VAR* var, /**< variable */
    935 SCIP_Real center, /**< center of var (original var domain) */
    936 SCIP_Bool* infeasible, /**< pointer to store whether infeasibility is found */
    937 int* nreductions, /**< pointer to store number of reductions */
    938 SCIP_Bool peekmode, /**< whether function is called in peek mode */
    939 int varidx, /**< index of var (or NULL) */
    940 SCIP_Real* peeklbs, /**< lower bounds of variables in peek mode (or NULL) */
    941 SCIP_Real* peekubs, /**< upper bounds of variables in peek mode (or NULL) */
    942 SCIP_Bool* peekbdset /**< whether peek bounds have been set (or NULL) */
    943 )
    944{
    945 SCIP_Real ub1;
    946 SCIP_Real ub2;
    947 SCIP_Real lb1;
    948 SCIP_Real lb2;
    949 SCIP_Bool tighten = FALSE;
    950
    951 assert( scip != NULL );
    952 assert( var != NULL );
    953 assert( infeasible != NULL );
    954 assert( nreductions != NULL );
    955 assert( (!peekmode) || peeklbs != NULL );
    956 assert( (!peekmode) || peekubs != NULL );
    957 assert( (!peekmode) || peekbdset != NULL );
    958
    959 SCIP_CALL( getVarBounds(var, var, peekmode, varidx, varidx, peeklbs, peekubs, peekbdset,
    960 &lb1, &ub1, &lb2, &ub2) );
    961
    962 if ( SCIPisLT(scip, ub1, center) )
    963 {
    964 *infeasible = TRUE;
    965 return SCIP_OKAY;
    966 }
    967 else if ( SCIPisLT(scip, lb1, center) )
    968 {
    969 if ( peekmode )
    970 {
    971 peeklbs[varidx] = center;
    972 peekubs[varidx] = ub1;
    973 peekbdset[varidx] = TRUE;
    974 }
    975 else
    976 {
    977 SCIP_CALL( SCIPtightenVarLb(scip, var, center, TRUE, infeasible, &tighten) );
    978 if ( tighten )
    979 {
    980 SCIPdebugMessage("Restricting variable LB %12s to %5.2f\n", SCIPvarGetName(var), center);
    981 *nreductions += 1;
    982 }
    983 else
    984 {
    985 SCIPdebugMessage("Restricting variable LB %12s to %5.2f (no success)\n",
    986 SCIPvarGetName(var), center);
    987 }
    988 if ( *infeasible )
    989 {
    990 SCIPdebugMessage("Detected infeasibility restricting variable LB %12s to %5.2f\n",
    991 SCIPvarGetName(var), center);
    992 return SCIP_OKAY;
    993 }
    994 }
    995 }
    996
    997 return SCIP_OKAY;
    998}
    999
    1000
    1001/** propagates lexicographic order for one pair of symmetric variables */
    1002static
    1004 SCIP* scip, /**< SCIP data structure */
    1005 SCIP_VAR* var1, /**< first variable in pair */
    1006 SCIP_VAR* var2, /**< second variable in pair */
    1007 SCIP_Real center1, /**< center of var1 (original var domain) */
    1008 SCIP_Real center2, /**< center of var2 (original var domain) */
    1009 SCIP_Bool isnegated, /**< whether var2 is negated by symmetry */
    1010 SCIP_Bool* infeasible, /**< pointer to store whether infeasibility is found */
    1011 int* nreductions, /**< pointer to store number of reductions */
    1012 SCIP_Bool peekmode, /**< whether function is called in peek mode */
    1013 int varidx1, /**< index of var1 (or NULL) */
    1014 int varidx2, /**< index of var2 (or NULL) */
    1015 SCIP_Real* peeklbs, /**< lower bounds of variables in peek mode (or NULL) */
    1016 SCIP_Real* peekubs, /**< upper bounds of variables in peek mode (or NULL) */
    1017 SCIP_Bool* peekbdset /**< whether peek bounds have been set (or NULL) */
    1018 )
    1019{
    1020 assert( scip != NULL );
    1021 assert( var1 != NULL );
    1022 assert( var2 != NULL );
    1023 assert( infeasible != NULL );
    1024 assert( nreductions != NULL );
    1025
    1026 /* perform lexicographic comparison: var1 - center1 >= +/- (var2 - center2) */
    1027 if ( alwaysLTshiftedVars(scip, var1, var2, center1, center2, isnegated, peekmode,
    1028 varidx1, varidx2, peeklbs, peekubs, peekbdset) )
    1029 {
    1030#ifdef SCIP_DEBUG
    1031 SCIP_Real ub1;
    1032 SCIP_Real ub2;
    1033 SCIP_Real lb1;
    1034 SCIP_Real lb2;
    1035
    1036 /* get bounds of shifted (and possibly negated) variables */
    1037 ub1 = SCIPvarGetUbLocal(var1);
    1038 lb1 = SCIPvarGetLbLocal(var1);
    1039 ub2 = SCIPvarGetUbLocal(var2);
    1040 lb2 = SCIPvarGetLbLocal(var2);
    1041
    1042 SCIPdebugMessage("Detected infeasibility: x < y for "
    1043 "x: lb=%5.2f, ub=%5.2f, shift=%5.2f "
    1044 "y: lb=%5.2f, ub=%5.2f, shift=%5.2f negated=%u\n",
    1045 lb1, ub1, center1, lb2, ub2, center2, isnegated);
    1046#endif
    1047
    1048 *infeasible = TRUE;
    1049 return SCIP_OKAY;
    1050 }
    1051
    1052 /* for signed permutations, a variable might be mapped to itself */
    1053 if ( var1 == var2 )
    1054 {
    1055 SCIP_CALL( propagateSelfReflectionVar(scip, var1, center1, infeasible, nreductions, peekmode, varidx1,
    1056 peeklbs, peekubs, peekbdset) );
    1057 }
    1058 else
    1059 {
    1060 SCIP_CALL( propagateLowerBoundVar(scip, var1, var2, center1, center2, isnegated, infeasible, nreductions, peekmode,
    1061 varidx1, varidx2, peeklbs, peekubs, peekbdset) );
    1062 if ( *infeasible )
    1063 return SCIP_OKAY;
    1064
    1065 SCIP_CALL( propagateUpperBoundSymVar(scip, var1, var2, center1, center2, isnegated, infeasible, nreductions, peekmode,
    1066 varidx1, varidx2, peeklbs, peekubs, peekbdset) );
    1067 }
    1068
    1069 return SCIP_OKAY;
    1070}
    1071
    1072/** checks if the static lexred with a certain variable ordering is feasible in the hypothetical scenario where
    1073 * variables with indices i and j are fixed to fixvalue (i.e., peeking)
    1074 */
    1075static
    1077 SCIP* scip, /**< SCIP data structure */
    1078 LEXDATA* lexdata, /**< pointer to data for this permutation */
    1079 int* varorder, /**< array populated with variable order (or NULL for static propagation) */
    1080 int nselvars, /**< number of variables in the ordering */
    1081 int fixi, /**< variable index of left fixed column */
    1082 int fixj, /**< variable index of right fixed column */
    1083 int fixrow, /**< row index in var ordering, from which to start peeking */
    1084 SCIP_Real fixvaluei, /**< value on which variables i is fixed */
    1085 SCIP_Real fixvaluej, /**< value on which variables j is fixed */
    1086 SCIP_Bool* peekfeasible, /**< pointer to store whether this is feasible or not */
    1087 SCIP_Real* peeklbs, /**< lower bounds of variables in peek mode (or NULL) */
    1088 SCIP_Real* peekubs, /**< upper bounds of variables in peek mode (or NULL) */
    1089 SCIP_Bool* peekbdset /**< whether peek bounds have been set (or NULL) */
    1090 )
    1091{
    1092 int row;
    1093 int i;
    1094 int j;
    1095 SCIP_VAR* vari;
    1096 SCIP_VAR* varj;
    1097 SCIP_Real centeri;
    1098 SCIP_Real centerj;
    1099 SCIP_Bool issigned;
    1100 SCIP_Bool isnegated;
    1101 SCIP_Bool infeasible = FALSE;
    1102 int nreductions;
    1103
    1104 assert( scip != NULL );
    1105 assert( lexdata != NULL );
    1106 assert( lexdata->vars != NULL );
    1107 assert( lexdata->nvars >= 0 );
    1108 assert( nselvars <= lexdata->nvars );
    1109 assert( nselvars > 0 );
    1110 assert( fixi >= 0 );
    1111 assert( fixi < lexdata->nvars );
    1112 assert( fixj < lexdata->nvars );
    1113 assert( fixi != fixj || lexdata->symtype == SYM_SYMTYPE_SIGNPERM );
    1114 assert( fixi != fixj || fixvaluei == fixvaluej ); /*lint !e777*/
    1115 assert( fixrow >= 0 );
    1116 assert( fixrow < nselvars );
    1117 assert( peekfeasible != NULL );
    1118 assert( fixi == varOrderGetIndex(varorder, fixrow) );
    1119 assert( fixj == (lexdata->invperm[varOrderGetIndex(varorder, fixrow)] % lexdata->nvars) );
    1120 assert( fixi == (lexdata->perm[fixj] % lexdata->nvars) );
    1121
    1122 *peekfeasible = TRUE;
    1123 issigned = lexdata->symtype == SYM_SYMTYPE_SIGNPERM ? TRUE : FALSE;
    1124 assert( (!issigned) || lexdata->vardomaincenter != NULL );
    1125
    1126 /* intialize peekbdset */
    1127 for (i = 0; i < lexdata->nvars; ++i)
    1128 peekbdset[i] = FALSE;
    1129
    1130 peeklbs[fixi] = fixvaluei;
    1131 peeklbs[fixj] = fixvaluej;
    1132 peekubs[fixi] = fixvaluei;
    1133 peekubs[fixj] = fixvaluej;
    1134 peekbdset[fixi] = TRUE;
    1135 peekbdset[fixj] = TRUE;
    1136
    1137 for (row = fixrow + 1; row < nselvars; ++row)
    1138 {
    1139 /* get left and right column indices */
    1140 i = varOrderGetIndex(varorder, row);
    1141 j = lexdata->invperm[i];
    1142 assert( i == lexdata->perm[j] );
    1143
    1144 /* no fixed points */
    1145 assert( i != j );
    1146
    1147 assert( 0 <= i && i < lexdata->nvars );
    1148 assert( 0 <= j && j < 2 * lexdata->nvars );
    1149 assert( issigned || j < lexdata->nvars );
    1150
    1151 vari = lexdata->vars[i];
    1152 if ( j >= lexdata->nvars )
    1153 {
    1154 assert( lexdata->symtype == SYM_SYMTYPE_SIGNPERM );
    1155 j = j - lexdata->nvars;
    1156 varj = lexdata->vars[j];
    1157 isnegated = TRUE;
    1158 }
    1159 else
    1160 {
    1161 varj = lexdata->vars[j];
    1162 isnegated = FALSE;
    1163 }
    1164
    1165 if ( issigned )
    1166 {
    1167 assert( lexdata->vardomaincenter != NULL );
    1168 centeri = lexdata->vardomaincenter[i];
    1169 centerj = lexdata->vardomaincenter[j];
    1170 }
    1171 else
    1172 {
    1173 centeri = 0.0;
    1174 centerj = 0.0;
    1175 }
    1176
    1177 /* propagate that vari >= varj */
    1178
    1179 /* vari >= varj can never hold if the maximal value of vari is smaller than the minimal value of varj */
    1180 if ( alwaysLTshiftedVars(scip, vari, varj, centeri, centerj, isnegated, TRUE, i, j, peeklbs, peekubs, peekbdset) )
    1181 {
    1182 *peekfeasible = FALSE;
    1183 SCIPdebugMessage("PEEK: Detected infeasibility at row %3d.\n", row);
    1184 break;
    1185 }
    1186
    1187 SCIP_CALL( propagateLowerBoundVar(scip, vari, varj, centeri, centerj, isnegated, &infeasible, &nreductions, TRUE,
    1188 i, j, peeklbs, peekubs, peekbdset) );
    1189
    1190 SCIP_CALL( propagateUpperBoundSymVar(scip, vari, varj, centeri, centerj, isnegated, &infeasible, &nreductions, TRUE,
    1191 i, j, peeklbs, peekubs, peekbdset) );
    1192
    1193 /* if there exists a solution with vari > varj, reductions are feasible w.r.t. lexred */
    1194 if ( canGTshiftedVars(scip, vari, varj, centeri, centerj, isnegated, TRUE,
    1195 i, j, peeklbs, peekubs, peekbdset) )
    1196 break;
    1197 }
    1198
    1199 return SCIP_OKAY;
    1200}
    1201
    1202/** propagates static lexicographic reduction with specified variable ordering */
    1203static
    1205 SCIP* scip, /**< SCIP data structure */
    1206 LEXDATA* lexdata, /**< pointer to data for this permutation */
    1207 int* varorder, /**< array populated with variable order (or NULL if static propagation) */
    1208 int nselvars, /**< number of variables in the ordering */
    1209 SCIP_Bool* infeasible, /**< pointer to store whether the problem is infeasible */
    1210 int* nreductions /**< pointer to store the number of found domain reductions */
    1211 )
    1212{ /*lint --e{771}*/
    1213 int row;
    1214 int i = -1;
    1215 int j = -1;
    1216 SCIP_VAR* vari = NULL;
    1217 SCIP_VAR* varj = NULL;
    1218 SCIP_Real centeri;
    1219 SCIP_Real centerj;
    1220 SCIP_Bool success;
    1221 SCIP_Bool issigned;
    1222 SCIP_Bool isnegated;
    1223
    1224 assert( scip != NULL );
    1225 assert( lexdata != NULL );
    1226 assert( nselvars >= 0 );
    1227 assert( infeasible != NULL );
    1228 assert( !*infeasible );
    1229 assert( nreductions != NULL );
    1230 assert( *nreductions >= 0 );
    1231
    1232 /* avoid trivial cases */
    1233 if ( nselvars <= 0 )
    1234 return SCIP_OKAY;
    1235
    1236 issigned = lexdata->symtype == SYM_SYMTYPE_SIGNPERM ? TRUE : FALSE;
    1237 assert( (!issigned) || lexdata->vardomaincenter != NULL );
    1238
    1239 /* iterate over the variable array entrywise
    1240 *
    1241 * We see this as two columns, with the left vector being the variable ordering,
    1242 * and the right column the permuted variables of this var ordering.
    1243 */
    1244 for (row = 0; row < nselvars; ++row)
    1245 {
    1246 /* left and right column indices */
    1247 i = varOrderGetIndex(varorder, row);
    1248 j = lexdata->invperm[i];
    1249 assert( i == lexdata->perm[j] );
    1250
    1251 /* no fixed points */
    1252 assert( i != j );
    1253
    1254 assert( 0 <= i && i < lexdata->nvars );
    1255 assert( 0 <= j && j < 2 * lexdata->nvars );
    1256 assert( issigned || j < lexdata->nvars );
    1257
    1258 vari = lexdata->vars[i];
    1259 if ( j >= lexdata->nvars )
    1260 {
    1261 assert( issigned );
    1262 j = j - lexdata->nvars;
    1263 varj = lexdata->vars[j];
    1264 isnegated = TRUE;
    1265 }
    1266 else
    1267 {
    1268 varj = lexdata->vars[j];
    1269 isnegated = FALSE;
    1270 }
    1271
    1272 if ( issigned )
    1273 {
    1274 assert( lexdata->vardomaincenter != NULL );
    1275 centeri = lexdata->vardomaincenter[i];
    1276 centerj = lexdata->vardomaincenter[j];
    1277 }
    1278 else
    1279 {
    1280 centeri = 0.0;
    1281 centerj = 0.0;
    1282 }
    1283
    1284 SCIP_CALL( propagateVariablePair(scip, vari, varj, centeri, centerj, isnegated, infeasible, nreductions, FALSE,
    1285 0, 0, NULL, NULL, NULL) );
    1286
    1287 if ( *infeasible )
    1288 return SCIP_OKAY;
    1289
    1290 /* terminate if there exists a solution being lexicographically strictly larger than its image */
    1291 if ( canGTshiftedVars(scip, vari, varj, centeri, centerj, isnegated, FALSE,
    1292 0, 0, NULL, NULL, NULL) )
    1293 break;
    1294 }
    1295 assert( vari != NULL );
    1296 assert( varj != NULL );
    1297 assert( 0 <= i && i < lexdata->nvars );
    1298 assert( 0 <= j && j < lexdata->nvars );
    1299
    1300 /* if the variables in "row" are fixed to the same value, we might find further propagations */
    1301 if ( row < nselvars )
    1302 {
    1303 SCIP_Real* peeklbs;
    1304 SCIP_Real* peekubs;
    1305 SCIP_Bool* peekbdset;
    1306 SCIP_Real ub1;
    1307 SCIP_Real ub2;
    1308 SCIP_Real lb1;
    1309 SCIP_Real lb2;
    1310 SCIP_Real lbi;
    1311 SCIP_Real ubi;
    1312 SCIP_Real lbj;
    1313 SCIP_Real ubj;
    1314 SCIP_Bool peekfeasible;
    1315
    1316 SCIP_CALL( getVarBounds(vari, varj, FALSE, 0, 0, NULL, NULL, NULL, &lb1, &ub1, &lb2, &ub2) );
    1317
    1318 /* special treatment if i-th and j-th variable are the same in a signed permutation */
    1319 if ( vari == varj )
    1320 {
    1321 assert( lexdata->symtype == SYM_SYMTYPE_SIGNPERM );
    1322 assert( SCIPsymGE(scip, lb1, lexdata->vardomaincenter[i]) ); /* propagation enforces xi - center >= center - xi */
    1323
    1324 /* both variables can only be the same if they are fixed to the domain center */
    1325 if ( SCIPsymGT(scip, lb1, lexdata->vardomaincenter[i]) )
    1326 return SCIP_OKAY;
    1327
    1328 SCIP_CALL( SCIPallocBufferArray(scip, &peeklbs, lexdata->nvars) );
    1329 SCIP_CALL( SCIPallocBufferArray(scip, &peekubs, lexdata->nvars) );
    1330 SCIP_CALL( SCIPallocBufferArray(scip, &peekbdset, lexdata->nvars) );
    1331
    1332 SCIP_CALL( peekStaticLexredIsFeasible(scip, lexdata, varorder, nselvars, i, j,
    1333 row, lexdata->vardomaincenter[i], lexdata->vardomaincenter[i],
    1334 &peekfeasible, peeklbs, peekubs, peekbdset) );
    1335 if ( !peekfeasible )
    1336 {
    1337 /* both variables cannot be the same, so the non-negated variable must be greater than the domain center */
    1338 if( SCIPvarIsIntegral(vari) )
    1339 {
    1340 assert( SCIPisIntegral(scip, lb1) );
    1341 SCIP_CALL( SCIPtightenVarLb(scip, vari, lexdata->vardomaincenter[i] + 1.0, TRUE, infeasible, &success) );
    1342 if ( success )
    1343 *nreductions += 1;
    1344 if ( *infeasible )
    1345 goto FREEMEMORY;
    1346 lb1 = lexdata->vardomaincenter[i] + 1.0;
    1347 assert( SCIPsymLE(scip, lb1, ub1) );
    1348 }
    1349 else
    1350 {
    1351 /* continuous variable type: act as if we increase the variable by a very little bit.
    1352 * This is only possible if we're able to increase the variable bound by a bit.
    1353 */
    1354 if ( SCIPsymEQ(scip, lb1, ub1) )
    1355 {
    1356 *infeasible = TRUE;
    1357 goto FREEMEMORY;
    1358 }
    1359 }
    1360 }
    1361 }
    1362 else
    1363 {
    1364 /* The previous loop is broken at row "row", which allows for choosing vari > varj.
    1365 *
    1366 * Now check if vari == varj is permitted, and if not, tighten the domain further.
    1367 *
    1368 * @todo We peek twice if vari and varj are unfixed
    1369 * But, if the subcycle only contains var1 and var2, a single peek suffices.
    1370 * This is similar to orbisack and symresack propagation.
    1371 *
    1372 * Case 1: vari is minimal (lbi).
    1373 * Then, propagation of lbi = vari >= varj can yield two situations:
    1374 * Option 1: varj can take a value < lbi. Then no further reductions can be detected.
    1375 * Option 2: varj gets fixed to lbi. Then, we must check if feasibility is found, still.
    1376 * If it turns out infeasible, then we know vari cannot take value lbi, so we can increase the lower bound.
    1377 */
    1378 centeri = 0.0;
    1379 centerj = 0.0;
    1380
    1381 if ( lexdata->vardomaincenter != NULL )
    1382 {
    1383 centeri = lexdata->vardomaincenter[i];
    1384 centerj = lexdata->vardomaincenter[j];
    1385 }
    1386
    1387 /* translate variable bounds to shifted variable domain and take negation into account */
    1388 lbi = lb1 - centeri;
    1389 ubi = ub1 - centeri;
    1390 if ( isnegated )
    1391 {
    1392 lbj = centerj - ub2;
    1393 ubj = centerj - lb2;
    1394 }
    1395 else
    1396 {
    1397 lbj = lb2 - centerj;
    1398 ubj = ub2 - centerj;
    1399 }
    1400
    1401 /* check whether peek is called */
    1402 if ( (!SCIPsymEQ(scip, lbi, lbj)) && (!SCIPsymEQ(scip, ubi, ubj)) )
    1403 return SCIP_OKAY;
    1404
    1405 SCIP_CALL( SCIPallocBufferArray(scip, &peeklbs, lexdata->nvars) );
    1406 SCIP_CALL( SCIPallocBufferArray(scip, &peekubs, lexdata->nvars) );
    1407 SCIP_CALL( SCIPallocBufferArray(scip, &peekbdset, lexdata->nvars) );
    1408
    1409 if ( SCIPsymEQ(scip, lbj, lbi) )
    1410 {
    1411 SCIP_Real fixvalj;
    1412
    1413 /* translate lbj back to original variable domain of variable j */
    1414 if ( isnegated )
    1415 fixvalj = centerj - lbj;
    1416 else
    1417 fixvalj = lbj + centerj;
    1418
    1419 /* this is Option 2: varj gets fixed to lbi by propagation. */
    1420 SCIP_CALL( peekStaticLexredIsFeasible(scip, lexdata, varorder, nselvars, i, j,
    1421 row, lbi + centeri, fixvalj, &peekfeasible, peeklbs, peekubs, peekbdset) );
    1422 if ( !peekfeasible )
    1423 {
    1424 /* vari cannot take value lb1, so we increase the lower bound (do not use lbi as this is a shifted domain bound) */
    1425 if( SCIPvarIsIntegral(vari) )
    1426 {
    1427 /* discrete variable type: increase lower bound by 1. */
    1428 assert( SCIPisIntegral(scip, lb1) );
    1429 SCIP_CALL( SCIPtightenVarLb(scip, vari, lb1 + 1.0, TRUE, infeasible, &success) );
    1430 if ( success )
    1431 *nreductions += 1;
    1432 if ( *infeasible )
    1433 goto FREEMEMORY;
    1434 lb1 = lb1 + 1.0;
    1435 assert( SCIPsymLE(scip, lb1, ub1) );
    1436 }
    1437 else
    1438 {
    1439 /* continuous variable type: act as if we increase the variable by a very little bit.
    1440 * That is only possible if we're able to increase the variable bound by a bit.
    1441 */
    1442 if ( SCIPsymEQ(scip, lbi, ubi) )
    1443 {
    1444 *infeasible = TRUE;
    1445 goto FREEMEMORY;
    1446 }
    1447 }
    1448 }
    1449 }
    1450
    1451 /* Case 2: varj is maximal (ubj).
    1452 * Then, propagation of vari >= varj = ubj can yield two situatiosn:
    1453 * Option 1: vari can take a value > ubj. Then, no further reductions can be detected.
    1454 * Option 2: vari gets fixed to ubj. Then, we must check if feasibility is found, still.
    1455 * If it turns out infeasible, then we know varj cannot take value ubj, so we can decrease the upper bound.
    1456 */
    1457 assert( SCIPsymGE(scip, ubi, ubj) ); /* this must be the case after reductions in the for-loop */
    1458 if ( SCIPsymEQ(scip, ubi, ubj) )
    1459 {
    1460 SCIP_Real fixvalj;
    1461
    1462 /* translate ubj back to original variable domain of variable j */
    1463 if ( isnegated )
    1464 fixvalj = centerj - ubj;
    1465 else
    1466 fixvalj = ubj + centerj;
    1467
    1468 /* this is Option 2: vari gets fixed to ubj by propagation. */
    1469 SCIP_CALL( peekStaticLexredIsFeasible(scip, lexdata, varorder, nselvars, i, j,
    1470 row, ubi + centeri, fixvalj, &peekfeasible, peeklbs, peekubs, peekbdset) );
    1471 if ( !peekfeasible )
    1472 {
    1473 /* varj cannot take value ub2, so we decrease the upper or lower bound (do not use ubj as this is a shifted domain bound) */
    1474 if( SCIPvarIsIntegral(varj) )
    1475 {
    1476 /* discrete variable type: decrease upper bound by 1. */
    1477 if ( isnegated )
    1478 {
    1479 assert( SCIPisIntegral(scip, lb2) );
    1480 SCIP_CALL( SCIPtightenVarUb(scip, varj, lb2 + 1.0, TRUE, infeasible, &success) );
    1481 }
    1482 else
    1483 {
    1484 assert( SCIPisIntegral(scip, ub2) );
    1485 SCIP_CALL( SCIPtightenVarUb(scip, varj, ub2 - 1.0, TRUE, infeasible, &success) );
    1486 }
    1487 if ( success )
    1488 *nreductions += 1;
    1489 if ( *infeasible )
    1490 goto FREEMEMORY;
    1491 ubj = ubj - 1.0;
    1492 assert( SCIPsymLE(scip, lbj, ubj) );
    1493 }
    1494 else
    1495 {
    1496 /* continuous variable type: act as if we decrease the variable by a very little bit.
    1497 * that is only possible if we're able to decrease the variable bound by a bit. */
    1498 if ( SCIPsymEQ(scip, lbj, ubj) )
    1499 {
    1500 *infeasible = TRUE;
    1501 goto FREEMEMORY;
    1502 }
    1503 }
    1504 }
    1505 }
    1506 }
    1507 FREEMEMORY:
    1508 SCIPfreeBufferArray(scip, &peekbdset);
    1509 SCIPfreeBufferArray(scip, &peekubs);
    1510 SCIPfreeBufferArray(scip, &peeklbs);
    1511 }
    1512
    1513 return SCIP_OKAY;
    1514}
    1515
    1516
    1517/** propagation method for a dynamic lexicographic reduction */
    1518static
    1520 SCIP* scip, /**< SCIP data structure */
    1521 SCIP_LEXREDDATA* masterdata, /**< pointer to global data for lexicographic reduction propagator */
    1522 LEXDATA* lexdata, /**< pointer to data for this permutation */
    1523 NODEDEPTHBRANCHINDEX* nodedepthbranchindices, /**< array with (depth, index)-information per variable in rooted path to focus node */
    1524 int nvarstotal, /**< length of nodedepthbranchindices array */
    1525 SCIP_VAR** branchvars, /**< array populated with variables branched on */
    1526 int nbranchvars, /**< number of elements in branchvars array */
    1527 SCIP_Bool* infeasible, /**< pointer to store whether the problem is infeasible */
    1528 int* nreductions /**< pointer to store the number of found domain reductions */
    1529 )
    1530{
    1531 int* varorder;
    1532 int nvarorder;
    1533 int nvars;
    1534
    1535 assert( scip != NULL );
    1536 assert( masterdata != NULL );
    1537 assert( lexdata != NULL );
    1538 assert( lexdata->isdynamic );
    1539 assert( nodedepthbranchindices != NULL );
    1540 assert( nvarstotal >= 0 );
    1541 assert( branchvars != NULL );
    1542 assert( nbranchvars >= 0 );
    1543 assert( infeasible != NULL );
    1544 assert( nreductions != NULL );
    1545
    1546 nvars = lexdata->nvars;
    1547
    1548 /* get variable order */
    1549 SCIP_CALL( SCIPallocBufferArray(scip, &varorder, nvars) );
    1550
    1551 SCIP_CALL( getVarOrder(scip, masterdata, lexdata, nodedepthbranchindices, nvarstotal, branchvars, nbranchvars,
    1552 varorder, &nvarorder, nvars) );
    1553 assert( nvarorder >= 0 );
    1554 assert( nvarorder <= nvars );
    1555
    1556 /* possibly propagate the constraint with this variable order */
    1557 if ( nvarorder > 0 )
    1558 {
    1559 SCIP_CALL( propagateStaticLexred(scip, lexdata, varorder, nvarorder, infeasible, nreductions) );
    1560 }
    1561 SCIPfreeBufferArray(scip, &varorder);
    1562
    1563 return SCIP_OKAY;
    1564}
    1565
    1566
    1567/** propagation method for a dynamic lexicographic reduction */
    1568static
    1570 SCIP* scip, /**< SCIP data structure */
    1571 SCIP_LEXREDDATA* masterdata, /**< pointer to global data for lexicographic reduction propagator */
    1572 LEXDATA* lexdata, /**< pointer to data for this permutation */
    1573 SCIP_Bool* infeasible, /**< pointer to store whether the problem is infeasible */
    1574 int* nreductions /**< pointer to store the number of found domain reductions */
    1575 )
    1576{
    1577 assert( scip != NULL );
    1578 assert( masterdata != NULL );
    1579 assert( lexdata != NULL );
    1580 assert( ! lexdata->isdynamic );
    1581 assert( infeasible != NULL );
    1582 assert( nreductions != NULL );
    1583
    1584 /* skip trivial cases */
    1585 if ( lexdata->nvars == 0 )
    1586 return SCIP_OKAY;
    1587
    1588 /* propagate the constraint with this variable order */
    1589 SCIP_CALL( propagateStaticLexred(scip, lexdata, NULL, lexdata->nvars, infeasible, nreductions) );
    1590
    1591 return SCIP_OKAY;
    1592}
    1593
    1594
    1595/** propagation method for applying dynamic lexicographic reduction for a single permutation */
    1596static
    1598 SCIP* scip, /**< SCIP data structure */
    1599 SCIP_LEXREDDATA* masterdata, /**< pointer to global data for lexicographic reduction propagator */
    1600 LEXDATA* lexdata, /**< pointer to data for this permutation */
    1601 NODEDEPTHBRANCHINDEX* nodedepthbranchindices, /**< array with (depth, index)-information per variable in rooted path to focus node */
    1602 int nvarstotal, /**< length of that array */
    1603 SCIP_VAR** branchvars, /**< array populated with variables branched on */
    1604 int nbranchvars, /**< number of elements in branchvars array */
    1605 SCIP_Bool* infeasible, /**< pointer to store whether the problem is infeasible */
    1606 int* nreductions /**< pointer to store the number of found domain reductions */
    1607 )
    1608{
    1609 assert( scip != NULL );
    1610 assert( masterdata != NULL );
    1611 assert( lexdata != NULL );
    1612 assert( nodedepthbranchindices != NULL || ! lexdata->isdynamic );
    1613 assert( nvarstotal >= 0 || ! lexdata->isdynamic );
    1614 assert( branchvars != NULL || ! lexdata->isdynamic );
    1615 assert( nbranchvars >= 0 || ! lexdata->isdynamic );
    1616 assert( infeasible != NULL );
    1617 assert( nreductions != NULL );
    1618
    1619 *nreductions = 0;
    1620 *infeasible = FALSE;
    1621
    1622 if ( lexdata->isdynamic )
    1623 {
    1625 nodedepthbranchindices, nvarstotal, branchvars, nbranchvars, infeasible, nreductions) );
    1626 }
    1627 else
    1628 {
    1629 SCIP_CALL( propagateLexredStatic(scip, masterdata, lexdata, infeasible, nreductions) );
    1630 }
    1631
    1632 return SCIP_OKAY;
    1633}
    1634
    1635
    1636/** populates array with information of first variable change
    1637 * @pre assuming nodedepthbranchindices is initially clean
    1638 */
    1639static
    1641 SCIP* scip, /**< SCIP data structure */
    1642 SCIP_LEXREDDATA* masterdata, /**< pointer to global data for lexicographic reduction propagator */
    1643 NODEDEPTHBRANCHINDEX* nodedepthbranchindices, /**< array to populate */
    1644 SCIP_VAR** branchvars, /**< array to populate with variables branched on */
    1645 int* nbranchvars, /**< number of elements in branchvars array */
    1646 SCIP_SHADOWTREE* shadowtree, /**< pointer to shadow tree structure */
    1647 SCIP_NODE* focusnode, /**< focusnode to which the rooted path is evaluated */
    1648 SCIP_Bool* inforesolved /**< pointer to store whether information is successfully resolved */
    1649 )
    1650{
    1651 SCIP_SHADOWNODE* shadownode;
    1652 SCIP_SHADOWNODE* shadowchild;
    1653 int shadowdepth;
    1654 SCIP_VAR* var;
    1655 int varindex;
    1656 int nlevelvars;
    1657 int c;
    1658 int i;
    1659
    1660 assert( scip != NULL );
    1661 assert( masterdata != NULL );
    1662 assert( masterdata->symvarmap != NULL );
    1663 assert( masterdata->nsymvars >= 0 );
    1664 assert( nodedepthbranchindices != NULL );
    1665 assert( branchvars != NULL );
    1666 assert( nbranchvars != NULL );
    1667 assert( shadowtree != NULL );
    1668 assert( focusnode != NULL );
    1669 assert( inforesolved != NULL );
    1670
    1671 shadownode = SCIPshadowTreeGetShadowNode(shadowtree, focusnode);
    1672
    1673 if ( shadownode == NULL )
    1674 {
    1675 /* the arrays to fill are unchanged, so they remain clean */
    1676 *inforesolved = FALSE;
    1677 if ( !masterdata->treewarninggiven )
    1678 {
    1679 SCIPwarningMessage(scip, "Attempting lexicographic reduction on nodes not existing in the symmetry shadowtree"
    1680 " (and suppressing future warnings)\n");
    1681 masterdata->treewarninggiven = TRUE;
    1682 }
    1683 return SCIP_OKAY;
    1684 }
    1685 shadowdepth = SCIPnodeGetDepth(focusnode);
    1686
    1687 /* branchvars array is initially empty */
    1688 *nbranchvars = 0;
    1689
    1690 /* We start looking one level lower, because we consider the branching decisions each time. */
    1691 shadownode = shadownode->parent;
    1692
    1693 /* Now, walk from the leaf to the root. Each time look at all the children of the node considered,
    1694 * and save the variable depth and index in the branching array. It is important to consider all children each time,
    1695 * because we need to comply with the instance where in different branches it is branched on different variables.
    1696 * This has to be consistent.
    1697 */
    1698 while (shadownode != NULL)
    1699 {
    1700 assert( shadowdepth > 0 );
    1701 nlevelvars = 0;
    1702 for (c = 0; c < shadownode->nchildren; ++c)
    1703 {
    1704 shadowchild = shadownode->children[c];
    1705
    1706 /* get the variables branched on, for each of the children (that's likely 1 variable each time) */
    1707 for (i = 0; i < shadowchild->nbranchingdecisions; ++i)
    1708 {
    1709 var = shadowchild->branchingdecisions[i].var;
    1710 assert( SCIPvarIsTransformed(var) );
    1711
    1712 varindex = SCIPhashmapGetImageInt(masterdata->symvarmap, var);
    1713
    1714 /* ignore variables that are irrelevant for lexicographic reduction */
    1715 if ( varindex == INT_MAX )
    1716 continue;
    1717
    1718 assert( varindex >= 0 );
    1719 assert( varindex < masterdata->nsymvars );
    1720
    1721 /* var already in other child at this level? Continue */
    1722 if ( nodedepthbranchindices[varindex].nodedepth == shadowdepth )
    1723 continue;
    1724
    1725 /* the variable is either not seen (nodedepth == 0), or it is at a higher level (nodedepth > shadowdepth) */
    1726 assert( nodedepthbranchindices[varindex].nodedepth == 0 ||
    1727 nodedepthbranchindices[varindex].nodedepth > shadowdepth);
    1728
    1729 if ( nodedepthbranchindices[varindex].nodedepth == 0 )
    1730 {
    1731 /* variable is not featured in branchvars, yet */
    1732 assert( *nbranchvars < masterdata->nsymvars );
    1733 branchvars[(*nbranchvars)++] = var;
    1734 }
    1735
    1736 /* var is not seen on this level yet. Update */
    1737 nodedepthbranchindices[varindex].nodedepth = shadowdepth;
    1738 nodedepthbranchindices[varindex].index = nlevelvars++;
    1739 }
    1740 }
    1741
    1742 /* prepare for the next iteration */
    1743 shadownode = shadownode->parent;
    1744 --shadowdepth;
    1745 }
    1746 /* In the last iteration, we handled the branching decisions at the root node, so shadowdepth must have value 0. */
    1747 assert( shadowdepth == 0 );
    1748
    1749 *inforesolved = TRUE;
    1750 return SCIP_OKAY;
    1751}
    1752
    1753
    1754/** cleans nodedepthbranchindices array */
    1755static
    1757 SCIP* scip, /**< SCIP data structure */
    1758 SCIP_LEXREDDATA* masterdata, /**< pointer to global data for lexicographic reduction propagator */
    1759 NODEDEPTHBRANCHINDEX* nodedepthbranchindices, /**< array populated by nodedepthbranchindices to clean */
    1760 SCIP_VAR** branchvars, /**< array populated with variables branched on */
    1761 int* nbranchvars, /**< number of elements in branchvars array */
    1762 SCIP_SHADOWTREE* shadowtree, /**< pointer to shadow tree structure */
    1763 SCIP_NODE* focusnode /**< focusnode to which the rooted path is evaluated */
    1764 )
    1765{
    1766 /* undo the operations from shadowtreeFillNodeDepthBranchIndices, which makes nodedepthbranchindices clean */
    1767 SCIP_SHADOWNODE* shadownode;
    1768 SCIP_SHADOWNODE* shadowchild;
    1769#ifndef NDEBUG
    1770 int shadowdepth;
    1771#endif
    1772 SCIP_VAR* var;
    1773 int varindex;
    1774 int c;
    1775 int i;
    1776
    1777 assert( scip != NULL );
    1778 assert( masterdata != NULL );
    1779 assert( masterdata->symvarmap != NULL );
    1780 assert( masterdata->nsymvars >= 0 );
    1781 assert( nodedepthbranchindices != NULL );
    1782 assert( branchvars != NULL );
    1783 assert( nbranchvars != NULL );
    1784 assert( *nbranchvars >= 0 );
    1785 assert( *nbranchvars <= masterdata->nsymvars );
    1786 assert( shadowtree != NULL );
    1787 assert( focusnode != NULL );
    1788
    1789 shadownode = SCIPshadowTreeGetShadowNode(shadowtree, focusnode);
    1790#ifndef NDEBUG
    1791 shadowdepth = SCIPnodeGetDepth(focusnode);
    1792#endif
    1793
    1794 /* clean nbranchvars array */
    1795 while ( *nbranchvars > 0 )
    1796 branchvars[--(*nbranchvars)] = NULL;
    1797 assert( *nbranchvars == 0 );
    1798
    1799 /* we start looking one level lower, because we consider the branching decisions each time */
    1800 /* coverity[dereference] */
    1801 shadownode = shadownode->parent;
    1802
    1803 /* now, walk from the leaf to the root. Each time look at all the children of the node considered,
    1804 * and save the variable depth and index in the branching array. It is important to consider all children each time,
    1805 * because we need to comply with the instance where in different branches it is branched on different variables.
    1806 * This has to be consistent.
    1807 */
    1808 while (shadownode != NULL)
    1809 {
    1810#ifndef NDEBUG
    1811 assert( shadowdepth > 0 );
    1812#endif
    1813 for (c = 0; c < shadownode->nchildren; ++c)
    1814 {
    1815 shadowchild = shadownode->children[c];
    1816 /* get the variables branched on, for each of the children (that's likely 1 variable each time) */
    1817 for (i = 0; i < shadowchild->nbranchingdecisions; ++i)
    1818 {
    1819 var = shadowchild->branchingdecisions[i].var;
    1820 /* ignore variables not relevant for lexicographic reduction */
    1821 if ( !SCIPhashmapExists(masterdata->symvarmap, (void*) var) )
    1822 continue;
    1823 assert( SCIPhashmapExists(masterdata->symvarmap, (void*) var) );
    1824
    1825 varindex = SCIPhashmapGetImageInt(masterdata->symvarmap, var);
    1826 assert( varindex >= 0 );
    1827 assert( varindex < masterdata->nsymvars );
    1828
    1829 /* reset */
    1830 nodedepthbranchindices[varindex].index = 0;
    1831 nodedepthbranchindices[varindex].nodedepth = 0;
    1832 }
    1833 }
    1834
    1835 /* prepare for the next iteration */
    1836 shadownode = shadownode->parent;
    1837#ifndef NDEBUG
    1838 --shadowdepth;
    1839#endif
    1840 }
    1841 /* In the last iteration, we handled the branching decisions at the root node, so shadowdepth must have value 0. */
    1842 assert( shadowdepth == 0 );
    1843
    1844 return SCIP_OKAY;
    1845}
    1846
    1847
    1848/*
    1849 * Interface methods
    1850 */
    1851
    1852
    1853/** prints lexicographic reduction propagation data */
    1855 SCIP* scip, /**< SCIP data structure */
    1856 SCIP_LEXREDDATA* masterdata, /**< pointer to global data for lexicographic reduction propagator */
    1857 int* nred, /**< total number of reductions applied */
    1858 int* ncutoff /**< total number of cutoffs applied */
    1859 )
    1860{
    1861 assert( scip != NULL );
    1862 assert( masterdata != NULL );
    1863 assert( nred != NULL );
    1864
    1865 *nred = masterdata->nred;
    1866 *ncutoff = masterdata->ncutoff;
    1867
    1868 return SCIP_OKAY;
    1869}
    1870
    1871/** prints lexicographic reduction propagation data */
    1873 SCIP* scip, /**< SCIP data structure */
    1874 SCIP_LEXREDDATA* masterdata /**< pointer to global data for lexicographic reduction propagator */
    1875 )
    1876{
    1877 int i;
    1878
    1879 assert( scip != NULL );
    1880 assert( masterdata != NULL );
    1881
    1882 if ( masterdata->nlexdatas == 0 )
    1883 {
    1884 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, " lexicographic reduction: no permutations\n");
    1885 return SCIP_OKAY;
    1886 }
    1887
    1888 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, " lexicographic reduction: %4d permutations with support sizes ",
    1889 masterdata->nlexdatas);
    1890
    1891 for (i = 0; i < masterdata->nlexdatas; ++i)
    1892 {
    1893 if ( i > 0 )
    1895 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "%d", masterdata->lexdatas[i]->nvars);
    1896 }
    1897
    1899
    1900 return SCIP_OKAY;
    1901}
    1902
    1903
    1904/** applies lexicographic reduction propagation */
    1906 SCIP* scip, /**< SCIP data structure */
    1907 SCIP_LEXREDDATA* masterdata, /**< pointer to global data for lexicographic reduction propagator */
    1908 SCIP_Bool* infeasible, /**< pointer to store whether infeasibility is found */
    1909 int* nred, /**< pointer to store the number of domain reductions */
    1910 SCIP_Bool* didrun /**< a global pointer maintaining if any symmetry propagator has run
    1911 * only set this to TRUE when a reduction is found, never set to FALSE */
    1912 )
    1913{
    1914 int nlocalred;
    1915 int p;
    1916 SCIP_SHADOWTREE* shadowtree = NULL;
    1917 SCIP_NODE* focusnode = NULL;
    1919 SCIP_VAR** branchvars = NULL;
    1920 int nbranchvars = 0;
    1921 SCIP_Bool inforesolved;
    1922
    1923 assert( scip != NULL );
    1924 assert( masterdata != NULL );
    1925 assert( (masterdata->lexdatas == NULL) == (masterdata->nlexdatas == 0) );
    1926 assert( masterdata->nlexdatas >= 0 );
    1927 assert( masterdata->nlexdatas <= masterdata->maxnlexdatas );
    1928 assert( infeasible != NULL );
    1929 assert( nred != NULL );
    1930 assert( didrun != NULL );
    1931
    1932 *infeasible = FALSE;
    1933 *nred = 0;
    1934 *didrun = FALSE;
    1935
    1936 /* early termination */
    1937 if ( masterdata->nlexdatas == 0 )
    1938 return SCIP_OKAY;
    1939
    1940 /* compute the variable ordering based on the branching decisions
    1941 * of the shadowtree if there exist dynamic permutations
    1942 */
    1943 if ( masterdata->hasdynamicperm )
    1944 {
    1945 assert( masterdata->shadowtreeeventhdlr != NULL );
    1946 shadowtree = SCIPgetShadowTree(masterdata->shadowtreeeventhdlr);
    1947 focusnode = SCIPgetFocusNode(scip);
    1948
    1949 /* fill the node-depth-branch-indices structure
    1950 *
    1951 * this is an array that maps every variable index to (depth, index) = (0, 0) if the variable is not branched on,
    1952 * or (depth, index) is the depth (branching at root node: depth 1) and variable index when it was branched thereon.
    1953 * For individual dynamic lexicographic reductions, we use this ordering the following way:
    1954 * 1. Choose those variables that have (depth, index) with depth > 0 (these)
    1955 * 2. Sort by depth, then by index, in increasing order.
    1956 */
    1958 SCIP_CALL( SCIPallocCleanBufferArray(scip, &branchvars, masterdata->nsymvars) );
    1960 branchvars, &nbranchvars, shadowtree, focusnode, &inforesolved) );
    1961
    1962 /* if the information cannot be resolved because a node is missing from the shadowtree, do not propagate */
    1963 if ( !inforesolved )
    1964 {
    1965 /* shadowtreeFillNodeDepthBranchIndices keeps the input arrays clean if it terminates early */
    1966 SCIPfreeCleanBufferArray(scip, &branchvars);
    1968 return SCIP_OKAY;
    1969 }
    1970 /* ... Do everything using this nodedepthbranchindices structure */
    1971 }
    1972
    1973 if ( nbranchvars > 0 || ! masterdata->hasdynamicperm )
    1974 {
    1975 /* apply lexicographic reduction propagator to all lexdata objects */
    1976 for (p = 0; p < masterdata->nlexdatas; ++p)
    1977 {
    1978 assert( masterdata->lexdatas[p] != NULL );
    1979
    1981 nodedepthbranchindices, masterdata->nsymvars, branchvars, nbranchvars, infeasible, &nlocalred) );
    1982
    1983 /* keep track of the total number of fixed vars */
    1984 *nred += nlocalred;
    1985
    1986 /* a symmetry propagator has ran, so set didrun to TRUE */
    1987 *didrun = TRUE;
    1988
    1989 /* stop if we find infeasibility */
    1990 if ( *infeasible )
    1991 break;
    1992 }
    1993
    1994 /* maintain total number of reductions made */
    1995 masterdata->nred += *nred;
    1996 if ( *infeasible )
    1997 ++masterdata->ncutoff;
    1998 }
    1999
    2000 /* possibly clean the node-depth-branch-indices structure */
    2001 if ( masterdata->hasdynamicperm )
    2002 {
    2003 assert( shadowtree != NULL );
    2004 assert( focusnode != NULL );
    2006 branchvars, &nbranchvars, shadowtree, focusnode) );
    2007 assert( nbranchvars == 0 );
    2008 SCIPfreeCleanBufferArray(scip, &branchvars);
    2010 }
    2011
    2012 return SCIP_OKAY;
    2013}
    2014
    2015
    2016/** adds permutation for lexicographic reduction propagation */
    2018 SCIP* scip, /**< SCIP data structure */
    2019 SCIP_LEXREDDATA* masterdata, /**< pointer to global data for lexicographic reduction propagator */
    2020 SCIP_VAR** permvars, /**< variable array of the permutation */
    2021 int npermvars, /**< number of variables in that array */
    2022 int* perm, /**< permutation */
    2023 SYM_SYMTYPE symtype, /**< type of symmetries in perm */
    2024 SCIP_Real* permvardomaincenter, /**< array containing center point for each variable domain */
    2025 SCIP_Bool usedynamicorder, /**< whether a dynamic variable order shall be used */
    2026 SCIP_Bool* success /**< to store whether the component is successfully added */
    2027 )
    2028{
    2029 assert( scip != NULL );
    2030 assert( masterdata != NULL );
    2031 assert( (masterdata->lexdatas == NULL) == (masterdata->nlexdatas == 0) );
    2032 assert( masterdata->nlexdatas >= 0 );
    2033 assert( masterdata->nlexdatas <= masterdata->maxnlexdatas );
    2034 assert( masterdata->shadowtreeeventhdlr != NULL );
    2035 assert( permvars != NULL );
    2036 assert( npermvars > 0 );
    2037 assert( perm != NULL );
    2038
    2039 if ( symtype != SYM_SYMTYPE_PERM && symtype != SYM_SYMTYPE_SIGNPERM )
    2040 {
    2041 *success = FALSE;
    2042 return SCIP_OKAY;
    2043 }
    2044 assert( symtype == SYM_SYMTYPE_PERM || permvardomaincenter != NULL );
    2045 assert( SCIPisTransformed(scip) );
    2046
    2047 /* resize component array if needed */
    2048 if ( masterdata->nlexdatas == masterdata->maxnlexdatas )
    2049 {
    2050 int newsize;
    2051
    2052 newsize = SCIPcalcMemGrowSize(scip, masterdata->nlexdatas + 1);
    2053 assert( newsize >= 0 );
    2054
    2055 if ( masterdata->nlexdatas == 0 )
    2056 {
    2057 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &masterdata->lexdatas, newsize) );
    2058 }
    2059 else
    2060 {
    2062 masterdata->maxnlexdatas, newsize) );
    2063 }
    2064
    2065 masterdata->maxnlexdatas = newsize;
    2066 }
    2067
    2068 /* prepare lexdatas */
    2069 SCIP_CALL( lexdataCreate(scip, masterdata, &masterdata->lexdatas[masterdata->nlexdatas],
    2070 permvars, npermvars, perm, symtype, permvardomaincenter, usedynamicorder, success) );
    2071
    2072 /* if not successfully added, undo increasing the counter */
    2073 if ( *success )
    2074 ++masterdata->nlexdatas;
    2075
    2076 return SCIP_OKAY;
    2077}
    2078
    2079
    2080/** resets lexicographic reduction propagation (removes all permutations) */
    2082 SCIP* scip, /**< SCIP data structure */
    2083 SCIP_LEXREDDATA* masterdata /**< pointer to global data for lexicographic reduction propagator */
    2084 )
    2085{
    2086 assert( scip != NULL );
    2087 assert( masterdata != NULL );
    2088 assert( (masterdata->lexdatas == NULL) == (masterdata->nlexdatas == 0) );
    2089 assert( masterdata->nlexdatas >= 0 );
    2090 assert( masterdata->nlexdatas <= masterdata->maxnlexdatas );
    2091 assert( masterdata->shadowtreeeventhdlr != NULL );
    2092
    2093 while ( masterdata->nlexdatas > 0 )
    2094 {
    2095 SCIP_CALL( lexdataFree(scip, &(masterdata->lexdatas[--masterdata->nlexdatas])) );
    2096 }
    2097 assert( masterdata->nlexdatas == 0 );
    2098
    2099 SCIPfreeBlockMemoryArrayNull(scip, &masterdata->lexdatas, masterdata->maxnlexdatas);
    2100 masterdata->lexdatas = NULL;
    2101 masterdata->maxnlexdatas = 0;
    2102
    2103 assert( masterdata->nsymvars >= 0 );
    2104 assert( (masterdata->symvarmap == NULL) == (masterdata->nsymvars == 0) );
    2105 if ( masterdata->symvarmap != NULL )
    2106 {
    2107 SCIPhashmapFree(&masterdata->symvarmap);
    2108 masterdata->symvarmap = NULL;
    2109 masterdata->nsymvars = 0;
    2110 }
    2111
    2112 masterdata->hasdynamicperm = FALSE;
    2113
    2114 return SCIP_OKAY;
    2115}
    2116
    2117
    2118/** frees lexicographic reduction data */
    2120 SCIP* scip, /**< SCIP data structure */
    2121 SCIP_LEXREDDATA** masterdata /**< pointer to global data for lexicographic reduction propagator */
    2122 )
    2123{
    2124 assert( scip != NULL );
    2125 assert( masterdata != NULL );
    2126 assert( *masterdata != NULL );
    2127
    2129 assert( (*masterdata)->lexdatas == NULL );
    2130 assert( (*masterdata)->symvarmap == NULL );
    2131
    2133 return SCIP_OKAY;
    2134}
    2135
    2136
    2137/** initializes structures needed for lexicographic reduction propagation
    2138 *
    2139 *
    2140 * This is only done exactly once.
    2141 */
    2143 SCIP* scip, /**< SCIP data structure */
    2144 SCIP_LEXREDDATA** masterdata, /**< pointer to global data for lexicographic reduction propagator */
    2145 SCIP_EVENTHDLR* shadowtreeeventhdlr /**< pointer to the shadow tree eventhdlr */
    2146 )
    2147{
    2148 assert( scip != NULL );
    2149 assert( masterdata != NULL );
    2150 assert( shadowtreeeventhdlr != NULL );
    2151
    2152 SCIP_CALL( SCIPcheckStage(scip, "SCIPincludeLexicographicReduction", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,
    2154
    2156
    2157 (*masterdata)->shadowtreeeventhdlr = shadowtreeeventhdlr;
    2158 (*masterdata)->symvarmap = NULL;
    2159 (*masterdata)->nsymvars = 0;
    2160 (*masterdata)->lexdatas = NULL;
    2161 (*masterdata)->nlexdatas = 0;
    2162 (*masterdata)->maxnlexdatas = 0;
    2163 (*masterdata)->nred = 0;
    2164 (*masterdata)->ncutoff = 0;
    2165 (*masterdata)->hasdynamicperm = FALSE;
    2166 (*masterdata)->treewarninggiven = FALSE;
    2167
    2168 return SCIP_OKAY;
    2169}
    methods for debugging
    #define SCIPcheckStage(scip, method, init, problem, transforming, transformed, initpresolve, presolving, exitpresolve, presolved, initsolve, solving, solved, exitsolve, freetrans, freescip)
    Definition: debug.h:364
    #define NULL
    Definition: def.h:248
    #define SCIP_Bool
    Definition: def.h:91
    #define SCIP_Real
    Definition: def.h:156
    #define TRUE
    Definition: def.h:93
    #define FALSE
    Definition: def.h:94
    #define SCIP_CALL_ABORT(x)
    Definition: def.h:334
    #define SCIP_CALL(x)
    Definition: def.h:355
    SCIP_RETCODE SCIPactivateShadowTree(SCIP *scip, SCIP_EVENTHDLR *eventhdlr)
    SCIP_SHADOWTREE * SCIPgetShadowTree(SCIP_EVENTHDLR *eventhdlr)
    SCIP_SHADOWNODE * SCIPshadowTreeGetShadowNode(SCIP_SHADOWTREE *shadowtree, SCIP_NODE *node)
    SCIP_Bool SCIPisTransformed(SCIP *scip)
    Definition: scip_general.c:647
    void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
    Definition: misc.c:3095
    int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3304
    SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
    Definition: misc.c:3061
    SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
    Definition: misc.c:3466
    SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
    Definition: misc.c:3179
    void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
    Definition: scip_message.c:225
    void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
    Definition: scip_message.c:120
    #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
    BMS_BLKMEM * SCIPblkmem(SCIP *scip)
    Definition: scip_mem.c:57
    int SCIPcalcMemGrowSize(SCIP *scip, int num)
    Definition: scip_mem.c:139
    #define SCIPallocBufferArray(scip, ptr, num)
    Definition: scip_mem.h:124
    #define SCIPfreeBufferArray(scip, ptr)
    Definition: scip_mem.h:136
    #define SCIPallocBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:93
    #define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
    Definition: scip_mem.h:99
    #define SCIPfreeBlockMemory(scip, ptr)
    Definition: scip_mem.h:108
    #define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
    Definition: scip_mem.h:111
    #define SCIPallocBlockMemory(scip, ptr)
    Definition: scip_mem.h:89
    int SCIPnodeGetDepth(SCIP_NODE *node)
    Definition: tree.c:8493
    SCIP_Bool SCIPsymGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    Definition: symmetry.c:2350
    SCIP_Bool SCIPsymEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    Definition: symmetry.c:2278
    SCIP_Bool SCIPsymGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    Definition: symmetry.c:2426
    SCIP_Bool SCIPsymLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    Definition: symmetry.c:2312
    SCIP_Bool SCIPisIntegral(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_NODE * SCIPgetFocusNode(SCIP *scip)
    Definition: scip_tree.c:72
    SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:6401
    SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
    Definition: var.c:24268
    SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
    Definition: var.c:23430
    SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
    Definition: scip_var.c:6651
    const char * SCIPvarGetName(SCIP_VAR *var)
    Definition: var.c:23267
    SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
    Definition: scip_var.c:1887
    SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
    Definition: var.c:23490
    SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
    Definition: var.c:24234
    SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:11057
    SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
    Definition: scip_var.c:1853
    void SCIPsortInd(int *indarray, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
    memory allocation routines
    public methods for managing constraints
    public methods for message output
    #define SCIPdebugMessage
    Definition: pub_message.h:96
    public methods for problem variables
    SCIP callable library.
    public methods for branching rule plugins and branching
    public methods for conflict handler plugins and conflict analysis
    public methods for constraint handler plugins and constraints
    public methods for problem copies
    public methods for cuts and aggregation rows
    general public methods
    public methods for the LP relaxation, rows and columns
    public methods for memory management
    public methods for message handling
    public methods for numerical tolerances
    public methods for SCIP parameter handling
    public methods for global and local (sub)problems
    public methods for the probing mode
    public methods for solutions
    public methods for SCIP variables
    SCIP_Bool isdynamic
    SCIP_Real * vardomaincenter
    SCIP_HASHMAP * varmap
    SYM_SYMTYPE symtype
    SCIP_VAR ** vars
    struct SCIP_ShadowNode ** children
    SCIP_SHADOWBOUNDUPDATE * branchingdecisions
    struct SCIP_ShadowNode * parent
    NODEDEPTHBRANCHINDEX * nodedepthbranchindices
    datastructures for block memory pools and memory buffers
    SCIP main data structure.
    data structures for branch and bound tree
    datastructures for problem variables
    methods for handling symmetries
    static SCIP_Bool canGTshiftedVars(SCIP *scip, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real shift1, SCIP_Real shift2, SCIP_Bool isnegated, SCIP_Bool peekmode, int varidx1, int varidx2, SCIP_Real *peeklbs, SCIP_Real *peekubs, SCIP_Bool *peekbdset)
    static SCIP_RETCODE propagateLowerBoundVar(SCIP *scip, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real center1, SCIP_Real center2, SCIP_Bool isnegated, SCIP_Bool *infeasible, int *nreductions, SCIP_Bool peekmode, int varidx1, int varidx2, SCIP_Real *peeklbs, SCIP_Real *peekubs, SCIP_Bool *peekbdset)
    static SCIP_RETCODE propagateVariablePair(SCIP *scip, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real center1, SCIP_Real center2, SCIP_Bool isnegated, SCIP_Bool *infeasible, int *nreductions, SCIP_Bool peekmode, int varidx1, int varidx2, SCIP_Real *peeklbs, SCIP_Real *peekubs, SCIP_Bool *peekbdset)
    static SCIP_RETCODE propagateLexredDynamic(SCIP *scip, SCIP_LEXREDDATA *masterdata, LEXDATA *lexdata, NODEDEPTHBRANCHINDEX *nodedepthbranchindices, int nvarstotal, SCIP_VAR **branchvars, int nbranchvars, SCIP_Bool *infeasible, int *nreductions)
    SCIP_RETCODE SCIPlexicographicReductionPropagate(SCIP *scip, SCIP_LEXREDDATA *masterdata, SCIP_Bool *infeasible, int *nred, SCIP_Bool *didrun)
    static SCIP_DECL_SORTINDCOMP(sortbynodedepthbranchindices)
    static SCIP_Bool alwaysLTshiftedVars(SCIP *scip, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real shift1, SCIP_Real shift2, SCIP_Bool isnegated, SCIP_Bool peekmode, int varidx1, int varidx2, SCIP_Real *peeklbs, SCIP_Real *peekubs, SCIP_Bool *peekbdset)
    SCIP_RETCODE SCIPlexicographicReductionGetStatistics(SCIP *scip, SCIP_LEXREDDATA *masterdata, int *nred, int *ncutoff)
    static SCIP_RETCODE peekStaticLexredIsFeasible(SCIP *scip, LEXDATA *lexdata, int *varorder, int nselvars, int fixi, int fixj, int fixrow, SCIP_Real fixvaluei, SCIP_Real fixvaluej, SCIP_Bool *peekfeasible, SCIP_Real *peeklbs, SCIP_Real *peekubs, SCIP_Bool *peekbdset)
    SCIP_RETCODE SCIPlexicographicReductionReset(SCIP *scip, SCIP_LEXREDDATA *masterdata)
    static SCIP_RETCODE propagateUpperBoundSymVar(SCIP *scip, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real center1, SCIP_Real center2, SCIP_Bool isnegated, SCIP_Bool *infeasible, int *nreductions, SCIP_Bool peekmode, int varidx1, int varidx2, SCIP_Real *peeklbs, SCIP_Real *peekubs, SCIP_Bool *peekbdset)
    static SCIP_RETCODE getVarBounds(SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Bool peekmode, int varidx1, int varidx2, SCIP_Real *peeklbs, SCIP_Real *peekubs, SCIP_Bool *peekbdset, SCIP_Real *lb1, SCIP_Real *ub1, SCIP_Real *lb2, SCIP_Real *ub2)
    SCIP_RETCODE SCIPlexicographicReductionPrintStatistics(SCIP *scip, SCIP_LEXREDDATA *masterdata)
    static SCIP_RETCODE propagateLexredStatic(SCIP *scip, SCIP_LEXREDDATA *masterdata, LEXDATA *lexdata, SCIP_Bool *infeasible, int *nreductions)
    static SCIP_RETCODE lexdataFree(SCIP *scip, LEXDATA **lexdata)
    static SCIP_RETCODE getVarOrder(SCIP *scip, SCIP_LEXREDDATA *masterdata, LEXDATA *lexdata, NODEDEPTHBRANCHINDEX *nodedepthbranchindices, int nvarstotal, SCIP_VAR **branchvars, int nbranchvars, int *varorder, int *nselvars, int maxnselvars)
    static SCIP_RETCODE shadowtreeUndoNodeDepthBranchIndices(SCIP *scip, SCIP_LEXREDDATA *masterdata, NODEDEPTHBRANCHINDEX *nodedepthbranchindices, SCIP_VAR **branchvars, int *nbranchvars, SCIP_SHADOWTREE *shadowtree, SCIP_NODE *focusnode)
    SCIP_RETCODE SCIPlexicographicReductionFree(SCIP *scip, SCIP_LEXREDDATA **masterdata)
    static SCIP_RETCODE propagateLexicographicReductionPerm(SCIP *scip, SCIP_LEXREDDATA *masterdata, LEXDATA *lexdata, NODEDEPTHBRANCHINDEX *nodedepthbranchindices, int nvarstotal, SCIP_VAR **branchvars, int nbranchvars, SCIP_Bool *infeasible, int *nreductions)
    SCIP_RETCODE SCIPlexicographicReductionAddPermutation(SCIP *scip, SCIP_LEXREDDATA *masterdata, SCIP_VAR **permvars, int npermvars, int *perm, SYM_SYMTYPE symtype, SCIP_Real *permvardomaincenter, SCIP_Bool usedynamicorder, SCIP_Bool *success)
    static SCIP_RETCODE propagateSelfReflectionVar(SCIP *scip, SCIP_VAR *var, SCIP_Real center, SCIP_Bool *infeasible, int *nreductions, SCIP_Bool peekmode, int varidx, SCIP_Real *peeklbs, SCIP_Real *peekubs, SCIP_Bool *peekbdset)
    static SCIP_RETCODE propagateStaticLexred(SCIP *scip, LEXDATA *lexdata, int *varorder, int nselvars, SCIP_Bool *infeasible, int *nreductions)
    static SCIP_RETCODE shadowtreeFillNodeDepthBranchIndices(SCIP *scip, SCIP_LEXREDDATA *masterdata, NODEDEPTHBRANCHINDEX *nodedepthbranchindices, SCIP_VAR **branchvars, int *nbranchvars, SCIP_SHADOWTREE *shadowtree, SCIP_NODE *focusnode, SCIP_Bool *inforesolved)
    SCIP_RETCODE SCIPincludeLexicographicReduction(SCIP *scip, SCIP_LEXREDDATA **masterdata, SCIP_EVENTHDLR *shadowtreeeventhdlr)
    static SCIP_RETCODE lexdataCreate(SCIP *scip, SCIP_LEXREDDATA *masterdata, LEXDATA **lexdata, SCIP_VAR *const *vars, int nvars, int *perm, SYM_SYMTYPE symtype, SCIP_Real *permvardomaincenter, SCIP_Bool usedynamicorder, SCIP_Bool *success)
    static int varOrderGetIndex(int *varorder, int pos)
    methods for handling symmetries by dynamic lexicographic ordering reduction
    struct SCIP_LexRedData SCIP_LEXREDDATA
    @ SCIP_VERBLEVEL_HIGH
    Definition: type_message.h:61
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    enum SYM_Symtype SYM_SYMTYPE
    Definition: type_symmetry.h:64
    @ SYM_SYMTYPE_SIGNPERM
    Definition: type_symmetry.h:62
    @ SYM_SYMTYPE_PERM
    Definition: type_symmetry.h:61
    type definitions for problem variables