prop_symmetry.c
Go to the documentation of this file.
25 * - It allows to compute symmetries of the problem and to store this information in adequate form. The symmetry
38 * - We treat implicit integer variables as if they were continuous/real variables. The reason is that there is currently
39 * no distinction between implicit integer and implicit binary. Moreover, currently implicit integer variables hurt
40 * our code more than continuous/real variables (we basically do not handle integral variables at all).
41 * - We do not copy symmetry information, since it is not clear how this information transfers. Moreover, copying
42 * symmetry might inhibit heuristics. But note that solving a sub-SCIP might then happen without symmetry information!
49 * - The code automatically detects whether symmetry substructures like symresacks or orbitopes are present and possibly
52 * - We try to compute symmetry as late as possible and then add constraints based on this information.
53 * - Currently, we only allocate memory for pointers to symresack constraints for group generators. If further
62 * The method computes orbits of variables with respect to the subgroup of the symmetry group that stabilizes the
63 * variables globally fixed or branched to 1. Then one can fix all variables in an orbit to 0 or 1 if one of the other
64 * variables in the orbit is fixed to 0 or 1, respectively. Different from Margot, the subgroup is obtained by filtering
67 * @pre All variable fixings applied by other components are required to be strict, i.e., if one variable is fixed to
68 * a certain value v, all other variables in the same variable orbit can be fixed to v as well, c.f.@n
69 * F. Margot: Symmetry in integer linear programming. 50 Years of Integer Programming, 647-686, Springer 2010.
72 * (x,y) \in \{0,1\}^{2 + n}\} \f$. Since \f$x_1\f$ and \f$x_2\f$ are independent from the remaining problem, the
73 * setppc constraint handler may fix \f$(x_1,x_2) = (1,0)\f$. However, since both variables are symmetric, this setting
74 * is not strict (if it was strict, both variables would have been set to the same value) and orbital fixing would
75 * declare this subsolution as infeasible (there exists an orbit of non-branching variables that are fixed to different
76 * values). To avoid this situation, we have to assume that all non-strict settings fix variables globally, i.e., we
77 * can take care of it by taking variables into account that have been globally fixed to 1. In fact, it suffices to
78 * consider one kind of global fixings since stabilizing one kind prevents an orbit to contain variables that have
81 * @pre All non-strict settings are global settings, since otherwise, we cannot (efficiently) take care of them.
83 * @pre No non-strict setting algorithm is interrupted early (e.g., by a time or iteration limit), since this may lead to
84 * wrong decisions by orbital fixing as well. For example, if cons_setppc in the above toy example starts by fixing
85 * \f$x_2 = 0\f$ and is interrupted afterwards, orbital fixing detects that the orbit \f$\{x_1, x_2\}\f$ contains
86 * one variable that is fixed to 0, and thus, it fixes \f$x_1\f$ to 0 as well. Thus, after these reductions, every
87 * feasible solution has objective 0 which is not optimal. This situation would not occur if the non-strict setting is
88 * complete, because then \f$x_1\f$ is globally fixed to 1, and thus, is stabilized in orbital fixing.
90 * Note that orbital fixing might lead to wrong results if it is called in repropagation of a node, because the path
91 * from the node to the root might have been changed. Thus, the stabilizers of global 1-fixing and 1-branchings of the
92 * initial propagation and repropagation might differ, which may cause conflicts. For this reason, orbital fixing cannot
95 * @note If, besides orbital fixing, also symmetry handling constraints shall be added, orbital fixing is only applied
102 * D. Salvagnin: Symmetry Breaking Inequalities from the Schreier-Sims table. CPAIOR 2018 Proceedings, 521-529, 2018.
104 * These inequalities are computed as follows. Throughout these procedure a set of so-called leaders is maintained.
105 * Initially the set of leaders is empty. In a first step, select a variable \f$x_i\f$ and compute its orbit w.r.t.
106 * the symmetry group of the mixed-integer program. For each variable \f$x_j\f$ in the orbit of \f$x_i\f$, the
107 * inequality \f$x_i \geq x_j\f$ is a valid symmetry handling inequality, which can be added to the mixed-integer
108 * program. We call \f$x_i\f$ the leader of this inequality. Add the leader \f$x_i\f$ to the set of leaders and
109 * compute the pointwise stabilizer of the leader set. In the next step, select a new variable, compute its orbit
110 * w.r.t. the stabilizer group of the leaders, add the inequalities based on this orbit, and add the new leader
111 * to the set of leaders. This procedure is iterated until the pointwise stabilizer group of the leaders has become
122 * @todo Order rows of orbitopes (in particular packing/partitioning) w.r.t. cliques in conflict graph.
127 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
158 #define PROP_DELAY FALSE /**< should propagation method be delayed, if other propagators found reductions? */
160 #define PROP_PRESOL_PRIORITY -10000000 /**< priority of the presolving method (>= 0: before, < 0: after constraint handlers) */
161 #define PROP_PRESOLTIMING SCIP_PRESOLTIMING_EXHAUSTIVE /* timing of the presolving method (fast, medium, or exhaustive) */
162 #define PROP_PRESOL_MAXROUNDS -1 /**< maximal number of presolving rounds the presolver participates in (-1: no limit) */
166 #define DEFAULT_MAXGENERATORS 1500 /**< limit on the number of generators that should be produced within symmetry detection (0 = no limit) */
167 #define DEFAULT_CHECKSYMMETRIES FALSE /**< Should all symmetries be checked after computation? */
168 #define DEFAULT_DISPLAYNORBITVARS FALSE /**< Should the number of variables affected by some symmetry be displayed? */
169 #define DEFAULT_USECOLUMNSPARSITY FALSE /**< Should the number of conss a variable is contained in be exploited in symmetry detection? */
171 #define DEFAULT_COMPRESSSYMMETRIES TRUE /**< Should non-affected variables be removed from permutation to save memory? */
172 #define DEFAULT_COMPRESSTHRESHOLD 0.5 /**< Compression is used if percentage of moved vars is at most the threshold. */
173 #define DEFAULT_SYMFIXNONBINARYVARS FALSE /**< Whether all non-binary variables shall be not affected by symmetries if OF is active? */
177 #define DEFAULT_CONSSADDLP TRUE /**< Should the symmetry breaking constraints be added to the LP? */
179 #define DEFAULT_DETECTORBITOPES TRUE /**< Should we check whether the components of the symmetry group can be handled by orbitopes? */
180 #define DEFAULT_DETECTSUBGROUPS TRUE /**< Should we try to detect orbitopes in subgroups of the symmetry group? */
181 #define DEFAULT_ADDWEAKSBCS TRUE /**< Should we add weak SBCs for enclosing orbit of symmetric subgroups? */
182 #define DEFAULT_ADDSTRONGSBCS FALSE /**< Should we add strong SBCs for enclosing orbit of symmetric subgroups if orbitopes are not used? */
183 #define DEFAULT_ADDCONSSTIMING 2 /**< timing of adding constraints (0 = before presolving, 1 = during presolving, 2 = after presolving) */
184 #define DEFAULT_MAXNCONSSSUBGROUP 500000 /**< Maximum number of constraints up to which subgroup structures are detected */
185 #define DEFAULT_USEDYNAMICPROP TRUE /**< whether dynamic propagation should be used for full orbitopes */
186 #define DEFAULT_PREFERLESSROWS TRUE /**< Shall orbitopes with less rows be preferred in detection? */
189 #define DEFAULT_OFSYMCOMPTIMING 2 /**< timing of symmetry computation for orbital fixing (0 = before presolving, 1 = during presolving, 2 = at first call) */
191 #define DEFAULT_RECOMPUTERESTART 0 /**< Recompute symmetries after a restart has occurred? (0 = never, 1 = always, 2 = if OF found reduction) */
194 #define DEFAULT_SSTTIEBREAKRULE 1 /**< index of tie break rule for selecting orbit for Schreier Sims constraints? */
195 #define DEFAULT_SSTLEADERRULE 0 /**< index of rule for selecting leader variables for Schreier Sims constraints? */
196 #define DEFAULT_SSTLEADERVARTYPE 14 /**< bitset encoding which variable types can be leaders (1: binary; 2: integer; 4: impl. int; 8: continuous);
198 #define DEFAULT_ADDCONFLICTCUTS TRUE /**< Should Schreier Sims constraints be added if we use a conflict based rule? */
200 #define DEFAULT_SSTMIXEDCOMPONENTS TRUE /**< Should Schreier Sims constraints be added if a symmetry component contains variables of different types? */
204 #define EVENTHDLR_SYMMETRY_DESC "filter global variable fixing event handler for orbital fixing"
210 #define TABLE_EARLIEST_ORBITALFIXING SCIP_STAGE_SOLVING /**< output of the statistics table is only printed from this stage onwards */
214 #define MAXGENNUMERATOR 64000000 /**< determine maximal number of generators by dividing this number by the number of variables */
215 #define SCIP_SPECIALVAL 1.12345678912345e+19 /**< special floating point value for handling zeros in bound disjunctions */
216 #define COMPRESSNVARSLB 25000 /**< lower bound on the number of variables above which compression could be performed */
242 int** permstrans; /**< pointer to store transposed permutation generators as (npermvars x nperms) matrix */
247 int nmovedimplintpermvars; /**< number of implicitly integer variables moved by any permutation */
249 SCIP_Shortbool* nonbinpermvarcaptured; /**< array to store which non-binary variables have been captured
260 unsigned* componentblocked; /**< array to store which symmetry methods have been applied to a component using
269 int maxgenerators; /**< limit on the number of generators that should be produced within symmetry detection (0 = no limit) */
271 SCIP_Bool displaynorbitvars; /**< Whether the number of variables in non-trivial orbits shall be computed */
272 SCIP_Bool compresssymmetries; /**< Should non-affected variables be removed from permutation to save memory? */
273 SCIP_Real compressthreshold; /**< Compression is used if percentage of moved vars is at most the threshold. */
277 SCIP_Bool usecolumnsparsity; /**< Should the number of conss a variable is contained in be exploited in symmetry detection? */
279 SCIP_Bool symfixnonbinaryvars; /**< Whether all non-binary variables shall be not affected by symmetries if OF is active? */
287 int addconsstiming; /**< timing of adding constraints (0 = before presolving, 1 = during presolving, 2 = after presolving) */
294 SCIP_Bool detectorbitopes; /**< Should we check whether the components of the symmetry group can be handled by orbitopes? */
295 SCIP_Bool detectsubgroups; /**< Should we try to detect orbitopes in subgroups of the symmetry group? */
296 SCIP_Bool addweaksbcs; /**< Should we add weak SBCs for enclosing orbit of symmetric subgroups? */
297 SCIP_Bool addstrongsbcs; /**< Should we add strong SBCs for enclosing orbit of symmetric subgroups if orbitopes are not used? */
301 int maxnconsssubgroup; /**< maximum number of constraints up to which subgroup structures are detected */
317 int recomputerestart; /**< Recompute symmetries after a restart has occured? (0 = never, 1 = always, 2 = if OF found reduction) */
318 int ofsymcomptiming; /**< timing of orbital fixing (0 = before presolving, 1 = during presolving, 2 = at first call) */
323 SCIP_Bool offoundreduction; /**< whether orbital fixing has found a reduction since the last time computing symmetries */
337 SCIP_Bool addconflictcuts; /**< Should Schreier Sims constraints be added if we use a conflict based rule? */
339 SCIP_Bool sstmixedcomponents; /**< Should Schreier Sims constraints be added if a symmetry component contains variables of different types? */
360 /** exec the event handler for handling global variable bound changes (necessary for orbital fixing)
362 * Global variable fixings during the solving process might arise because parts of the tree are pruned or if certain
363 * preprocessing steps are performed that do not correspond to strict setting algorithms. Since these fixings might be
364 * caused by or be in conflict with orbital fixing, they can be in conflict with the symmetry handling decisions of
365 * orbital fixing in the part of the tree that is not pruned. Thus, we have to take global fixings into account when
370 {
446 {
459 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, file, " vars fixed to 0 :%11d\n", tabledata->propdata->nfixedzero);
460 SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, file, " vars fixed to 1 :%11d\n", tabledata->propdata->nfixedone);
470 {
495 * Compare the types of two variables according to objective, lower and upper bound, variable type, and column sparsity.
499 {
539 return SCIPhashFour(SCIPrealHashCode(k->obj), SCIPrealHashCode(k->lb), SCIPrealHashCode((double) k->nconss), SCIPrealHashCode(k->ub));
544 {
548 };
553 {
556 };
570 {
604 {
631 {
761 /* If symmetry is computed before presolving, it might happen that some variables are turned into binary
762 * variables, for which no event has been catched. Since there currently is no way of checking whether a var
766 SCIP_CALL( SCIPdropVarEvent(scip, propdata->permvars[i], SCIP_EVENTTYPE_GLBCHANGED | SCIP_EVENTTYPE_GUBCHANGED,
792 SCIPfreeBlockMemoryArray(scip, &propdata->nonbinpermvarcaptured, propdata->npermvars - propdata->nbinpermvars);
924 /* if orbital fixing runs exclusively, propdata->perms was already freed in determineSymmetry() */
1059 (SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPvarGetType(var) == SCIP_VARTYPE_IMPLINT) )
1065 /** Transforms given variables, scalars, and constant to the corresponding active variables, scalars, and constant.
1073 SCIP_Real** scalars, /**< pointer to scalars a_1, ..., a_n in linear sum a_1*x_1 + ... + a_n*x_n + c */
1092 SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *nvars, constant, &requiredsize, TRUE) );
1099 SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, requiredsize, constant, &requiredsize, TRUE) );
1120 SCIP_Real* linvals, /**< array of linear coefficients values (or NULL if all linear coefficient values are 1) */
1183 /* check whether we have to resize; note that we have to add 2 * nvars since two inequalities may be added */
1190 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(matrixdata->matidx), matrixdata->nmaxmatcoef, newsize) );
1191 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(matrixdata->matrhsidx), matrixdata->nmaxmatcoef, newsize) );
1192 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(matrixdata->matvaridx), matrixdata->nmaxmatcoef, newsize) );
1193 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(matrixdata->matcoef), matrixdata->nmaxmatcoef, newsize) );
1194 SCIPdebugMsg(scip, "Resized matrix coefficients from %d to %d.\n", matrixdata->nmaxmatcoef, newsize);
1226 assert( 0 <= SCIPvarGetProbindex(vars[j]) && SCIPvarGetProbindex(vars[j]) < SCIPgetNVars(scip) );
1239 /* add negative of equation; increases chance to detect symmetry, but might increase time to compute symmetry. */
1245 assert( 0 <= SCIPvarGetProbindex(vars[j]) && SCIPvarGetProbindex(vars[j]) < SCIPgetNVars(scip) );
1287 assert( 0 <= SCIPvarGetProbindex(vars[j]) && SCIPvarGetProbindex(vars[j]) < SCIPgetNVars(scip) );
1316 assert( 0 <= SCIPvarGetProbindex(vars[j]) && SCIPvarGetProbindex(vars[j]) < SCIPgetNVars(scip) );
1339 * We need the matrix and rhs in the original order in order to speed up the comparison process. The matrix is needed
1378 /* create hashmaps for variable permutation and constraints in non-linear part array for occuring variables */
1458 if ( matrixdata->rhssense[r1] == matrixdata->rhssense[r2] && SCIPisEQ(scip, matrixdata->rhscoef[r1], matrixdata->rhscoef[r2]) )
1466 while ( j < matrixdata->nmatcoef && matrixdata->matrhsidx[j] == r2 && SCIPisEQ(scip, permrow[matrixdata->matvaridx[j]], matrixdata->matcoef[j] ) )
1554 SCIP_CALL( SCIPsimplifyExpr(scip, permutedexpr, &permutedexpr, &success, &infeasible, NULL, NULL) );
1645 return propdata->conshdlr_nonlinear != NULL && SCIPconshdlrGetNActiveConss(propdata->conshdlr_nonlinear) > 0;
1660 int* nmovedvars, /**< pointer to store number of vars affected by symmetry (if usecompression) or NULL */
1661 SCIP_Bool* binvaraffected, /**< pointer to store whether a binary variable is affected by symmetry */
1663 SCIP_Real compressthreshold, /**< if percentage of moved vars is at most threshold, compression is done */
1760 /* detect whether binary variable is affected by symmetry and count number of binary permvars */
1784 SCIP_Bool compresssymmetries, /**< Should non-affected variables be removed from permutation to save memory? */
1785 SCIP_Real compressthreshold, /**< Compression is used if percentage of moved vars is at most the threshold. */
1790 SCIP_Bool usecolumnsparsity, /**< Should the number of conss a variable is contained in be exploited in symmetry detection? */
1796 int* nmaxperms, /**< pointer to store maximal number of permutations (needed for freeing storage) */
1801 SCIP_Bool* binvaraffected, /**< pointer to store wether a binary variable is affected by symmetry */
1898 SCIPdebugMsg(scip, "Detecting %ssymmetry on %d variables and %d constraints.\n", local ? "local " : "", nvars, nactiveconss);
1901 SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &vars, SCIPgetVars(scip), nvars) ); /*lint !e666*/
1906 /* use a staggered scheme for allocating space for non-zeros of constraint matrix since it can become large */
1993 SCIP_CALL( collectCoefficients(scip, doubleequations, SCIPgetVarsLinear(scip, cons), SCIPgetValsLinear(scip, cons),
2006 /* SCIPgetBinVarsLinking returns the number of binary variables, but we also need the integer variable */
2016 /* set final entry of vars and vals to the linking variable and its coefficient, respectively */
2033 SCIP_CALL( collectCoefficients(scip, doubleequations, linvars, 0, nconsvars, 1.0, 1.0, SCIPconsIsTransformed(cons), SYM_SENSE_EQUATION, &matrixdata, nconssforvar) );
2036 SCIP_CALL( collectCoefficients(scip, doubleequations, linvars, 0, nconsvars, -SCIPinfinity(scip), 1.0, SCIPconsIsTransformed(cons), SYM_SENSE_INEQUALITY, &matrixdata, nconssforvar) );
2039 SCIP_CALL( collectCoefficients(scip, doubleequations, linvars, 0, nconsvars, 1.0, SCIPinfinity(scip), SCIPconsIsTransformed(cons), SYM_SENSE_INEQUALITY, &matrixdata, nconssforvar) );
2072 SCIP_CALL( collectCoefficients(scip, doubleequations, consvars, consvals, nconsvars, (SCIP_Real) SCIPgetRhsXor(scip, cons),
2073 (SCIP_Real) SCIPgetRhsXor(scip, cons), SCIPconsIsTransformed(cons), SYM_SENSE_XOR, &matrixdata, nconssforvar) );
2127 SCIP_CALL( collectCoefficients(scip, doubleequations, SCIPgetVarsLogicor(scip, cons), 0, SCIPgetNVarsLogicor(scip, cons),
2128 1.0, SCIPinfinity(scip), SCIPconsIsTransformed(cons), SYM_SENSE_INEQUALITY, &matrixdata, nconssforvar) );
2142 SCIP_CALL( collectCoefficients(scip, doubleequations, SCIPgetVarsKnapsack(scip, cons), consvals, nconsvars, -SCIPinfinity(scip),
2143 (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons), SCIPconsIsTransformed(cons), SYM_SENSE_INEQUALITY, &matrixdata, nconssforvar) );
2153 SCIP_CALL( collectCoefficients(scip, doubleequations, consvars, consvals, 2, SCIPgetLhsVarbound(scip, cons),
2154 SCIPgetRhsVarbound(scip, cons), SCIPconsIsTransformed(cons), SYM_SENSE_INEQUALITY, &matrixdata, nconssforvar) );
2168 * is of type 1. If the bound disjunction has length two and both disjunctions contain the same variable,
2169 * we say the bound disjunction is of type 2. Further bound disjunctions are possible, but can currently
2180 * Note that problems arise if \fb'_i = 0\f for some variable \fx_i\f, because its coefficient in the
2218 /* stop, we cannot handle bounddisjunctions with more than two variables that contain a variable twice */
2224 " Deactivated symmetry handling methods, there exist constraints that cannot be handled by symmetry methods.\n");
2249 SCIP_CALL( collectCoefficients(scip, doubleequations, consvars, consvals, nbounddisjvars, 0.0, 0.0,
2279 for (expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it)) /*lint !e441*/ /*lint !e440*/
2283 /* for variables, we check whether they appear nonlinearly and store the result in the resp. array */
2287 (*isnonlinvar)[SCIPvarGetProbindex(SCIPgetVarExprVar(expr))] = (SCIPexpriterGetParentDFS(it) != rootexpr || !SCIPisExprSum(scip, rootexpr));
2314 SCIPerrorMessage("Cannot determine symmetries for constraint <%s> of constraint handler <%s>.\n",
2357 SCIP_CALL( SCIPhashtableCreate(&vartypemap, SCIPblkmem(scip), 5 * nvars, SYMhashGetKeyVartype, SYMhashKeyEQVartype, SYMhashKeyValVartype, (void*) scip) );
2377 if ( SymmetryFixVar(fixedtype, var) || (nnlconss > 0 && SCIPhashsetExists(auxvars, (void*) var)) )
2381 SCIPdebugMsg(scip, "Detected variable <%s> of fixed type %d - color %d.\n", SCIPvarGetName(var), SCIPvarGetType(var), matrixdata.nuniquevars - 1);
2412 SCIPdebugMsg(scip, "Detected variable <%s> of new type (probindex: %d, obj: %g, lb: %g, ub: %g, type: %d) - color %d.\n",
2413 SCIPvarGetName(var), SCIPvarGetProbindex(var), vt->obj, vt->lb, vt->ub, vt->type, matrixdata.nuniquevars - 1);
2476 SCIPdebugMsg(scip, "Detected new matrix entry type %f - color: %d\n.", val, matrixdata.nuniquemat);
2510 SCIPdebugMsg(scip, "Detected new rhs type %f, type: %u - color: %d\n", val, sense, matrixdata.nuniquerhs);
2525 SCIPdebugMsg(scip, "Number of detected different variables: %d (total: %d).\n", matrixdata.nuniquevars, nvars);
2526 SCIPdebugMsg(scip, "Number of detected different rhs types: %d (total: %d).\n", matrixdata.nuniquerhs, matrixdata.nrhscoef);
2527 SCIPdebugMsg(scip, "Number of detected different matrix coefficients: %d (total: %d).\n", matrixdata.nuniquemat, matrixdata.nmatcoef);
2529 /* do not compute symmetry if all variables are non-equivalent (unique) or if all matrix coefficients are different */
2530 if ( matrixdata.nuniquevars < nvars && (matrixdata.nuniquemat == 0 || matrixdata.nuniquemat < matrixdata.nmatcoef) )
2533 SCIP_CALL( SYMcomputeSymmetryGenerators(scip, maxgenerators, &matrixdata, &exprdata, nperms, nmaxperms,
2538 if ( checksymmetries && SCIPgetStage(scip) > SCIP_STAGE_INITPRESOLVE && ! SCIPisStopped(scip) )
2545 SCIP_CALL( setSymmetryData(scip, vars, nvars, nbinvars, permvars, npermvars, nbinpermvars, *perms, *nperms,
2599 SYM_SPEC symspecrequire, /**< symmetry specification for which we need to compute symmetries */
2600 SYM_SPEC symspecrequirefixed /**< symmetry specification of variables which must be fixed by symmetries */
2651 " Deactivated symmetry handling methods, since SCIP was built without symmetry detector (SYM=none).\n");
2677 /* do not compute symmetry if there are no binary variables and non-binary variables cannot be handled, but only binary variables would be used */
2700 /* count implicit integer variables as real variables, since we cannot currently handle integral variables well */
2708 " (%.1fs) symmetry computation skipped: type (bin %c, int %c, cont %c) does not match requirements (bin %c, int %c, cont %c).\n",
2725 if ( SCIPgetNRuns(scip) > propdata->lastrestart && (propdata->recomputerestart == SCIP_RECOMPUTESYM_ALWAYS ||
2746 " (%.1fs) symmetry computation skipped: there exist constraints that cannot be handled by symmetry methods.\n",
2767 " (%.1fs) symmetry computation started: requiring (bin %c, int %c, cont %c), (fixed: bin %c, int %c, cont %c)\n",
2785 SCIP_CALL( computeSymmetryGroup(scip, propdata->doubleequations, propdata->compresssymmetries, propdata->compressthreshold,
2786 maxgenerators, symspecrequirefixed, FALSE, propdata->checksymmetries, propdata->usecolumnsparsity, propdata->conshdlr_nonlinear,
2787 &propdata->npermvars, &propdata->nbinpermvars, &propdata->permvars, &propdata->nperms, &propdata->nmaxperms,
2801 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, " (%.1fs) could not compute symmetry\n", SCIPgetSolvingTime(scip));
2814 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, " (%.1fs) no symmetry present\n", SCIPgetSolvingTime(scip));
2824 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, " (%.1fs) symmetry computation finished: %d generators found (max: ",
2834 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, ", log10 of symmetry group size: %.1f", propdata->log10groupsize);
2840 SCIP_CALL( SCIPdetermineNVarsAffectedSym(scip, propdata->perms, propdata->nperms, propdata->permvars,
2843 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, ", number of affected variables: %d)\n", propdata->nmovedvars);
2847 /* exit if no binary variables are affected by symmetry and we cannot handle non-binary symmetries */
2850 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, " (%.1fs) no symmetry on binary variables present.\n", SCIPgetSolvingTime(scip));
2856 ! ( ISSSTINTACTIVE(propdata->sstleadervartype) || ISSSTIMPLINTACTIVE(propdata->sstleadervartype)
2861 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, " (%.1fs) -> no handable symmetry found, free symmetry data.\n",
2880 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, " (%.1fs) component computation started\n", SCIPgetSolvingTime(scip));
2883 /* we only need the components for orbital fixing, orbitope and subgroup detection, and Schreier Sims constraints */
2887 SCIP_CALL( SCIPcomputeComponentsSym(scip, propdata->perms, propdata->nperms, propdata->permvars,
2893 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, " (%.1fs) component computation finished\n", SCIPgetSolvingTime(scip));
2959 /* Only catch binary variables, since integer variables should be fixed pointwise; implicit integer variables
2964 SCIP_CALL( SCIPcatchVarEvent(scip, propdata->permvars[v], SCIP_EVENTTYPE_GLBCHANGED | SCIP_EVENTTYPE_GUBCHANGED,
3035 /* if Schreier-Sims constraints are enabled, also capture symmetric variables and forbid multi aggregation of handable vars */
3090 /** Checks whether given set of 2-cycle permutations forms an orbitope and if so, builds the variable index matrix.
3092 * If @p activevars == NULL, then the function assumes all permutations of the component are active and therefore all
3095 * We need to keep track of the number of generatored columns, because we might not be able to detect all orbitopes.
3096 * For example (1,2), (2,3), (3,4), (3,5) defines the symmetric group on {1,2,3,4,5}, but the generators we expect
3191 /* in the subgroup case it might happen that a generator has less than ntwocycles many 2-cyles */
3234 j = 0; /*lint !e850*/ /* reset j since previous permutations can now intersect with the latest added column */
3271 j = 0; /*lint !e850*/ /* reset j since previous permutations can now intersect with the latest added column */
3294 int* ntwocycleperms /**< pointer to store the number of 2-cycle permutations in component compidx */
3336 SCIP_CALL( SCIPisInvolutionPerm(perm, propdata->permvars, npermvars, &(ntwocycles[i]), &nbincycles, FALSE) );
3362 * After execution, @p graphcomponents contains all permvars sorted by their color and component,
3363 * @p graphcompbegins points to the indices where new components in @p graphcomponents start and
3373 int** graphcomponents, /**< buffer to store the components of the graph (ordered var indices) */
3446 /* iteratively handle each swap of perm until an invalid one is found or all edges have been added */
3466 /* another permutation has already merged these variables into one component; store its color */
3485 /* a generator is not allowed to connect two components of the same color, since they depend on each other */
3553 assert( SCIPdisjointsetFind(comptocolor, SCIPdisjointsetFind(vartocomponent, k)) == firstcolor );
3554 assert( SCIPdisjointsetFind(comptocolor, SCIPdisjointsetFind(vartocomponent, img)) == firstcolor );
3564 * disjoint sets to the arrays graphcomponents, graphcompbegins, and compcolorbegins (see above).
3650 SCIP_Bool mayinteract, /**< whether orbitope's symmetries might interact with other symmetries */
3739 /* it might happen that we cannot detect the orbitope if it is generated by permutations with different
3775 for (k = compcolorbegins[graphcoloridx]; k < compcolorbegins[graphcoloridx+1] && (*compidxfirstrow) < 0; ++k)
3787 /* iterate over all columns (elements in orbit), because we cannot see from ngencols which columns
3817 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "suborbitope_%d_%d", graphcoloridx, propdata->norbitopes);
3820 SCIP_ORBITOPETYPE_FULL, nrows, ngencols, FALSE, mayinteract, FALSE, FALSE, propdata->conssaddlp,
3851 SCIP_Bool storelexorder, /**< whether the lexicographic order induced by the orbitope shall be stored */
3904 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "strong_sbcs_%s_%s", SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]));
3925 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &propdata->genlinconss, propdata->genlinconsssize, newsize) );
3950 SCIP_Bool storelexorder, /**< whether the lexicographic order induced by the orbitope shall be stored */
4006 assert( ! SCIPhashmapExists(varsinlexorder, (void*) (long) (*lexorder)[k]) ); /* Use int as pointer */
4011 /* We will store the newest and the largest orbit and activeorb will be used to mark at which entry of the array
4029 /* if the first variable was already contained in another orbit or if there are no variables left anyway, skip the
4078 SCIPdebugMsg(scip, " adding %d weak sbcs for enclosing orbit of color %d.\n", orbitsize[activeorb]-1, chosencolor);
4090 (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "weak_sbcs_%d_%s_%s", symgrpcompidx, SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]));
4111 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &propdata->genlinconss, propdata->genlinconsssize, newsize) );
4142 /* the leader of the weak inequalities has to be the first element in the lexicographic order */
4190 SCIP_VAR** modifiedpermvars, /**< memory for array of permutation vars w.r.t. new variable ordering */
4226 /* Iterate over leaders and put the l-th leader to the l-th position of the lexicographic order.
4227 * We do this by swapping the l-th leader with the element at position l of the current permvars array. */
4389 /* create arrays for modified permutations in case we adapt the lexicographic order because of suborbitopes */
4404 SCIPdebugMsg(scip, "starting subgroup detection routine for %d components\n", propdata->ncomponents);
4440 /* set the first npermsincomp entries of genorder; the others are not used for this component */
4449 SCIPdebugMsg(scip, "component %d has %d permutations consisting of 2-cycles\n", i, ntwocycleperms);
4477 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "(%s,", SCIPvarGetName(propdata->permvars[k]));
4481 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "%s,", SCIPvarGetName(propdata->permvars[j]));
4508 SCIPdebugMsg(scip, " created subgroup detection graph using %d of the permutations\n", nusedperms);
4549 norbitopesincomp = getNOrbitopesInComp(propdata->permvars, graphcomponents, graphcompbegins, compcolorbegins,
4552 /* if there is just one orbitope satisfying the requirements, handle the full component by symresacks */
4564 SCIP_CALL( SCIPcreateSymbreakCons(scip, &cons, name, propdata->perms[propdata->components[propdata->componentbegins[i] + k]],
4610 SCIPdebugMsg(scip, " color %d has %d components with overall %d variables\n", j, compcolorbegins[j+1] - compcolorbegins[j],
4662 SCIPdebugMsg(scip, " affected types (bin,int,cont): (%d,%d,%d)\n", binaffected, intaffected, contaffected);
4675 SCIPdebugMsg(scip, " detected an orbitope with %d rows and %d columns\n", nbinarycomps, largestcompsize);
4682 * It might happen that we cannot generate the orbitope matrix if the orbitope is not generated by permutations
4683 * all having the same number of 2-cycles, e.g., the orbitope generated by (1,2)(4,5), (2,3), (5,6).
4696 /* adapt the first variable per color to be compatible with the created orbiope (upper left variable) */
4736 SCIP_CALL( addStrongSBCsSubgroup(scip, propdata, graphcompbegins, graphcomponents, largestcolorcomp,
4740 if ( ! SCIPvarIsBinary(propdata->permvars[graphcomponents[graphcompbegins[largestcolorcomp]]]) )
4787 SCIPdebugMsg(scip, " don't add weak sbcs because all generators were used or the settings forbid it\n");
4789 /* if suborbitopes or strong group actions have been found, potentially add symresacks adapted to
4810 SCIP_CALL( SCIPcreateSymbreakCons(scip, &cons, name, modifiedperms[propdata->components[propdata->componentbegins[i] + k]],
4825 SCIPdebugMsg(scip, " add symresack for permutation %d of component %d adapted to suborbitope lexorder\n", k, i);
4866 /** sorts orbitope vars matrix such that rows are sorted increasingly w.r.t. minimum variable index in row;
4956 int* componentbegins, /**< array containing begin positions of components in components array */
5045 /* no or different number of 2-cycles or not all vars binary: permutations cannot generate orbitope */
5066 SCIP_CALL( SCIPallocBufferArray(scip, &orbitopevaridx[j], npermsincomponent + 1) ); /*lint !e866*/
5105 SCIP_CALL( SCIPgenerateOrbitopeVarsMatrix(scip, &vars, ntwocyclescomp, npermsincomponent + 1, permvars,
5106 npermvars, orbitopevaridx, columnorder, nusedelems, rowisbinary, &infeasibleorbitope, FALSE, NULL, NULL, NULL) );
5112 SCIPdebugMsg(scip, "found an orbitope of size %d x %d in component %d\n", ntwocyclescomp, npermsincomponent + 1, i);
5117 SCIP_CALL( SCIPsortOrbitope(scip, orbitopevaridx, vars, nbincyclescomp, npermsincomponent + 1) );
5160 SCIP_VAR** graphvars, /**< variables encoded in conflict graph (either all vars or permvars) */
5309 SCIP_Bool* success /**< pointer to store whether conflict graph could be created successfully */
5337 SCIPdebugMsg(scip, "Could not find setppc conshdlr --> construction of conflict graph aborted.\n");
5346 SCIPdebugMsg(scip, "No setppc constraints present --> construction of conflict graph aborted.\n");
5418 SCIPdebugMsg(scip, "Construction of conflict graph terminated; %d conflicts detected.\n", nedges);
5467 int* componentbegins, /**< array containing begin positions of components in components array */
5508 /* adapt natural variable order to a variable order that is compatible with Schreier Sims constraints */
5521 SCIP_CALL( adaptSymmetryDataSST(scip, perms, modifiedperms, nperms, permvars, modifiedpermvars, npermvars,
5587 SCIP_CALL( SCIPcreateSymbreakCons(scip, &cons, name, modifiedperms[permidx], modifiedpermvars, npermvars, FALSE,
5592 SCIP_CALL( SCIPcreateSymbreakCons(scip, &cons, name, perms[permidx], permvars, npermvars, FALSE,
5636 SCIP_Shortbool* orbitvarinconflict, /**< indicator whether orbitvar is in conflict with orbit leader */
5670 /* variables in conflict with leader are fixed and not treated by a cut; trailing -1 to not count the leader */
5792 SCIP_HASHMAP* varmap, /**< map from variable to node label in conflict graph or NULL if useconflictgraph == FALSE */
5803 SCIP_Shortbool* orbitvarinconflict, /**< array to store whether a var in the orbit is conflicting with leader */
5804 int* norbitvarinconflict, /**< pointer to store number of vars in the orbit in conflict with leader */
5849 if ( leaderrule == (int) SCIP_LEADERRULE_FIRSTINORBIT || leaderrule == (int) SCIP_LEADERRULE_LASTINORBIT )