Scippy

    SCIP

    Solving Constraint Integer Programs

    symmetry.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.c
    26 * @ingroup OTHER_CFILES
    27 * @brief methods for handling symmetries
    28 * @author Jasper van Doornmalen
    29 * @author Christopher Hojny
    30 * @author Marc Pfetsch
    31 */
    32
    33/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    34
    35#include "scip/symmetry.h"
    36#include "scip/scip.h"
    37#include "scip/cons_setppc.h"
    38#include "scip/cons_orbitope.h"
    39#include "scip/misc.h"
    42
    43
    44/** returns inferred type of variable used for symmetry handling */
    46 SCIP_VAR* var /**< variable whose inferred type has to be returned */
    47 )
    48{
    49 assert(var != NULL);
    50
    51 if( SCIPvarIsBinary(var) )
    53 if( SCIPvarIsIntegral(var) )
    55
    57}
    58
    59/** compute non-trivial orbits of symmetry group
    60 *
    61 * The non-trivial orbits of the group action are stored in the array orbits of length npermvars. This array contains
    62 * the indices of variables from the permvars array such that variables that are contained in the same orbit appear
    63 * consecutively in the orbits array. The variables of the i-th orbit have indices
    64 * orbits[orbitbegins[i]], ... , orbits[orbitbegins[i + 1] - 1].
    65 * Note that the description of the orbits ends at orbitbegins[norbits] - 1.
    66 */
    68 SCIP* scip, /**< SCIP instance */
    69 SCIP_Bool issigned, /**< whether orbits for signed permutations shall be computed */
    70 SCIP_VAR** permvars, /**< variables considered in a permutation */
    71 int npermvars, /**< length of a permutation array */
    72 int** perms, /**< matrix containing in each row a permutation of the symmetry group */
    73 int nperms, /**< number of permutations encoded in perms */
    74 int* orbits, /**< array of non-trivial orbits */
    75 int* orbitbegins, /**< array containing begin positions of new orbits in orbits array */
    76 int* norbits /**< pointer to number of orbits currently stored in orbits */
    77 )
    78{
    79 SCIP_Shortbool* varadded;
    80 int permlen;
    81 int orbitidx = 0;
    82 int i;
    83
    84 assert( scip != NULL );
    85 assert( permvars != NULL );
    86 assert( perms != NULL );
    87 assert( nperms > 0 );
    88 assert( npermvars > 0 );
    89 assert( orbits != NULL );
    90 assert( orbitbegins != NULL );
    91 assert( norbits != NULL );
    92
    93 permlen = npermvars;
    94 if ( issigned )
    95 permlen *= 2;
    96
    97 /* init data structures*/
    98 SCIP_CALL( SCIPallocBufferArray(scip, &varadded, permlen) );
    99
    100 /* initially, every variable is contained in no orbit */
    101 for (i = 0; i < permlen; ++i)
    102 varadded[i] = FALSE;
    103
    104 /* find variable orbits */
    105 *norbits = 0;
    106 for (i = 0; i < permlen; ++i)
    107 {
    108 int beginorbitidx;
    109 int j;
    110
    111 /* skip variable already contained in an orbit of a previous variable */
    112 if ( varadded[i] )
    113 continue;
    114
    115 /* store first variable */
    116 beginorbitidx = orbitidx;
    117 orbits[orbitidx++] = i;
    118 varadded[i] = TRUE;
    119
    120 /* iterate over variables in curorbit and compute their images */
    121 j = beginorbitidx;
    122 while ( j < orbitidx )
    123 {
    124 int curelem;
    125 int image;
    126 int p;
    127
    128 curelem = orbits[j];
    129
    130 for (p = 0; p < nperms; ++p)
    131 {
    132 image = perms[p][curelem];
    133
    134 /* found new element of the orbit of i */
    135 if ( ! varadded[image] )
    136 {
    137 orbits[orbitidx++] = image;
    138 assert( orbitidx <= permlen );
    139 varadded[image] = TRUE;
    140 }
    141 }
    142 ++j;
    143 }
    144
    145 /* if the orbit is trivial, reset storage, otherwise store orbit */
    146 if ( orbitidx <= beginorbitidx + 1 )
    147 orbitidx = beginorbitidx;
    148 else
    149 orbitbegins[(*norbits)++] = beginorbitidx;
    150 }
    151
    152 /* store end in "last" orbitbegins entry */
    153 assert( *norbits < permlen );
    154 orbitbegins[*norbits] = orbitidx;
    155
    156#ifdef SCIP_OUTPUT
    157 printf("Orbits (total number: %d):\n", *norbits);
    158 for (i = 0; i < *norbits; ++i)
    159 {
    160 int j;
    161
    162 printf("%d: ", i);
    163 for (j = orbitbegins[i]; j < orbitbegins[i+1]; ++j)
    164 printf("%d ", orbits[j]);
    165 printf("\n");
    166 }
    167#endif
    168
    169 /* free memory */
    170 SCIPfreeBufferArray(scip, &varadded);
    171
    172 return SCIP_OKAY;
    173}
    174
    175
    176/** compute non-trivial orbits of symmetry group using filtered generators
    177 *
    178 * The non-trivial orbits of the group action are stored in the array orbits of length npermvars. This array contains
    179 * the indices of variables from the permvars array such that variables that are contained in the same orbit appear
    180 * consecutively in the orbits array. The variables of the i-th orbit have indices
    181 * orbits[orbitbegins[i]], ... , orbits[orbitbegins[i + 1] - 1].
    182 * Note that the description of the orbits ends at orbitbegins[norbits] - 1.
    183 *
    184 * Only permutations that are not inactive (as marked by @p inactiveperms) are used. Thus, one can use this array to
    185 * filter out permutations.
    186 */
    188 SCIP* scip, /**< SCIP instance */
    189 int npermvars, /**< length of a permutation array */
    190 int** permstrans, /**< transposed matrix containing in each column a
    191 * permutation of the symmetry group */
    192 int nperms, /**< number of permutations encoded in perms */
    193 SCIP_Shortbool* inactiveperms, /**< array to store whether permutations are inactive */
    194 int* orbits, /**< array of non-trivial orbits */
    195 int* orbitbegins, /**< array containing begin positions of new orbits in orbits array */
    196 int* norbits, /**< pointer to number of orbits currently stored in orbits */
    197 int* components, /**< array containing the indices of permutations sorted by components */
    198 int* componentbegins, /**< array containing in i-th position the first position of
    199 * component i in components array */
    200 int* vartocomponent, /**< array containing for each permvar the index of the component it is
    201 * contained in (-1 if not affected) */
    202 unsigned* componentblocked, /**< array to store which symmetry methods have been used on a component
    203 * using the same bitset information as for misc/usesymmetry */
    204 int ncomponents, /**< number of components of symmetry group */
    205 int nmovedpermvars /**< number of variables moved by any permutation in a symmetry component
    206 * that is handled by orbital fixing */
    207 )
    208{
    209 SCIP_Shortbool* varadded;
    210 int nvaradded = 0;
    211 int orbitidx = 0;
    212 int i;
    213
    214 assert( scip != NULL );
    215 assert( permstrans != NULL );
    216 assert( nperms > 0 );
    217 assert( npermvars > 0 );
    218 assert( inactiveperms != NULL );
    219 assert( orbits != NULL );
    220 assert( orbitbegins != NULL );
    221 assert( norbits != NULL );
    222 assert( components != NULL );
    223 assert( componentbegins != NULL );
    224 assert( vartocomponent != NULL );
    225 assert( ncomponents > 0 );
    226 assert( nmovedpermvars > 0 );
    227
    228 /* init data structures */
    229 SCIP_CALL( SCIPallocBufferArray(scip, &varadded, npermvars) );
    230
    231 /* initially, every variable is contained in no orbit */
    232 for (i = 0; i < npermvars; ++i)
    233 varadded[i] = FALSE;
    234
    235 /* find variable orbits */
    236 *norbits = 0;
    237 for (i = 0; i < npermvars; ++i)
    238 {
    239 int beginorbitidx;
    240 int componentidx;
    241 int j;
    242
    243 /* skip unaffected variables and blocked components */
    244 componentidx = vartocomponent[i];
    245 if ( componentidx < 0 || componentblocked[componentidx] )
    246 continue;
    247
    248 /* skip variable already contained in an orbit of a previous variable */
    249 if ( varadded[i] )
    250 continue;
    251
    252 /* store first variable */
    253 beginorbitidx = orbitidx;
    254 orbits[orbitidx++] = i;
    255 varadded[i] = TRUE;
    256 ++nvaradded;
    257
    258 /* iterate over variables in curorbit and compute their images */
    259 j = beginorbitidx;
    260 while ( j < orbitidx )
    261 {
    262 int* pt;
    263 int curelem;
    264 int image;
    265 int p;
    266
    267 curelem = orbits[j];
    268
    269 pt = permstrans[curelem];
    270 for (p = componentbegins[componentidx]; p < componentbegins[componentidx + 1]; ++p)
    271 {
    272 int perm;
    273
    274 perm = components[p];
    275
    276 if ( ! inactiveperms[perm] )
    277 {
    278 image = pt[perm];
    279 assert( vartocomponent[image] == componentidx );
    280
    281 /* found new element of the orbit of i */
    282 if ( ! varadded[image] )
    283 {
    284 orbits[orbitidx++] = image;
    285 assert( orbitidx <= npermvars );
    286 varadded[image] = TRUE;
    287 ++nvaradded;
    288 }
    289 }
    290 }
    291 ++j;
    292 }
    293
    294 /* if the orbit is trivial, reset storage, otherwise store orbit */
    295 if ( orbitidx <= beginorbitidx + 1 )
    296 orbitidx = beginorbitidx;
    297 else
    298 orbitbegins[(*norbits)++] = beginorbitidx;
    299
    300 /* stop if all variables are covered */
    301 if ( nvaradded >= nmovedpermvars )
    302 break;
    303 }
    304
    305 /* store end in "last" orbitbegins entry */
    306 assert( *norbits < npermvars );
    307 orbitbegins[*norbits] = orbitidx;
    308
    309#ifdef SCIP_OUTPUT
    310 printf("Orbits (total number: %d):\n", *norbits);
    311 for (i = 0; i < *norbits; ++i)
    312 {
    313 int j;
    314
    315 printf("%d: ", i);
    316 for (j = orbitbegins[i]; j < orbitbegins[i+1]; ++j)
    317 printf("%d ", orbits[j]);
    318 printf("\n");
    319 }
    320#endif
    321
    322 /* free memory */
    323 SCIPfreeBufferArray(scip, &varadded);
    324
    325 return SCIP_OKAY;
    326}
    327
    328/** Compute orbit of a given variable and store it in @p orbit. The first entry of the orbit will
    329 * be the given variable index and the rest is filled with the remaining variables excluding
    330 * the ones specified in @p ignoredvars.
    331 *
    332 * @pre orbit is an initialized array of size propdata->npermvars
    333 * @pre at least one of @p perms and @p permstrans should not be NULL
    334 */
    336 SCIP* scip, /**< SCIP instance */
    337 int npermvars, /**< number of variables in permvars */
    338 int** perms, /**< the generators of the permutation group (or NULL) */
    339 int** permstrans, /**< the transposed matrix of generators (or NULL) */
    340 int* components, /**< the components of the permutation group */
    341 int* componentbegins, /**< array containing the starting index of each component */
    342 SCIP_Shortbool* ignoredvars, /**< array indicating which variables should be ignored */
    343 SCIP_Shortbool* varfound, /**< bitmap to mark which variables have been added (or NULL) */
    344 int varidx, /**< index of variable for which the orbit is requested */
    345 int component, /**< component that var is in */
    346 int* orbit, /**< array in which the orbit should be stored */
    347 int* orbitsize /**< buffer to store the size of the orbit */
    348 )
    349{ /*lint --e{571}*/
    350 SCIP_Shortbool* varadded;
    351 int* varstotest;
    352 int nvarstotest;
    353 int j;
    354 int p;
    355
    356 assert( scip != NULL );
    357 assert( perms != NULL || permstrans != NULL );
    358 assert( components != NULL );
    359 assert( componentbegins != NULL );
    360 assert( ignoredvars != NULL );
    361 assert( orbit != NULL );
    362 assert( orbitsize != NULL );
    363 assert( 0 <= varidx && varidx < npermvars );
    364 assert( component >= 0 );
    365 assert( npermvars > 0 );
    366
    367 /* init data structures*/
    368 SCIP_CALL( SCIPallocClearBufferArray(scip, &varadded, npermvars) );
    369 SCIP_CALL( SCIPallocClearBufferArray(scip, &varstotest, npermvars) );
    370
    371 /* compute and store orbit if it is non-trivial */
    372 orbit[0] = varidx;
    373 varstotest[0] = varidx;
    374 *orbitsize = 1;
    375 nvarstotest = 1;
    376 varadded[varidx] = TRUE;
    377
    378 if ( varfound != NULL )
    379 varfound[varidx] = TRUE;
    380
    381 /* iterate over variables in orbit and compute their images */
    382 j = 0;
    383 while ( j < nvarstotest )
    384 {
    385 int currvar;
    386
    387 currvar = varstotest[j++];
    388
    389 for (p = componentbegins[component]; p < componentbegins[component+1]; ++p)
    390 {
    391 int image;
    392 int comp;
    393
    394 comp = components[p];
    395
    396 if ( perms != NULL )
    397 image = perms[comp][currvar]; /*lint !e613*/
    398 else
    399 image = permstrans[currvar][comp];
    400
    401 /* found new element of the orbit of varidx */
    402 if ( ! varadded[image] )
    403 {
    404 varstotest[nvarstotest++] = image;
    405 varadded[image] = TRUE;
    406
    407 if ( ! ignoredvars[image] )
    408 {
    409 orbit[(*orbitsize)++] = image;
    410
    411 if ( varfound != NULL )
    412 varfound[image] = TRUE;
    413 }
    414 }
    415 }
    416 }
    417
    418 /* free memory */
    419 SCIPfreeBufferArray(scip, &varstotest);
    420 SCIPfreeBufferArray(scip, &varadded);
    421
    422 return SCIP_OKAY;
    423}
    424
    425/** compute non-trivial orbits of symmetry group
    426 *
    427 * The non-trivial orbits of the group action are stored in the array orbits of length npermvars. This array contains
    428 * the indices of variables from the permvars array such that variables that are contained in the same orbit appear
    429 * consecutively in the orbits array. The variables of the i-th orbit have indices
    430 * orbits[orbitbegins[i]], ... , orbits[orbitbegins[i + 1] - 1].
    431 * Note that the description of the orbits ends at orbitbegins[norbits] - 1.
    432 *
    433 * This function is adapted from computeGroupOrbitsFilter().
    434 */
    436 SCIP* scip, /**< SCIP instance */
    437 int npermvars, /**< length of a permutation array */
    438 int** permstrans, /**< transposed matrix containing in each column a permutation of the symmetry group */
    439 int nperms, /**< number of permutations encoded in perms */
    440 int* components, /**< array containing the indices of permutations sorted by components */
    441 int* componentbegins, /**< array containing in i-th position the first position of component i in components array */
    442 int* vartocomponent, /**< array containing for each permvar the index of the component it is
    443 * contained in (-1 if not affected) */
    444 int ncomponents, /**< number of components of symmetry group */
    445 int* orbits, /**< array of non-trivial orbits */
    446 int* orbitbegins, /**< array containing begin positions of new orbits in orbits array */
    447 int* norbits, /**< pointer to number of orbits currently stored in orbits */
    448 int* varorbitmap /**< array for storing the orbits for each variable */
    449 )
    450{
    451 SCIP_Shortbool* varadded;
    452 int orbitidx = 0;
    453 int i;
    454
    455 assert( scip != NULL );
    456 assert( permstrans != NULL );
    457 assert( nperms > 0 );
    458 assert( npermvars > 0 );
    459 assert( components != NULL );
    460 assert( componentbegins != NULL );
    461 assert( vartocomponent != NULL );
    462 assert( ncomponents > 0 );
    463 assert( orbits != NULL );
    464 assert( orbitbegins != NULL );
    465 assert( norbits != NULL );
    466 assert( varorbitmap != NULL );
    467
    468 /* init data structures */
    469 SCIP_CALL( SCIPallocBufferArray(scip, &varadded, npermvars) );
    470
    471 /* initially, every variable is contained in no orbit */
    472 for (i = 0; i < npermvars; ++i)
    473 {
    474 varadded[i] = FALSE;
    475 varorbitmap[i] = -1;
    476 }
    477
    478 /* find variable orbits */
    479 *norbits = 0;
    480 for (i = 0; i < npermvars; ++i)
    481 {
    482 int beginorbitidx;
    483 int componentidx;
    484 int j;
    485
    486 /* skip unaffected variables - note that we also include blocked components */
    487 componentidx = vartocomponent[i];
    488 if ( componentidx < 0 )
    489 continue;
    490
    491 /* skip variable already contained in an orbit of a previous variable */
    492 if ( varadded[i] )
    493 continue;
    494
    495 /* store first variable */
    496 beginorbitidx = orbitidx;
    497 orbits[orbitidx++] = i;
    498 varadded[i] = TRUE;
    499 varorbitmap[i] = *norbits;
    500
    501 /* iterate over variables in curorbit and compute their images */
    502 j = beginorbitidx;
    503 while ( j < orbitidx )
    504 {
    505 int* pt;
    506 int curelem;
    507 int image;
    508 int p;
    509
    510 curelem = orbits[j];
    511
    512 pt = permstrans[curelem];
    513 for (p = componentbegins[componentidx]; p < componentbegins[componentidx + 1]; ++p)
    514 {
    515 int perm;
    516
    517 perm = components[p];
    518 image = pt[perm];
    519 assert( vartocomponent[image] == componentidx );
    520
    521 /* found new element of the orbit of i */
    522 if ( ! varadded[image] )
    523 {
    524 orbits[orbitidx++] = image;
    525 assert( orbitidx <= npermvars );
    526 varadded[image] = TRUE;
    527 varorbitmap[image] = *norbits;
    528 }
    529 }
    530 ++j;
    531 }
    532
    533 /* if the orbit is trivial, reset storage, otherwise store orbit */
    534 if ( orbitidx <= beginorbitidx + 1 )
    535 {
    536 orbitidx = beginorbitidx;
    537 varorbitmap[i] = -1;
    538 }
    539 else
    540 orbitbegins[(*norbits)++] = beginorbitidx;
    541 }
    542
    543 /* store end in "last" orbitbegins entry */
    544 assert( *norbits < npermvars );
    545 orbitbegins[*norbits] = orbitidx;
    546
    547 /* free memory */
    548 SCIPfreeBufferArray(scip, &varadded);
    549
    550 return SCIP_OKAY;
    551}
    552
    553
    554/** Checks whether a permutation is a composition of 2-cycles and in this case determines the number of overall
    555 * 2-cycles and binary 2-cycles. It is a composition of 2-cycles iff @p ntwocyclesperm > 0 upon termination.
    556 */
    558 int* perm, /**< permutation */
    559 SCIP_VAR** vars, /**< array of variables perm is acting on */
    560 int nvars, /**< number of variables */
    561 int* ntwocyclesperm, /**< pointer to store number of 2-cycles or 0 if perm is not an involution */
    562 int* nbincyclesperm, /**< pointer to store number of binary cycles */
    563 SCIP_Bool earlytermination /**< whether we terminate early if not all affected variables are binary */
    564 )
    565{
    566 int ntwocycles = 0;
    567 int i;
    568
    569 assert( perm != NULL );
    570 assert( vars != NULL );
    571 assert( ntwocyclesperm != NULL );
    572 assert( nbincyclesperm != NULL );
    573
    574 *ntwocyclesperm = 0;
    575 *nbincyclesperm = 0;
    576 for (i = 0; i < nvars; ++i)
    577 {
    578 assert( 0 <= perm[i] && perm[i] < nvars );
    579
    580 /* skip fixed points and avoid treating the same 2-cycle twice */
    581 if ( perm[i] <= i )
    582 continue;
    583
    584 if ( perm[perm[i]] == i )
    585 {
    586 if ( SCIPvarIsBinary(vars[i]) && SCIPvarIsBinary(vars[perm[i]]) )
    587 ++(*nbincyclesperm);
    588 else if ( earlytermination )
    589 return SCIP_OKAY;
    590
    591 ++ntwocycles;
    592 }
    593 else
    594 {
    595 /* we do not have only 2-cycles */
    596 return SCIP_OKAY;
    597 }
    598 }
    599
    600 /* at this point the permutation is a composition of 2-cycles */
    601 *ntwocyclesperm = ntwocycles;
    602
    603 return SCIP_OKAY;
    604}
    605
    606
    607/** determine number of variables affected by symmetry group */
    609 SCIP* scip, /**< SCIP instance */
    610 int** perms, /**< permutations */
    611 int nperms, /**< number of permutations in perms */
    612 SCIP_VAR** permvars, /**< variables corresponding to permutations */
    613 int npermvars, /**< number of permvars in perms */
    614 int* nvarsaffected /**< pointer to store number of all affected variables */
    615 )
    616{
    617 SCIP_Shortbool* affected;
    618 int i;
    619 int p;
    620
    621 assert( scip != NULL );
    622 assert( perms != NULL );
    623 assert( nperms > 0 );
    624 assert( permvars != NULL );
    625 assert( npermvars > 0 );
    626 assert( nvarsaffected != NULL );
    627
    628 *nvarsaffected = 0;
    629
    630 SCIP_CALL( SCIPallocClearBufferArray(scip, &affected, npermvars) );
    631
    632 /* iterate over permutations and check which variables are affected by some symmetry */
    633 for (p = 0; p < nperms; ++p)
    634 {
    635 for (i = 0; i < npermvars; ++i)
    636 {
    637 if ( affected[i] )
    638 continue;
    639
    640 if ( perms[p][i] != i )
    641 {
    642 affected[i] = TRUE;
    643 ++(*nvarsaffected);
    644 }
    645 }
    646 }
    647 SCIPfreeBufferArray(scip, &affected);
    648
    649 return SCIP_OKAY;
    650}
    651
    652
    653/** Given a matrix with nrows and \#perms + 1 columns whose first nfilledcols columns contain entries of variables, this routine
    654 * checks whether the 2-cycles of perm intersect each row of column coltoextend in exactly one position. In this case,
    655 * we add one column to the suborbitope of the first nfilledcols columns.
    656 *
    657 * @pre Every non-trivial cycle of perm is a 2-cycle.
    658 * @pre perm has nrows many 2-cycles
    659 */
    661 int** suborbitope, /**< matrix containing suborbitope entries */
    662 int nrows, /**< number of rows of suborbitope */
    663 int nfilledcols, /**< number of columns of suborbitope which are filled with entries */
    664 int coltoextend, /**< index of column that should be extended by perm */
    665 int* perm, /**< permutation */
    666 SCIP_Bool leftextension, /**< whether we extend the suborbitope to the left */
    667 int** nusedelems, /**< pointer to array storing how often an element was used in the orbitope */
    668 SCIP_VAR** permvars, /**< permutation vars array */
    669 SCIP_Shortbool* rowisbinary, /**< array encoding whether variables in an orbitope row are binary (or NULL) */
    670 SCIP_Bool* success, /**< pointer to store whether extension was successful */
    671 SCIP_Bool* infeasible /**< pointer to store if the number of intersecting cycles is too small */
    672 )
    673{
    674 int nintersections = 0;
    675 int row;
    676 int idx1;
    677 int idx2;
    678
    679 assert( suborbitope != NULL );
    680 assert( nrows > 0 );
    681 assert( nfilledcols > 0 );
    682 assert( coltoextend >= 0 );
    683 assert( perm != NULL );
    684 assert( nusedelems != NULL );
    685 assert( permvars != NULL );
    686 assert( success != NULL );
    687 assert( infeasible != NULL );
    688
    689 *success = FALSE;
    690 *infeasible = FALSE;
    691
    692 /* if we try to extend the first orbitope generator by another one,
    693 * we can change the order of entries in each row of suborbitope */
    694 if ( nfilledcols == 2 )
    695 {
    696 /* check whether each cycle of perm intersects with a row of suborbitope */
    697 for (row = 0; row < nrows; ++row)
    698 {
    699 idx1 = suborbitope[row][0];
    700 idx2 = suborbitope[row][1];
    701
    702 /* if idx1 or idx2 is affected by perm, we can extend the row of the orbitope */
    703 if ( idx1 != perm[idx1] )
    704 {
    705 /* change order of idx1 and idx2 for right extensions */
    706 if ( ! leftextension )
    707 {
    708 suborbitope[row][0] = idx2;
    709 suborbitope[row][1] = idx1;
    710 }
    711 assert( rowisbinary == NULL || rowisbinary[row] == SCIPvarIsBinary(permvars[perm[idx1]]) );
    712
    713 suborbitope[row][2] = perm[idx1];
    714 ++nintersections;
    715
    716 ++(*nusedelems)[idx1];
    717 ++(*nusedelems)[perm[idx1]];
    718
    719 /* if an element appears too often in the orbitope matrix */
    720 if ( (*nusedelems)[idx1] + (*nusedelems)[perm[idx1]] > 3 )
    721 {
    722 *infeasible = TRUE;
    723 break;
    724 }
    725 }
    726 else if ( idx2 != perm[idx2] )
    727 {
    728 /* change order of idx1 and idx2 for left extensions */
    729 if ( leftextension )
    730 {
    731 suborbitope[row][0] = idx2;
    732 suborbitope[row][1] = idx1;
    733 }
    734 assert( rowisbinary == NULL || rowisbinary[row] == SCIPvarIsBinary(permvars[perm[idx1]]) );
    735
    736 suborbitope[row][2] = perm[idx2];
    737 ++nintersections;
    738
    739 ++(*nusedelems)[idx2];
    740 ++(*nusedelems)[perm[idx2]];
    741
    742 /* if an element appears too often in the orbitope matrix */
    743 if ( (*nusedelems)[idx2] + (*nusedelems)[perm[idx2]] > 3 )
    744 {
    745 *infeasible = TRUE;
    746 break;
    747 }
    748 }
    749 }
    750 }
    751 else
    752 {
    753 /* check whether each cycle of perm intersects with a row of suborbitope */
    754 for (row = 0; row < nrows; ++row)
    755 {
    756 idx1 = suborbitope[row][coltoextend];
    757
    758 /* if idx1 is affected by perm, we can extend the row of the orbitope */
    759 if ( idx1 != perm[idx1] )
    760 {
    761 assert( rowisbinary == NULL || rowisbinary[row] == SCIPvarIsBinary(permvars[perm[idx1]]) );
    762
    763 suborbitope[row][nfilledcols] = perm[idx1];
    764 ++nintersections;
    765
    766 ++(*nusedelems)[idx1];
    767 ++(*nusedelems)[perm[idx1]];
    768
    769 /* if an element appears to often in the orbitope matrix */
    770 if ( (*nusedelems)[idx1] + (*nusedelems)[perm[idx1]] > 3 )
    771 {
    772 *infeasible = TRUE;
    773 break;
    774 }
    775 }
    776 }
    777 }
    778
    779 /* if there are too few intersection, this is not an orbitope */
    780 if ( nintersections > 0 && nintersections < nrows )
    781 *infeasible = TRUE;
    782 else if ( nintersections == nrows )
    783 *success = TRUE;
    784
    785 return SCIP_OKAY;
    786}
    787
    788
    789/** compute components of symmetry group */
    791 SCIP* scip, /**< SCIP instance */
    792 SYM_SYMTYPE symtype, /**< type of symmetries in perms */
    793 int** perms, /**< permutation generators as
    794 * (either nperms x npermvars or npermvars x nperms) matrix */
    795 int nperms, /**< number of permutations */
    796 SCIP_VAR** permvars, /**< variables on which permutations act */
    797 int npermvars, /**< number of variables for permutations */
    798 SCIP_Bool transposed, /**< transposed permutation generators as (npermvars x nperms) matrix */
    799 int** components, /**< array containing the indices of permutations sorted by components */
    800 int** componentbegins, /**< array containing in i-th position the first position of
    801 * component i in components array */
    802 int** vartocomponent, /**< array containing for each permvar the index of the component it is
    803 * contained in (-1 if not affected) */
    804 unsigned** componentblocked, /**< array to store which symmetry methods have been used on a component
    805 * using the same bitset information as for misc/usesymmetry */
    806 int* ncomponents /**< pointer to store number of components of symmetry group */
    807 )
    808{
    809 SCIP_DISJOINTSET* componentstovar = NULL;
    810 int* permtovarcomp;
    811 int* permtocomponent;
    812 int p;
    813 int i;
    814 int idx;
    815
    816 assert( scip != NULL );
    817 assert( permvars != NULL );
    818 assert( npermvars > 0 );
    819 assert( perms != NULL );
    820 assert( components != NULL );
    821 assert( componentbegins != NULL );
    822 assert( vartocomponent != NULL );
    823 assert( componentblocked != NULL );
    824 assert( ncomponents != NULL );
    825
    826 if ( nperms <= 0 )
    827 return SCIP_OKAY;
    828
    829 SCIP_CALL( SCIPdisjointsetCreate(&componentstovar, SCIPblkmem(scip), npermvars) );
    830 *ncomponents = npermvars;
    831
    832 /* init array that stores for each permutation the representative of its affected variables */
    833 SCIP_CALL( SCIPallocBufferArray(scip, &permtovarcomp, nperms) );
    834 for (p = 0; p < nperms; ++p)
    835 permtovarcomp[p] = -1;
    836
    837 /* find permutation components and store for each variable an affecting permutation (or -1) */
    838 SCIP_CALL( SCIPallocBlockMemoryArray(scip, vartocomponent, npermvars) );
    839 for (i = 0; i < npermvars; ++i)
    840 {
    841 (*vartocomponent)[i] = -1;
    842
    843 for (p = 0; p < nperms; ++p)
    844 {
    845 int img;
    846
    847 img = transposed ? perms[i][p] : perms[p][i];
    848
    849 /* perm p affects i -> possibly merge var components */
    850 if ( img != i )
    851 {
    852 int component1;
    853 int component2;
    854 int representative;
    855
    856 if ( img >= npermvars )
    857 {
    858 assert( symtype == SYM_SYMTYPE_SIGNPERM );
    859 img -= npermvars;
    860 assert( 0 <= img && img < npermvars );
    861 }
    862
    863 component1 = SCIPdisjointsetFind(componentstovar, i);
    864 component2 = SCIPdisjointsetFind(componentstovar, img);
    865 (*vartocomponent)[i] = p;
    866 (*vartocomponent)[img] = p;
    867
    868 /* ensure component1 <= component2 */
    869 if ( component2 < component1 )
    870 {
    871 int swap;
    872
    873 swap = component1;
    874 component1 = component2;
    875 component2 = swap;
    876 }
    877
    878 /* init permtovarcomp[p] to component of first moved variable or update the value */
    879 if ( permtovarcomp[p] == -1 )
    880 {
    881 permtovarcomp[p] = component1;
    882 representative = component1;
    883 }
    884 else
    885 {
    886 permtovarcomp[p] = SCIPdisjointsetFind(componentstovar, permtovarcomp[p]);
    887 representative = permtovarcomp[p];
    888 }
    889
    890 /* merge both components if they differ */
    891 if ( component1 != component2 )
    892 {
    893 SCIPdisjointsetUnion(componentstovar, component1, component2, TRUE);
    894 --(*ncomponents);
    895 }
    896
    897 /* possibly merge new component and permvartocom[p] and ensure the latter
    898 * to have the smallest value */
    899 if ( representative != component1 && representative != component2 )
    900 {
    901 if ( representative > component1 )
    902 {
    903 SCIPdisjointsetUnion(componentstovar, component1, representative, TRUE);
    904 permtovarcomp[p] = component1;
    905 }
    906 else
    907 SCIPdisjointsetUnion(componentstovar, representative, component1, TRUE);
    908 --(*ncomponents);
    909 }
    910 else if ( representative > component1 )
    911 {
    912 assert( representative == component2 );
    913 permtovarcomp[p] = component1;
    914 }
    915 }
    916 }
    917
    918 /* reduce number of components by singletons */
    919 if ( (*vartocomponent)[i] == -1 )
    920 --(*ncomponents);
    921 }
    922 assert( *ncomponents > 0 );
    923
    924 /* update permvartocomp array to final variable representatives */
    925 for (p = 0; p < nperms; ++p)
    926 permtovarcomp[p] = SCIPdisjointsetFind(componentstovar, permtovarcomp[p]);
    927
    928 /* init components array by trivial natural order of permutations */
    929 SCIP_CALL( SCIPallocBlockMemoryArray(scip, components, nperms) );
    930 for (p = 0; p < nperms; ++p)
    931 (*components)[p] = p;
    932
    933 /* get correct order of components array */
    934 SCIPsortIntInt(permtovarcomp, *components, nperms);
    935
    936 /* determine componentbegins and store components for each permutation */
    937 SCIP_CALL( SCIPallocBlockMemoryArray(scip, componentbegins, *ncomponents + 1) );
    938 SCIP_CALL( SCIPallocBufferArray(scip, &permtocomponent, nperms) );
    939
    940 (*componentbegins)[0] = 0;
    941 permtocomponent[(*components)[0]] = 0;
    942 idx = 0;
    943
    944 for (p = 1; p < nperms; ++p)
    945 {
    946 if ( permtovarcomp[p] > permtovarcomp[p - 1] )
    947 (*componentbegins)[++idx] = p;
    948
    949 assert( (*components)[p] >= 0 );
    950 assert( (*components)[p] < nperms );
    951 permtocomponent[(*components)[p]] = idx;
    952 }
    953 assert( *ncomponents == idx + 1 );
    954 (*componentbegins)[++idx] = nperms;
    955
    956 /* determine vartocomponent */
    957 for (i = 0; i < npermvars; ++i)
    958 {
    959 int permidx;
    960 permidx = (*vartocomponent)[i];
    961 assert( -1 <= permidx && permidx < nperms );
    962
    963 if ( permidx != -1 )
    964 {
    965 assert( 0 <= permtocomponent[permidx] );
    966 assert( permtocomponent[permidx] < *ncomponents );
    967
    968 (*vartocomponent)[i] = permtocomponent[permidx];
    969 }
    970 }
    971
    972 /* init componentblocked */
    973 SCIP_CALL( SCIPallocBlockMemoryArray(scip, componentblocked, *ncomponents) );
    974 for (i = 0; i < *ncomponents; ++i)
    975 (*componentblocked)[i] = 0;
    976
    977 SCIPfreeBufferArray(scip, &permtocomponent);
    978 SCIPfreeBufferArray(scip, &permtovarcomp);
    979 SCIPdisjointsetFree(&componentstovar, SCIPblkmem(scip));
    980
    981#ifdef SCIP_OUTPUT
    982 printf("number of components: %d\n", *ncomponents);
    983 for (i = 0; i < *ncomponents; ++i)
    984 {
    985 printf("Component %d contains the following permutations:\n\t", i);
    986 for (p = (*componentbegins)[i]; p < (*componentbegins)[i + 1]; ++p)
    987 {
    988 printf("%d, ", (*components)[p]);
    989 }
    990 printf("\n");
    991 }
    992#endif
    993
    994 return SCIP_OKAY;
    995}
    996
    997
    998/** generate variable matrix for orbitope constraint handler
    999 *
    1000 * @pre if storelexorder is TRUE, then the permutations define an orbitope
    1001 */
    1003 SCIP* scip, /**< SCIP instance */
    1004 SCIP_VAR**** vars, /**< pointer to matrix of orbitope variables */
    1005 int nrows, /**< number of rows of orbitope */
    1006 int ncols, /**< number of columns of orbitope */
    1007 SCIP_VAR** permvars, /**< superset of variables that are contained in orbitope */
    1008 int npermvars, /**< number of variables in permvars array */
    1009 int** orbitopevaridx, /**< permuted index table of variables in permvars that are contained in orbitope */
    1010 int* columnorder, /**< permutation to reorder column of orbitopevaridx */
    1011 int* nusedelems, /**< array storing how often an element was used in the orbitope */
    1012 SCIP_Shortbool* rowisbinary, /**< array encoding whether a row contains only binary variables (or NULL) */
    1013 SCIP_Bool* infeasible, /**< pointer to store whether the potential orbitope is not an orbitope */
    1014 SCIP_Bool storelexorder, /**< whether the lexicographic order induced by the orbitope shall be stored */
    1015 int** lexorder, /**< pointer to array storing the lexorder (or NULL) */
    1016 int* nvarsorder, /**< pointer to store number of variables in lexorder (or NULL) */
    1017 int* maxnvarsorder /**< pointer to store maximum number of variables in lexorder (or NULL) */
    1018 )
    1019{
    1020 int nfilledcols = 0;
    1021 int curcolumn;
    1022 int i;
    1023 int cnt;
    1024 int nvarsorderold = 0;
    1025
    1026 assert( vars != NULL );
    1027 assert( nrows > 0 );
    1028 assert( ncols > 0 );
    1029 assert( permvars != NULL );
    1030 assert( npermvars > 0 );
    1031 assert( orbitopevaridx != NULL );
    1032 assert( columnorder != NULL );
    1033 assert( nusedelems != NULL );
    1034 assert( infeasible != NULL );
    1035 assert( ! storelexorder || lexorder != NULL );
    1036 assert( ! storelexorder || nvarsorder != NULL );
    1037 assert( ! storelexorder || maxnvarsorder != NULL );
    1038
    1039 /* possibly store lexicographic order defined by orbitope
    1040 *
    1041 * position (i,j) of orbitope has position nrows * j + i in lexicographic order
    1042 */
    1043 if ( storelexorder )
    1044 {
    1045 assert( *nvarsorder == *maxnvarsorder );
    1046 assert( lexorder != NULL );
    1047
    1048 *maxnvarsorder += nrows * ncols;
    1049 nvarsorderold = *nvarsorder;
    1050
    1051 if ( *lexorder == NULL )
    1052 {
    1053 SCIP_CALL( SCIPallocBlockMemoryArray(scip, lexorder, *maxnvarsorder) );
    1054 }
    1055 else
    1056 {
    1057 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, lexorder, *nvarsorder, *maxnvarsorder) );
    1058 }
    1059 }
    1060
    1061 curcolumn = ncols - 1;
    1062
    1063 /* start filling vars matrix with the right-most column w.r.t. columnorder */
    1064 while ( curcolumn >= 0 && columnorder[curcolumn] >= 0 && ! *infeasible )
    1065 {
    1066 cnt = 0;
    1067 for (i = 0; i < nrows; ++i)
    1068 {
    1069 /* skip rows containing non-binary variables */
    1070 if ( rowisbinary != NULL && ! rowisbinary[i] )
    1071 continue;
    1072
    1073 assert( 0 <= orbitopevaridx[i][curcolumn] && orbitopevaridx[i][curcolumn] < npermvars );
    1074 assert( SCIPvarIsBinary(permvars[orbitopevaridx[i][curcolumn]]) );
    1075
    1076 /* elements in first column of orbitope have to appear exactly once in the orbitope */
    1077 if ( nfilledcols == 0 && nusedelems[orbitopevaridx[i][curcolumn]] > 1 )
    1078 {
    1079 *infeasible = TRUE;
    1080 assert( ! storelexorder );
    1081 break;
    1082 }
    1083
    1084 if ( storelexorder )
    1085 {
    1086 (*lexorder)[nvarsorderold + nrows * nfilledcols + cnt] = orbitopevaridx[i][curcolumn];
    1087 ++(*nvarsorder);
    1088 }
    1089 (*vars)[cnt++][nfilledcols] = permvars[orbitopevaridx[i][curcolumn]];
    1090 }
    1091 --curcolumn;
    1092 ++nfilledcols;
    1093 }
    1094
    1095 /* There are three possibilities for the structure of columnorder:
    1096 * 1) [0, 1, -1, -1, ..., -1]
    1097 * 2) [0, 1, 1, 1, ..., 1]
    1098 * 3) [0, 1, -1, -1, ...., -1, 1, 1, ..., 1]
    1099 */
    1100 /* Either we are in case 1) or case 3), or all columns should have been added to vars in case 2) */
    1101 assert( curcolumn > 1 || (curcolumn < 0 && nfilledcols == ncols) );
    1102
    1103 if ( curcolumn > 1 && ! *infeasible )
    1104 {
    1105 /* add column with columnorder 1 to vars */
    1106 cnt = 0;
    1107 for (i = 0; i < nrows; ++i)
    1108 {
    1109 /* skip rows containing non-binary variables*/
    1110 if ( rowisbinary != NULL && ! rowisbinary[i] )
    1111 continue;
    1112
    1113 assert( orbitopevaridx[i][1] < npermvars );
    1114 assert( SCIPvarIsBinary(permvars[orbitopevaridx[i][1]]) );
    1115
    1116 if ( storelexorder )
    1117 {
    1118 (*lexorder)[nvarsorderold + nrows * nfilledcols + cnt] = orbitopevaridx[i][1];
    1119 ++(*nvarsorder);
    1120 }
    1121 (*vars)[cnt++][nfilledcols] = permvars[orbitopevaridx[i][1]];
    1122 }
    1123 ++nfilledcols;
    1124
    1125 /* add column with columnorder 0 to vars */
    1126 cnt = 0;
    1127 for (i = 0; i < nrows; ++i)
    1128 {
    1129 /* skip rows containing non-binary variables*/
    1130 if ( rowisbinary != NULL && ! rowisbinary[i] )
    1131 continue;
    1132
    1133 assert( orbitopevaridx[i][0] < npermvars );
    1134 assert( SCIPvarIsBinary(permvars[orbitopevaridx[i][0]]) );
    1135
    1136 if ( storelexorder )
    1137 {
    1138 (*lexorder)[nvarsorderold + nrows * nfilledcols + cnt] = orbitopevaridx[i][0];
    1139 ++(*nvarsorder);
    1140 }
    1141 (*vars)[cnt++][nfilledcols] = permvars[orbitopevaridx[i][0]];
    1142 }
    1143 ++nfilledcols;
    1144
    1145 /* add columns with a negative column order to vars */
    1146 if ( nfilledcols < ncols )
    1147 {
    1148 assert( ncols > 2 );
    1149
    1150 curcolumn = 2;
    1151 while ( nfilledcols < ncols && ! *infeasible )
    1152 {
    1153 assert( columnorder[curcolumn] < 0 );
    1154
    1155 cnt = 0;
    1156 for (i = 0; i < nrows; ++i)
    1157 {
    1158 /* skip rows containing non-binary variables*/
    1159 if ( rowisbinary != NULL && ! rowisbinary[i] )
    1160 continue;
    1161
    1162 assert( orbitopevaridx[i][curcolumn] < npermvars );
    1163 assert( SCIPvarIsBinary(permvars[orbitopevaridx[i][curcolumn]]) );
    1164
    1165 /* elements in last column of orbitope have to appear exactly once in the orbitope */
    1166 if ( nfilledcols == ncols - 1 && nusedelems[orbitopevaridx[i][curcolumn]] > 1 )
    1167 {
    1168 *infeasible = TRUE;
    1169 assert( ! storelexorder );
    1170 break;
    1171 }
    1172
    1173 if ( storelexorder )
    1174 {
    1175 (*lexorder)[nvarsorderold + nrows * nfilledcols + cnt] = orbitopevaridx[i][curcolumn];
    1176 ++(*nvarsorder);
    1177 }
    1178 (*vars)[cnt++][nfilledcols] = permvars[orbitopevaridx[i][curcolumn]];
    1179 }
    1180 ++curcolumn;
    1181 ++nfilledcols;
    1182 }
    1183 }
    1184 }
    1185
    1186 return SCIP_OKAY;
    1187}
    1188
    1189
    1190/** checks whether an orbitope is a packing or partitioning orbitope; if npprows != NULL,
    1191 * count how many rows are contained in packing/partitioning constraints
    1192 */
    1194 SCIP* scip, /**< SCIP data structure */
    1195 SCIP_VAR*** vars, /**< variable matrix of orbitope constraint */
    1196 int nrows, /**< pointer to number of rows of variable matrix */
    1197 int ncols, /**< number of columns of variable matrix */
    1198 SCIP_Bool** pprows, /**< pointer to store which rows are are contained in
    1199 * packing/partitioning constraints or NULL if not needed */
    1200 int* npprows, /**< pointer to store how many rows are contained
    1201 * in packing/partitioning constraints or NULL if not needed */
    1202 SCIP_ORBITOPETYPE* type /**< pointer to store type of orbitope constraint after strengthening */
    1203 )
    1204{
    1205 SCIP_CONSHDLR* setppcconshdlr;
    1206 SCIP_CONS** setppcconss;
    1207 int nsetppcconss;
    1208 int* covered;
    1209 int nprobvars;
    1210 int* rowidxvar;
    1211 int* rowcoveragesetppc;
    1212 int* rowsinsetppc;
    1213 int ncovered;
    1214 int ncoveredpart;
    1215 int i;
    1216 int j;
    1217 int c;
    1218
    1219 assert( scip != NULL );
    1220 assert( vars != NULL );
    1221 assert( vars != NULL );
    1222 assert( nrows > 0 );
    1223 assert( ncols > 0 );
    1224 assert( type != NULL );
    1225
    1226 *type = SCIP_ORBITOPETYPE_FULL;
    1227 if ( npprows != NULL )
    1228 *npprows = 0;
    1229
    1230 setppcconshdlr = SCIPfindConshdlr(scip, "setppc");
    1231 if ( setppcconshdlr == NULL )
    1232 return SCIP_OKAY;
    1233
    1234 setppcconss = SCIPconshdlrGetConss(setppcconshdlr);
    1235 nsetppcconss = SCIPconshdlrGetNConss(setppcconshdlr);
    1236
    1237 /* we can terminate early if there are not sufficiently many setppc conss
    1238 * (for orbitopes treating a full component, we might allow to remove rows
    1239 * not contained in setppc cons; for this reason we need the second check)
    1240 */
    1241 if ( nsetppcconss == 0 || (nsetppcconss < nrows && npprows == NULL ))
    1242 return SCIP_OKAY;
    1243 assert( setppcconss != NULL );
    1244
    1245 /* whether a row is contained in packing/partitioning constraint */
    1246 SCIP_CALL( SCIPallocClearBufferArray(scip, &covered, nrows) );
    1247 ncovered = 0;
    1248 ncoveredpart = 0;
    1249
    1250 nprobvars = SCIPgetNTotalVars(scip);
    1251
    1252 /* array storing index of orbitope row a variable is contained in */
    1253 SCIP_CALL( SCIPallocBufferArray(scip, &rowidxvar, nprobvars) );
    1254
    1255 for (i = 0; i < nprobvars; ++i)
    1256 rowidxvar[i] = -1;
    1257
    1258 for (i = 0; i < nrows; ++i)
    1259 {
    1260 for (j = 0; j < ncols; ++j)
    1261 {
    1262 assert( 0 <= SCIPvarGetIndex(vars[i][j]) && SCIPvarGetIndex(vars[i][j]) < nprobvars );
    1263 rowidxvar[SCIPvarGetIndex(vars[i][j])] = i;
    1264 }
    1265 }
    1266
    1267 /* storage for number of vars per row that are contained in current setppc cons and
    1268 * labels of rows intersecting with current setppc cons
    1269 */
    1270 SCIP_CALL( SCIPallocCleanBufferArray(scip, &rowcoveragesetppc, nrows) );
    1271 SCIP_CALL( SCIPallocClearBufferArray(scip, &rowsinsetppc, nrows) );
    1272
    1273 /* iterate over set packing and partitioning constraints and check whether the constraint's
    1274 * support is a row r of the orbitope (covered[r] = 2) or contains row r (covered[r] = 1)
    1275 *
    1276 * @todo Check whether we can improve the following loop by using a hash value to check
    1277 * whether the setppccons intersects the orbitope matrix
    1278 */
    1279 for (c = 0; c < nsetppcconss && ncoveredpart < ncols; ++c)
    1280 {
    1281 int nsetppcvars;
    1282 SCIP_VAR** setppcvars;
    1283 int nrowintersect = 0;
    1284 int nvarsinorbitope;
    1285
    1286 /* skip covering constraints */
    1287 if ( SCIPgetTypeSetppc(scip, setppcconss[c]) == SCIP_SETPPCTYPE_COVERING )
    1288 continue;
    1289
    1290 /* get number of set packing/partitioning variables */
    1291 nsetppcvars = SCIPgetNVarsSetppc(scip, setppcconss[c]);
    1292
    1293 /* constraint does not contain enough variables */
    1294 if ( nsetppcvars < ncols )
    1295 continue;
    1296
    1297 setppcvars = SCIPgetVarsSetppc(scip, setppcconss[c]);
    1298 assert( setppcvars != NULL );
    1299
    1300 /* upper bound on variables potentially contained in orbitope */
    1301 nvarsinorbitope = nsetppcvars;
    1302
    1303 /* for each setppc var, check whether it appears in a row of the orbitope and store
    1304 * for each row the number of such variables; can be terminated early, if less than
    1305 * ncols variables are contained in the orbitope
    1306 */
    1307 for (i = 0; i < nsetppcvars && nvarsinorbitope >= ncols; ++i)
    1308 {
    1309 SCIP_VAR* var;
    1310 int idx;
    1311 int rowidx;
    1312
    1313 var = setppcvars[i];
    1314 idx = SCIPvarGetIndex(var);
    1315
    1316 assert( 0 <= idx && idx < nprobvars );
    1317
    1318 rowidx = rowidxvar[idx];
    1319
    1320 /* skip variables not contained in the orbitope */
    1321 if ( rowidx < 0 )
    1322 {
    1323 --nvarsinorbitope;
    1324 continue;
    1325 }
    1326
    1327 /* skip variables corresponding to already treated rows */
    1328 if ( covered[rowidx] == 2 || (covered[rowidx] == 1 && (nsetppcvars > ncols || nrowintersect > 1)) )
    1329 {
    1330 --nvarsinorbitope;
    1331 continue;
    1332 }
    1333
    1334 /* store information which rows intersect the setppc cons's support */
    1335 if ( rowcoveragesetppc[rowidx] == 0 )
    1336 rowsinsetppc[nrowintersect++] = rowidx;
    1337 ++(rowcoveragesetppc[rowidx]);
    1338
    1339 /* we can stop early if not enough variables are left to completely cover one of the rows that
    1340 * intersect the setppc cons
    1341 */
    1342 if ( nsetppcvars - nrowintersect < ncols - 1 )
    1343 break;
    1344 }
    1345
    1346 /* store whether rows coincide with set partitioning cons's support or whether
    1347 * row is covered by a set packing/partitioning cons's support
    1348 */
    1349 if ( SCIPgetTypeSetppc(scip, setppcconss[c]) == SCIP_SETPPCTYPE_PARTITIONING
    1350 && nrowintersect == 1 && rowcoveragesetppc[rowsinsetppc[0]] == ncols && nsetppcvars == ncols )
    1351 {
    1352 if ( covered[rowsinsetppc[0]] == 1 )
    1353 --ncovered;
    1354 covered[rowsinsetppc[0]] = 2;
    1355 ++ncoveredpart;
    1356 ++ncovered;
    1357 }
    1358 else
    1359 {
    1360 for (i = 0; i < nrowintersect; ++i)
    1361 {
    1362 if ( covered[rowsinsetppc[i]] == 0 && rowcoveragesetppc[rowsinsetppc[i]] >= ncols )
    1363 {
    1364 covered[rowsinsetppc[i]] = 1;
    1365 ++ncovered;
    1366 }
    1367 }
    1368 }
    1369
    1370 /* reset data */
    1371 for (i = 0; i < nrowintersect; ++i)
    1372 rowcoveragesetppc[rowsinsetppc[i]] = 0;
    1373 }
    1374
    1375 /* check type of orbitope */
    1376 if ( ncovered == nrows )
    1377 {
    1378 if ( ncoveredpart == nrows )
    1380 else
    1382 }
    1383
    1384 if ( npprows != NULL )
    1385 *npprows = ncovered;
    1386
    1387 if ( pprows != NULL )
    1388 {
    1389 SCIP_CALL( SCIPallocBlockMemoryArray(scip, pprows, nrows) );
    1390 for (i = 0; i < nrows; ++i)
    1391 (*pprows)[i] = covered[i] > 0 ? 1 : 0;
    1392 }
    1393
    1394 SCIPfreeBufferArray(scip, &rowsinsetppc);
    1395 SCIPfreeCleanBufferArray(scip, &rowcoveragesetppc);
    1396 SCIPfreeBufferArray(scip, &rowidxvar);
    1397 SCIPfreeBufferArray(scip, &covered);
    1398
    1399 return SCIP_OKAY;
    1400}
    1401
    1402/** checks whether a (signed) permutation is an involution */
    1403static
    1405 int* perm, /**< permutation */
    1406 int permlen, /**< number of original (non-negated) variables in a permutation */
    1407 SCIP_Bool* isinvolution, /**< pointer to store whether perm is an involution */
    1408 int* ntwocycles /**< pointer to store number of 2-cycles in an involution */
    1409 )
    1410{
    1411 int v;
    1412
    1413 assert( perm != NULL );
    1414 assert( permlen > 0 );
    1415 assert( isinvolution != NULL );
    1416 assert( ntwocycles != NULL );
    1417
    1418 *ntwocycles = 0;
    1419 *isinvolution = TRUE;
    1420 for (v = 0; v < permlen && *isinvolution; ++v)
    1421 {
    1422 /* do not handle variables twice */
    1423 if ( perm[v] <= v )
    1424 continue;
    1425
    1426 /* detect two cycles */
    1427 if ( perm[perm[v]] == v )
    1428 ++(*ntwocycles);
    1429 else
    1430 *isinvolution = FALSE;
    1431 }
    1432
    1433 return SCIP_OKAY;
    1434}
    1435
    1436/** checks whether selected permutations define orbitopal symmetries */
    1437static
    1439 SCIP* scip, /**< SCIP pointer */
    1440 int** perms, /**< array of permutations */
    1441 int* selectedperms, /**< indices of permutations in perm that shall be considered */
    1442 int nselectedperms, /**< number of permutations in selectedperms */
    1443 int permlen, /**< number of variables in a permutation */
    1444 int nrows, /**< number of rows of potential orbitopal symmetries */
    1445 SCIP_Bool* success, /**< pointer to store if orbitopal symmetries could be found */
    1446 int**** matrices, /**< pointer to store matrices of orbitopal symmetries */
    1447 int** ncols, /**< pointer to store number of columns of matrices in matrices */
    1448 int* nmatrices /**< pointer to store the number of matrices in matrices */
    1449 )
    1450{ /*lint --e{771}*/
    1451 SCIP_DISJOINTSET* conncomps;
    1452 SCIP_DISJOINTSET* compcolors;
    1453 int* complastperm;
    1454 int* permstoconsider;
    1455 int* colorbegins;
    1456 int* compidx;
    1457 int* colidx;
    1458 int* varidx;
    1459 int* degrees;
    1460 int* perm;
    1461 int nposdegree = 0;
    1462 int npermstoconsider;
    1463 int colorrepresentative1 = -1;
    1464 int colorrepresentative2 = -1;
    1465 int elemtomove;
    1466 int ncurcols;
    1467 int curcomp1;
    1468 int curcomp2;
    1469 int curdeg1;
    1470 int curdeg2;
    1471 int curcolor1;
    1472 int curcolor2;
    1473 int ncolors;
    1474 int cnt;
    1475 int c;
    1476 int p;
    1477 int v;
    1478 int w;
    1479
    1480 assert( scip != NULL );
    1481 assert( perms != NULL );
    1482 assert( selectedperms != NULL );
    1483 assert( nselectedperms >= 0 );
    1484 assert( permlen > 0 );
    1485 assert( nrows > 0 || nselectedperms == 0 );
    1486 assert( success != NULL );
    1487 assert( matrices != NULL );
    1488 assert( ncols != NULL );
    1489 assert( nmatrices != NULL );
    1490
    1491 /* initialize data */
    1492 *success = TRUE;
    1493 *matrices = NULL;
    1494 *ncols = NULL;
    1495 *nmatrices = 0;
    1496
    1497 /* we have found the empty set of orbitopal symmetries */
    1498 if ( nselectedperms == 0 )
    1499 return SCIP_OKAY;
    1500
    1501 /* build a graph to encode potential orbitopal symmetries
    1502 *
    1503 * The 2-cycles of a permutation define a set of edges that need to be added simultaneously. We encode
    1504 * this as a disjoint set data structure to only encode the connected components of the graph. To ensure
    1505 * correctness, we keep track of the degrees of each node and extend a component by a permutation only if
    1506 * all nodes to be extended have the same degree. We also make sure that each connected component is a
    1507 * path. Although this might not detect all orbitopal symmetries, it seems to cover most of the cases when
    1508 * computing symmetries using bliss. We also keep track of which variables are affected by the same
    1509 * permutations by coloring the connected components.
    1510 */
    1511 SCIP_CALL( SCIPcreateDisjointset(scip, &conncomps, permlen) );
    1512 SCIP_CALL( SCIPcreateDisjointset(scip, &compcolors, permlen) );
    1513 SCIP_CALL( SCIPallocClearBufferArray(scip, &degrees, permlen) );
    1514 SCIP_CALL( SCIPallocBufferArray(scip, &complastperm, permlen) );
    1515 for (v = 0; v < permlen; ++v)
    1516 complastperm[v] = -1;
    1517
    1518 /* try to add edges of permutations to graph */
    1519 for (p = 0; p < nselectedperms; ++p)
    1520 {
    1521 perm = perms[selectedperms[p]];
    1522 curdeg1 = -1;
    1523 curdeg2 = -1;
    1524
    1525 /* check whether all potential edges can be added */
    1526 for (v = 0; v < permlen; ++v)
    1527 {
    1528 /* treat each cycle exactly once */
    1529 if ( perm[v] <= v )
    1530 continue;
    1531 w = perm[v];
    1532
    1533 curcomp1 = SCIPdisjointsetFind(conncomps, v);
    1534 curcomp2 = SCIPdisjointsetFind(conncomps, w);
    1535
    1536 /* an edge is not allowed to connect nodes from the same connected component */
    1537 if ( curcomp1 == curcomp2 )
    1538 break;
    1539
    1540 /* permutation p is not allowed to add two edges to the same connected component */
    1541 if ( complastperm[curcomp1] == p || complastperm[curcomp2] == p )
    1542 break;
    1543
    1544 /* get colors of nodes */
    1545 curcolor1 = SCIPdisjointsetFind(compcolors, v);
    1546 curcolor2 = SCIPdisjointsetFind(compcolors, w);
    1547
    1548 /* an edge is not allowed to connect two nodes with the same color */
    1549 if ( curcolor1 == curcolor2 )
    1550 break;
    1551
    1552 if ( curdeg1 == -1 )
    1553 {
    1554 assert( curdeg2 == -1 );
    1555
    1556 curdeg1 = degrees[v];
    1557 curdeg2 = degrees[w];
    1558 colorrepresentative1 = curcolor1;
    1559 colorrepresentative2 = curcolor2;
    1560
    1561 /* stop, we will generate a vertex with degree 3 */
    1562 if ( curdeg1 == 2 || curdeg2 == 2 )
    1563 break;
    1564 }
    1565 else
    1566 {
    1567 /* check whether nodes have compatible degrees */
    1568 if ( ! ((curdeg1 == degrees[v] && curdeg2 == degrees[w])
    1569 || (curdeg1 == degrees[w] && curdeg2 == degrees[v])) )
    1570 break;
    1571 assert( colorrepresentative1 >= 0 );
    1572 assert( colorrepresentative2 >= 0 || curdeg2 == -1 );
    1573
    1574 /* check whether all components have compatible colors */
    1575 if ( curdeg1 > 0 && curcolor1 != colorrepresentative1 && curcolor2 != colorrepresentative1 )
    1576 break;
    1577 if ( curdeg2 > 0 && curcolor1 != colorrepresentative2 && curcolor2 != colorrepresentative2 )
    1578 break;
    1579 }
    1580
    1581 /* store that permutation p extends the connected components */
    1582 complastperm[curcomp1] = p;
    1583 complastperm[curcomp2] = p;
    1584 }
    1585
    1586 /* terminate if not all edges can be added */
    1587 if ( v < permlen )
    1588 {
    1589 *success = FALSE;
    1590 goto FREEMEMORY;
    1591 }
    1592 assert( curdeg1 >= 0 && curdeg2 >= 0 );
    1593
    1594 /* add edges to graph */
    1595 for (v = 0; v < permlen; ++v)
    1596 {
    1597 /* treat each cycle exactly once */
    1598 if ( perm[v] <= v )
    1599 continue;
    1600 w = perm[v];
    1601
    1602#ifndef NDEBUG
    1603 curcomp1 = SCIPdisjointsetFind(conncomps, v);
    1604 curcomp2 = SCIPdisjointsetFind(conncomps, w);
    1605 assert( curcomp1 != curcomp2 );
    1606#endif
    1607
    1608 /* add edge */
    1609 SCIPdisjointsetUnion(conncomps, v, w, FALSE);
    1610 ++degrees[v];
    1611 ++degrees[w];
    1612
    1613 /* possibly update colors */
    1614 curcolor1 = SCIPdisjointsetFind(compcolors, v);
    1615 curcolor2 = SCIPdisjointsetFind(compcolors, w);
    1616
    1617 if ( curcolor1 != curcolor2 )
    1618 {
    1619 /* coverity[negative_returns] */
    1620 SCIPdisjointsetUnion(compcolors, colorrepresentative1, v, TRUE);
    1621 SCIPdisjointsetUnion(compcolors, colorrepresentative1, w, TRUE);
    1622 }
    1623 }
    1624 }
    1625
    1626 /* find non-trivial components */
    1627 for (v = 0; v < permlen; ++v)
    1628 {
    1629 if ( degrees[v] > 0 )
    1630 ++nposdegree;
    1631 }
    1632
    1633 SCIP_CALL( SCIPallocBufferArray(scip, &compidx, nposdegree) );
    1634 SCIP_CALL( SCIPallocBufferArray(scip, &colidx, nposdegree) );
    1635 SCIP_CALL( SCIPallocBufferArray(scip, &varidx, nposdegree) );
    1636
    1637 for (v = 0, w = 0; v < permlen; ++v)
    1638 {
    1639 if ( degrees[v] > 0 )
    1640 {
    1641 compidx[w] = SCIPdisjointsetFind(conncomps, v);
    1642 colidx[w] = SCIPdisjointsetFind(compcolors, v);
    1643#ifndef NDEBUG
    1644 if ( w > 0 && compidx[w] == compidx[w-1] )
    1645 assert( colidx[w] == colidx[w-1]);
    1646#endif
    1647 varidx[w++] = v;
    1648 }
    1649 }
    1650 assert( w == nposdegree );
    1651
    1652 /* sort variable indices: first by colors, then by components */
    1653 SCIP_CALL( SCIPallocBufferArray(scip, &colorbegins, permlen + 1) );
    1654
    1655 SCIPsortIntIntInt(colidx, compidx, varidx, nposdegree);
    1656 w = 0;
    1657 ncolors = 0;
    1658 colorbegins[0] = 0;
    1659 for (v = 1; v < nposdegree; ++v)
    1660 {
    1661 if ( colidx[v] != colidx[w] )
    1662 {
    1663 SCIPsortIntInt(&compidx[w], &varidx[w], v - w);
    1664 colorbegins[++ncolors] = v;
    1665 w = v;
    1666 }
    1667 }
    1668 SCIPsortIntInt(&compidx[w], &varidx[w], nposdegree - w);
    1669 colorbegins[++ncolors] = nposdegree;
    1670
    1671 /* try to find the correct order of variable indices per color class */
    1672 SCIP_CALL( SCIPallocBufferArray(scip, &permstoconsider, nselectedperms) );
    1673
    1674 SCIP_CALL( SCIPallocBlockMemoryArray(scip, matrices, ncolors) );
    1675 SCIP_CALL( SCIPallocBlockMemoryArray(scip, ncols, ncolors) );
    1676 *nmatrices = ncolors;
    1677
    1678 for (c = 0; c < ncolors; ++c)
    1679 {
    1680 /* find an element in the first connected component with degree 1 */
    1681 for (v = colorbegins[c]; compidx[v] == compidx[colorbegins[c]]; ++v)
    1682 {
    1683 assert( v < nposdegree ); /* there should be a node of degree 1 */
    1684
    1685 if ( degrees[varidx[v]] == 1 )
    1686 break;
    1687 }
    1688 assert( compidx[v] == compidx[colorbegins[c]] );
    1689 elemtomove = varidx[v];
    1690
    1691 /* find the permutations affecting the variables in the first connected component */
    1692 npermstoconsider = 0;
    1693 for (p = 0; p < nselectedperms; ++p)
    1694 {
    1695 perm = perms[selectedperms[p]];
    1696 for (v = colorbegins[c]; v < nposdegree && compidx[v] == compidx[colorbegins[c]]; ++v)
    1697 {
    1698 if ( perm[varidx[v]] != varidx[v] )
    1699 {
    1700 permstoconsider[npermstoconsider++] = selectedperms[p];
    1701 break;
    1702 }
    1703 }
    1704 }
    1705
    1706 /* allocate memory for matrix */
    1707 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*matrices)[c], nrows) );
    1708 (*ncols)[c] = npermstoconsider + 1;
    1709 for (p = 0; p < nrows; ++p)
    1710 {
    1711 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*matrices)[c][p], (*ncols)[c]) );
    1712 }
    1713
    1714 /* find a permutation that moves the degree-1 element and iteratively extend this to a matrix */
    1715 assert( degrees[elemtomove] == 1 );
    1716
    1717 /* find the first and second column */
    1718 for (p = 0; p < npermstoconsider; ++p)
    1719 {
    1720 perm = perms[permstoconsider[p]];
    1721 if ( perm[elemtomove] != elemtomove )
    1722 break;
    1723 }
    1724 assert( p < npermstoconsider );
    1725
    1726 /* elements moved by perm that have degree 1 are in the first column */
    1727 for (v = 0, cnt = 0; v < permlen; ++v)
    1728 {
    1729 if ( perm[v] > v ) /*lint !e771*/
    1730 {
    1731 if ( degrees[v] == 1 )
    1732 {
    1733 (*matrices)[c][cnt][0] = v;
    1734 (*matrices)[c][cnt++][1] = perm[v];
    1735 }
    1736 else
    1737 {
    1738 (*matrices)[c][cnt][0] = perm[v];
    1739 (*matrices)[c][cnt++][1] = v;
    1740 }
    1741 }
    1742 }
    1743
    1744 /* if the selected permutation do not form orbitopal symmetries */
    1745 if ( cnt < nrows )
    1746 {
    1747 *success = FALSE;
    1748 for (p = nrows - 1; p >= 0; --p)
    1749 {
    1750 SCIPfreeBufferArray(scip, &(*matrices)[c][p]);
    1751 }
    1752 SCIPfreeBlockMemoryArray(scip, &(*matrices)[c], nrows);
    1753 SCIPfreeBlockMemoryArray(scip, matrices, ncolors);
    1754 SCIPfreeBlockMemoryArray(scip, ncols, ncolors);
    1755 *matrices = NULL;
    1756 *ncols = NULL;
    1757 goto FREEMOREMEMORY;
    1758 }
    1759 assert( cnt == nrows );
    1760
    1761 /* remove p from the list of permutations to be considered */
    1762 permstoconsider[p] = permstoconsider[--npermstoconsider];
    1763
    1764 ncurcols = 1;
    1765 while ( npermstoconsider > 0 )
    1766 {
    1767 elemtomove = (*matrices)[c][0][ncurcols];
    1768
    1769 /* find permutation moving the elemtomove */
    1770 for (p = 0; p < npermstoconsider; ++p)
    1771 {
    1772 perm = perms[permstoconsider[p]];
    1773 if ( perm[elemtomove] != elemtomove )
    1774 break;
    1775 }
    1776 assert( p < npermstoconsider );
    1777
    1778 /* extend matrix */
    1779 for (v = 0; v < nrows; ++v)
    1780 {
    1781 assert( perm[(*matrices)[c][v][ncurcols]] != (*matrices)[c][v][ncurcols] );
    1782 (*matrices)[c][v][ncurcols + 1] = perm[(*matrices)[c][v][ncurcols]];
    1783 }
    1784 ++ncurcols;
    1785 permstoconsider[p] = permstoconsider[--npermstoconsider];
    1786 }
    1787 }
    1788
    1789 FREEMOREMEMORY:
    1790 SCIPfreeBufferArray(scip, &permstoconsider);
    1791 SCIPfreeBufferArray(scip, &colorbegins);
    1792 SCIPfreeBufferArray(scip, &varidx);
    1793 SCIPfreeBufferArray(scip, &colidx);
    1794 SCIPfreeBufferArray(scip, &compidx);
    1795
    1796 FREEMEMORY:
    1797 SCIPfreeBufferArray(scip, &complastperm);
    1798 SCIPfreeBufferArray(scip, &degrees);
    1799 SCIPfreeDisjointset(scip, &compcolors);
    1800 SCIPfreeDisjointset(scip, &conncomps);
    1801
    1802 return SCIP_OKAY;
    1803}
    1804
    1805/** checks whether two families of orbitopal symmetries define a double lex matrix, and in case of success, generates matrix
    1806 *
    1807 * The columns of matrix1 will serve as the columns of the matrix to be generated, the columns of matrix2 will
    1808 * serve as rows.
    1809 */
    1810static
    1812 SCIP* scip, /**< SCIP pointer */
    1813 int nsymvars, /**< number of variables on which symmetries act */
    1814 int*** matrices1, /**< first list of matrices associated with orbitopal symmetries */
    1815 int nrows1, /**< number of rows of first family of matrices */
    1816 int* ncols1, /**< for each matrix in the first family, its number of columns */
    1817 int nmatrices1, /**< number of matrices in the first family */
    1818 int*** matrices2, /**< second list of matrices associated with orbitopal symmetries */
    1819 int nrows2, /**< number of rows of second family of matrices */
    1820 int* ncols2, /**< for each matrix in the second family, its number of columns */
    1821 int nmatrices2, /**< number of matrices in the second family */
    1822 int*** doublelexmatrix, /**< pointer to store combined matrix */
    1823 int* nrows, /**< pointer to store number of rows in combined matrix */
    1824 int* ncols, /**< pointer to store number of columns in combined matrix */
    1825 int** rowsbegin, /**< pointer to store the begin positions of a new lex subset of rows */
    1826 int** colsbegin, /**< pointer to store the begin positions of a new lex subset of columns */
    1827 SCIP_Bool* success /**< pointer to store whether combined matrix could be generated */
    1828 )
    1829{
    1830 int* idxtomatrix1;
    1831 int* idxtomatrix2;
    1832 int* idxtorow1;
    1833 int* idxtorow2;
    1834 int* idxtocol1;
    1835 int* idxtocol2;
    1836 int* sortvals;
    1837 int elem;
    1838 int mat;
    1839 int col;
    1840 int col2;
    1841 int mat2;
    1842 int cnt;
    1843 int c;
    1844 int d;
    1845 int i;
    1846 int j;
    1847
    1848 assert( scip != NULL );
    1849 assert( nsymvars >= 0 );
    1850 assert( matrices1 != NULL );
    1851 assert( nrows1 > 0 );
    1852 assert( ncols1 != NULL );
    1853 assert( nmatrices1 > 0 );
    1854 assert( matrices2 != NULL );
    1855 assert( nrows2 > 0 || nmatrices2 == 0 );
    1856 assert( ncols2 != NULL );
    1857 assert( nmatrices2 >= 0 );
    1858 assert( doublelexmatrix != NULL );
    1859 assert( nrows != NULL );
    1860 assert( ncols != NULL );
    1861 assert( rowsbegin != NULL );
    1862 assert( colsbegin != NULL );
    1863 assert( success != NULL );
    1864
    1865 /* initialize data */
    1866 *nrows = nrows1;
    1867 *ncols = nrows2;
    1868 *success = TRUE;
    1869
    1870 /* check whether expecteded sizes of matrix match */
    1871 for (j = 0, cnt = 0; j < nmatrices1; ++j)
    1872 cnt += ncols1[j];
    1873 if ( cnt != *ncols )
    1874 {
    1875 *success = FALSE;
    1876 return SCIP_OKAY;
    1877 }
    1878
    1879 for (i = 0, cnt = 0; i < nmatrices2; ++i)
    1880 cnt += ncols2[i];
    1881 if ( cnt != *nrows )
    1882 {
    1883 *success = FALSE;
    1884 return SCIP_OKAY;
    1885 }
    1886
    1887 /* collect information about entries in matrices */
    1888 SCIP_CALL( SCIPallocBufferArray(scip, &idxtomatrix1, nsymvars) );
    1889 SCIP_CALL( SCIPallocBufferArray(scip, &idxtomatrix2, nsymvars) );
    1890 SCIP_CALL( SCIPallocBufferArray(scip, &idxtorow1, nsymvars) );
    1891 SCIP_CALL( SCIPallocBufferArray(scip, &idxtorow2, nsymvars) );
    1892 SCIP_CALL( SCIPallocBufferArray(scip, &idxtocol1, nsymvars) );
    1893 SCIP_CALL( SCIPallocBufferArray(scip, &idxtocol2, nsymvars) );
    1894
    1895 /* use separate loops for efficiency reasons */
    1896 for (i = 0; i < nsymvars; ++i)
    1897 idxtomatrix1[i] = -1;
    1898 for (i = 0; i < nsymvars; ++i)
    1899 idxtomatrix2[i] = -1;
    1900 for (i = 0; i < nsymvars; ++i)
    1901 idxtorow1[i] = -1;
    1902 for (i = 0; i < nsymvars; ++i)
    1903 idxtorow2[i] = -1;
    1904 for (i = 0; i < nsymvars; ++i)
    1905 idxtocol1[i] = -1;
    1906 for (i = 0; i < nsymvars; ++i)
    1907 idxtocol2[i] = -1;
    1908
    1909 for (c = 0; c < nmatrices1; ++c)
    1910 {
    1911 for (i = 0; i < nrows1; ++i)
    1912 {
    1913 for (j = 0; j < ncols1[c]; ++j)
    1914 {
    1915 idxtomatrix1[matrices1[c][i][j]] = c;
    1916 idxtorow1[matrices1[c][i][j]] = i;
    1917 idxtocol1[matrices1[c][i][j]] = j;
    1918 }
    1919 }
    1920 }
    1921 for (c = 0; c < nmatrices2; ++c)
    1922 {
    1923 for (i = 0; i < nrows2; ++i)
    1924 {
    1925 for (j = 0; j < ncols2[c]; ++j)
    1926 {
    1927 idxtomatrix2[matrices2[c][i][j]] = c;
    1928 idxtorow2[matrices2[c][i][j]] = i;
    1929 idxtocol2[matrices2[c][i][j]] = j;
    1930 }
    1931 }
    1932 }
    1933
    1934 /* check whether the variables of the two orbitopes coincide */
    1935 for (i = 0; i < nsymvars; ++i)
    1936 {
    1937 if ( (idxtomatrix1[i] == -1) != (idxtomatrix2[i] == -1) )
    1938 {
    1939 *success = FALSE;
    1940 goto FREEINITMEMORY;
    1941 }
    1942 }
    1943
    1944 /* Find a big matrix such that the columns of this matrix correspond to the columns of matrices in matrices1
    1945 * and the rows of this matrix correspond to the columns of matrices in matrices2. In total, this leads to
    1946 * a matrix of block shape
    1947 *
    1948 * A | B | ... | C
    1949 * D | E | ... | F
    1950 * . | . | | .
    1951 * G | H | ... | I
    1952 *
    1953 * We start by filling the first column of the big matrix by the first column in matrices1. Sort the column
    1954 * according to the matrices in matrices2.
    1955 */
    1956 SCIP_CALL( SCIPallocBufferArray(scip, &sortvals, MAX(*nrows, *ncols)) );
    1957 SCIP_CALL( SCIPallocBlockMemoryArray(scip, doublelexmatrix, *nrows) );
    1958 for (i = 0; i < *nrows; ++i)
    1959 {
    1960 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*doublelexmatrix)[i], *ncols) );
    1961 (*doublelexmatrix)[i][0] = matrices1[0][i][0];
    1962 sortvals[i] = idxtomatrix2[matrices1[0][i][0]];
    1963 }
    1964 SCIPsortIntPtr(sortvals, (void*) (*doublelexmatrix), *nrows);
    1965
    1966 /* check that the first column can be covered by rows of matrices2 */
    1967 cnt = 0;
    1968 for (i = 0; i < nmatrices2; ++i)
    1969 {
    1970 int end;
    1971
    1972 end = cnt + ncols2[i] - 1;
    1973 for (j = cnt; j < end; ++j)
    1974 {
    1975 assert( idxtomatrix2[(*doublelexmatrix)[j][0]] == idxtomatrix2[(*doublelexmatrix)[j + 1][0]] );
    1976 if( idxtorow2[(*doublelexmatrix)[j][0]] != idxtorow2[(*doublelexmatrix)[j + 1][0]] )
    1977 {
    1978 *success = FALSE;
    1979 goto FREEMEMORY;
    1980 }
    1981 }
    1982 }
    1983
    1984 /* fill first row of big matrix */
    1985 mat = idxtomatrix2[(*doublelexmatrix)[0][0]];
    1986 col = idxtocol2[(*doublelexmatrix)[0][0]];
    1987 cnt = 0;
    1988 for (j = 0; j < *ncols; ++j)
    1989 {
    1990 /* skip the entry that is already contained in the first column */
    1991 if ( matrices2[mat][j][col] == (*doublelexmatrix)[0][0] )
    1992 continue;
    1993
    1994 sortvals[cnt++] = idxtomatrix1[matrices2[mat][j][col]];
    1995 (*doublelexmatrix)[0][cnt] = matrices2[mat][j][col];
    1996 }
    1997 assert( cnt == nrows2 - 1);
    1998 SCIPsortIntInt(sortvals, &((*doublelexmatrix)[0][1]), cnt);
    1999
    2000 /* fill the remaining entries of the big matrix */
    2001 for (i = 1; i < *nrows; ++i)
    2002 {
    2003 for (j = 1; j < *ncols; ++j)
    2004 {
    2005 /* get the matrices and column/row of the entry */
    2006 mat = idxtomatrix1[(*doublelexmatrix)[0][j]];
    2007 mat2 = idxtomatrix2[(*doublelexmatrix)[i][0]];
    2008 col = idxtocol1[(*doublelexmatrix)[0][j]];
    2009 col2 = idxtocol2[(*doublelexmatrix)[i][0]];
    2010
    2011 /* find the unique element in the col column of matrix mat and the row column of matrix mat2 */
    2012 /* @todo improve this by first sorting the columns */
    2013 cnt = 0;
    2014 elem = -1;
    2015 for (c = 0; c < *nrows; ++c)
    2016 {
    2017 for (d = 0; d < *ncols; ++d)
    2018 {
    2019 if ( matrices1[mat][c][col] == matrices2[mat2][d][col2] )
    2020 {
    2021 ++cnt;
    2022 elem = matrices1[mat][c][col];
    2023 break;
    2024 }
    2025 }
    2026 }
    2027
    2028 /* stop: the columns do not overlap properly */
    2029 if ( cnt != 1 )
    2030 {
    2031 *success = FALSE;
    2032 goto FREEMEMORY;
    2033 }
    2034 (*doublelexmatrix)[i][j] = elem;
    2035 }
    2036 }
    2037
    2038 /* store begin positions of row and column blocks */
    2039 if ( *success )
    2040 {
    2041 assert( nmatrices2 > 0 );
    2042 SCIP_CALL( SCIPallocBlockMemoryArray(scip, rowsbegin, nmatrices2 + 1) );
    2043 SCIP_CALL( SCIPallocBlockMemoryArray(scip, colsbegin, nmatrices1 + 1) );
    2044 (*rowsbegin)[0] = 0;
    2045 (*colsbegin)[0] = 0;
    2046 for (j = 0; j < nmatrices2; ++j)
    2047 (*rowsbegin)[j + 1] = (*rowsbegin)[j] + ncols2[j];
    2048 for (j = 0; j < nmatrices1; ++j)
    2049 (*colsbegin)[j + 1] = (*colsbegin)[j] + ncols1[j];
    2050 }
    2051
    2052 /* check whether the rows of doublelexmatrix are covered by rows of matrices1 */
    2053 for (i = 0; i < *nrows; ++i)
    2054 {
    2055 for (c = 0; c < nmatrices1; ++c)
    2056 {
    2057 for (j = (*colsbegin)[c]; j < (*colsbegin)[c + 1] - 1; ++j)
    2058 {
    2059 assert( idxtomatrix1[(*doublelexmatrix)[i][j]] == idxtomatrix1[(*doublelexmatrix)[i][j + 1]] );
    2060 if( idxtorow1[(*doublelexmatrix)[i][j]] != idxtorow1[(*doublelexmatrix)[i][j + 1]] )
    2061 {
    2062 *success = FALSE;
    2063 goto FREEMEMORY;
    2064 }
    2065 }
    2066 }
    2067 }
    2068
    2069 /* check whether the columns of doublelexmatrix are covered by rows of matrices1 */
    2070 for (i = 0; i < *ncols; ++i)
    2071 {
    2072 for (c = 0; c < nmatrices2; ++c)
    2073 {
    2074 for (j = (*rowsbegin)[c]; j < (*rowsbegin)[c + 1] - 1; ++j)
    2075 {
    2076 assert( idxtomatrix2[(*doublelexmatrix)[j][i]] == idxtomatrix2[(*doublelexmatrix)[j + 1][i]] );
    2077 if( idxtorow2[(*doublelexmatrix)[j][i]] != idxtorow2[(*doublelexmatrix)[j + 1][i]] )
    2078 {
    2079 *success = FALSE;
    2080 goto FREEMEMORY;
    2081 }
    2082 }
    2083 }
    2084 }
    2085
    2086 FREEMEMORY:
    2087 SCIPfreeBufferArray(scip, &sortvals);
    2088
    2089 if ( !(*success) )
    2090 {
    2091 for (i = *nrows - 1; i >= 0; --i)
    2092 {
    2093 SCIPfreeBlockMemoryArray(scip, &(*doublelexmatrix)[i], *ncols);
    2094 }
    2095 SCIPfreeBlockMemoryArray(scip, doublelexmatrix, *nrows);
    2096 *doublelexmatrix = NULL;
    2097 *rowsbegin = NULL;
    2098 *colsbegin = NULL;
    2099 }
    2100
    2101 FREEINITMEMORY:
    2102 SCIPfreeBufferArray(scip, &idxtocol2);
    2103 SCIPfreeBufferArray(scip, &idxtocol1);
    2104 SCIPfreeBufferArray(scip, &idxtorow2);
    2105 SCIPfreeBufferArray(scip, &idxtorow1);
    2106 SCIPfreeBufferArray(scip, &idxtomatrix2);
    2107 SCIPfreeBufferArray(scip, &idxtomatrix1);
    2108
    2109 return SCIP_OKAY;
    2110}
    2111
    2112/** detects whether permutations define single or double lex matrices
    2113 *
    2114 * A single lex matrix is a matrix whose columns can be partitioned into blocks such that the
    2115 * columns within each block can be permuted arbitrarily. A double lex matrix is a single lex
    2116 * matrix such that also blocks of rows have the aforementioned property.
    2117 */
    2119 SCIP* scip, /**< SCIP pointer */
    2120 SCIP_Bool detectsinglelex, /**< whether single lex matrices shall be detected */
    2121 int** perms, /**< array of permutations */
    2122 int nperms, /**< number of permutations in perms */
    2123 int permlen, /**< number of variables in a permutation */
    2124 SCIP_Bool* success, /**< pointer to store whether structure could be detected */
    2125 SCIP_Bool* isorbitope, /**< pointer to store whether detected matrix is orbitopal */
    2126 int*** lexmatrix, /**< pointer to store single or double lex matrix */
    2127 int* nrows, /**< pointer to store number of rows of lexmatrix */
    2128 int* ncols, /**< pointer to store number of columns of lexmatrix */
    2129 int** lexrowsbegin, /**< pointer to store array indicating begin of new row-lexmatrix */
    2130 int** lexcolsbegin, /**< pointer to store array indicating begin of new col-lexmatrix */
    2131 int* nrowmatrices, /**< pointer to store number of single lex row matrices in rows */
    2132 int* ncolmatrices /**< pointer to store number of single lex column matrices in rows */
    2133 )
    2134{
    2135 int*** matricestype1 = NULL;
    2136 int*** matricestype2 = NULL;
    2137 int* ncolstype1 = NULL;
    2138 int* ncolstype2 = NULL;
    2139 int nmatricestype1 = 0;
    2140 int nmatricestype2 = 0;
    2141 int* permstype1;
    2142 int* permstype2;
    2143 int npermstype1 = 0;
    2144 int npermstype2 = 0;
    2145 int ncycs1 = -1;
    2146 int ncycs2 = -1;
    2147 int tmpncycs;
    2148 int p;
    2149 int i;
    2150 SCIP_Bool isinvolution;
    2151
    2152 assert( scip != NULL );
    2153 assert( perms != NULL );
    2154 assert( nperms > 0 );
    2155 assert( permlen > 0 );
    2156 assert( success != NULL );
    2157 assert( lexmatrix != NULL );
    2158 assert( nrows != NULL );
    2159 assert( ncols != NULL );
    2160 assert( lexrowsbegin != NULL );
    2161 assert( lexcolsbegin != NULL );
    2162 assert( nrowmatrices != NULL );
    2163 assert( ncolmatrices != NULL );
    2164
    2165 *success = TRUE;
    2166 *isorbitope = FALSE;
    2167 *nrowmatrices = 0;
    2168 *ncolmatrices = 0;
    2169
    2170 /* arrays to store the different types of involutions */
    2171 SCIP_CALL( SCIPallocBufferArray(scip, &permstype1, nperms) );
    2172 SCIP_CALL( SCIPallocBufferArray(scip, &permstype2, nperms) );
    2173
    2174 /* check whether we can expect lexicographically sorted rows and columns */
    2175 for (p = 0; p < nperms; ++p)
    2176 {
    2177 SCIP_CALL( isPermInvolution(perms[p], permlen, &isinvolution, &tmpncycs) );
    2178
    2179 /* terminate if not all permutations are involutions */
    2180 if ( ! isinvolution )
    2181 {
    2182 *success = FALSE;
    2183 goto FREEMEMORY;
    2184 }
    2185
    2186 /* store number of cycles or terminate if too many different types of involutions */
    2187 if ( ncycs1 == -1 || ncycs1 == tmpncycs )
    2188 {
    2189 ncycs1 = tmpncycs;
    2190 permstype1[npermstype1++] = p;
    2191 }
    2192 else if ( ncycs2 == -1 || ncycs2 == tmpncycs )
    2193 {
    2194 ncycs2 = tmpncycs;
    2195 permstype2[npermstype2++] = p;
    2196 }
    2197 else
    2198 {
    2199 *success = FALSE;
    2200 goto FREEMEMORY;
    2201 }
    2202 }
    2203
    2204 /* for each type, check whether permutations define (disjoint) orbitopal symmetries */
    2205 SCIP_CALL( detectOrbitopalSymmetries(scip, perms, permstype1, npermstype1, permlen, ncycs1, success,
    2206 &matricestype1, &ncolstype1, &nmatricestype1) );
    2207 if ( ! *success )
    2208 goto FREEMEMORY;
    2209
    2210 SCIP_CALL( detectOrbitopalSymmetries(scip, perms, permstype2, npermstype2, permlen, ncycs2, success,
    2211 &matricestype2, &ncolstype2, &nmatricestype2) );
    2212 if ( ! *success )
    2213 goto FREEMEMORY;
    2214
    2215 /* check whether a double lex matrix is defined */
    2216 *success = FALSE;
    2217 if ( !detectsinglelex && ncycs2 != -1 )
    2218 {
    2219 assert( ncycs1 > 0 );
    2220
    2221 SCIP_CALL( isDoublelLexSym(scip, permlen, matricestype1, ncycs1, ncolstype1, nmatricestype1,
    2222 matricestype2, ncycs2, ncolstype2, nmatricestype2,
    2223 lexmatrix, nrows, ncols, lexrowsbegin, lexcolsbegin, success) );
    2224
    2225 if ( *success )
    2226 {
    2227 *nrowmatrices = nmatricestype2;
    2228 *ncolmatrices = nmatricestype1;
    2229 }
    2230 }
    2231
    2232 /* if no double lex matrix is detected, possibly return orbitope */
    2233 if ( !(*success) && ncycs2 == -1 && nmatricestype1 == 1 )
    2234 {
    2235 SCIP_CALL( SCIPallocBlockMemoryArray(scip, lexmatrix, ncycs1) );
    2236 for (i = 0; i < ncycs1; ++i)
    2237 {
    2238 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*lexmatrix)[i], ncolstype1[0]) );
    2239 for (p = 0; p < ncolstype1[0]; ++p)
    2240 (*lexmatrix)[i][p] = matricestype1[0][i][p];
    2241 }
    2242 *nrows = ncycs1;
    2243 *ncols = ncolstype1[0];
    2244 *success = TRUE;
    2245 *isorbitope = TRUE;
    2246 }
    2247
    2248 FREEMEMORY:
    2249 for (p = nmatricestype2 - 1; p >= 0; --p)
    2250 {
    2251 for (i = ncycs2 - 1; i >= 0; --i)
    2252 {
    2253 SCIPfreeBlockMemoryArray(scip, &matricestype2[p][i], ncolstype2[p]);
    2254 }
    2255 SCIPfreeBlockMemoryArray(scip, &matricestype2[p], ncycs2);
    2256 }
    2257 SCIPfreeBlockMemoryArrayNull(scip, &matricestype2, nmatricestype2);
    2258 SCIPfreeBlockMemoryArrayNull(scip, &ncolstype2, nmatricestype2);
    2259 for (p = nmatricestype1 - 1; p >= 0; --p)
    2260 {
    2261 for (i = ncycs1 - 1; i >= 0; --i)
    2262 {
    2263 SCIPfreeBlockMemoryArray(scip, &matricestype1[p][i], ncolstype1[p]);
    2264 }
    2265 SCIPfreeBlockMemoryArray(scip, &matricestype1[p], ncycs1);
    2266 }
    2267 SCIPfreeBlockMemoryArrayNull(scip, &matricestype1, nmatricestype1);
    2268 SCIPfreeBlockMemoryArrayNull(scip, &ncolstype1, nmatricestype1);
    2269
    2270 SCIPfreeBufferArray(scip, &permstype2);
    2271 SCIPfreeBufferArray(scip, &permstype1);
    2272
    2273 return SCIP_OKAY;
    2274}
    2275
    2276
    2277/** helper function to test if val1 = val2 while permitting infinity-values */
    2279 SCIP* scip, /**< SCIP data structure */
    2280 SCIP_Real val1, /**< left-hand side value */
    2281 SCIP_Real val2 /**< right-hand side value */
    2282 )
    2283{
    2284 SCIP_Bool inf1;
    2285 SCIP_Bool inf2;
    2286 SCIP_Bool minf1;
    2287 SCIP_Bool minf2;
    2288
    2289 inf1 = SCIPisInfinity(scip, val1);
    2290 inf2 = SCIPisInfinity(scip, val2);
    2291 if ( inf1 && inf2 )
    2292 return TRUE;
    2293 if ( inf1 != inf2 )
    2294 return FALSE;
    2295 assert( !inf1 );
    2296 assert( !inf2 );
    2297
    2298 minf1 = SCIPisInfinity(scip, -val1);
    2299 minf2 = SCIPisInfinity(scip, -val2);
    2300 if ( minf1 && minf2 )
    2301 return TRUE;
    2302 if ( minf1 != minf2 )
    2303 return FALSE;
    2304 assert( !minf1 );
    2305 assert( !minf2 );
    2306
    2307 return SCIPisEQ(scip, val1, val2);
    2308}
    2309
    2310
    2311/** helper function to test if val1 <= val2 while permitting infinity-values */
    2313 SCIP* scip, /**< SCIP data structure */
    2314 SCIP_Real val1, /**< left-hand side value */
    2315 SCIP_Real val2 /**< right-hand side value */
    2316 )
    2317{
    2318 SCIP_Bool inf1;
    2319 SCIP_Bool inf2;
    2320 SCIP_Bool minf1;
    2321 SCIP_Bool minf2;
    2322
    2323 inf1 = SCIPisInfinity(scip, val1);
    2324 inf2 = SCIPisInfinity(scip, val2);
    2325 if ( inf1 && inf2 )
    2326 return TRUE;
    2327 if ( !inf1 && inf2 )
    2328 return TRUE;
    2329 if ( inf1 && !inf2 )
    2330 return FALSE;
    2331 assert( !inf1 );
    2332 assert( !inf2 );
    2333
    2334 minf1 = SCIPisInfinity(scip, -val1);
    2335 minf2 = SCIPisInfinity(scip, -val2);
    2336 if ( minf1 && minf2 )
    2337 return TRUE;
    2338 if ( !minf1 && minf2 )
    2339 return FALSE;
    2340 if ( minf1 && !minf2 )
    2341 return TRUE;
    2342 assert( !minf1 );
    2343 assert( !minf2 );
    2344
    2345 return SCIPisLE(scip, val1, val2);
    2346}
    2347
    2348
    2349/** helper function to test if val1 >= val2 while permitting infinity-values */
    2351 SCIP* scip, /**< SCIP data structure */
    2352 SCIP_Real val1, /**< left-hand side value */
    2353 SCIP_Real val2 /**< right-hand side value */
    2354 )
    2355{
    2356 SCIP_Bool inf1;
    2357 SCIP_Bool inf2;
    2358 SCIP_Bool minf1;
    2359 SCIP_Bool minf2;
    2360
    2361 inf1 = SCIPisInfinity(scip, val1);
    2362 inf2 = SCIPisInfinity(scip, val2);
    2363 if ( inf1 && inf2 )
    2364 return TRUE;
    2365 if ( !inf1 && inf2 )
    2366 return FALSE;
    2367 if ( inf1 && !inf2 )
    2368 return TRUE;
    2369 assert( !inf1 );
    2370 assert( !inf2 );
    2371
    2372 minf1 = SCIPisInfinity(scip, -val1);
    2373 minf2 = SCIPisInfinity(scip, -val2);
    2374 if ( minf1 && minf2 )
    2375 return TRUE;
    2376 if ( !minf1 && minf2 )
    2377 return TRUE;
    2378 if ( minf1 && !minf2 )
    2379 return FALSE;
    2380 assert( !minf1 );
    2381 assert( !minf2 );
    2382
    2383 return SCIPisGE(scip, val1, val2);
    2384}
    2385
    2386
    2387/** helper function to test if val1 < val2 while permitting infinity-values */
    2389 SCIP* scip, /**< SCIP data structure */
    2390 SCIP_Real val1, /**< left-hand side value */
    2391 SCIP_Real val2 /**< right-hand side value */
    2392 )
    2393{
    2394 SCIP_Bool inf1;
    2395 SCIP_Bool inf2;
    2396 SCIP_Bool minf1;
    2397 SCIP_Bool minf2;
    2398
    2399 inf1 = SCIPisInfinity(scip, val1);
    2400 inf2 = SCIPisInfinity(scip, val2);
    2401 if ( inf1 && inf2 )
    2402 return FALSE;
    2403 if ( !inf1 && inf2 )
    2404 return TRUE;
    2405 if ( inf1 && !inf2 )
    2406 return FALSE;
    2407 assert( !inf1 );
    2408 assert( !inf2 );
    2409
    2410 minf1 = SCIPisInfinity(scip, -val1);
    2411 minf2 = SCIPisInfinity(scip, -val2);
    2412 if ( minf1 && minf2 )
    2413 return FALSE;
    2414 if ( !minf1 && minf2 )
    2415 return FALSE;
    2416 if ( minf1 && !minf2 )
    2417 return TRUE;
    2418 assert( !minf1 );
    2419 assert( !minf2 );
    2420
    2421 return SCIPisLT(scip, val1, val2);
    2422}
    2423
    2424
    2425/** helper function to test if val1 > val2 while permitting infinity-values */
    2427 SCIP* scip, /**< SCIP data structure */
    2428 SCIP_Real val1, /**< left-hand side value */
    2429 SCIP_Real val2 /**< right-hand side value */
    2430 )
    2431{
    2432 SCIP_Bool inf1;
    2433 SCIP_Bool inf2;
    2434 SCIP_Bool minf1;
    2435 SCIP_Bool minf2;
    2436
    2437 inf1 = SCIPisInfinity(scip, val1);
    2438 inf2 = SCIPisInfinity(scip, val2);
    2439 if ( inf1 && inf2 )
    2440 return FALSE;
    2441 if ( !inf1 && inf2 )
    2442 return FALSE;
    2443 if ( inf1 && !inf2 )
    2444 return TRUE;
    2445 assert( !inf1 );
    2446 assert( !inf2 );
    2447
    2448 minf1 = SCIPisInfinity(scip, -val1);
    2449 minf2 = SCIPisInfinity(scip, -val2);
    2450 if ( minf1 && minf2 )
    2451 return FALSE;
    2452 if ( !minf1 && minf2 )
    2453 return TRUE;
    2454 if ( minf1 && !minf2 )
    2455 return FALSE;
    2456 assert( !minf1 );
    2457 assert( !minf2 );
    2458
    2459 return SCIPisGT(scip, val1, val2);
    2460}
    SCIP_VAR * w
    Definition: circlepacking.c:67
    interface for constraint handlers of type partitioning, packing, and full
    Constraint handler for the set partitioning / packing / covering constraints .
    #define NULL
    Definition: def.h:248
    #define SCIP_Shortbool
    Definition: def.h:99
    #define SCIP_Bool
    Definition: def.h:91
    #define SCIP_Real
    Definition: def.h:156
    #define TRUE
    Definition: def.h:93
    #define FALSE
    Definition: def.h:94
    #define MAX(x, y)
    Definition: def.h:220
    #define SCIP_CALL(x)
    Definition: def.h:355
    int SCIPgetNVarsSetppc(SCIP *scip, SCIP_CONS *cons)
    Definition: cons_setppc.c:9596
    SCIP_VAR ** SCIPgetVarsSetppc(SCIP *scip, SCIP_CONS *cons)
    Definition: cons_setppc.c:9619
    SCIP_SETPPCTYPE SCIPgetTypeSetppc(SCIP *scip, SCIP_CONS *cons)
    Definition: cons_setppc.c:9642
    @ SCIP_SETPPCTYPE_PARTITIONING
    Definition: cons_setppc.h:87
    @ SCIP_SETPPCTYPE_COVERING
    Definition: cons_setppc.h:89
    void SCIPfreeDisjointset(SCIP *scip, SCIP_DISJOINTSET **djset)
    int SCIPdisjointsetFind(SCIP_DISJOINTSET *djset, int element)
    Definition: misc.c:11247
    void SCIPdisjointsetUnion(SCIP_DISJOINTSET *djset, int p, int q, SCIP_Bool forcerepofp)
    Definition: misc.c:11274
    SCIP_RETCODE SCIPcreateDisjointset(SCIP *scip, SCIP_DISJOINTSET **djset, int ncomponents)
    int SCIPgetNTotalVars(SCIP *scip)
    Definition: scip_prob.c:3064
    int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4778
    SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
    Definition: scip_cons.c:940
    SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
    Definition: cons.c:4735
    #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
    #define SCIPallocClearBufferArray(scip, ptr, num)
    Definition: scip_mem.h:126
    #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 SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
    Definition: scip_mem.h:111
    SCIP_RETCODE SCIPdetermineNVarsAffectedSym(SCIP *scip, int **perms, int nperms, SCIP_VAR **permvars, int npermvars, int *nvarsaffected)
    Definition: symmetry.c:608
    SCIP_RETCODE SCIPcomputeComponentsSym(SCIP *scip, SYM_SYMTYPE symtype, int **perms, int nperms, SCIP_VAR **permvars, int npermvars, SCIP_Bool transposed, int **components, int **componentbegins, int **vartocomponent, unsigned **componentblocked, int *ncomponents)
    Definition: symmetry.c:790
    SCIP_RETCODE SCIPcomputeOrbitVar(SCIP *scip, int npermvars, int **perms, int **permstrans, int *components, int *componentbegins, SCIP_Shortbool *ignoredvars, SCIP_Shortbool *varfound, int varidx, int component, int *orbit, int *orbitsize)
    Definition: symmetry.c:335
    SCIP_RETCODE SCIPisInvolutionPerm(int *perm, SCIP_VAR **vars, int nvars, int *ntwocyclesperm, int *nbincyclesperm, SCIP_Bool earlytermination)
    Definition: symmetry.c:557
    SCIP_Bool SCIPsymGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    Definition: symmetry.c:2350
    SCIP_RETCODE SCIPcomputeOrbitsComponentsSym(SCIP *scip, int npermvars, int **permstrans, int nperms, int *components, int *componentbegins, int *vartocomponent, int ncomponents, int *orbits, int *orbitbegins, int *norbits, int *varorbitmap)
    Definition: symmetry.c:435
    SCIP_Bool SCIPsymEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    Definition: symmetry.c:2278
    SCIP_RETCODE SCIPcomputeOrbitsSym(SCIP *scip, SCIP_Bool issigned, SCIP_VAR **permvars, int npermvars, int **perms, int nperms, int *orbits, int *orbitbegins, int *norbits)
    Definition: symmetry.c:67
    SCIP_Bool SCIPsymLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    Definition: symmetry.c:2388
    SCIP_VARTYPE SCIPgetSymInferredVarType(SCIP_VAR *var)
    Definition: symmetry.c:45
    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_RETCODE SCIPdetectSingleOrDoubleLexMatrices(SCIP *scip, SCIP_Bool detectsinglelex, int **perms, int nperms, int permlen, SCIP_Bool *success, SCIP_Bool *isorbitope, int ***lexmatrix, int *nrows, int *ncols, int **lexrowsbegin, int **lexcolsbegin, int *nrowmatrices, int *ncolmatrices)
    Definition: symmetry.c:2118
    SCIP_RETCODE SCIPgenerateOrbitopeVarsMatrix(SCIP *scip, SCIP_VAR ****vars, int nrows, int ncols, SCIP_VAR **permvars, int npermvars, int **orbitopevaridx, int *columnorder, int *nusedelems, SCIP_Shortbool *rowisbinary, SCIP_Bool *infeasible, SCIP_Bool storelexorder, int **lexorder, int *nvarsorder, int *maxnvarsorder)
    Definition: symmetry.c:1002
    SCIP_RETCODE SCIPisPackingPartitioningOrbitope(SCIP *scip, SCIP_VAR ***vars, int nrows, int ncols, SCIP_Bool **pprows, int *npprows, SCIP_ORBITOPETYPE *type)
    Definition: symmetry.c:1193
    SCIP_RETCODE SCIPcomputeOrbitsFilterSym(SCIP *scip, int npermvars, int **permstrans, int nperms, SCIP_Shortbool *inactiveperms, int *orbits, int *orbitbegins, int *norbits, int *components, int *componentbegins, int *vartocomponent, unsigned *componentblocked, int ncomponents, int nmovedpermvars)
    Definition: symmetry.c:187
    SCIP_RETCODE SCIPextendSubOrbitope(int **suborbitope, int nrows, int nfilledcols, int coltoextend, int *perm, SCIP_Bool leftextension, int **nusedelems, SCIP_VAR **permvars, SCIP_Shortbool *rowisbinary, SCIP_Bool *success, SCIP_Bool *infeasible)
    Definition: symmetry.c:660
    SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
    SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
    SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
    Definition: var.c:23478
    int SCIPvarGetIndex(SCIP_VAR *var)
    Definition: var.c:23652
    SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
    Definition: var.c:23490
    void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
    void SCIPsortIntIntInt(int *intarray1, int *intarray2, int *intarray3, int len)
    void SCIPsortIntPtr(int *intarray, void **ptrarray, int len)
    void SCIPdisjointsetFree(SCIP_DISJOINTSET **djset, BMS_BLKMEM *blkmem)
    Definition: misc.c:11325
    SCIP_RETCODE SCIPdisjointsetCreate(SCIP_DISJOINTSET **djset, BMS_BLKMEM *blkmem, int ncomponents)
    Definition: misc.c:11207
    internal miscellaneous methods
    SCIP callable library.
    structs for symmetry computations
    static SCIP_RETCODE detectOrbitopalSymmetries(SCIP *scip, int **perms, int *selectedperms, int nselectedperms, int permlen, int nrows, SCIP_Bool *success, int ****matrices, int **ncols, int *nmatrices)
    Definition: symmetry.c:1438
    static SCIP_RETCODE isPermInvolution(int *perm, int permlen, SCIP_Bool *isinvolution, int *ntwocycles)
    Definition: symmetry.c:1404
    static SCIP_RETCODE isDoublelLexSym(SCIP *scip, int nsymvars, int ***matrices1, int nrows1, int *ncols1, int nmatrices1, int ***matrices2, int nrows2, int *ncols2, int nmatrices2, int ***doublelexmatrix, int *nrows, int *ncols, int **rowsbegin, int **colsbegin, SCIP_Bool *success)
    Definition: symmetry.c:1811
    methods for handling symmetries
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    type definitions for symmetry computations
    @ SCIP_ORBITOPETYPE_PACKING
    @ SCIP_ORBITOPETYPE_FULL
    @ SCIP_ORBITOPETYPE_PARTITIONING
    enum SYM_Symtype SYM_SYMTYPE
    Definition: type_symmetry.h:64
    enum SCIP_OrbitopeType SCIP_ORBITOPETYPE
    @ SYM_SYMTYPE_SIGNPERM
    Definition: type_symmetry.h:62
    @ SCIP_VARTYPE_INTEGER
    Definition: type_var.h:65
    @ SCIP_VARTYPE_CONTINUOUS
    Definition: type_var.h:71
    @ SCIP_VARTYPE_BINARY
    Definition: type_var.h:64
    enum SCIP_Vartype SCIP_VARTYPE
    Definition: type_var.h:73