Scippy

    SCIP

    Solving Constraint Integer Programs

    compute_symmetry_dejavu.cpp
    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 compute_symmetry_dejavu.cpp
    26 * @brief interface for symmetry computations to dejavu
    27 * @author Marc Pfetsch
    28 */
    29
    30/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
    31
    32#include "compute_symmetry.h"
    33
    34/* possibly turn on the dejavu debug mode */
    35#ifdef SCIP_DEBUG
    36#define DEJDEBUG
    37#endif
    38
    39#include <string> /* for dejvu */
    40#include "build_dejavu_graph.h" /* also includes dejavu */
    41
    42#include "scip/expr_var.h"
    43#include "scip/expr_sum.h"
    44#include "scip/expr_pow.h"
    45#include "scip/expr.h"
    46#include "scip/cons_nonlinear.h"
    47#include "scip/cons_linear.h"
    48#include "scip/scip_mem.h"
    49#include "scip/symmetry_graph.h"
    50
    51
    52/** struct for symmetry callback */
    54{
    55 SCIP* scip; /**< SCIP pointer */
    56 SYM_SYMTYPE symtype; /**< type of symmetries that need to be computed */
    57 int npermvars; /**< number of variables for permutations */
    58 int nperms; /**< number of permutations */
    59 int** perms; /**< permutation generators as (nperms x npermvars) matrix */
    60 int nmaxperms; /**< maximal number of permutations */
    61 int maxgenerators; /**< maximal number of generators constructed (= 0 if unlimited) */
    62 SCIP_Bool restricttovars; /**< whether permutations shall be restricted to variables */
    63};
    64
    65
    66/* ------------------- hook functions ------------------- */
    67
    68/** callback function for dejavu */ /*lint -e{715}*/
    69static
    71 void* user_param, /**< parameter supplied at call to dejavu */
    72 int n, /**< dimension of permutations */
    73 const int* aut, /**< permutation */
    74 int nsupp, /**< support size */
    75 const int* suppa /**< support list */
    76 )
    77{
    78 assert( aut != NULL );
    79 assert( user_param != NULL );
    80
    81 SYMMETRY_Data* data = static_cast<SYMMETRY_Data*>(user_param);
    82 assert( data->scip != NULL );
    83 assert( data->maxgenerators >= 0 );
    84
    85 /* make sure we do not generate more that maxgenerators many permutations */
    86 if ( data->maxgenerators != 0 && data->nperms >= data->maxgenerators )
    87 return;
    88
    89 /* copy first part of automorphism */
    90 bool isIdentity = true;
    91 int* p = 0;
    92 int permlen;
    93 if ( data->restricttovars )
    94 {
    95 switch ( data->symtype )
    96 {
    98 permlen = data->npermvars;
    99 break;
    100 default:
    101 assert( data->symtype == SYM_SYMTYPE_SIGNPERM );
    102 permlen = 2 * data->npermvars;
    103 }
    104 }
    105 else
    106 permlen = n;
    107
    108 /* check whether permutation is identity */
    109 for (int j = 0; j < permlen; ++j)
    110 {
    111 if ( (int) aut[j] != j )
    112 isIdentity = false;
    113 }
    114
    115 /* don't store identity permutations */
    116 if ( isIdentity )
    117 return;
    118
    119 if ( SCIPallocBlockMemoryArray(data->scip, &p, permlen) != SCIP_OKAY )
    120 return;
    121
    122 /* store symmetry */
    123 for (int j = 0; j < permlen; ++j)
    124 p[j] = (int) aut[j];
    125
    126 /* check whether we should allocate space for perms */
    127 if ( data->nmaxperms <= 0 )
    128 {
    129 if ( data->maxgenerators == 0 )
    130 data->nmaxperms = 100; /* seems to cover many cases */
    131 else
    132 data->nmaxperms = data->maxgenerators;
    133
    134 if ( SCIPallocBlockMemoryArray(data->scip, &data->perms, data->nmaxperms) != SCIP_OKAY )
    135 return;
    136 }
    137 else if ( data->nperms >= data->nmaxperms ) /* check whether we need to resize */
    138 {
    139 int newsize = SCIPcalcMemGrowSize(data->scip, data->nperms + 1);
    140 assert( newsize >= data->nperms );
    141 assert( data->maxgenerators == 0 );
    142
    143 if ( SCIPreallocBlockMemoryArray(data->scip, &data->perms, data->nmaxperms, newsize) != SCIP_OKAY )
    144 return;
    145
    146 data->nmaxperms = newsize;
    147 }
    148
    149 data->perms[data->nperms++] = p;
    150}
    151
    152
    153/** return whether symmetry can be computed */
    155{
    156 return TRUE;
    157}
    158
    159#define STR(x) #x
    160#define XSTR(x) STR(x)
    161
    162/** return name of external program used to compute generators */
    163const char* SYMsymmetryGetName(void)
    164{
    165 return "dejavu " XSTR(DEJAVU_VERSION_MAJOR) "." XSTR(DEJAVU_VERSION_MINOR);
    166}
    167
    168/** return description of external program used to compute generators */
    169const char* SYMsymmetryGetDesc(void)
    170{
    171 return "Monte Carlo symmetry computation library by M. Anders (github.com/markusa4/dejavu)";
    172}
    173
    174/** return name of additional external program used for computing symmetries */
    175const char* SYMsymmetryGetAddName(void)
    176{
    177 return NULL;
    178}
    179
    180/** return description of additional external program used to compute symmetries */
    181const char* SYMsymmetryGetAddDesc(void)
    182{
    183 return NULL;
    184}
    185
    186/** computes autormorphisms of a graph */
    187static
    189 SCIP* scip, /**< SCIP pointer */
    190 SYM_SYMTYPE symtype, /**< type of symmetries that need to be computed */
    191 dejavu::static_graph* G, /**< pointer to graph for that automorphisms are computed */
    192 int nsymvars, /**< number of variables encoded in graph */
    193 int maxgenerators, /**< maximum number of generators to be constructed (=0 if unlimited) */
    194 int*** perms, /**< pointer to store generators as (nperms x npermvars) matrix */
    195 int* nperms, /**< pointer to store number of permutations */
    196 int* nmaxperms, /**< pointer to store maximal number of permutations
    197 * (needed for freeing storage) */
    198 SCIP_Real* log10groupsize, /**< pointer to store log10 of size of group */
    199 SCIP_Bool restricttovars, /**< whether permutations shall be restricted to variables */
    200 SCIP_Real* symcodetime /**< pointer to store the time for symmetry code */
    201 )
    202{
    203 SCIP_Real oldtime;
    204
    205 assert( scip != NULL );
    206 assert( G != NULL );
    207 assert( maxgenerators >= 0 );
    208 assert( perms != NULL );
    209 assert( nperms != NULL );
    210 assert( nmaxperms != NULL );
    211 assert( log10groupsize != NULL );
    212 assert( symcodetime != NULL );
    213
    214 /* init */
    215 *nperms = 0;
    216 *nmaxperms = 0;
    217 *perms = NULL;
    218 *log10groupsize = 0;
    219 *symcodetime = 0.0;
    220
    221 /* init data */
    222 struct SYMMETRY_Data data;
    223 data.scip = scip;
    224 data.symtype = symtype;
    225 data.npermvars = nsymvars;
    226 data.nperms = 0;
    227 data.nmaxperms = 0;
    229 data.perms = NULL;
    231
    232 oldtime = SCIPgetSolvingTime(scip);
    233
    234 /* set up dejavu */
    235 dejavu::solver dejavu;
    236
    237 dejavu.set_prefer_dfs(true);
    238
    239#ifndef SCIP_DEBUG
    240 dejavu.set_print(false);
    241#endif
    242
    243 /* lambda function to have access to data and pass it to dejavuhook above */
    244 dejavu_hook dejavuhookglue = [&](int n, const int* p, int nsupp, const int* suppa) {
    245 dejavuhook((void*)&data, n, p, nsupp, suppa);
    246 };
    247
    248 /* call dejavu */
    249 dejavu.automorphisms(G, &dejavuhookglue);
    250 *symcodetime = SCIPgetSolvingTime(scip) - oldtime;
    251
    252 /* prepare return values */
    253 if ( data.nperms > 0 )
    254 {
    255 *perms = data.perms;
    256 *nperms = data.nperms;
    257 *nmaxperms = data.nmaxperms;
    258 }
    259 else
    260 {
    261 assert( data.perms == NULL );
    262 assert( data.nmaxperms == 0 );
    263
    264 *perms = NULL;
    265 *nperms = 0;
    266 *nmaxperms = 0;
    267 }
    268
    269 /* determine log10 of symmetry group size */
    270 dejavu::big_number size = dejavu.get_automorphism_group_size();
    271 *log10groupsize = (SCIP_Real) size.exponent + log10(size.mantissa);
    272
    273 return SCIP_OKAY;
    274}
    275
    276/** compute generators of symmetry group */
    278 SCIP* scip, /**< SCIP pointer */
    279 int maxgenerators, /**< maximal number of generators constructed (= 0 if unlimited) */
    280 SYM_GRAPH* graph, /**< symmetry detection graph */
    281 int* nperms, /**< pointer to store number of permutations */
    282 int* nmaxperms, /**< pointer to store maximal number of permutations (needed for freeing storage) */
    283 int*** perms, /**< pointer to store permutation generators as (nperms x npermvars) matrix */
    284 SCIP_Real* log10groupsize, /**< pointer to store log10 of size of group */
    285 SCIP_Real* symcodetime /**< pointer to store the time for symmetry code */
    286 )
    287{
    288 SCIP_Bool success = FALSE;
    289
    290 assert( scip != NULL );
    291 assert( maxgenerators >= 0 );
    292 assert( graph != NULL );
    293 assert( nperms != NULL );
    294 assert( nmaxperms != NULL );
    295 assert( perms != NULL );
    296 assert( log10groupsize != NULL );
    297 assert( symcodetime != NULL );
    298
    299 /* init */
    300 *nperms = 0;
    301 *nmaxperms = 0;
    302 *perms = NULL;
    303 *log10groupsize = 0;
    304 *symcodetime = 0.0;
    305
    306 /* create dejavu graph */
    307 dejavu::static_graph dejavugraph;
    308
    309 SCIP_CALL( SYMbuildDejavuGraph(scip, &dejavugraph, graph, &success) );
    310
    311#ifdef WRITE_GRAPH
    312 std::string filename = std::string(SCIPgetProbName(scip)) + std::string(".dimacs");
    313 dejavugraph.dump_dimacs(filename);
    314#endif
    315
    316 /* compute symmetries */
    318 maxgenerators, perms, nperms, nmaxperms, log10groupsize, TRUE, symcodetime) );
    319
    320 return SCIP_OKAY;
    321}
    322
    323/** returns whether two given graphs are identical */
    325 SCIP* scip, /**< SCIP pointer */
    326 SYM_SYMTYPE symtype, /**< type of symmetries to be checked */
    327 SYM_GRAPH* G1, /**< first graph */
    328 SYM_GRAPH* G2 /**< second graph */
    329 )
    330{
    331 int** perms;
    332 int nnodes;
    333 int nperms;
    334 int nmaxperms;
    335 int nnodesfromG1;
    336 SCIP_Real symcodetime = 0.0;
    337 SCIP_Real log10groupsize;
    338 SCIP_Bool success;
    339
    340 /* create dejavu graph */
    341 dejavu::static_graph dejavugraph;
    342
    343 SCIP_CALL( SYMbuildDejavuGraphCheck(scip, &dejavugraph, G1, G2, &nnodes, &nnodesfromG1, &success) );
    344
    345 if ( ! success )
    346 return FALSE;
    347
    348 /* compute symmetries */
    350 &perms, &nperms, &nmaxperms, &log10groupsize, FALSE, &symcodetime) );
    351
    352 /* since G1 and G2 are connected and disjoint, they are isomorphic iff there is a permutation
    353 * mapping a node from G1 to a node of G2
    354 */
    355 success = FALSE;
    356 for (int p = 0; p < nperms && ! success; ++p)
    357 {
    358 for (int i = 0; i < nnodesfromG1; ++i)
    359 {
    360 if ( perms[p][i] >= nnodesfromG1 )
    361 {
    362 success = TRUE;
    363 break;
    364 }
    365 }
    366 }
    367
    368 for (int p = 0; p < nperms; ++p)
    369 {
    371 }
    373
    374 return success;
    375}
    SCIP_RETCODE SYMbuildDejavuGraphCheck(SCIP *scip, dejavu::static_graph *dejavugraph, SYM_GRAPH *G1, SYM_GRAPH *G2, int *nnodes, int *nnodesfromG1, SCIP_Bool *success)
    SCIP_RETCODE SYMbuildDejavuGraph(SCIP *scip, dejavu::static_graph *dejavugraph, SYM_GRAPH *graph, SCIP_Bool *success)
    methods to build dejavu graph for symmetry detection
    interface for symmetry computations
    SCIP_Bool SYMcheckGraphsAreIdentical(SCIP *scip, SYM_SYMTYPE symtype, SYM_GRAPH *G1, SYM_GRAPH *G2)
    const char * SYMsymmetryGetName(void)
    static void dejavuhook(void *user_param, int n, const int *aut, int nsupp, const int *suppa)
    const char * SYMsymmetryGetAddName(void)
    SCIP_RETCODE SYMcomputeSymmetryGenerators(SCIP *scip, int maxgenerators, SYM_GRAPH *graph, int *nperms, int *nmaxperms, int ***perms, SCIP_Real *log10groupsize, SCIP_Real *symcodetime)
    SCIP_Bool SYMcanComputeSymmetry(void)
    const char * SYMsymmetryGetDesc(void)
    #define XSTR(x)
    const char * SYMsymmetryGetAddDesc(void)
    static SCIP_RETCODE computeAutomorphisms(SCIP *scip, SYM_SYMTYPE symtype, dejavu::static_graph *G, int nsymvars, int maxgenerators, int ***perms, int *nperms, int *nmaxperms, SCIP_Real *log10groupsize, SCIP_Bool restricttovars, SCIP_Real *symcodetime)
    Constraint handler for linear constraints in their most general form, .
    constraint handler for nonlinear constraints specified by algebraic expressions
    #define NULL
    Definition: def.h:248
    #define SCIP_Bool
    Definition: def.h:91
    #define SCIP_Real
    Definition: def.h:156
    #define TRUE
    Definition: def.h:93
    #define FALSE
    Definition: def.h:94
    #define SCIP_CALL_ABORT(x)
    Definition: def.h:334
    #define SCIP_CALL(x)
    Definition: def.h:355
    private functions to work with algebraic expressions
    power and signed power expression handlers
    sum expression handler
    variable expression handler
    #define nnodes
    Definition: gastrans.c:74
    const char * SCIPgetProbName(SCIP *scip)
    Definition: scip_prob.c:1242
    #define SCIPfreeBlockMemoryArray(scip, ptr, num)
    Definition: scip_mem.h:110
    int SCIPcalcMemGrowSize(SCIP *scip, int num)
    Definition: scip_mem.c:139
    #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_Real SCIPgetSolvingTime(SCIP *scip)
    Definition: scip_timing.c:378
    SYM_SYMTYPE SCIPgetSymgraphSymtype(SYM_GRAPH *graph)
    int SCIPgetSymgraphNVars(SYM_GRAPH *graph)
    public methods for memory management
    methods for dealing with symmetry detection graphs
    @ SCIP_OKAY
    Definition: type_retcode.h:42
    enum SCIP_Retcode SCIP_RETCODE
    Definition: type_retcode.h:63
    enum SYM_Symtype SYM_SYMTYPE
    Definition: type_symmetry.h:64
    @ SYM_SYMTYPE_SIGNPERM
    Definition: type_symmetry.h:62
    @ SYM_SYMTYPE_PERM
    Definition: type_symmetry.h:61