Scippy

SCIP

Solving Constraint Integer Programs

prop_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-2023 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 prop_symmetry.c
26  * @ingroup DEFPLUGINS_PROP
27  * @brief propagator for handling symmetries
28  * @author Marc Pfetsch
29  * @author Thomas Rehn
30  * @author Christopher Hojny
31  * @author Fabian Wegscheider
32  *
33  * This propagator combines the following symmetry handling functionalities:
34  * - It allows to compute symmetries of the problem and to store this information in adequate form. The symmetry
35  * information can be accessed through external functions.
36  * - It allows to add the following symmetry breaking constraints:
37  * - symresack constraints, which separate minimal cover inequalities
38  * - orbitope constraints, if special symmetry group structures are detected
39  * - It allows to apply orbital fixing.
40  *
41  *
42  * @section SYMCOMP Symmetry Computation
43  *
44  * The following comments apply to symmetry computation.
45  *
46  * - The generic functionality of the compute_symmetry.h interface is used.
47  * - We treat implicit integer variables as if they were continuous/real variables. The reason is that there is currently
48  * no distinction between implicit integer and implicit binary. Moreover, currently implicit integer variables hurt
49  * our code more than continuous/real variables (we basically do not handle integral variables at all).
50  * - We do not copy symmetry information, since it is not clear how this information transfers. Moreover, copying
51  * symmetry might inhibit heuristics. But note that solving a sub-SCIP might then happen without symmetry information!
52  *
53  *
54  * @section SYMBREAK Symmetry Handling Constraints
55  *
56  * The following comments apply to adding symmetry handling constraints.
57  *
58  * - The code automatically detects whether symmetry substructures like symresacks or orbitopes are present and possibly
59  * adds the corresponding constraints.
60  * - If orbital fixing is active, only orbitopes are added (if present) and no symresacks.
61  * - We try to compute symmetry as late as possible and then add constraints based on this information.
62  * - Currently, we only allocate memory for pointers to symresack constraints for group generators. If further
63  * constraints are considered, we have to reallocate memory.
64  *
65  *
66  * @section OF Orbital Fixing
67  *
68  * Orbital fixing is implemented as introduced by@n
69  * F. Margot: Exploiting orbits in symmetric ILP. Math. Program., 98(1-3):3–21, 2003.
70  *
71  * The method computes orbits of variables with respect to the subgroup of the symmetry group that stabilizes the
72  * 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
73  * variables in the orbit is fixed to 0 or 1, respectively. Different from Margot, the subgroup is obtained by filtering
74  * out generators that do not individually stabilize the variables branched to 1.
75  *
76  * @pre All variable fixings applied by other components are required to be strict, i.e., if one variable is fixed to
77  * a certain value v, all other variables in the same variable orbit can be fixed to v as well, c.f.@n
78  * F. Margot: Symmetry in integer linear programming. 50 Years of Integer Programming, 647-686, Springer 2010.
79  *
80  * To illustrate this, consider the example \f$\max\{x_1 + x_2 : x_1 + x_2 \leq 1, Ay \leq b,
81  * (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
82  * setppc constraint handler may fix \f$(x_1,x_2) = (1,0)\f$. However, since both variables are symmetric, this setting
83  * is not strict (if it was strict, both variables would have been set to the same value) and orbital fixing would
84  * declare this subsolution as infeasible (there exists an orbit of non-branching variables that are fixed to different
85  * values). To avoid this situation, we have to assume that all non-strict settings fix variables globally, i.e., we
86  * can take care of it by taking variables into account that have been globally fixed to 1. In fact, it suffices to
87  * consider one kind of global fixings since stabilizing one kind prevents an orbit to contain variables that have
88  * been fixed globally to different values.
89  *
90  * @pre All non-strict settings are global settings, since otherwise, we cannot (efficiently) take care of them.
91  *
92  * @pre No non-strict setting algorithm is interrupted early (e.g., by a time or iteration limit), since this may lead to
93  * wrong decisions by orbital fixing as well. For example, if cons_setppc in the above toy example starts by fixing
94  * \f$x_2 = 0\f$ and is interrupted afterwards, orbital fixing detects that the orbit \f$\{x_1, x_2\}\f$ contains
95  * one variable that is fixed to 0, and thus, it fixes \f$x_1\f$ to 0 as well. Thus, after these reductions, every
96  * feasible solution has objective 0 which is not optimal. This situation would not occur if the non-strict setting is
97  * complete, because then \f$x_1\f$ is globally fixed to 1, and thus, is stabilized in orbital fixing.
98  *
99  * Note that orbital fixing might lead to wrong results if it is called in repropagation of a node, because the path
100  * from the node to the root might have been changed. Thus, the stabilizers of global 1-fixing and 1-branchings of the
101  * initial propagation and repropagation might differ, which may cause conflicts. For this reason, orbital fixing cannot
102  * be called in repropagation.
103  *
104  * @note If, besides orbital fixing, also symmetry handling constraints shall be added, orbital fixing is only applied
105  * to symmetry components that are not handled by orbitope constraints.
106  *
107  *
108  * @section SST Cuts derived from the Schreier Sims table
109  *
110  * SST cuts have been introduced by@n
111  * D. Salvagnin: Symmetry Breaking Inequalities from the Schreier-Sims table. CPAIOR 2018 Proceedings, 521-529, 2018.
112  *
113  * These inequalities are computed as follows. Throughout these procedure a set of so-called leaders is maintained.
114  * 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.
115  * the symmetry group of the mixed-integer program. For each variable \f$x_j\f$ in the orbit of \f$x_i\f$, the
116  * inequality \f$x_i \geq x_j\f$ is a valid symmetry handling inequality, which can be added to the mixed-integer
117  * 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
118  * compute the pointwise stabilizer of the leader set. In the next step, select a new variable, compute its orbit
119  * w.r.t. the stabilizer group of the leaders, add the inequalities based on this orbit, and add the new leader
120  * to the set of leaders. This procedure is iterated until the pointwise stabilizer group of the leaders has become
121  * trivial.
122  *
123  * @todo Possibly turn off propagator in subtrees.
124  * @todo Check application of conflict resolution.
125  * @todo Check whether one should switch the role of 0 and 1
126  * @todo Implement stablizer computation?
127  * @todo Implement isomorphism pruning?
128  * @todo Implement particular preprocessing rules
129  * @todo Separate permuted cuts (first experiments not successful)
130  * @todo Allow the computation of local symmetries
131  * @todo Order rows of orbitopes (in particular packing/partitioning) w.r.t. cliques in conflict graph.
132  */
133 /* #define SCIP_OUTPUT */
134 /* #define SCIP_OUTPUT_COMPONENT */
135 
136 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
137 
138 #include <scip/cons_linear.h>
139 #include <scip/cons_knapsack.h>
140 #include <scip/cons_varbound.h>
141 #include <scip/cons_setppc.h>
142 #include <scip/cons_and.h>
143 #include <scip/cons_logicor.h>
144 #include <scip/cons_or.h>
145 #include <scip/cons_orbitope.h>
146 #include <scip/cons_symresack.h>
147 #include <scip/cons_xor.h>
148 #include <scip/cons_linking.h>
150 #include <scip/cons_nonlinear.h>
151 #include <scip/pub_expr.h>
152 #include <scip/misc.h>
154 
155 #include <scip/prop_symmetry.h>
157 #include <scip/symmetry.h>
158 
159 #include <string.h>
160 
161 /* propagator properties */
162 #define PROP_NAME "symmetry"
163 #define PROP_DESC "propagator for handling symmetry"
164 #define PROP_TIMING SCIP_PROPTIMING_BEFORELP /**< propagation timing mask */
165 #define PROP_PRIORITY -1000000 /**< propagator priority */
166 #define PROP_FREQ 1 /**< propagator frequency */
167 #define PROP_DELAY FALSE /**< should propagation method be delayed, if other propagators found reductions? */
168 
169 #define PROP_PRESOL_PRIORITY -10000000 /**< priority of the presolving method (>= 0: before, < 0: after constraint handlers) */
170 #define PROP_PRESOLTIMING SCIP_PRESOLTIMING_EXHAUSTIVE /* timing of the presolving method (fast, medium, or exhaustive) */
171 #define PROP_PRESOL_MAXROUNDS -1 /**< maximal number of presolving rounds the presolver participates in (-1: no limit) */
172 
173 
174 /* default parameter values for symmetry computation */
175 #define DEFAULT_MAXGENERATORS 1500 /**< limit on the number of generators that should be produced within symmetry detection (0 = no limit) */
176 #define DEFAULT_CHECKSYMMETRIES FALSE /**< Should all symmetries be checked after computation? */
177 #define DEFAULT_DISPLAYNORBITVARS FALSE /**< Should the number of variables affected by some symmetry be displayed? */
178 #define DEFAULT_USECOLUMNSPARSITY FALSE /**< Should the number of conss a variable is contained in be exploited in symmetry detection? */
179 #define DEFAULT_DOUBLEEQUATIONS FALSE /**< Double equations to positive/negative version? */
180 #define DEFAULT_COMPRESSSYMMETRIES TRUE /**< Should non-affected variables be removed from permutation to save memory? */
181 #define DEFAULT_COMPRESSTHRESHOLD 0.5 /**< Compression is used if percentage of moved vars is at most the threshold. */
182 #define DEFAULT_SYMFIXNONBINARYVARS FALSE /**< Whether all non-binary variables shall be not affected by symmetries if OF is active? */
183 #define DEFAULT_ONLYBINARYSYMMETRY TRUE /**< Is only symmetry on binary variables used? */
184 
185 /* default parameters for linear symmetry constraints */
186 #define DEFAULT_CONSSADDLP TRUE /**< Should the symmetry breaking constraints be added to the LP? */
187 #define DEFAULT_ADDSYMRESACKS FALSE /**< Add inequalities for symresacks for each generator? */
188 #define DEFAULT_DETECTORBITOPES TRUE /**< Should we check whether the components of the symmetry group can be handled by orbitopes? */
189 #define DEFAULT_DETECTSUBGROUPS TRUE /**< Should we try to detect orbitopes in subgroups of the symmetry group? */
190 #define DEFAULT_ADDWEAKSBCS TRUE /**< Should we add weak SBCs for enclosing orbit of symmetric subgroups? */
191 #define DEFAULT_ADDSTRONGSBCS FALSE /**< Should we add strong SBCs for enclosing orbit of symmetric subgroups if orbitopes are not used? */
192 #define DEFAULT_ADDCONSSTIMING 2 /**< timing of adding constraints (0 = before presolving, 1 = during presolving, 2 = after presolving) */
193 #define DEFAULT_MAXNCONSSSUBGROUP 500000 /**< Maximum number of constraints up to which subgroup structures are detected */
194 #define DEFAULT_USEDYNAMICPROP TRUE /**< whether dynamic propagation should be used for full orbitopes */
195 #define DEFAULT_PREFERLESSROWS TRUE /**< Shall orbitopes with less rows be preferred in detection? */
196 
197 /* default parameters for orbital fixing */
198 #define DEFAULT_OFSYMCOMPTIMING 2 /**< timing of symmetry computation for orbital fixing (0 = before presolving, 1 = during presolving, 2 = at first call) */
199 #define DEFAULT_PERFORMPRESOLVING FALSE /**< Run orbital fixing during presolving? */
200 #define DEFAULT_RECOMPUTERESTART 0 /**< Recompute symmetries after a restart has occurred? (0 = never) */
201 
202 /* default parameters for Schreier Sims constraints */
203 #define DEFAULT_SSTTIEBREAKRULE 1 /**< index of tie break rule for selecting orbit for Schreier Sims constraints? */
204 #define DEFAULT_SSTLEADERRULE 0 /**< index of rule for selecting leader variables for Schreier Sims constraints? */
205 #define DEFAULT_SSTLEADERVARTYPE 14 /**< bitset encoding which variable types can be leaders (1: binary; 2: integer; 4: impl. int; 8: continuous);
206  * if multiple types are allowed, take the one with most affected vars */
207 #define DEFAULT_ADDCONFLICTCUTS TRUE /**< Should Schreier Sims constraints be added if we use a conflict based rule? */
208 #define DEFAULT_SSTADDCUTS TRUE /**< Should Schreier Sims constraints be added? */
209 #define DEFAULT_SSTMIXEDCOMPONENTS TRUE /**< Should Schreier Sims constraints be added if a symmetry component contains variables of different types? */
211 /* event handler properties */
212 #define EVENTHDLR_SYMMETRY_NAME "symmetry"
213 #define EVENTHDLR_SYMMETRY_DESC "filter global variable fixing event handler for orbital fixing"
215 /* output table properties */
216 #define TABLE_NAME_ORBITALFIXING "orbitalfixing"
217 #define TABLE_DESC_ORBITALFIXING "orbital fixing statistics"
218 #define TABLE_POSITION_ORBITALFIXING 7001 /**< the position of the statistics table */
219 #define TABLE_EARLIEST_ORBITALFIXING SCIP_STAGE_SOLVING /**< output of the statistics table is only printed from this stage onwards */
221 
222 /* other defines */
223 #define MAXGENNUMERATOR 64000000 /**< determine maximal number of generators by dividing this number by the number of variables */
224 #define SCIP_SPECIALVAL 1.12345678912345e+19 /**< special floating point value for handling zeros in bound disjunctions */
225 #define COMPRESSNVARSLB 25000 /**< lower bound on the number of variables above which compression could be performed */
227 /* macros for getting activeness of symmetry handling methods */
228 #define ISSYMRETOPESACTIVE(x) (((unsigned) x & SYM_HANDLETYPE_SYMBREAK) != 0)
229 #define ISORBITALFIXINGACTIVE(x) (((unsigned) x & SYM_HANDLETYPE_ORBITALFIXING) != 0)
230 #define ISSSTACTIVE(x) (((unsigned) x & SYM_HANDLETYPE_SST) != 0)
232 #define ISSSTBINACTIVE(x) (((unsigned) x & SCIP_SSTTYPE_BINARY) != 0)
233 #define ISSSTINTACTIVE(x) (((unsigned) x & SCIP_SSTTYPE_INTEGER) != 0)
234 #define ISSSTIMPLINTACTIVE(x) (((unsigned) x & SCIP_SSTTYPE_IMPLINT) != 0)
235 #define ISSSTCONTACTIVE(x) (((unsigned) x & SCIP_SSTTYPE_CONTINUOUS) != 0)
237 
238 /** propagator data */
239 struct SCIP_PropData
240 {
241  /* symmetry group information */
242  int npermvars; /**< number of variables for permutations */
243  int nbinpermvars; /**< number of binary variables for permuations */
244  SCIP_VAR** permvars; /**< variables on which permutations act */
245 #ifndef NDEBUG
246  SCIP_Real* permvarsobj; /**< objective values of permuted variables (for debugging) */
247 #endif
248  int nperms; /**< number of permutations */
249  int nmaxperms; /**< maximal number of permutations (needed for freeing storage) */
250  int** perms; /**< pointer to store permutation generators as (nperms x npermvars) matrix */
251  int** permstrans; /**< pointer to store transposed permutation generators as (npermvars x nperms) matrix */
252  SCIP_HASHMAP* permvarmap; /**< map of variables to indices in permvars array */
253  int nmovedpermvars; /**< number of variables moved by any permutation */
254  int nmovedbinpermvars; /**< number of binary variables moved by any permutation */
255  int nmovedintpermvars; /**< number of integer variables moved by any permutation */
256  int nmovedimplintpermvars; /**< number of implicitly integer variables moved by any permutation */
257  int nmovedcontpermvars; /**< number of continuous variables moved by any permutation */
258  SCIP_Shortbool* nonbinpermvarcaptured; /**< array to store which non-binary variables have been captured
259  * (only necessary for SST cuts) */
260 
261  /* components of symmetry group */
262  int ncomponents; /**< number of components of symmetry group */
263  int ncompblocked; /**< number of components that have been blocked */
264  int* components; /**< array containing the indices of permutations sorted by components */
265  int* componentbegins; /**< array containing in i-th position the first position of
266  * component i in components array */
267  int* vartocomponent; /**< array containing for each permvar the index of the component it is
268  * contained in (-1 if not affected) */
269  unsigned* componentblocked; /**< array to store which symmetry methods have been applied to a component using
270  * the same bitset as for misc/usesymmetry */
271 
272  /* further symmetry information */
273  int nmovedvars; /**< number of variables moved by some permutation */
274  SCIP_Real log10groupsize; /**< log10 of size of symmetry group */
275  SCIP_Bool binvaraffected; /**< whether binary variables are affected by some symmetry */
276 
277  /* for symmetry computation */
278  int maxgenerators; /**< limit on the number of generators that should be produced within symmetry detection (0 = no limit) */
279  SCIP_Bool checksymmetries; /**< Should all symmetries be checked after computation? */
280  SCIP_Bool displaynorbitvars; /**< Whether the number of variables in non-trivial orbits shall be computed */
281  SCIP_Bool compresssymmetries; /**< Should non-affected variables be removed from permutation to save memory? */
282  SCIP_Real compressthreshold; /**< Compression is used if percentage of moved vars is at most the threshold. */
283  SCIP_Bool compressed; /**< Whether symmetry data has been compressed */
284  SCIP_Bool computedsymmetry; /**< Have we already tried to compute symmetries? */
285  int usesymmetry; /**< encoding of active symmetry handling methods (for debugging) */
286  SCIP_Bool usecolumnsparsity; /**< Should the number of conss a variable is contained in be exploited in symmetry detection? */
287  SCIP_Bool doubleequations; /**< Double equations to positive/negative version? */
288  SCIP_Bool symfixnonbinaryvars; /**< Whether all non-binary variables shall be not affected by symmetries if OF is active? */
289  SCIP_Bool onlybinarysymmetry; /**< Whether only symmetry on binary variables is used */
290 
291  /* for symmetry constraints */
292  SCIP_Bool symconsenabled; /**< Should symmetry constraints be added? */
293  SCIP_Bool triedaddconss; /**< whether we already tried to add symmetry breaking constraints */
294  SCIP_Bool conssaddlp; /**< Should the symmetry breaking constraints be added to the LP? */
295  SCIP_Bool addsymresacks; /**< Add symresack constraints for each generator? */
296  int addconsstiming; /**< timing of adding constraints (0 = before presolving, 1 = during presolving, 2 = after presolving) */
297  SCIP_CONS** genorbconss; /**< list of generated orbitope/orbisack/symresack constraints */
298  SCIP_CONS** genlinconss; /**< list of generated linear constraints */
299  int ngenorbconss; /**< number of generated orbitope/orbisack/symresack constraints */
300  int ngenlinconss; /**< number of generated linear constraints */
301  int genlinconsssize; /**< size of linear constraints array */
302  int nsymresacks; /**< number of symresack constraints */
303  SCIP_Bool detectorbitopes; /**< Should we check whether the components of the symmetry group can be handled by orbitopes? */
304  SCIP_Bool detectsubgroups; /**< Should we try to detect orbitopes in subgroups of the symmetry group? */
305  SCIP_Bool addweaksbcs; /**< Should we add weak SBCs for enclosing orbit of symmetric subgroups? */
306  SCIP_Bool addstrongsbcs; /**< Should we add strong SBCs for enclosing orbit of symmetric subgroups if orbitopes are not used? */
307  int norbitopes; /**< number of orbitope constraints */
308  SCIP_Bool* isnonlinvar; /**< array indicating whether variables apper non-linearly */
309  SCIP_CONSHDLR* conshdlr_nonlinear; /**< nonlinear constraint handler */
310  int maxnconsssubgroup; /**< maximum number of constraints up to which subgroup structures are detected */
311  SCIP_Bool usedynamicprop; /**< whether dynamic propagation should be used for full orbitopes */
312  SCIP_Bool preferlessrows; /**< Shall orbitopes with less rows be preferred in detection? */
313 
314  /* data necessary for orbital fixing */
315  SCIP_Bool ofenabled; /**< Run orbital fixing? */
316  SCIP_EVENTHDLR* eventhdlr; /**< event handler for handling global variable fixings */
317  SCIP_Shortbool* bg0; /**< bitset to store variables globally fixed to 0 */
318  int* bg0list; /**< list of variables globally fixed to 0 */
319  int nbg0; /**< number of variables in bg0 and bg0list */
320  SCIP_Shortbool* bg1; /**< bitset to store variables globally fixed or branched to 1 */
321  int* bg1list; /**< list of variables globally fixed or branched to 1 */
322  int nbg1; /**< number of variables in bg1 and bg1list */
323  int* permvarsevents; /**< stores events caught for permvars */
324  SCIP_Shortbool* inactiveperms; /**< array to store whether permutations are inactive */
325  SCIP_Bool performpresolving; /**< Run orbital fixing during presolving? */
326  int recomputerestart; /**< Recompute symmetries after a restart has occured? (0 = never, 1 = always, 2 = if OF found reduction) */
327  int ofsymcomptiming; /**< timing of orbital fixing (0 = before presolving, 1 = during presolving, 2 = at first call) */
328  int lastrestart; /**< last restart for which symmetries have been computed */
329  int nfixedzero; /**< number of variables fixed to 0 */
330  int nfixedone; /**< number of variables fixed to 1 */
331  SCIP_Longint nodenumber; /**< number of node where propagation has been last applied */
332  SCIP_Bool offoundreduction; /**< whether orbital fixing has found a reduction since the last time computing symmetries */
333 
334  /* data necessary for Schreier Sims constraints */
335  SCIP_Bool sstenabled; /**< Use Schreier Sims constraints? */
336  SCIP_CONS** sstconss; /**< list of generated schreier sims conss */
337  int nsstconss; /**< number of generated schreier sims conss */
338  int maxnsstconss; /**< maximum number of conss in sstconss */
339  int sstleaderrule; /**< rule to select leader */
340  int ssttiebreakrule; /**< tie break rule for leader selection */
341  int sstleadervartype; /**< bitset encoding which variable types can be leaders;
342  * if multiple types are allowed, take the one with most affected vars */
343  int* leaders; /**< index of orbit leaders in permvars */
344  int nleaders; /**< number of orbit leaders in leaders array */
345  int maxnleaders; /**< maximum number of leaders in leaders array */
346  SCIP_Bool addconflictcuts; /**< Should Schreier Sims constraints be added if we use a conflict based rule? */
347  SCIP_Bool sstaddcuts; /**< Should Schreier Sims constraints be added? */
348  SCIP_Bool sstmixedcomponents; /**< Should Schreier Sims constraints be added if a symmetry component contains variables of different types? */
349 };
350 
351 /** node data of a given node in the conflict graph */
352 struct SCIP_NodeData
353 {
354  SCIP_VAR* var; /**< variable belonging to node */
355  int orbitidx; /**< orbit of variable w.r.t. current stabilizer subgroup
356  * or -1 if not affected by symmetry */
357  int nconflictinorbit; /**< number of variables the node's var is in conflict with */
358  int orbitsize; /**< size of the variable's orbit */
359  int posinorbit; /**< position of variable in its orbit */
360  SCIP_Bool active; /**< whether variable has not been fixed by Schreier Sims code */
361 };
362 typedef struct SCIP_NodeData SCIP_NODEDATA;
364 
365 /*
366  * Event handler callback methods
367  */
368 
369 /** exec the event handler for handling global variable bound changes (necessary for orbital fixing)
370  *
371  * Global variable fixings during the solving process might arise because parts of the tree are pruned or if certain
372  * preprocessing steps are performed that do not correspond to strict setting algorithms. Since these fixings might be
373  * caused by or be in conflict with orbital fixing, they can be in conflict with the symmetry handling decisions of
374  * orbital fixing in the part of the tree that is not pruned. Thus, we have to take global fixings into account when
375  * filtering out symmetries.
376  */
377 static
378 SCIP_DECL_EVENTEXEC(eventExecSymmetry)
379 {
380  SCIP_PROPDATA* propdata;
381  SCIP_VAR* var;
382  int varidx;
383 
384  assert( eventhdlr != NULL );
385  assert( eventdata != NULL );
386  assert( strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_SYMMETRY_NAME) == 0 );
387  assert( event != NULL );
388 
389  propdata = (SCIP_PROPDATA*) eventdata;
390  assert( propdata != NULL );
391  assert( propdata->permvarmap != NULL );
392  assert( propdata->permstrans != NULL );
393  assert( propdata->nperms > 0 );
394  assert( propdata->permvars != NULL );
395  assert( propdata->npermvars > 0 );
396 
397  /* get fixed variable */
398  var = SCIPeventGetVar(event);
399  assert( var != NULL );
400  assert( SCIPvarGetType(var) == SCIP_VARTYPE_BINARY );
401 
402  if ( ! SCIPhashmapExists(propdata->permvarmap, (void*) var) )
403  {
404  SCIPerrorMessage("Invalid variable.\n");
405  SCIPABORT();
406  return SCIP_INVALIDDATA; /*lint !e527*/
407  }
408  varidx = SCIPhashmapGetImageInt(propdata->permvarmap, (void*) var);
409  assert( 0 <= varidx && varidx < propdata->npermvars );
410 
412  {
413  assert( SCIPisEQ(scip, SCIPeventGetNewbound(event), 0.0) );
414  assert( SCIPisEQ(scip, SCIPeventGetOldbound(event), 1.0) );
415 
416  SCIPdebugMsg(scip, "Mark variable <%s> as globally fixed to 0.\n", SCIPvarGetName(var));
417  assert( ! propdata->bg0[varidx] );
418  propdata->bg0[varidx] = TRUE;
419  propdata->bg0list[propdata->nbg0++] = varidx;
420  assert( propdata->nbg0 <= propdata->npermvars );
421  }
422 
424  {
425  assert( SCIPisEQ(scip, SCIPeventGetNewbound(event), 1.0) );
426  assert( SCIPisEQ(scip, SCIPeventGetOldbound(event), 0.0) );
427 
428  SCIPdebugMsg(scip, "Mark variable <%s> as globally fixed to 1.\n", SCIPvarGetName(var));
429  assert( ! propdata->bg1[varidx] );
430  propdata->bg1[varidx] = TRUE;
431  propdata->bg1list[propdata->nbg1++] = varidx;
432  assert( propdata->nbg1 <= propdata->npermvars );
433  }
434 
435  return SCIP_OKAY;
436 }
437 
438 
439 
440 
441 /*
442  * Table callback methods
443  */
444 
445 /** table data */
446 struct SCIP_TableData
447 {
448  SCIP_PROPDATA* propdata; /** pass data of propagator for table output function */
449 };
450 
451 
452 /** output method of orbital fixing propagator statistics table to output file stream 'file' */
453 static
454 SCIP_DECL_TABLEOUTPUT(tableOutputOrbitalfixing)
455 {
456  SCIP_TABLEDATA* tabledata;
457 
458  assert( scip != NULL );
459  assert( table != NULL );
460 
461  tabledata = SCIPtableGetData(table);
462  assert( tabledata != NULL );
463  assert( tabledata->propdata != NULL );
464 
465  if ( tabledata->propdata->nperms > 0 )
466  {
467  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, file, "Orbital fixing :\n");
468  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, file, " vars fixed to 0 :%11d\n", tabledata->propdata->nfixedzero);
469  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, file, " vars fixed to 1 :%11d\n", tabledata->propdata->nfixedone);
470  }
471 
472  return SCIP_OKAY;
473 }
474 
475 
476 /** destructor of statistics table to free user data (called when SCIP is exiting) */
477 static
478 SCIP_DECL_TABLEFREE(tableFreeOrbitalfixing)
479 {
480  SCIP_TABLEDATA* tabledata;
481  tabledata = SCIPtableGetData(table);
482  assert( tabledata != NULL );
483 
484  SCIPfreeBlockMemory(scip, &tabledata);
485 
486  return SCIP_OKAY;
487 }
488 
489 
490 
491 /*
492  * local data structures
493  */
494 
495 /** gets the key of the given element */
496 static
497 SCIP_DECL_HASHGETKEY(SYMhashGetKeyVartype)
498 { /*lint --e{715}*/
499  return elem;
500 }
501 
502 /** returns TRUE iff both keys are equal
503  *
504  * Compare the types of two variables according to objective, lower and upper bound, variable type, and column sparsity.
505  */
506 static
507 SCIP_DECL_HASHKEYEQ(SYMhashKeyEQVartype)
508 {
509  SCIP* scip;
510  SYM_VARTYPE* k1;
511  SYM_VARTYPE* k2;
512 
513  scip = (SCIP*) userptr;
514  k1 = (SYM_VARTYPE*) key1;
515  k2 = (SYM_VARTYPE*) key2;
516 
517  /* first check objective coefficients */
518  if ( ! SCIPisEQ(scip, k1->obj, k2->obj) )
519  return FALSE;
520 
521  /* if still undecided, take lower bound */
522  if ( ! SCIPisEQ(scip, k1->lb, k2->lb) )
523  return FALSE;
524 
525  /* if still undecided, take upper bound */
526  if ( ! SCIPisEQ(scip, k1->ub, k2->ub) )
527  return FALSE;
528 
529  /* if still undecided, take variable type */
530  if ( k1->type != k2->type )
531  return FALSE;
532 
533  /* if still undecided, take number of conss var is contained in */
534  if ( k1->nconss != k2->nconss )
535  return FALSE;
536 
537  return TRUE;
538 }
539 
540 /** returns the hash value of the key */
541 static
542 SCIP_DECL_HASHKEYVAL(SYMhashKeyValVartype)
543 { /*lint --e{715}*/
544  SYM_VARTYPE* k;
545 
546  k = (SYM_VARTYPE*) key;
547 
549 }
550 
551 /** data structure to store arrays used for sorting rhs types */
552 struct SYM_Sortrhstype
553 {
554  SCIP_Real* vals; /**< array of values */
555  SYM_RHSSENSE* senses; /**< array of senses of rhs */
556  int nrhscoef; /**< size of arrays (for debugging) */
557 };
558 typedef struct SYM_Sortrhstype SYM_SORTRHSTYPE;
560 /** data structure to store arrays used for sorting colored component types */
562 {
563  int* components; /**< array of components */
564  int* colors; /**< array of colors */
565 };
568 /** sorts rhs types - first by sense, then by value
569  *
570  * Due to numerical issues, we first sort by sense, then by value.
571  *
572  * result:
573  * < 0: ind1 comes before (is better than) ind2
574  * = 0: both indices have the same value
575  * > 0: ind2 comes after (is worse than) ind2
576  */
577 static
578 SCIP_DECL_SORTINDCOMP(SYMsortRhsTypes)
579 {
580  SYM_SORTRHSTYPE* data;
581  SCIP_Real diffvals;
582 
583  data = (SYM_SORTRHSTYPE*) dataptr;
584  assert( 0 <= ind1 && ind1 < data->nrhscoef );
585  assert( 0 <= ind2 && ind2 < data->nrhscoef );
586 
587  /* first sort by senses */
588  if ( data->senses[ind1] < data->senses[ind2] )
589  return -1;
590  else if ( data->senses[ind1] > data->senses[ind2] )
591  return 1;
592 
593  /* senses are equal, use values */
594  diffvals = data->vals[ind1] - data->vals[ind2];
595 
596  if ( diffvals < 0.0 )
597  return -1;
598  else if ( diffvals > 0.0 )
599  return 1;
600 
601  return 0;
602 }
603 
604 /** sorts matrix coefficients
605  *
606  * result:
607  * < 0: ind1 comes before (is better than) ind2
608  * = 0: both indices have the same value
609  * > 0: ind2 comes after (is worse than) ind2
610  */
611 static
612 SCIP_DECL_SORTINDCOMP(SYMsortMatCoef)
613 {
614  SCIP_Real diffvals;
615  SCIP_Real* vals;
616 
617  vals = (SCIP_Real*) dataptr;
618  diffvals = vals[ind1] - vals[ind2];
619 
620  if ( diffvals < 0.0 )
621  return -1;
622  else if ( diffvals > 0.0 )
623  return 1;
624 
625  return 0;
626 }
627 
628 
629 /** sorts variable indices according to their corresponding component in the graph
630  *
631  * Variables are sorted first by the color of their component and then by the component index.
632  *
633  * result:
634  * < 0: ind1 comes before (is better than) ind2
635  * = 0: both indices have the same value
636  * > 0: ind2 comes after (is worse than) ind2
637  */
638 static
639 SCIP_DECL_SORTINDCOMP(SYMsortGraphCompVars)
640 {
641  SYM_SORTGRAPHCOMPVARS* data;
642 
643  data = (SYM_SORTGRAPHCOMPVARS*) dataptr;
644 
645  if ( data->colors[ind1] < data->colors[ind2] )
646  return -1;
647  else if ( data->colors[ind1] > data->colors[ind2] )
648  return 1;
649 
650  if ( data->components[ind1] < data->components[ind2] )
651  return -1;
652  if ( data->components[ind1] > data->components[ind2] )
653  return 1;
654 
655  return 0;
656 }
657 
658 
659 
660 /*
661  * Local methods
662  */
663 
664 #ifndef NDEBUG
665 /** checks that symmetry data is all freed */
666 static
668  SCIP_PROPDATA* propdata /**< propagator data */
669  )
670 {
671  assert( propdata->permvarmap == NULL );
672  assert( propdata->permvarsevents == NULL );
673  assert( propdata->bg0list == NULL );
674  assert( propdata->bg0 == NULL );
675  assert( propdata->bg1list == NULL );
676  assert( propdata->bg1 == NULL );
677  assert( propdata->nbg0 == 0 );
678  assert( propdata->nbg1 == 0 );
679  assert( propdata->genorbconss == NULL );
680  assert( propdata->genlinconss == NULL );
681  assert( propdata->sstconss == NULL );
682  assert( propdata->leaders == NULL );
683 
684  assert( propdata->permvars == NULL );
685  assert( propdata->permvarsobj == NULL );
686  assert( propdata->inactiveperms == NULL );
687  assert( propdata->perms == NULL );
688  assert( propdata->permstrans == NULL );
689  assert( propdata->nonbinpermvarcaptured == NULL );
690  assert( propdata->npermvars == 0 );
691  assert( propdata->nbinpermvars == 0 );
692  assert( propdata->nperms == -1 || propdata->nperms == 0 );
693  assert( propdata->nmaxperms == 0 );
694  assert( propdata->nmovedpermvars == -1 );
695  assert( propdata->nmovedbinpermvars == 0 );
696  assert( propdata->nmovedintpermvars == 0 );
697  assert( propdata->nmovedimplintpermvars == 0 );
698  assert( propdata->nmovedcontpermvars == 0 );
699  assert( propdata->nmovedvars == -1 );
700  assert( propdata->binvaraffected == FALSE );
701  assert( propdata->isnonlinvar == NULL );
702 
703  assert( propdata->componentblocked == NULL );
704  assert( propdata->componentbegins == NULL );
705  assert( propdata->components == NULL );
706  assert( propdata->ncomponents == -1 );
707  assert( propdata->ncompblocked == 0 );
708 
709  return TRUE;
710 }
711 #endif
712 
713 
714 /** checks whether a variable has a type compatible with the leader vartype */
715 static
717  SCIP_VAR* var, /**< variable to check */
718  int leadervartype /**< bit set encoding possible leader variable types */
719  )
720 {
721  SCIP_VARTYPE vartype;
722  unsigned int vartypeencoding;
723 
724  assert( var != NULL );
725  assert( leadervartype >= 0 );
726  assert( leadervartype <= 15 );
727 
728  vartype = SCIPvarGetType(var);
729 
730  if ( vartype == SCIP_VARTYPE_BINARY )
731  vartypeencoding = 1;
732  else if ( vartype == SCIP_VARTYPE_INTEGER )
733  vartypeencoding = 2;
734  else if ( vartype == SCIP_VARTYPE_IMPLINT )
735  vartypeencoding = 4;
736  else
737  vartypeencoding = 8;
738 
739  return (SCIP_Bool) (vartypeencoding & (unsigned) leadervartype);
740 }
741 
742 
743 /** sets in propdata which symmetry handling methods are active */
744 static
746  SCIP_PROPDATA* propdata /**< propagator data */
747  )
748 {
749  assert( propdata != NULL );
750 
751  if ( ISSYMRETOPESACTIVE(propdata->usesymmetry) )
752  propdata->symconsenabled = TRUE;
753  else
754  propdata->symconsenabled = FALSE;
755 
756  if ( ISORBITALFIXINGACTIVE(propdata->usesymmetry) )
757  propdata->ofenabled = TRUE;
758  else
759  propdata->ofenabled = FALSE;
760 
761  if ( ISSSTACTIVE(propdata->usesymmetry) )
762  propdata->sstenabled = TRUE;
763  else
764  propdata->sstenabled = FALSE;
765 
766  return SCIP_OKAY;
767 }
768 
769 
770 /** frees symmetry data */
771 static
773  SCIP* scip, /**< SCIP pointer */
774  SCIP_PROPDATA* propdata /**< propagator data */
775  )
776 {
777  int i;
778 
779  assert( scip != NULL );
780  assert( propdata != NULL );
781 
782  if ( propdata->permvarmap != NULL )
783  {
784  SCIPhashmapFree(&propdata->permvarmap);
785  }
786 
787  /* drop events */
788  if ( propdata->permvarsevents != NULL )
789  {
790  assert( propdata->permvars != NULL );
791  assert( propdata->npermvars > 0 );
792 
793  for (i = 0; i < propdata->npermvars; ++i)
794  {
795  if ( SCIPvarGetType(propdata->permvars[i]) == SCIP_VARTYPE_BINARY )
796  {
797  /* If symmetry is computed before presolving, it might happen that some variables are turned into binary
798  * variables, for which no event has been catched. Since there currently is no way of checking whether a var
799  * event has been caught for a particular variable, we use the stored eventfilter positions. */
800  if ( propdata->permvarsevents[i] >= 0 )
801  {
803  propdata->eventhdlr, (SCIP_EVENTDATA*) propdata, propdata->permvarsevents[i]) );
804  }
805  }
806  }
807  SCIPfreeBlockMemoryArray(scip, &propdata->permvarsevents, propdata->npermvars);
808  }
809 
810  /* release variables */
811  if ( propdata->nonbinpermvarcaptured != NULL )
812  {
813  int cnt;
814 
815  /* memory should have been allocated only if the leader type is not binary */
816  assert( propdata->sstenabled && propdata->sstleadervartype != (int) SCIP_SSTTYPE_BINARY );
817 
818  for (i = propdata->nbinpermvars, cnt = 0; i < propdata->npermvars; ++i, ++cnt)
819  {
820  /* release captured non-binary variables
821  * (cannot use isLeadervartypeCompatible(), because vartype may have changed in between)
822  */
823  if ( propdata->nonbinpermvarcaptured[cnt] )
824  {
825  SCIP_CALL( SCIPreleaseVar(scip, &propdata->permvars[i]) );
826  }
827  }
828  SCIPfreeBlockMemoryArray(scip, &propdata->nonbinpermvarcaptured, propdata->npermvars - propdata->nbinpermvars);
829  propdata->nonbinpermvarcaptured = NULL;
830  }
831 
832  if ( propdata->binvaraffected )
833  {
834  for (i = 0; i < propdata->nbinpermvars; ++i)
835  {
836  SCIP_CALL( SCIPreleaseVar(scip, &propdata->permvars[i]) );
837  }
838  }
839 
840  /* free lists for orbitopal fixing */
841  if ( propdata->bg0list != NULL )
842  {
843  assert( propdata->bg0 != NULL );
844  assert( propdata->bg1list != NULL );
845  assert( propdata->bg1 != NULL );
846 
847  SCIPfreeBlockMemoryArray(scip, &propdata->bg0list, propdata->npermvars);
848  SCIPfreeBlockMemoryArray(scip, &propdata->bg0, propdata->npermvars);
849  SCIPfreeBlockMemoryArray(scip, &propdata->bg1list, propdata->npermvars);
850  SCIPfreeBlockMemoryArray(scip, &propdata->bg1, propdata->npermvars);
851 
852  propdata->nbg0 = 0;
853  propdata->nbg1 = 0;
854  }
855 
856  /* other data */
857  SCIPfreeBlockMemoryArrayNull(scip, &propdata->inactiveperms, propdata->nperms);
858 
859  /* free permstrans matrix*/
860  if ( propdata->permstrans != NULL )
861  {
862  assert( propdata->nperms > 0 );
863  assert( propdata->permvars != NULL );
864  assert( propdata->npermvars > 0 );
865  assert( propdata->nmaxperms > 0 );
866 
867  for (i = 0; i < propdata->npermvars; ++i)
868  {
869  SCIPfreeBlockMemoryArray(scip, &propdata->permstrans[i], propdata->nmaxperms);
870  }
871  SCIPfreeBlockMemoryArray(scip, &propdata->permstrans, propdata->npermvars);
872  }
873 
874  /* free data of added orbitope/orbisack/symresack constraints */
875  if ( propdata->genorbconss != NULL )
876  {
877  assert( propdata->ngenorbconss + propdata->ngenlinconss > 0
878  || (ISORBITALFIXINGACTIVE(propdata->usesymmetry) && propdata->norbitopes == 0) );
879 
880  /* release constraints */
881  for (i = 0; i < propdata->ngenorbconss; ++i)
882  {
883  assert( propdata->genorbconss[i] != NULL );
884  SCIP_CALL( SCIPreleaseCons(scip, &propdata->genorbconss[i]) );
885  }
886 
887  /* free pointers to symmetry group and binary variables */
888  SCIPfreeBlockMemoryArray(scip, &propdata->genorbconss, propdata->nperms);
889  propdata->ngenorbconss = 0;
890  }
891 
892  /* free data of added constraints */
893  if ( propdata->genlinconss != NULL )
894  {
895  /* release constraints */
896  for (i = 0; i < propdata->ngenlinconss; ++i)
897  {
898  assert( propdata->genlinconss[i] != NULL );
899  SCIP_CALL( SCIPreleaseCons(scip, &propdata->genlinconss[i]) );
900  }
901 
902  /* free pointers to symmetry group and binary variables */
903  SCIPfreeBlockMemoryArray(scip, &propdata->genlinconss, propdata->genlinconsssize);
904  propdata->ngenlinconss = 0;
905  propdata->genlinconsssize = 0;
906  }
907 
908  if ( propdata->sstconss != NULL )
909  {
910  assert( propdata->nsstconss > 0 );
911 
912  /* release constraints */
913  for (i = 0; i < propdata->nsstconss; ++i)
914  {
915  assert( propdata->sstconss[i] != NULL );
916  SCIP_CALL( SCIPreleaseCons(scip, &propdata->sstconss[i]) );
917  }
918 
919  /* free pointers to symmetry group and binary variables */
920  SCIPfreeBlockMemoryArray(scip, &propdata->sstconss, propdata->maxnsstconss);
921  propdata->sstconss = NULL;
922  propdata->nsstconss = 0;
923  propdata->maxnsstconss = 0;
924  }
925 
926  if ( propdata->leaders != NULL )
927  {
928  assert( propdata->maxnleaders > 0 );
929 
930  SCIPfreeBlockMemoryArray(scip, &propdata->leaders, propdata->maxnleaders);
931  propdata->maxnleaders = 0;
932  propdata->leaders = NULL;
933  propdata->nleaders = 0;
934  }
935 
936  /* free components */
937  if ( propdata->ncomponents > 0 )
938  {
939  assert( propdata->componentblocked != NULL );
940  assert( propdata->vartocomponent != NULL );
941  assert( propdata->componentbegins != NULL );
942  assert( propdata->components != NULL );
943 
944  SCIPfreeBlockMemoryArray(scip, &propdata->componentblocked, propdata->ncomponents);
945  SCIPfreeBlockMemoryArray(scip, &propdata->vartocomponent, propdata->npermvars);
946  SCIPfreeBlockMemoryArray(scip, &propdata->componentbegins, propdata->ncomponents + 1);
947  SCIPfreeBlockMemoryArray(scip, &propdata->components, propdata->nperms);
948 
949  propdata->ncomponents = -1;
950  propdata->ncompblocked = 0;
951  }
952 
953  /* free main symmetry data */
954  if ( propdata->nperms > 0 )
955  {
956  assert( propdata->permvars != NULL );
957 
958  SCIPfreeBlockMemoryArray(scip, &propdata->permvars, propdata->npermvars);
959 
960  /* if orbital fixing runs exclusively, propdata->perms was already freed in determineSymmetry() */
961  if ( propdata->perms != NULL )
962  {
963  for (i = 0; i < propdata->nperms; ++i)
964  {
965  SCIPfreeBlockMemoryArray(scip, &propdata->perms[i], propdata->npermvars);
966  }
967  SCIPfreeBlockMemoryArray(scip, &propdata->perms, propdata->nmaxperms);
968  }
969 
970 #ifndef NDEBUG
971  SCIPfreeBlockMemoryArrayNull(scip, &propdata->permvarsobj, propdata->npermvars);
972 #endif
973 
974  SCIPfreeBlockMemoryArrayNull(scip, &propdata->isnonlinvar, propdata->npermvars);
975 
976  propdata->npermvars = 0;
977  propdata->nbinpermvars = 0;
978  propdata->nperms = -1;
979  propdata->nmaxperms = 0;
980  propdata->nmovedpermvars = -1;
981  propdata->nmovedbinpermvars = 0;
982  propdata->nmovedintpermvars = 0;
983  propdata->nmovedimplintpermvars = 0;
984  propdata->nmovedcontpermvars = 0;
985  propdata->nmovedvars = -1;
986  propdata->log10groupsize = -1.0;
987  propdata->binvaraffected = FALSE;
988  propdata->isnonlinvar = NULL;
989  }
990  propdata->nperms = -1;
991 
992  assert( checkSymmetryDataFree(propdata) );
993 
994  propdata->computedsymmetry = FALSE;
995  propdata->compressed = FALSE;
996 
997  return SCIP_OKAY;
998 }
999 
1000 
1001 /** determines whether variable should be fixed by permutations */
1002 static
1004  SYM_SPEC fixedtype, /**< bitset of variable types that should be fixed */
1005  SCIP_VAR* var /**< variable to be considered */
1006  )
1007 {
1008  if ( (fixedtype & SYM_SPEC_INTEGER) && SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER )
1009  return TRUE;
1010  if ( (fixedtype & SYM_SPEC_BINARY) && SCIPvarGetType(var) == SCIP_VARTYPE_BINARY )
1011  return TRUE;
1012  if ( (fixedtype & SYM_SPEC_REAL) &&
1014  return TRUE;
1015  return FALSE;
1016 }
1017 
1018 
1019 /** Transforms given variables, scalars, and constant to the corresponding active variables, scalars, and constant.
1020  *
1021  * @note @p constant needs to be initialized!
1022  */
1023 static
1025  SCIP* scip, /**< SCIP data structure */
1026  SCIP_VAR*** vars, /**< pointer to vars array to get active variables for */
1027  SCIP_Real** scalars, /**< pointer to scalars a_1, ..., a_n in linear sum a_1*x_1 + ... + a_n*x_n + c */
1028  int* nvars, /**< pointer to number of variables and values in vars and vals array */
1029  SCIP_Real* constant, /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c */
1030  SCIP_Bool transformed /**< transformed constraint? */
1031  )
1032 {
1033  int requiredsize;
1034  int v;
1035 
1036  assert( scip != NULL );
1037  assert( vars != NULL );
1038  assert( scalars != NULL );
1039  assert( *vars != NULL );
1040  assert( *scalars != NULL );
1041  assert( nvars != NULL );
1042  assert( constant != NULL );
1043 
1044  if ( transformed )
1045  {
1046  SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *nvars, constant, &requiredsize, TRUE) );
1047 
1048  if ( requiredsize > *nvars )
1049  {
1050  SCIP_CALL( SCIPreallocBufferArray(scip, vars, requiredsize) );
1051  SCIP_CALL( SCIPreallocBufferArray(scip, scalars, requiredsize) );
1052 
1053  SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, requiredsize, constant, &requiredsize, TRUE) );
1054  assert( requiredsize <= *nvars );
1055  }
1056  }
1057  else
1058  {
1059  for (v = 0; v < *nvars; ++v)
1060  {
1061  SCIP_CALL( SCIPvarGetOrigvarSum(&(*vars)[v], &(*scalars)[v], constant) );
1062  }
1063  }
1064  return SCIP_OKAY;
1065 }
1066 
1067 
1068 /** fills in matrix elements into coefficient arrays */
1069 static
1071  SCIP* scip, /**< SCIP data structure */
1072  SCIP_Bool doubleequations, /**< Double equations to positive/negative version? */
1073  SCIP_VAR** linvars, /**< array of linear variables */
1074  SCIP_Real* linvals, /**< array of linear coefficients values (or NULL if all linear coefficient values are 1) */
1075  int nlinvars, /**< number of linear variables */
1076  SCIP_Real lhs, /**< left hand side */
1077  SCIP_Real rhs, /**< right hand side */
1078  SCIP_Bool istransformed, /**< whether the constraint is transformed */
1079  SYM_RHSSENSE rhssense, /**< identifier of constraint type */
1080  SYM_MATRIXDATA* matrixdata, /**< matrix data to be filled in */
1081  int* nconssforvar /**< pointer to array to store for each var the number of conss */
1082  )
1083 {
1084  SCIP_VAR** vars;
1085  SCIP_Real* vals;
1086  SCIP_Real constant = 0.0;
1087  int nrhscoef;
1088  int nmatcoef;
1089  int nvars;
1090  int j;
1091 
1092  assert( scip != NULL );
1093  assert( nlinvars == 0 || linvars != NULL );
1094  assert( lhs <= rhs );
1095 
1096  /* do nothing if constraint is empty */
1097  if ( nlinvars == 0 )
1098  return SCIP_OKAY;
1099 
1100  /* ignore redundant constraints */
1101  if ( SCIPisInfinity(scip, -lhs) && SCIPisInfinity(scip, rhs) )
1102  return SCIP_OKAY;
1103 
1104  /* duplicate variable and value array */
1105  nvars = nlinvars;
1106  SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, linvars, nvars) );
1107  if ( linvals != NULL )
1108  {
1109  SCIP_CALL( SCIPduplicateBufferArray(scip, &vals, linvals, nvars) );
1110  }
1111  else
1112  {
1113  SCIP_CALL( SCIPallocBufferArray(scip, &vals, nvars) );
1114  for (j = 0; j < nvars; ++j)
1115  vals[j] = 1.0;
1116  }
1117  assert( vars != NULL );
1118  assert( vals != NULL );
1119 
1120  /* get active variables */
1121  SCIP_CALL( getActiveVariables(scip, &vars, &vals, &nvars, &constant, istransformed) );
1122 
1123  /* check whether constraint is empty after transformation to active variables */
1124  if ( nvars <= 0 )
1125  {
1126  SCIPfreeBufferArray(scip, &vals);
1127  SCIPfreeBufferArray(scip, &vars);
1128  return SCIP_OKAY;
1129  }
1130 
1131  /* handle constant */
1132  if ( ! SCIPisInfinity(scip, -lhs) )
1133  lhs -= constant;
1134  if ( ! SCIPisInfinity(scip, rhs) )
1135  rhs -= constant;
1136 
1137  /* check whether we have to resize; note that we have to add 2 * nvars since two inequalities may be added */
1138  if ( matrixdata->nmatcoef + 2 * nvars > matrixdata->nmaxmatcoef )
1139  {
1140  int newsize;
1141 
1142  newsize = SCIPcalcMemGrowSize(scip, matrixdata->nmatcoef + 2 * nvars);
1143  assert( newsize >= 0 );
1144  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(matrixdata->matidx), matrixdata->nmaxmatcoef, newsize) );
1145  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(matrixdata->matrhsidx), matrixdata->nmaxmatcoef, newsize) );
1146  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(matrixdata->matvaridx), matrixdata->nmaxmatcoef, newsize) );
1147  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(matrixdata->matcoef), matrixdata->nmaxmatcoef, newsize) );
1148  SCIPdebugMsg(scip, "Resized matrix coefficients from %d to %d.\n", matrixdata->nmaxmatcoef, newsize);
1149  matrixdata->nmaxmatcoef = newsize;
1150  }
1151 
1152  nrhscoef = matrixdata->nrhscoef;
1153  nmatcoef = matrixdata->nmatcoef;
1154 
1155  /* check lhs/rhs */
1156  if ( SCIPisEQ(scip, lhs, rhs) )
1157  {
1158  SCIP_Bool poscoef = FALSE;
1159  SCIP_Bool negcoef = FALSE;
1160 
1161  assert( ! SCIPisInfinity(scip, rhs) );
1162 
1163  /* equality constraint */
1164  matrixdata->rhscoef[nrhscoef] = rhs;
1165 
1166  /* if we deal with special constraints */
1167  if ( rhssense >= SYM_SENSE_XOR )
1168  matrixdata->rhssense[nrhscoef] = rhssense;
1169  else
1170  matrixdata->rhssense[nrhscoef] = SYM_SENSE_EQUATION;
1171  matrixdata->rhsidx[nrhscoef] = nrhscoef;
1172 
1173  for (j = 0; j < nvars; ++j)
1174  {
1175  assert( nmatcoef < matrixdata->nmaxmatcoef );
1176 
1177  matrixdata->matidx[nmatcoef] = nmatcoef;
1178  matrixdata->matrhsidx[nmatcoef] = nrhscoef;
1179 
1180  assert( 0 <= SCIPvarGetProbindex(vars[j]) && SCIPvarGetProbindex(vars[j]) < SCIPgetNVars(scip) );
1181 
1182  if ( nconssforvar != NULL )
1183  nconssforvar[SCIPvarGetProbindex(vars[j])] += 1;
1184  matrixdata->matvaridx[nmatcoef] = SCIPvarGetProbindex(vars[j]);
1185  matrixdata->matcoef[nmatcoef++] = vals[j];
1186  if ( SCIPisPositive(scip, vals[j]) )
1187  poscoef = TRUE;
1188  else
1189  negcoef = TRUE;
1190  }
1191  nrhscoef++;
1192 
1193  /* add negative of equation; increases chance to detect symmetry, but might increase time to compute symmetry. */
1194  if ( doubleequations && poscoef && negcoef )
1195  {
1196  for (j = 0; j < nvars; ++j)
1197  {
1198  assert( nmatcoef < matrixdata->nmaxmatcoef );
1199  assert( 0 <= SCIPvarGetProbindex(vars[j]) && SCIPvarGetProbindex(vars[j]) < SCIPgetNVars(scip) );
1200 
1201  matrixdata->matidx[nmatcoef] = nmatcoef;
1202  matrixdata->matrhsidx[nmatcoef] = nrhscoef;
1203  matrixdata->matvaridx[nmatcoef] = SCIPvarGetProbindex(vars[j]);
1204  matrixdata->matcoef[nmatcoef++] = -vals[j];
1205  }
1206  matrixdata->rhssense[nrhscoef] = SYM_SENSE_EQUATION;
1207  matrixdata->rhsidx[nrhscoef] = nrhscoef;
1208  matrixdata->rhscoef[nrhscoef++] = -rhs;
1209  }
1210  }
1211  else
1212  {
1213 #ifndef NDEBUG
1214  if ( rhssense == SYM_SENSE_BOUNDIS_TYPE_2 )
1215  {
1216  assert( ! SCIPisInfinity(scip, -lhs) );
1217  assert( ! SCIPisInfinity(scip, rhs) );
1218  }
1219 #endif
1220 
1221  if ( ! SCIPisInfinity(scip, -lhs) )
1222  {
1223  matrixdata->rhscoef[nrhscoef] = -lhs;
1224  if ( rhssense >= SYM_SENSE_XOR )
1225  {
1226  assert( rhssense == SYM_SENSE_BOUNDIS_TYPE_2 );
1227  matrixdata->rhssense[nrhscoef] = rhssense;
1228  }
1229  else
1230  matrixdata->rhssense[nrhscoef] = SYM_SENSE_INEQUALITY;
1231 
1232  matrixdata->rhsidx[nrhscoef] = nrhscoef;
1233 
1234  for (j = 0; j < nvars; ++j)
1235  {
1236  assert( nmatcoef < matrixdata->nmaxmatcoef );
1237  matrixdata->matidx[nmatcoef] = nmatcoef;
1238  matrixdata->matrhsidx[nmatcoef] = nrhscoef;
1239  matrixdata->matvaridx[nmatcoef] = SCIPvarGetProbindex(vars[j]);
1240 
1241  assert( 0 <= SCIPvarGetProbindex(vars[j]) && SCIPvarGetProbindex(vars[j]) < SCIPgetNVars(scip) );
1242 
1243  if ( nconssforvar != NULL )
1244  nconssforvar[SCIPvarGetProbindex(vars[j])] += 1;
1245 
1246  matrixdata->matcoef[nmatcoef++] = -vals[j];
1247  }
1248  nrhscoef++;
1249  }
1250 
1251  if ( ! SCIPisInfinity(scip, rhs) )
1252  {
1253  matrixdata->rhscoef[nrhscoef] = rhs;
1254  if ( rhssense >= SYM_SENSE_XOR )
1255  {
1256  assert( rhssense == SYM_SENSE_BOUNDIS_TYPE_2 );
1257  matrixdata->rhssense[nrhscoef] = rhssense;
1258  }
1259  else
1260  matrixdata->rhssense[nrhscoef] = SYM_SENSE_INEQUALITY;
1261 
1262  matrixdata->rhsidx[nrhscoef] = nrhscoef;
1263 
1264  for (j = 0; j < nvars; ++j)
1265  {
1266  assert( nmatcoef < matrixdata->nmaxmatcoef );
1267  matrixdata->matidx[nmatcoef] = nmatcoef;
1268  matrixdata->matrhsidx[nmatcoef] = nrhscoef;
1269 
1270  assert( 0 <= SCIPvarGetProbindex(vars[j]) && SCIPvarGetProbindex(vars[j]) < SCIPgetNVars(scip) );
1271 
1272  if ( nconssforvar != NULL )
1273  nconssforvar[SCIPvarGetProbindex(vars[j])] += 1;
1274 
1275  matrixdata->matvaridx[nmatcoef] = SCIPvarGetProbindex(vars[j]);
1276  matrixdata->matcoef[nmatcoef++] = vals[j];
1277  }
1278  nrhscoef++;
1279  }
1280  }
1281  matrixdata->nrhscoef = nrhscoef;
1282  matrixdata->nmatcoef = nmatcoef;
1283 
1284  SCIPfreeBufferArray(scip, &vals);
1285  SCIPfreeBufferArray(scip, &vars);
1286 
1287  return SCIP_OKAY;
1288 }
1289 
1290 
1291 /** checks whether given permutations form a symmetry of a MIP
1292  *
1293  * We need the matrix and rhs in the original order in order to speed up the comparison process. The matrix is needed
1294  * in the right order to easily check rows. The rhs is used because of cache effects.
1295  */
1296 static
1298  SCIP* scip, /**< SCIP data structure */
1299  SYM_SPEC fixedtype, /**< variable types that must be fixed by symmetries */
1300  SYM_MATRIXDATA* matrixdata, /**< matrix data */
1301  int nperms, /**< number of permutations */
1302  int** perms /**< permutations */
1303  )
1304 {
1305  SCIP_CONSHDLR* conshdlr;
1306  SCIP_HASHMAP* varmap;
1307  SCIP_VAR** occuringvars;
1308  SCIP_Real* permrow = 0;
1309  SCIP_Bool success;
1310  int* rhsmatbeg = 0;
1311  int nconss;
1312  int noccuringvars;
1313  int oldrhs;
1314  int i;
1315  int j;
1316  int p;
1317 
1318  SCIPdebugMsg(scip, "Checking whether symmetries are symmetries (generators: %d).\n", nperms);
1319 
1320  /* set up dense row for permuted row */
1321  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &permrow, matrixdata->npermvars) );
1322 
1323  /* set up map between rows and first entry in matcoef array */
1324  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &rhsmatbeg, matrixdata->nrhscoef) );
1325  for (j = 0; j < matrixdata->nrhscoef; ++j)
1326  rhsmatbeg[j] = -1;
1327 
1328  /* get info for non-linear part */
1329  conshdlr = SCIPfindConshdlr(scip, "nonlinear");
1330  nconss = conshdlr != NULL ? SCIPconshdlrGetNConss(conshdlr) : 0;
1331 
1332  /* create hashmaps for variable permutation and constraints in non-linear part array for occuring variables */
1333  SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(scip), matrixdata->npermvars) );
1334  SCIP_CALL( SCIPallocBufferArray(scip, &occuringvars, matrixdata->npermvars) );
1335 
1336  /* build map from rhs into matrix */
1337  oldrhs = -1;
1338  for (j = 0; j < matrixdata->nmatcoef; ++j)
1339  {
1340  int rhs;
1341 
1342  rhs = matrixdata->matrhsidx[j];
1343  if ( rhs != oldrhs )
1344  {
1345  assert( 0 <= rhs && rhs < matrixdata->nrhscoef );
1346  rhsmatbeg[rhs] = j;
1347  oldrhs = rhs;
1348  }
1349  }
1350 
1351  /* create row */
1352  for (j = 0; j < matrixdata->npermvars; ++j)
1353  permrow[j] = 0.0;
1354 
1355  /* check all generators */
1356  for (p = 0; p < nperms; ++p)
1357  {
1358  int* P;
1359  int r1;
1360  int r2;
1361 
1362  SCIPdebugMsg(scip, "Verifying automorphism group generator #%d for linear part ...\n", p);
1363  P = perms[p];
1364  assert( P != NULL );
1365 
1366  for (j = 0; j < matrixdata->npermvars; ++j)
1367  {
1368  if ( SymmetryFixVar(fixedtype, matrixdata->permvars[j]) && P[j] != j )
1369  {
1370  SCIPdebugMsg(scip, "Permutation does not fix types %u, moving variable %d.\n", fixedtype, j);
1371  return SCIP_ERROR;
1372  }
1373  }
1374 
1375  /*
1376  * linear part
1377  */
1378 
1379  /* check all linear constraints == rhs */
1380  for (r1 = 0; r1 < matrixdata->nrhscoef; ++r1)
1381  {
1382  int npermuted = 0;
1383 
1384  /* fill row into permrow (dense) */
1385  j = rhsmatbeg[r1];
1386  assert( 0 <= j && j < matrixdata->nmatcoef );
1387  assert( matrixdata->matrhsidx[j] == r1 ); /* note: row cannot be empty by construction */
1388 
1389  /* loop through row */
1390  while ( j < matrixdata->nmatcoef && matrixdata->matrhsidx[j] == r1 )
1391  {
1392  int varidx;
1393 
1394  assert( matrixdata->matvaridx[j] < matrixdata->npermvars );
1395  varidx = P[matrixdata->matvaridx[j]];
1396  assert( 0 <= varidx && varidx < matrixdata->npermvars );
1397  if ( varidx != matrixdata->matvaridx[j] )
1398  ++npermuted;
1399  assert( SCIPisZero(scip, permrow[varidx]) );
1400  permrow[varidx] = matrixdata->matcoef[j];
1401  ++j;
1402  }
1403 
1404  /* if row is not affected by permutation, we do not have to check it */
1405  if ( npermuted > 0 )
1406  {
1407  /* check other rows (sparse) */
1408  SCIP_Bool found = FALSE;
1409  for (r2 = 0; r2 < matrixdata->nrhscoef; ++r2)
1410  {
1411  /* a permutation must map constraints of the same type and respect rhs coefficients */
1412  if ( matrixdata->rhssense[r1] == matrixdata->rhssense[r2] && SCIPisEQ(scip, matrixdata->rhscoef[r1], matrixdata->rhscoef[r2]) )
1413  {
1414  j = rhsmatbeg[r2];
1415  assert( 0 <= j && j < matrixdata->nmatcoef );
1416  assert( matrixdata->matrhsidx[j] == r2 );
1417  assert( matrixdata->matvaridx[j] < matrixdata->npermvars );
1418 
1419  /* loop through row r2 and check whether it is equal to permuted row r */
1420  while ( j < matrixdata->nmatcoef && matrixdata->matrhsidx[j] == r2 && SCIPisEQ(scip, permrow[matrixdata->matvaridx[j]], matrixdata->matcoef[j] ) )
1421  ++j;
1422 
1423  /* check whether rows are completely equal */
1424  if ( j >= matrixdata->nmatcoef || matrixdata->matrhsidx[j] != r2 )
1425  {
1426  /* perm[p] is indeed a symmetry */
1427  found = TRUE;
1428  break;
1429  }
1430  }
1431  }
1432 
1433  assert( found );
1434  if ( ! found ) /*lint !e774*/
1435  {
1436  SCIPerrorMessage("Found permutation that is not a symmetry.\n");
1437  return SCIP_ERROR;
1438  }
1439  }
1440 
1441  /* reset permrow */
1442  j = rhsmatbeg[r1];
1443  while ( j < matrixdata->nmatcoef && matrixdata->matrhsidx[j] == r1 )
1444  {
1445  int varidx;
1446  varidx = P[matrixdata->matvaridx[j]];
1447  permrow[varidx] = 0.0;
1448  ++j;
1449  }
1450  }
1451 
1452  /*
1453  * non-linear part
1454  */
1455 
1456  SCIPdebugMsg(scip, "Verifying automorphism group generator #%d for non-linear part ...\n", p);
1457 
1458  /* fill hashmap according to permutation */
1459  for (j = 0; j < matrixdata->npermvars; ++j)
1460  {
1461  SCIP_CALL( SCIPhashmapInsert(varmap, matrixdata->permvars[j], matrixdata->permvars[P[j]]) );
1462  }
1463 
1464  /* check all non-linear constraints */
1465  for (i = 0; i < nconss; ++i)
1466  {
1467  SCIP_CONS* cons1;
1468  SCIP_Bool permuted = FALSE;
1469 
1470  cons1 = SCIPconshdlrGetConss(conshdlr)[i];
1471 
1472  SCIP_CALL( SCIPgetConsVars(scip, cons1, occuringvars, matrixdata->npermvars, &success) );
1473  assert(success);
1474  SCIP_CALL( SCIPgetConsNVars(scip, cons1, &noccuringvars, &success) );
1475  assert(success);
1476 
1477  /* count number of affected variables in this constraint */
1478  for (j = 0; j < noccuringvars && ! permuted; ++j)
1479  {
1480  int varidx;
1481 
1482  varidx = SCIPvarGetProbindex(occuringvars[j]);
1483  assert( varidx >= 0 && varidx < matrixdata->npermvars );
1484 
1485  if ( P[varidx] != varidx )
1486  permuted = TRUE;
1487  }
1488 
1489  /* if constraint is not affected by permutation, we do not have to check it */
1490  if ( permuted )
1491  {
1492  SCIP_CONS* permutedcons = NULL;
1493  SCIP_EXPR* permutedexpr;
1494  SCIP_Bool found = FALSE;
1495  SCIP_Bool infeasible;
1496 
1497  /* copy contraints but exchange variables according to hashmap */
1498  SCIP_CALL( SCIPgetConsCopy(scip, scip, cons1, &permutedcons, conshdlr, varmap, NULL, NULL,
1502  SCIPconsIsStickingAtNode(cons1), FALSE, &success) );
1503  assert(success);
1504  assert(permutedcons != NULL);
1505 
1506  /* simplify permuted expr in order to guarantee sorted variables */
1507  permutedexpr = SCIPgetExprNonlinear(permutedcons);
1508  SCIP_CALL( SCIPsimplifyExpr(scip, permutedexpr, &permutedexpr, &success, &infeasible, NULL, NULL) );
1509  assert( !infeasible );
1510 
1511  /* look for a constraint with same lhs, rhs and expression */
1512  for (j = 0; j < nconss; ++j)
1513  {
1514  SCIP_CONS* cons2;
1515 
1516  cons2 = SCIPconshdlrGetConss(conshdlr)[j];
1517 
1518  if ( SCIPisEQ(scip, SCIPgetRhsNonlinear(cons2), SCIPgetRhsNonlinear(permutedcons))
1519  && SCIPisEQ(scip, SCIPgetLhsNonlinear(cons2), SCIPgetLhsNonlinear(permutedcons))
1520  && (SCIPcompareExpr(scip, SCIPgetExprNonlinear(cons2), permutedexpr) == 0) )
1521  {
1522  found = TRUE;
1523  break;
1524  }
1525  }
1526 
1527  /* release copied constraint and expression because simplify captures it */
1528  SCIP_CALL( SCIPreleaseExpr(scip, &permutedexpr) );
1529  SCIP_CALL( SCIPreleaseCons(scip, &permutedcons) );
1530 
1531  assert( found );
1532  if( !found ) /*lint !e774*/
1533  {
1534  SCIPerrorMessage("Found permutation that is not a symmetry.\n");
1535  return SCIP_ERROR;
1536  }
1537  }
1538  }
1539 
1540  /* reset varmap */
1541  SCIP_CALL( SCIPhashmapRemoveAll(varmap) );
1542  }
1543 
1544  SCIPhashmapFree(&varmap);
1545  SCIPfreeBufferArray(scip, &occuringvars);
1546  SCIPfreeBlockMemoryArray(scip, &rhsmatbeg, matrixdata->nrhscoef);
1547  SCIPfreeBlockMemoryArray(scip, &permrow, matrixdata->npermvars);
1548 
1549  return SCIP_OKAY;
1550 }
1551 
1552 
1553 /** returns the number of active constraints that can be handled by symmetry */
1554 static
1556  SCIP* scip, /**< SCIP instance */
1557  SCIP_CONSHDLR* conshdlr_nonlinear /**< nonlinear constraint handler, if included */
1558  )
1559 {
1560  SCIP_CONSHDLR* conshdlr;
1561  int nhandleconss = 0;
1562 
1563  assert( scip != NULL );
1564 
1565  conshdlr = SCIPfindConshdlr(scip, "linear");
1566  nhandleconss += SCIPconshdlrGetNActiveConss(conshdlr);
1567  conshdlr = SCIPfindConshdlr(scip, "linking");
1568  nhandleconss += SCIPconshdlrGetNActiveConss(conshdlr);
1569  conshdlr = SCIPfindConshdlr(scip, "setppc");
1570  nhandleconss += SCIPconshdlrGetNActiveConss(conshdlr);
1571  conshdlr = SCIPfindConshdlr(scip, "xor");
1572  nhandleconss += SCIPconshdlrGetNActiveConss(conshdlr);
1573  conshdlr = SCIPfindConshdlr(scip, "and");
1574  nhandleconss += SCIPconshdlrGetNActiveConss(conshdlr);
1575  conshdlr = SCIPfindConshdlr(scip, "or");
1576  nhandleconss += SCIPconshdlrGetNActiveConss(conshdlr);
1577  conshdlr = SCIPfindConshdlr(scip, "logicor");
1578  nhandleconss += SCIPconshdlrGetNActiveConss(conshdlr);
1579  conshdlr = SCIPfindConshdlr(scip, "knapsack");
1580  nhandleconss += SCIPconshdlrGetNActiveConss(conshdlr);
1581  conshdlr = SCIPfindConshdlr(scip, "varbound");
1582  nhandleconss += SCIPconshdlrGetNActiveConss(conshdlr);
1583  conshdlr = SCIPfindConshdlr(scip, "bounddisjunction");
1584  nhandleconss += SCIPconshdlrGetNActiveConss(conshdlr);
1585  if( conshdlr_nonlinear != NULL )
1586  nhandleconss += SCIPconshdlrGetNActiveConss(conshdlr_nonlinear);
1587 
1588  return nhandleconss;
1589 }
1590 
1591 /** returns whether there are any active nonlinear constraints */
1592 static
1594  SCIP_PROPDATA* propdata /**< propagator data */
1595  )
1596 {
1597  assert(propdata != NULL);
1598 
1599  return propdata->conshdlr_nonlinear != NULL && SCIPconshdlrGetNActiveConss(propdata->conshdlr_nonlinear) > 0;
1600 }
1601 
1602 /** set symmetry data */
1603 static
1605  SCIP* scip, /**< SCIP pointer */
1606  SCIP_VAR** vars, /**< vars present at time of symmetry computation */
1607  int nvars, /**< number of vars present at time of symmetry computation */
1608  int nbinvars, /**< number of binary vars present at time of symmetry computation */
1609  SCIP_VAR*** permvars, /**< pointer to permvars array */
1610  int* npermvars, /**< pointer to store number of permvars */
1611  int* nbinpermvars, /**< pointer to store number of binary permvars */
1612  int** perms, /**< permutations matrix (nperms x nvars) */
1613  int nperms, /**< number of permutations */
1614  int* nmovedvars, /**< pointer to store number of vars affected by symmetry (if usecompression) or NULL */
1615  SCIP_Bool* binvaraffected, /**< pointer to store whether a binary variable is affected by symmetry */
1616  SCIP_Bool usecompression, /**< whether symmetry data shall be compressed */
1617  SCIP_Real compressthreshold, /**< if percentage of moved vars is at most threshold, compression is done */
1618  SCIP_Bool* compressed /**< pointer to store whether compression has been performed */
1619  )
1620 {
1621  int i;
1622  int p;
1623 
1624  assert( scip != NULL );
1625  assert( vars != NULL );
1626  assert( nvars > 0 );
1627  assert( permvars != NULL );
1628  assert( npermvars != NULL );
1629  assert( nbinpermvars != NULL );
1630  assert( perms != NULL );
1631  assert( nperms > 0 );
1632  assert( binvaraffected != NULL );
1633  assert( SCIPisGE(scip, compressthreshold, 0.0) );
1634  assert( SCIPisLE(scip, compressthreshold, 1.0) );
1635  assert( compressed != NULL );
1636 
1637  /* set default return values */
1638  *permvars = vars;
1639  *npermvars = nvars;
1640  *nbinpermvars = nbinvars;
1641  *binvaraffected = FALSE;
1642  *compressed = FALSE;
1643 
1644  /* if we possibly perform compression */
1645  if ( usecompression && SCIPgetNVars(scip) >= COMPRESSNVARSLB )
1646  {
1647  SCIP_Real percentagemovedvars;
1648  int* labelmovedvars;
1649  int* labeltopermvaridx;
1650  int nbinvarsaffected = 0;
1651 
1652  assert( nmovedvars != NULL );
1653 
1654  *nmovedvars = 0;
1655 
1656  /* detect number of moved vars and label moved vars */
1657  SCIP_CALL( SCIPallocBufferArray(scip, &labelmovedvars, nvars) );
1658  SCIP_CALL( SCIPallocBufferArray(scip, &labeltopermvaridx, nvars) );
1659  for (i = 0; i < nvars; ++i)
1660  {
1661  labelmovedvars[i] = -1;
1662 
1663  for (p = 0; p < nperms; ++p)
1664  {
1665  if ( perms[p][i] != i )
1666  {
1667  labeltopermvaridx[*nmovedvars] = i;
1668  labelmovedvars[i] = (*nmovedvars)++;
1669 
1670  if ( SCIPvarGetType(vars[i]) == SCIP_VARTYPE_BINARY )
1671  ++nbinvarsaffected;
1672  break;
1673  }
1674  }
1675  }
1676 
1677  if ( nbinvarsaffected > 0 )
1678  *binvaraffected = TRUE;
1679 
1680  /* check whether compression should be performed */
1681  percentagemovedvars = (SCIP_Real) *nmovedvars / (SCIP_Real) nvars;
1682  if ( *nmovedvars > 0 && SCIPisLE(scip, percentagemovedvars, compressthreshold) )
1683  {
1684  /* remove variables from permutations that are not affected by any permutation */
1685  for (p = 0; p < nperms; ++p)
1686  {
1687  /* iterate over labels and adapt permutation */
1688  for (i = 0; i < *nmovedvars; ++i)
1689  {
1690  assert( i <= labeltopermvaridx[i] );
1691  perms[p][i] = labelmovedvars[perms[p][labeltopermvaridx[i]]];
1692  }
1693 
1694  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &perms[p], nvars, *nmovedvars) );
1695  }
1696 
1697  /* remove variables from permvars array that are not affected by any symmetry */
1698  SCIP_CALL( SCIPallocBlockMemoryArray(scip, permvars, *nmovedvars) );
1699  for (i = 0; i < *nmovedvars; ++i)
1700  {
1701  (*permvars)[i] = vars[labeltopermvaridx[i]];
1702  }
1703  *npermvars = *nmovedvars;
1704  *nbinpermvars = nbinvarsaffected;
1705  *compressed = TRUE;
1706 
1707  SCIPfreeBlockMemoryArray(scip, &vars, nvars);
1708  }
1709  SCIPfreeBufferArray(scip, &labeltopermvaridx);
1710  SCIPfreeBufferArray(scip, &labelmovedvars);
1711  }
1712  else
1713  {
1714  /* detect whether binary variable is affected by symmetry and count number of binary permvars */
1715  for (i = 0; i < nbinvars; ++i)
1716  {
1717  for (p = 0; p < nperms && ! *binvaraffected; ++p)
1718  {
1719  if ( perms[p][i] != i )
1720  {
1721  if ( SCIPvarGetType(vars[i]) == SCIP_VARTYPE_BINARY )
1722  *binvaraffected = TRUE;
1723  break;
1724  }
1725  }
1726  }
1727  }
1728 
1729  return SCIP_OKAY;
1730 }
1731 
1732 
1733 /** computes symmetry group of a MIP */
1734 static
1736  SCIP* scip, /**< SCIP pointer */
1737  SCIP_Bool doubleequations, /**< Double equations to positive/negative version? */
1738  SCIP_Bool compresssymmetries, /**< Should non-affected variables be removed from permutation to save memory? */
1739  SCIP_Real compressthreshold, /**< Compression is used if percentage of moved vars is at most the threshold. */
1740  int maxgenerators, /**< maximal number of generators constructed (= 0 if unlimited) */
1741  SYM_SPEC fixedtype, /**< variable types that must be fixed by symmetries */
1742  SCIP_Bool local, /**< Use local variable bounds? */
1743  SCIP_Bool checksymmetries, /**< Should all symmetries be checked after computation? */
1744  SCIP_Bool usecolumnsparsity, /**< Should the number of conss a variable is contained in be exploited in symmetry detection? */
1745  SCIP_CONSHDLR* conshdlr_nonlinear, /**< Nonlinear constraint handler, if included */
1746  int* npermvars, /**< pointer to store number of variables for permutations */
1747  int* nbinpermvars, /**< pointer to store number of binary variables for permutations */
1748  SCIP_VAR*** permvars, /**< pointer to store variables on which permutations act */
1749  int* nperms, /**< pointer to store number of permutations */
1750  int* nmaxperms, /**< pointer to store maximal number of permutations (needed for freeing storage) */
1751  int*** perms, /**< pointer to store permutation generators as (nperms x npermvars) matrix */
1752  SCIP_Real* log10groupsize, /**< pointer to store log10 of size of group */
1753  int* nmovedvars, /**< pointer to store number of moved vars */
1754  SCIP_Bool** isnonlinvar, /**< pointer to store which variables appear nonlinearly */
1755  SCIP_Bool* binvaraffected, /**< pointer to store wether a binary variable is affected by symmetry */
1756  SCIP_Bool* compressed, /**< pointer to store whether compression has been performed */
1757  SCIP_Real* symcodetime, /**< pointer to store the time for symmetry code */
1758  SCIP_Bool* success /**< pointer to store whether symmetry computation was successful */
1759  )
1760 {
1761  SCIP_CONSHDLR* conshdlr;
1762  SYM_MATRIXDATA matrixdata;
1763  SYM_EXPRDATA exprdata;
1764  SCIP_HASHTABLE* vartypemap;
1765  SCIP_VAR** consvars;
1766  SCIP_Real* consvals;
1767  SCIP_CONS** conss;
1768  SCIP_VAR** vars;
1769  SCIP_EXPRITER* it = NULL;
1770  SCIP_HASHSET* auxvars = NULL;
1771  SYM_VARTYPE* uniquevararray;
1772  SYM_RHSSENSE oldsense = SYM_SENSE_UNKOWN;
1773  SYM_SORTRHSTYPE sortrhstype;
1774  SCIP_Real oldcoef = SCIP_INVALID;
1775  SCIP_Real val;
1776  int* nconssforvar = NULL;
1777  int nuniquevararray = 0;
1778  int nhandleconss;
1779  int nactiveconss;
1780  int nnlconss;
1781  int nconss;
1782  int nvars;
1783  int nbinvars;
1784  int nvarsorig;
1785  int nallvars;
1786  int c;
1787  int j;
1788 
1789  assert( scip != NULL );
1790  assert( npermvars != NULL );
1791  assert( nbinpermvars != NULL );
1792  assert( permvars != NULL );
1793  assert( nperms != NULL );
1794  assert( nmaxperms != NULL );
1795  assert( perms != NULL );
1796  assert( log10groupsize != NULL );
1797  assert( binvaraffected != NULL );
1798  assert( compressed != NULL );
1799  assert( symcodetime != NULL );
1800  assert( success != NULL );
1801  assert( isnonlinvar != NULL );
1802  assert( SYMcanComputeSymmetry() );
1803 
1804  /* init */
1805  *npermvars = 0;
1806  *nbinpermvars = 0;
1807  *permvars = NULL;
1808  *nperms = 0;
1809  *nmaxperms = 0;
1810  *perms = NULL;
1811  *log10groupsize = 0;
1812  *nmovedvars = -1;
1813  *binvaraffected = FALSE;
1814  *compressed = FALSE;
1815  *success = FALSE;
1816  *symcodetime = 0.0;
1817 
1818  nconss = SCIPgetNConss(scip);
1819  nvars = SCIPgetNVars(scip);
1820  nbinvars = SCIPgetNBinVars(scip);
1821  nvarsorig = nvars;
1822 
1823  /* exit if no constraints or no variables are available */
1824  if ( nconss == 0 || nvars == 0 )
1825  {
1826  *success = TRUE;
1827  return SCIP_OKAY;
1828  }
1829 
1830  conss = SCIPgetConss(scip);
1831  assert( conss != NULL );
1832 
1833  /* compute the number of active constraints */
1834  nactiveconss = SCIPgetNActiveConss(scip);
1835  nnlconss = conshdlr_nonlinear != NULL ? SCIPconshdlrGetNActiveConss(conshdlr_nonlinear) : 0;
1836 
1837  /* exit if no active constraints are available */
1838  if ( nactiveconss == 0 )
1839  {
1840  *success = TRUE;
1841  return SCIP_OKAY;
1842  }
1843 
1844  /* before we set up the matrix, check whether we can handle all constraints */
1845  nhandleconss = getNSymhandableConss(scip, conshdlr_nonlinear);
1846  assert( nhandleconss <= nactiveconss );
1847  if ( nhandleconss < nactiveconss )
1848  {
1849  /* In this case we found unkown constraints and we exit, since we cannot handle them. */
1850  *success = FALSE;
1851  *nperms = -1;
1852  return SCIP_OKAY;
1853  }
1854 
1855  SCIPdebugMsg(scip, "Detecting %ssymmetry on %d variables and %d constraints.\n", local ? "local " : "", nvars, nactiveconss);
1856 
1857  /* copy variables */
1858  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &vars, SCIPgetVars(scip), nvars) ); /*lint !e666*/
1859  assert( vars != NULL );
1860 
1861  /* fill matrixdata */
1862 
1863  /* use a staggered scheme for allocating space for non-zeros of constraint matrix since it can become large */
1864  if ( nvars <= 100000 )
1865  matrixdata.nmaxmatcoef = 100 * nvars;
1866  else if ( nvars <= 1000000 )
1867  matrixdata.nmaxmatcoef = 32 * nvars;
1868  else if ( nvars <= 16700000 )
1869  matrixdata.nmaxmatcoef = 16 * nvars;
1870  else
1871  matrixdata.nmaxmatcoef = INT_MAX / 10;
1872 
1873  matrixdata.nmatcoef = 0;
1874  matrixdata.nrhscoef = 0;
1875  matrixdata.nuniquemat = 0;
1876  matrixdata.nuniquevars = 0;
1877  matrixdata.nuniquerhs = 0;
1878  matrixdata.npermvars = nvars;
1879  matrixdata.permvars = vars;
1880  matrixdata.permvarcolors = NULL;
1881  matrixdata.matcoefcolors = NULL;
1882  matrixdata.rhscoefcolors = NULL;
1883 
1884  /* fill exprdata */
1885  exprdata.nuniqueoperators = 0;
1886  exprdata.nuniquecoefs = 0;
1887  exprdata.nuniqueconstants = 0;
1888 
1889  /* prepare matrix data (use block memory, since this can become large) */
1890  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &matrixdata.matcoef, matrixdata.nmaxmatcoef) );
1891  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &matrixdata.matidx, matrixdata.nmaxmatcoef) );
1892  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &matrixdata.matrhsidx, matrixdata.nmaxmatcoef) );
1893  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &matrixdata.matvaridx, matrixdata.nmaxmatcoef) );
1894  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &matrixdata.rhscoef, 2 * nactiveconss) );
1895  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &matrixdata.rhssense, 2 * nactiveconss) );
1896  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &matrixdata.rhsidx, 2 * nactiveconss) );
1897 
1898  /* prepare temporary constraint data (use block memory, since this can become large);
1899  * also allocate memory for fixed vars since some vars might have been deactivated meanwhile */
1900  nallvars = nvars + SCIPgetNFixedVars(scip);
1901  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consvars, nallvars) );
1902  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consvals, nallvars) );
1903 
1904  /* create hashset for auxvars and iterator for nonlinear constraints */
1905  if( nnlconss > 0 )
1906  {
1907  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, isnonlinvar, nvars) );
1908  SCIP_CALL( SCIPhashsetCreate(&auxvars, SCIPblkmem(scip), nnlconss) );
1909  SCIP_CALL( SCIPcreateExpriter(scip, &it) );
1910  }
1911  else
1912  *isnonlinvar = NULL;
1913 
1914  /* allocate memory for getting the number of constraints that contain a variable */
1915  if ( usecolumnsparsity )
1916  {
1917  SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &nconssforvar, nvars) );
1918  }
1919 
1920  /* loop through all constraints */
1921  for (c = 0; c < nconss; ++c)
1922  {
1923  const char* conshdlrname;
1924  SCIP_CONS* cons;
1925  SCIP_VAR** linvars;
1926  int nconsvars;
1927 
1928  /* get constraint */
1929  cons = conss[c];
1930  assert( cons != NULL );
1931 
1932  /* skip non-active constraints */
1933  if ( ! SCIPconsIsActive(cons) )
1934  continue;
1935 
1936  /* Skip conflict constraints if we are late in the solving process */
1937  if ( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsConflict(cons) )
1938  continue;
1939 
1940  /* get constraint handler */
1941  conshdlr = SCIPconsGetHdlr(cons);
1942  assert( conshdlr != NULL );
1943 
1944  conshdlrname = SCIPconshdlrGetName(conshdlr);
1945  assert( conshdlrname != NULL );
1946 
1947  /* check type of constraint */
1948  if ( strcmp(conshdlrname, "linear") == 0 )
1949  {
1950  SCIP_CALL( collectCoefficients(scip, doubleequations, SCIPgetVarsLinear(scip, cons), SCIPgetValsLinear(scip, cons),
1951  SCIPgetNVarsLinear(scip, cons), SCIPgetLhsLinear(scip, cons), SCIPgetRhsLinear(scip, cons),
1952  SCIPconsIsTransformed(cons), SYM_SENSE_UNKOWN, &matrixdata, nconssforvar) );
1953  }
1954  else if ( strcmp(conshdlrname, "linking") == 0 )
1955  {
1956  SCIP_VAR** curconsvars;
1957  SCIP_Real* curconsvals;
1958  int i;
1959 
1960  /* get constraint variables and their coefficients */
1961  curconsvals = SCIPgetValsLinking(scip, cons);
1962  SCIP_CALL( SCIPgetBinvarsLinking(scip, cons, &curconsvars, &nconsvars) );
1963  /* SCIPgetBinVarsLinking returns the number of binary variables, but we also need the integer variable */
1964  nconsvars++;
1965 
1966  /* copy vars and vals for binary variables */
1967  for (i = 0; i < nconsvars - 1; i++)
1968  {
1969  consvars[i] = curconsvars[i];
1970  consvals[i] = (SCIP_Real) curconsvals[i];
1971  }
1972 
1973  /* set final entry of vars and vals to the linking variable and its coefficient, respectively */
1974  consvars[nconsvars - 1] = SCIPgetLinkvarLinking(scip, cons);
1975  consvals[nconsvars - 1] = -1.0;
1976 
1977  SCIP_CALL( collectCoefficients(scip, doubleequations, consvars, consvals, nconsvars, 0.0, 0.0,
1978  SCIPconsIsTransformed(cons), SYM_SENSE_UNKOWN, &matrixdata, nconssforvar) );
1979  SCIP_CALL( collectCoefficients(scip, doubleequations, consvars, NULL, nconsvars - 1, 1.0, 1.0,
1980  SCIPconsIsTransformed(cons), SYM_SENSE_UNKOWN, &matrixdata, nconssforvar) );
1981  }
1982  else if ( strcmp(conshdlrname, "setppc") == 0 )
1983  {
1984  linvars = SCIPgetVarsSetppc(scip, cons);
1985  nconsvars = SCIPgetNVarsSetppc(scip, cons);
1986 
1987  switch ( SCIPgetTypeSetppc(scip, cons) )
1988  {
1990  SCIP_CALL( collectCoefficients(scip, doubleequations, linvars, 0, nconsvars, 1.0, 1.0, SCIPconsIsTransformed(cons), SYM_SENSE_EQUATION, &matrixdata, nconssforvar) );
1991  break;
1993  SCIP_CALL( collectCoefficients(scip, doubleequations, linvars, 0, nconsvars, -SCIPinfinity(scip), 1.0, SCIPconsIsTransformed(cons), SYM_SENSE_INEQUALITY, &matrixdata, nconssforvar) );
1994  break;
1996  SCIP_CALL( collectCoefficients(scip, doubleequations, linvars, 0, nconsvars, 1.0, SCIPinfinity(scip), SCIPconsIsTransformed(cons), SYM_SENSE_INEQUALITY, &matrixdata, nconssforvar) );
1997  break;
1998  default:
1999  SCIPerrorMessage("Unknown setppc type %d.\n", SCIPgetTypeSetppc(scip, cons));
2000  return SCIP_ERROR;
2001  }
2002  }
2003  else if ( strcmp(conshdlrname, "xor") == 0 )
2004  {
2005  SCIP_VAR** curconsvars;
2006  SCIP_VAR* var;
2007 
2008  /* get number of variables of XOR constraint (without integer variable) */
2009  nconsvars = SCIPgetNVarsXor(scip, cons);
2010 
2011  /* get variables of XOR constraint */
2012  curconsvars = SCIPgetVarsXor(scip, cons);
2013  for (j = 0; j < nconsvars; ++j)
2014  {
2015  assert( curconsvars[j] != NULL );
2016  consvars[j] = curconsvars[j];
2017  consvals[j] = 1.0;
2018  }
2019 
2020  /* intVar of xor constraint might have been removed */
2021  var = SCIPgetIntVarXor(scip, cons);
2022  if ( var != NULL )
2023  {
2024  consvars[nconsvars] = var;
2025  consvals[nconsvars++] = 2.0;
2026  }
2027  assert( nconsvars <= nallvars );
2028 
2029  SCIP_CALL( collectCoefficients(scip, doubleequations, consvars, consvals, nconsvars, (SCIP_Real) SCIPgetRhsXor(scip, cons),
2030  (SCIP_Real) SCIPgetRhsXor(scip, cons), SCIPconsIsTransformed(cons), SYM_SENSE_XOR, &matrixdata, nconssforvar) );
2031  }
2032  else if ( strcmp(conshdlrname, "and") == 0 )
2033  {
2034  SCIP_VAR** curconsvars;
2035 
2036  /* get number of variables of AND constraint (without resultant) */
2037  nconsvars = SCIPgetNVarsAnd(scip, cons);
2038 
2039  /* get variables of AND constraint */
2040  curconsvars = SCIPgetVarsAnd(scip, cons);
2041 
2042  for (j = 0; j < nconsvars; ++j)
2043  {
2044  assert( curconsvars[j] != NULL );
2045  consvars[j] = curconsvars[j];
2046  consvals[j] = 1.0;
2047  }
2048 
2049  assert( SCIPgetResultantAnd(scip, cons) != NULL );
2050  consvars[nconsvars] = SCIPgetResultantAnd(scip, cons);
2051  consvals[nconsvars++] = 2.0;
2052  assert( nconsvars <= nallvars );
2053 
2054  SCIP_CALL( collectCoefficients(scip, doubleequations, consvars, consvals, nconsvars, 0.0, 0.0,
2055  SCIPconsIsTransformed(cons), SYM_SENSE_AND, &matrixdata, nconssforvar) );
2056  }
2057  else if ( strcmp(conshdlrname, "or") == 0 )
2058  {
2059  SCIP_VAR** curconsvars;
2060 
2061  /* get number of variables of OR constraint (without resultant) */
2062  nconsvars = SCIPgetNVarsOr(scip, cons);
2063 
2064  /* get variables of OR constraint */
2065  curconsvars = SCIPgetVarsOr(scip, cons);
2066 
2067  for (j = 0; j < nconsvars; ++j)
2068  {
2069  assert( curconsvars[j] != NULL );
2070  consvars[j] = curconsvars[j];
2071  consvals[j] = 1.0;
2072  }
2073 
2074  assert( SCIPgetResultantOr(scip, cons) != NULL );
2075  consvars[nconsvars] = SCIPgetResultantOr(scip, cons);
2076  consvals[nconsvars++] = 2.0;
2077  assert( nconsvars <= nallvars );
2078 
2079  SCIP_CALL( collectCoefficients(scip, doubleequations, consvars, consvals, nconsvars, 0.0, 0.0,
2080  SCIPconsIsTransformed(cons), SYM_SENSE_OR, &matrixdata, nconssforvar) );
2081  }
2082  else if ( strcmp(conshdlrname, "logicor") == 0 )
2083  {
2084  SCIP_CALL( collectCoefficients(scip, doubleequations, SCIPgetVarsLogicor(scip, cons), 0, SCIPgetNVarsLogicor(scip, cons),
2085  1.0, SCIPinfinity(scip), SCIPconsIsTransformed(cons), SYM_SENSE_INEQUALITY, &matrixdata, nconssforvar) );
2086  }
2087  else if ( strcmp(conshdlrname, "knapsack") == 0 )
2088  {
2089  SCIP_Longint* weights;
2090 
2091  nconsvars = SCIPgetNVarsKnapsack(scip, cons);
2092 
2093  /* copy Longint array to SCIP_Real array and get active variables of constraint */
2094  weights = SCIPgetWeightsKnapsack(scip, cons);
2095  for (j = 0; j < nconsvars; ++j)
2096  consvals[j] = (SCIP_Real) weights[j];
2097  assert( nconsvars <= nallvars );
2098 
2099  SCIP_CALL( collectCoefficients(scip, doubleequations, SCIPgetVarsKnapsack(scip, cons), consvals, nconsvars, -SCIPinfinity(scip),
2100  (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons), SCIPconsIsTransformed(cons), SYM_SENSE_INEQUALITY, &matrixdata, nconssforvar) );
2101  }
2102  else if ( strcmp(conshdlrname, "varbound") == 0 )
2103  {
2104  consvars[0] = SCIPgetVarVarbound(scip, cons);
2105  consvals[0] = 1.0;
2106 
2107  consvars[1] = SCIPgetVbdvarVarbound(scip, cons);
2108  consvals[1] = SCIPgetVbdcoefVarbound(scip, cons);
2109 
2110  SCIP_CALL( collectCoefficients(scip, doubleequations, consvars, consvals, 2, SCIPgetLhsVarbound(scip, cons),
2111  SCIPgetRhsVarbound(scip, cons), SCIPconsIsTransformed(cons), SYM_SENSE_INEQUALITY, &matrixdata, nconssforvar) );
2112  }
2113  else if ( strcmp(conshdlrname, "bounddisjunction") == 0 )
2114  {
2115  /* To model bound disjunctions, we normalize each constraint
2116  * \f[
2117  * (x_1 \{\leq,\geq\} b_1) \vee \ldots \vee (x_n \{\leq,\geq\} b_n)
2118  * \f]
2119  * to a constraint of type
2120  * \f[
2121  * (x_1 \leq b'_1 \vee \ldots \vee (x_n \leq b'_n).
2122  * \f]
2123  *
2124  * If no variable appears twice in such a normalized constraint, we say this bound disjunction
2125  * is of type 1. If the bound disjunction has length two and both disjunctions contain the same variable,
2126  * we say the bound disjunction is of type 2. Further bound disjunctions are possible, but can currently
2127  * not be handled.
2128  *
2129  * Bound disjunctions of type 1 are modeled as the linear constraint
2130  * \f[
2131  * b'_1 \cdot x_1 + \ldots + b'_n \cdot x_n = 0
2132  * \f]
2133  * and bound disjunctions of type 2 are modeled as the linear constraint
2134  * \f[
2135  * \min\{b'_1, b'_2\} \leq x_1 \leq \max\{b'_1, b'_2\}.
2136  * \f]
2137  * Note that problems arise if \fb'_i = 0\f for some variable \fx_i\f, because its coefficient in the
2138  * linear constraint is 0. To avoid this, we replace 0 by a special number.
2139  */
2140  SCIP_VAR** bounddisjvars;
2141  SCIP_BOUNDTYPE* boundtypes;
2142  SCIP_Real* bounds;
2143  SCIP_Bool repetition = FALSE;
2144  int nbounddisjvars;
2145  int k;
2146 
2147  /* collect coefficients for normalized constraint */
2148  nbounddisjvars = SCIPgetNVarsBounddisjunction(scip, cons);
2149  bounddisjvars = SCIPgetVarsBounddisjunction(scip, cons);
2150  boundtypes = SCIPgetBoundtypesBounddisjunction(scip, cons);
2151  bounds = SCIPgetBoundsBounddisjunction(scip, cons);
2152 
2153  /* copy data */
2154  for (j = 0; j < nbounddisjvars; ++j)
2155  {
2156  consvars[j] = bounddisjvars[j];
2157 
2158  /* normalize bounddisjunctions to SCIP_BOUNDTYPE_LOWER */
2159  if ( boundtypes[j] == SCIP_BOUNDTYPE_LOWER )
2160  consvals[j] = - bounds[j];
2161  else
2162  consvals[j] = bounds[j];
2163 
2164  /* special treatment of 0 values */
2165  if ( SCIPisZero(scip, consvals[j]) )
2166  consvals[j] = SCIP_SPECIALVAL;
2167 
2168  /* detect whether a variable appears in two literals */
2169  for (k = 0; k < j && ! repetition; ++k)
2170  {
2171  if ( consvars[j] == consvars[k] )
2172  repetition = TRUE;
2173  }
2174 
2175  /* stop, we cannot handle bounddisjunctions with more than two variables that contain a variable twice */
2176  if ( repetition && nbounddisjvars > 2 )
2177  {
2178  *success = FALSE;
2179 
2181  " Deactivated symmetry handling methods, there exist constraints that cannot be handled by symmetry methods.\n");
2182 
2183  if ( usecolumnsparsity )
2184  SCIPfreeBlockMemoryArrayNull(scip, &nconssforvar, nvars);
2185 
2186  SCIPfreeBlockMemoryArrayNull(scip, &consvals, nallvars);
2187  SCIPfreeBlockMemoryArrayNull(scip, &consvars, nallvars);
2188  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.rhsidx, 2 * nactiveconss);
2189  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.rhssense, 2 * nactiveconss);
2190  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.rhscoef, 2 * nactiveconss);
2191  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matvaridx, matrixdata.nmaxmatcoef);
2192  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matrhsidx, matrixdata.nmaxmatcoef);
2193  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matidx, matrixdata.nmaxmatcoef);
2194  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matcoef, matrixdata.nmaxmatcoef);
2195  SCIPfreeBlockMemoryArrayNull(scip, &vars, nvars);
2196 
2197  return SCIP_OKAY;
2198  }
2199  }
2200  assert( ! repetition || nbounddisjvars == 2 );
2201 
2202  /* if no variable appears twice */
2203  if ( ! repetition )
2204  {
2205  /* add information for bounddisjunction of type 1 */
2206  SCIP_CALL( collectCoefficients(scip, doubleequations, consvars, consvals, nbounddisjvars, 0.0, 0.0,
2207  SCIPconsIsTransformed(cons), SYM_SENSE_BOUNDIS_TYPE_1, &matrixdata, nconssforvar) );
2208  }
2209  else
2210  {
2211  /* add information for bounddisjunction of type 2 */
2212  SCIP_Real lhs;
2213  SCIP_Real rhs;
2214 
2215  lhs = MIN(consvals[0], consvals[1]);
2216  rhs = MAX(consvals[0], consvals[1]);
2217 
2218  consvals[0] = 1.0;
2219 
2220  SCIP_CALL( collectCoefficients(scip, doubleequations, consvars, consvals, 1, lhs, rhs,
2221  SCIPconsIsTransformed(cons), SYM_SENSE_BOUNDIS_TYPE_2, &matrixdata, nconssforvar) );
2222  }
2223  }
2224  else if ( strcmp(conshdlrname, "nonlinear") == 0 )
2225  {
2226  SCIP_EXPR* expr;
2227  SCIP_EXPR* rootexpr;
2228 
2229  rootexpr = SCIPgetExprNonlinear(cons);
2230  assert(rootexpr != NULL);
2231 
2232  /* for nonlinear constraints, only collect auxiliary variables for now */
2233  SCIP_CALL( SCIPexpriterInit(it, rootexpr, SCIP_EXPRITER_DFS, TRUE) );
2235 
2236  for (expr = SCIPexpriterGetCurrent(it); !SCIPexpriterIsEnd(it); expr = SCIPexpriterGetNext(it)) /*lint !e441*/ /*lint !e440*/
2237  {
2239 
2240  /* for variables, we check whether they appear nonlinearly and store the result in the resp. array */
2241  if ( SCIPisExprVar(scip, expr) )
2242  {
2243  assert(*isnonlinvar != NULL);
2244  (*isnonlinvar)[SCIPvarGetProbindex(SCIPgetVarExprVar(expr))] = (SCIPexpriterGetParentDFS(it) != rootexpr || !SCIPisExprSum(scip, rootexpr));
2245  }
2246  else
2247  {
2248  SCIP_VAR* auxvar = SCIPgetExprAuxVarNonlinear(expr);
2249 
2250  if ( auxvar != NULL && !SCIPhashsetExists(auxvars, (void*) auxvar) )
2251  {
2252  SCIP_CALL( SCIPhashsetInsert(auxvars, SCIPblkmem(scip), (void*) auxvar) );
2253  }
2254 
2255  if ( SCIPisExprValue(scip, expr) )
2256  ++exprdata.nuniqueconstants;
2257  else if ( SCIPisExprSum(scip, expr) )
2258  {
2259  ++exprdata.nuniqueoperators;
2260  ++exprdata.nuniqueconstants;
2261  exprdata.nuniquecoefs += SCIPexprGetNChildren(expr);
2262  }
2263  else
2264  ++exprdata.nuniqueoperators;
2265  }
2266  }
2267  }
2268  else
2269  {
2270  /* if constraint is not one of the previous types, it cannot be handled */
2271  SCIPerrorMessage("Cannot determine symmetries for constraint <%s> of constraint handler <%s>.\n",
2272  SCIPconsGetName(cons), SCIPconshdlrGetName(conshdlr) );
2273  return SCIP_ERROR;
2274  }
2275  }
2276  assert( matrixdata.nrhscoef <= 2 * (nactiveconss - nnlconss) );
2277  assert( matrixdata.nrhscoef >= 0 );
2278 
2279  SCIPfreeBlockMemoryArray(scip, &consvals, nallvars);
2280  SCIPfreeBlockMemoryArray(scip, &consvars, nallvars);
2281 
2282  /* if no active constraint contains active variables */
2283  if ( nnlconss == 0 && matrixdata.nrhscoef == 0 )
2284  {
2285  *success = TRUE;
2286 
2287  if ( usecolumnsparsity )
2288  SCIPfreeBlockMemoryArrayNull(scip, &nconssforvar, nvars);
2289 
2290  /* free matrix data */
2291  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.rhsidx, 2 * nactiveconss);
2292  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.rhssense, 2 * nactiveconss);
2293  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.rhscoef, 2 * nactiveconss);
2294  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matvaridx, matrixdata.nmaxmatcoef);
2295  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matrhsidx, matrixdata.nmaxmatcoef);
2296  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matidx, matrixdata.nmaxmatcoef);
2297  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matcoef, matrixdata.nmaxmatcoef);
2298 
2299  SCIPfreeBlockMemoryArray(scip, &vars, nvars);
2300 
2301  return SCIP_OKAY;
2302  }
2303 
2304  /* sort matrix coefficients (leave matrix array intact) */
2305  SCIPsort(matrixdata.matidx, SYMsortMatCoef, (void*) matrixdata.matcoef, matrixdata.nmatcoef);
2306 
2307  /* sort rhs types (first by sense, then by value, leave rhscoef intact) */
2308  sortrhstype.vals = matrixdata.rhscoef;
2309  sortrhstype.senses = matrixdata.rhssense;
2310  sortrhstype.nrhscoef = matrixdata.nrhscoef;
2311  SCIPsort(matrixdata.rhsidx, SYMsortRhsTypes, (void*) &sortrhstype, matrixdata.nrhscoef);
2312 
2313  /* create map for variables to indices */
2314  SCIP_CALL( SCIPhashtableCreate(&vartypemap, SCIPblkmem(scip), 5 * nvars, SYMhashGetKeyVartype, SYMhashKeyEQVartype, SYMhashKeyValVartype, (void*) scip) );
2315  assert( vartypemap != NULL );
2316 
2317  /* allocate space for mappings to colors */
2318  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &matrixdata.permvarcolors, nvars) );
2319  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &matrixdata.matcoefcolors, matrixdata.nmatcoef) );
2320  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &matrixdata.rhscoefcolors, matrixdata.nrhscoef) );
2321  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &uniquevararray, nvars) );
2322 
2323  /* determine number of different coefficients */
2324 
2325  /* find non-equivalent variables: same objective, lower and upper bounds, and variable type */
2326  for (j = 0; j < nvars; ++j)
2327  {
2328  SCIP_VAR* var;
2329 
2330  var = vars[j];
2331  assert( var != NULL );
2332 
2333  /* if the variable type should be fixed, just increase the color */
2334  if ( SymmetryFixVar(fixedtype, var) || (nnlconss > 0 && SCIPhashsetExists(auxvars, (void*) var)) )
2335  {
2336  matrixdata.permvarcolors[j] = matrixdata.nuniquevars++;
2337 #ifdef SCIP_OUTPUT
2338  SCIPdebugMsg(scip, "Detected variable <%s> of fixed type %d - color %d.\n", SCIPvarGetName(var), SCIPvarGetType(var), matrixdata.nuniquevars - 1);
2339 #endif
2340  }
2341  else
2342  {
2343  SYM_VARTYPE* vt;
2344 
2345  vt = &uniquevararray[nuniquevararray];
2346  assert( nuniquevararray <= matrixdata.nuniquevars );
2347 
2348  vt->obj = SCIPvarGetObj(var);
2349  if ( local )
2350  {
2351  vt->lb = SCIPvarGetLbLocal(var);
2352  vt->ub = SCIPvarGetUbLocal(var);
2353  }
2354  else
2355  {
2356  vt->lb = SCIPvarGetLbGlobal(var);
2357  vt->ub = SCIPvarGetUbGlobal(var);
2358  }
2359  vt->type = SCIPvarGetType(var);
2360  vt->nconss = usecolumnsparsity ? nconssforvar[j] : 0; /*lint !e613*/
2361 
2362  if ( ! SCIPhashtableExists(vartypemap, (void*) vt) )
2363  {
2364  SCIP_CALL( SCIPhashtableInsert(vartypemap, (void*) vt) );
2365  vt->color = matrixdata.nuniquevars;
2366  matrixdata.permvarcolors[j] = matrixdata.nuniquevars++;
2367  ++nuniquevararray;
2368 #ifdef SCIP_OUTPUT
2369  SCIPdebugMsg(scip, "Detected variable <%s> of new type (probindex: %d, obj: %g, lb: %g, ub: %g, type: %d) - color %d.\n",
2370  SCIPvarGetName(var), SCIPvarGetProbindex(var), vt->obj, vt->lb, vt->ub, vt->type, matrixdata.nuniquevars - 1);
2371 #endif
2372  }
2373  else
2374  {
2375  SYM_VARTYPE* vtr;
2376 
2377  vtr = (SYM_VARTYPE*) SCIPhashtableRetrieve(vartypemap, (void*) vt);
2378  matrixdata.permvarcolors[j] = vtr->color;
2379  }
2380  }
2381  }
2382 
2383  /* If every variable is unique, terminate. -> no symmetries can be present */
2384  if ( matrixdata.nuniquevars == nvars )
2385  {
2386  *success = TRUE;
2387 
2388  /* free matrix data */
2389  SCIPfreeBlockMemoryArray(scip, &uniquevararray, nvars);
2390 
2391  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.rhscoefcolors, matrixdata.nrhscoef);
2392  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matcoefcolors, matrixdata.nmatcoef);
2393  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.permvarcolors, nvars);
2394  SCIPhashtableFree(&vartypemap);
2395 
2396  if ( usecolumnsparsity )
2397  SCIPfreeBlockMemoryArrayNull(scip, &nconssforvar, nvars);
2398 
2399  if ( nnlconss > 0 )
2400  {
2401  SCIPfreeExpriter(&it);
2402  SCIPhashsetFree(&auxvars, SCIPblkmem(scip));
2403  SCIPfreeBlockMemoryArrayNull(scip, isnonlinvar, nvars);
2404  }
2405 
2406  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.rhsidx, 2 * nactiveconss);
2407  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.rhssense, 2 * nactiveconss);
2408  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.rhscoef, 2 * nactiveconss);
2409  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matvaridx, matrixdata.nmaxmatcoef);
2410  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matrhsidx, matrixdata.nmaxmatcoef);
2411  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matidx, matrixdata.nmaxmatcoef);
2412  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matcoef, matrixdata.nmaxmatcoef);
2413 
2414  SCIPfreeBlockMemoryArray(scip, &vars, nvars);
2415 
2416  return SCIP_OKAY;
2417  }
2418 
2419  /* find non-equivalent matrix entries (use sorting to avoid too many map calls) */
2420  for (j = 0; j < matrixdata.nmatcoef; ++j)
2421  {
2422  int idx;
2423 
2424  idx = matrixdata.matidx[j];
2425  assert( 0 <= idx && idx < matrixdata.nmatcoef );
2426 
2427  val = matrixdata.matcoef[idx];
2428  assert( oldcoef == SCIP_INVALID || oldcoef <= val ); /*lint !e777*/
2429 
2430  if ( ! SCIPisEQ(scip, val, oldcoef) )
2431  {
2432 #ifdef SCIP_OUTPUT
2433  SCIPdebugMsg(scip, "Detected new matrix entry type %f - color: %d\n.", val, matrixdata.nuniquemat);
2434 #endif
2435  matrixdata.matcoefcolors[idx] = matrixdata.nuniquemat++;
2436  oldcoef = val;
2437  }
2438  else
2439  {
2440  assert( matrixdata.nuniquemat > 0 );
2441  matrixdata.matcoefcolors[idx] = matrixdata.nuniquemat - 1;
2442  }
2443  }
2444 
2445  /* find non-equivalent rhs */
2446  oldcoef = SCIP_INVALID;
2447  for (j = 0; j < matrixdata.nrhscoef; ++j)
2448  {
2449  SYM_RHSSENSE sense;
2450  int idx;
2451 
2452  idx = matrixdata.rhsidx[j];
2453  assert( 0 <= idx && idx < matrixdata.nrhscoef );
2454  sense = matrixdata.rhssense[idx];
2455  val = matrixdata.rhscoef[idx];
2456 
2457  /* make sure that new senses are treated with new color */
2458  if ( sense != oldsense )
2459  oldcoef = SCIP_INVALID;
2460  oldsense = sense;
2461  assert( oldcoef == SCIP_INVALID || oldcoef <= val ); /*lint !e777*/
2462 
2463  /* assign new color to new type */
2464  if ( ! SCIPisEQ(scip, val, oldcoef) )
2465  {
2466 #ifdef SCIP_OUTPUT
2467  SCIPdebugMsg(scip, "Detected new rhs type %f, type: %u - color: %d\n", val, sense, matrixdata.nuniquerhs);
2468 #endif
2469  matrixdata.rhscoefcolors[idx] = matrixdata.nuniquerhs++;
2470  oldcoef = val;
2471  }
2472  else
2473  {
2474  assert( matrixdata.nuniquerhs > 0 );
2475  matrixdata.rhscoefcolors[idx] = matrixdata.nuniquerhs - 1;
2476  }
2477  }
2478  assert( 0 < matrixdata.nuniquevars && matrixdata.nuniquevars <= nvars );
2479  assert( 0 <= matrixdata.nuniquerhs && matrixdata.nuniquerhs <= matrixdata.nrhscoef );
2480  assert( 0 <= matrixdata.nuniquemat && matrixdata.nuniquemat <= matrixdata.nmatcoef );
2481 
2482  SCIPdebugMsg(scip, "Number of detected different variables: %d (total: %d).\n", matrixdata.nuniquevars, nvars);
2483  SCIPdebugMsg(scip, "Number of detected different rhs types: %d (total: %d).\n", matrixdata.nuniquerhs, matrixdata.nrhscoef);
2484  SCIPdebugMsg(scip, "Number of detected different matrix coefficients: %d (total: %d).\n", matrixdata.nuniquemat, matrixdata.nmatcoef);
2485 
2486  /* do not compute symmetry if all variables are non-equivalent (unique) or if all matrix coefficients are different */
2487  if ( matrixdata.nuniquevars < nvars && (matrixdata.nuniquemat == 0 || matrixdata.nuniquemat < matrixdata.nmatcoef) )
2488  {
2489  /* determine generators */
2490  SCIP_CALL( SYMcomputeSymmetryGenerators(scip, maxgenerators, &matrixdata, &exprdata, nperms, nmaxperms,
2491  perms, log10groupsize, symcodetime) );
2492  assert( *nperms <= *nmaxperms );
2493 
2494  /* SCIPisStopped() might call SCIPgetGap() which is only available after initpresolve */
2495  if ( checksymmetries && SCIPgetStage(scip) > SCIP_STAGE_INITPRESOLVE && ! SCIPisStopped(scip) )
2496  {
2497  SCIP_CALL( checkSymmetriesAreSymmetries(scip, fixedtype, &matrixdata, *nperms, *perms) );
2498  }
2499 
2500  if ( *nperms > 0 )
2501  {
2502  SCIP_CALL( setSymmetryData(scip, vars, nvars, nbinvars, permvars, npermvars, nbinpermvars, *perms, *nperms,
2503  nmovedvars, binvaraffected, compresssymmetries, compressthreshold, compressed) );
2504  }
2505  else
2506  {
2507  SCIPfreeBlockMemoryArrayNull(scip, isnonlinvar, nvars);
2508  SCIPfreeBlockMemoryArray(scip, &vars, nvars);
2509  }
2510  }
2511  else
2512  {
2513  SCIPfreeBlockMemoryArrayNull(scip, isnonlinvar, nvars);
2514  SCIPfreeBlockMemoryArray(scip, &vars, nvars);
2515  }
2516  *success = TRUE;
2517 
2518  /* free matrix data */
2519  SCIPfreeBlockMemoryArray(scip, &uniquevararray, nvarsorig);
2520 
2521  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.rhscoefcolors, matrixdata.nrhscoef);
2522  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matcoefcolors, matrixdata.nmatcoef);
2523  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.permvarcolors, nvarsorig);
2524  SCIPhashtableFree(&vartypemap);
2525 
2526  if ( usecolumnsparsity )
2527  SCIPfreeBlockMemoryArrayNull(scip, &nconssforvar, nvarsorig);
2528 
2529  /* free cons expr specific data */
2530  if ( nnlconss > 0 )
2531  {
2532  assert( it != NULL );
2533  assert( auxvars != NULL );
2534 
2535  SCIPfreeExpriter(&it);
2536  SCIPhashsetFree(&auxvars, SCIPblkmem(scip));
2537  }
2538 
2539  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.rhsidx, 2 * nactiveconss);
2540  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.rhssense, 2 * nactiveconss);
2541  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.rhscoef, 2 * nactiveconss);
2542  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matvaridx, matrixdata.nmaxmatcoef);
2543  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matrhsidx, matrixdata.nmaxmatcoef);
2544  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matidx, matrixdata.nmaxmatcoef);
2545  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matcoef, matrixdata.nmaxmatcoef);
2546 
2547  return SCIP_OKAY;
2548 }
2549 
2550 
2551 /** determines symmetry */
2552 static
2554  SCIP* scip, /**< SCIP instance */
2555  SCIP_PROPDATA* propdata, /**< propagator data */
2556  SYM_SPEC symspecrequire, /**< symmetry specification for which we need to compute symmetries */
2557  SYM_SPEC symspecrequirefixed /**< symmetry specification of variables which must be fixed by symmetries */
2558  )
2559 { /*lint --e{641}*/
2560  SCIP_Bool successful;
2561  SCIP_Real symcodetime = 0.0;
2562  int maxgenerators;
2563  int nhandleconss;
2564  int nconss;
2565  unsigned int type = 0;
2566  int nvars;
2567  int j;
2568  int p;
2569 
2570  assert( scip != NULL );
2571  assert( propdata != NULL );
2572  assert( propdata->usesymmetry >= 0 );
2573  assert( propdata->ofenabled || propdata->symconsenabled || propdata->sstenabled );
2574 
2575  /* do not compute symmetry if reoptimization is enabled */
2576  if ( SCIPisReoptEnabled(scip) )
2577  {
2578  propdata->ofenabled = FALSE;
2579  propdata->symconsenabled = FALSE;
2580  propdata->sstenabled = FALSE;
2581  return SCIP_OKAY;
2582  }
2583 
2584  /* do not compute symmetry if Benders decomposition enabled */
2585  if ( SCIPgetNActiveBenders(scip) > 0 )
2586  {
2587  propdata->ofenabled = FALSE;
2588  propdata->symconsenabled = FALSE;
2589  propdata->sstenabled = FALSE;
2590  return SCIP_OKAY;
2591  }
2592 
2593  /* skip symmetry computation if no graph automorphism code was linked */
2594  if ( ! SYMcanComputeSymmetry() )
2595  {
2596  propdata->ofenabled = FALSE;
2597  propdata->symconsenabled = FALSE;
2598  propdata->sstenabled = FALSE;
2599 
2600  nconss = SCIPgetNActiveConss(scip);
2601  nhandleconss = getNSymhandableConss(scip, propdata->conshdlr_nonlinear);
2602 
2603  /* print verbMessage only if problem consists of symmetry handable constraints */
2604  assert( nhandleconss <= nconss );
2605  if ( nhandleconss < nconss )
2606  return SCIP_OKAY;
2607 
2609  " Deactivated symmetry handling methods, since SCIP was built without symmetry detector (SYM=none).\n");
2610 
2611  return SCIP_OKAY;
2612  }
2613 
2614  /* do not compute symmetry if there are active pricers */
2615  if ( SCIPgetNActivePricers(scip) > 0 )
2616  {
2617  propdata->ofenabled = FALSE;
2618  propdata->symconsenabled = FALSE;
2619  propdata->sstenabled = FALSE;
2620 
2621  return SCIP_OKAY;
2622  }
2623 
2624  /* avoid trivial cases */
2625  nvars = SCIPgetNVars(scip);
2626  if ( nvars <= 0 )
2627  {
2628  propdata->ofenabled = FALSE;
2629  propdata->symconsenabled = FALSE;
2630  propdata->sstenabled = FALSE;
2631 
2632  return SCIP_OKAY;
2633  }
2634 
2635  /* do not compute symmetry if there are no binary variables and non-binary variables cannot be handled, but only binary variables would be used */
2636  if ( propdata->onlybinarysymmetry && SCIPgetNBinVars(scip) == 0 )
2637  {
2638  propdata->ofenabled = FALSE;
2639  propdata->symconsenabled = FALSE;
2640 
2641  /* terminate if only Schreier Sims for binary variables is selected */
2642  if ( propdata->sstenabled )
2643  {
2644  if ( ! ((ISSSTINTACTIVE(propdata->sstleadervartype) && SCIPgetNIntVars(scip) > 0)
2645  || (ISSSTIMPLINTACTIVE(propdata->sstleadervartype) && SCIPgetNImplVars(scip) > 0)
2646  || (ISSSTCONTACTIVE(propdata->sstleadervartype) && SCIPgetNContVars(scip) > 0)) )
2647  return SCIP_OKAY;
2648  }
2649  else
2650  return SCIP_OKAY;
2651  }
2652 
2653  /* determine symmetry specification */
2654  if ( SCIPgetNBinVars(scip) > 0 )
2655  type |= (int) SYM_SPEC_BINARY;
2656  if ( SCIPgetNIntVars(scip) > 0 )
2657  type |= (int) SYM_SPEC_INTEGER;
2658  /* count implicit integer variables as real variables, since we cannot currently handle integral variables well */
2659  if ( SCIPgetNContVars(scip) > 0 || SCIPgetNImplVars(scip) > 0 )
2660  type |= (int) SYM_SPEC_REAL;
2661 
2662  /* skip symmetry computation if required variables are not present */
2663  if ( ! (type & symspecrequire) )
2664  {
2666  " (%.1fs) symmetry computation skipped: type (bin %c, int %c, cont %c) does not match requirements (bin %c, int %c, cont %c).\n",
2667  SCIPgetSolvingTime(scip),
2668  SCIPgetNBinVars(scip) > 0 ? '+' : '-',
2669  SCIPgetNIntVars(scip) > 0 ? '+' : '-',
2670  SCIPgetNContVars(scip) + SCIPgetNImplVars(scip) > 0 ? '+' : '-',
2671  (symspecrequire & (int) SYM_SPEC_BINARY) != 0 ? '+' : '-',
2672  (symspecrequire & (int) SYM_SPEC_INTEGER) != 0 ? '+' : '-',
2673  (symspecrequire & (int) SYM_SPEC_REAL) != 0 ? '+' : '-');
2674 
2675  propdata->ofenabled = FALSE;
2676  propdata->symconsenabled = FALSE;
2677  propdata->sstenabled = FALSE;
2678 
2679  return SCIP_OKAY;
2680  }
2681 
2682  /* skip computation if symmetry has already been computed */
2683  if ( propdata->computedsymmetry )
2684  return SCIP_OKAY;
2685 
2686  /* skip symmetry computation if there are constraints that cannot be handled by symmetry */
2687  nconss = SCIPgetNActiveConss(scip);
2688  nhandleconss = getNSymhandableConss(scip, propdata->conshdlr_nonlinear);
2689  if ( nhandleconss < nconss )
2690  {
2692  " (%.1fs) symmetry computation skipped: there exist constraints that cannot be handled by symmetry methods.\n",
2693  SCIPgetSolvingTime(scip));
2694 
2695  propdata->ofenabled = FALSE;
2696  propdata->symconsenabled = FALSE;
2697  propdata->sstenabled = FALSE;
2698 
2699  return SCIP_OKAY;
2700  }
2701 
2702  assert( propdata->npermvars == 0 );
2703  assert( propdata->permvars == NULL );
2704 #ifndef NDEBUG
2705  assert( propdata->permvarsobj == NULL );
2706 #endif
2707  assert( propdata->nperms < 0 );
2708  assert( propdata->nmaxperms == 0 );
2709  assert( propdata->perms == NULL );
2710 
2711  /* output message */
2713  " (%.1fs) symmetry computation started: requiring (bin %c, int %c, cont %c), (fixed: bin %c, int %c, cont %c)\n",
2714  SCIPgetSolvingTime(scip),
2715  (symspecrequire & (int) SYM_SPEC_BINARY) != 0 ? '+' : '-',
2716  (symspecrequire & (int) SYM_SPEC_INTEGER) != 0 ? '+' : '-',
2717  (symspecrequire & (int) SYM_SPEC_REAL) != 0 ? '+' : '-',
2718  (symspecrequirefixed & (int) SYM_SPEC_BINARY) != 0 ? '+' : '-',
2719  (symspecrequirefixed & (int) SYM_SPEC_INTEGER) != 0 ? '+' : '-',
2720  (symspecrequirefixed & (int) SYM_SPEC_REAL) != 0 ? '+' : '-');
2721 
2722  /* output warning if we want to fix certain symmetry parts that we also want to compute */
2723  if ( symspecrequire & symspecrequirefixed )
2724  SCIPwarningMessage(scip, "Warning: some required symmetries must be fixed.\n");
2725 
2726  /* determine maximal number of generators depending on the number of variables */
2727  maxgenerators = propdata->maxgenerators;
2728  maxgenerators = MIN(maxgenerators, MAXGENNUMERATOR / nvars);
2729 
2730  /* actually compute (global) symmetry */
2731  SCIP_CALL( computeSymmetryGroup(scip, propdata->doubleequations, propdata->compresssymmetries, propdata->compressthreshold,
2732  maxgenerators, symspecrequirefixed, FALSE, propdata->checksymmetries, propdata->usecolumnsparsity, propdata->conshdlr_nonlinear,
2733  &propdata->npermvars, &propdata->nbinpermvars, &propdata->permvars, &propdata->nperms, &propdata->nmaxperms,
2734  &propdata->perms, &propdata->log10groupsize, &propdata->nmovedvars, &propdata->isnonlinvar,
2735  &propdata->binvaraffected, &propdata->compressed, &symcodetime, &successful) );
2736 
2737  /* mark that we have computed the symmetry group */
2738  propdata->computedsymmetry = TRUE;
2739 
2740  /* store restart level */
2741  propdata->lastrestart = SCIPgetNRuns(scip);
2742 
2743  /* return if not successful */
2744  if ( ! successful )
2745  {
2746  assert( checkSymmetryDataFree(propdata) );
2747  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, " (%.1fs) could not compute symmetry\n", SCIPgetSolvingTime(scip));
2748 
2749  propdata->ofenabled = FALSE;
2750  propdata->symconsenabled = FALSE;
2751  propdata->sstenabled = FALSE;
2752 
2753  return SCIP_OKAY;
2754  }
2755 
2756  /* return if no symmetries found */
2757  if ( propdata->nperms == 0 )
2758  {
2759  assert( checkSymmetryDataFree(propdata) );
2760  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, " (%.1fs) no symmetry present (symcode time: %.2f)\n", SCIPgetSolvingTime(scip), symcodetime);
2761 
2762  propdata->ofenabled = FALSE;
2763  propdata->symconsenabled = FALSE;
2764  propdata->sstenabled = FALSE;
2765 
2766  return SCIP_OKAY;
2767  }
2768 
2769  /* display statistics */
2770  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, " (%.1fs) symmetry computation finished: %d generators found (max: ",
2771  SCIPgetSolvingTime(scip), propdata->nperms);
2772 
2773  /* display statistics: maximum number of generators */
2774  if ( maxgenerators == 0 )
2776  else
2777  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "%d", maxgenerators);
2778 
2779  /* display statistics: log10 group size, number of affected vars*/
2780  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, ", log10 of symmetry group size: %.1f", propdata->log10groupsize);
2781 
2782  if ( propdata->displaynorbitvars )
2783  {
2784  if ( propdata->nmovedvars == -1 )
2785  {
2786  SCIP_CALL( SCIPdetermineNVarsAffectedSym(scip, propdata->perms, propdata->nperms, propdata->permvars,
2787  propdata->npermvars, &(propdata->nmovedvars)) );
2788  }
2789  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, ", number of affected variables: %d)\n", propdata->nmovedvars);
2790  }
2791  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, ") (symcode time: %.2f)\n", symcodetime);
2792 
2793  /* exit if no binary variables are affected by symmetry and we cannot handle non-binary symmetries */
2794  if ( ! propdata->binvaraffected )
2795  {
2796  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, " (%.1fs) no symmetry on binary variables present.\n", SCIPgetSolvingTime(scip));
2797 
2798  /* disable OF and symmetry handling constraints based on symretopes */
2799  propdata->ofenabled = FALSE;
2800  propdata->symconsenabled = FALSE;
2801  if ( ! propdata->sstenabled ||
2802  ! ( ISSSTINTACTIVE(propdata->sstleadervartype) || ISSSTIMPLINTACTIVE(propdata->sstleadervartype)
2803  || ISSSTCONTACTIVE(propdata->sstleadervartype) ) )
2804  {
2805  propdata->sstenabled = FALSE;
2806 
2807  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, " (%.1fs) -> no handable symmetry found, free symmetry data.\n",
2808  SCIPgetSolvingTime(scip));
2809 
2810  /* free data and exit */
2811  SCIP_CALL( freeSymmetryData(scip, propdata) );
2812 
2813  return SCIP_OKAY;
2814  }
2815  }
2816 
2817  assert( propdata->nperms > 0 );
2818  assert( propdata->npermvars > 0 );
2819 
2820  /* compute components */
2821  assert( propdata->components == NULL );
2822  assert( propdata->componentbegins == NULL );
2823  assert( propdata->vartocomponent == NULL );
2824 
2825 #ifdef SCIP_OUTPUT_COMPONENT
2826  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, " (%.1fs) component computation started\n", SCIPgetSolvingTime(scip));
2827 #endif
2828 
2829  /* we only need the components for orbital fixing, orbitope and subgroup detection, and Schreier Sims constraints */
2830  if ( propdata->ofenabled || ( propdata->symconsenabled && propdata->detectorbitopes )
2831  || propdata->detectsubgroups || propdata->sstenabled )
2832  {
2833  SCIP_CALL( SCIPcomputeComponentsSym(scip, propdata->perms, propdata->nperms, propdata->permvars,
2834  propdata->npermvars, FALSE, &propdata->components, &propdata->componentbegins,
2835  &propdata->vartocomponent, &propdata->componentblocked, &propdata->ncomponents) );
2836  }
2837 
2838 #ifdef SCIP_OUTPUT_COMPONENT
2839  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, " (%.1fs) component computation finished\n", SCIPgetSolvingTime(scip));
2840 #endif
2841 
2842  /* set up data for OF */
2843  if ( propdata->ofenabled )
2844  {
2845  int componentidx;
2846  int v;
2847 
2848  /* transpose symmetries matrix here if necessary */
2849  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->permstrans, propdata->npermvars) );
2850  for (v = 0; v < propdata->npermvars; ++v)
2851  {
2852  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->permstrans[v]), propdata->nmaxperms) );
2853  for (p = 0; p < propdata->nperms; ++p)
2854  {
2855  if ( SCIPvarIsBinary(propdata->permvars[v]) || propdata->sstenabled )
2856  propdata->permstrans[v][p] = propdata->perms[p][v];
2857  else
2858  propdata->permstrans[v][p] = v; /* ignore symmetry information on non-binary variables */
2859  }
2860  }
2861 
2862  /* prepare array for active permutations */
2863  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->inactiveperms, propdata->nperms) );
2864  for (v = 0; v < propdata->nperms; ++v)
2865  propdata->inactiveperms[v] = FALSE;
2866 
2867  /* create hashmap for storing the indices of variables */
2868  assert( propdata->permvarmap == NULL );
2869  SCIP_CALL( SCIPhashmapCreate(&propdata->permvarmap, SCIPblkmem(scip), propdata->npermvars) );
2870 
2871  /* prepare data structures */
2872  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->permvarsevents, propdata->npermvars) );
2873  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->bg0, propdata->npermvars) );
2874  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->bg0list, propdata->npermvars) );
2875  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->bg1, propdata->npermvars) );
2876  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->bg1list, propdata->npermvars) );
2877 
2878  /* insert variables into hashmap */
2879  assert( propdata->nmovedpermvars == -1 );
2880  propdata->nmovedpermvars = 0;
2881  for (v = 0; v < propdata->npermvars; ++v)
2882  {
2883  SCIP_CALL( SCIPhashmapInsertInt(propdata->permvarmap, propdata->permvars[v], v) );
2884 
2885  propdata->bg0[v] = FALSE;
2886  propdata->bg1[v] = FALSE;
2887  propdata->permvarsevents[v] = -1;
2888 
2889  /* collect number of moved permvars */
2890  componentidx = propdata->vartocomponent[v];
2891  if ( componentidx > -1 && ! propdata->componentblocked[componentidx] )
2892  {
2893  propdata->nmovedpermvars += 1;
2894 
2895  if ( SCIPvarGetType(propdata->permvars[v]) == SCIP_VARTYPE_BINARY )
2896  ++propdata->nmovedbinpermvars;
2897  else if ( SCIPvarGetType(propdata->permvars[v]) == SCIP_VARTYPE_INTEGER )
2898  ++propdata->nmovedintpermvars;
2899  else if ( SCIPvarGetType(propdata->permvars[v]) == SCIP_VARTYPE_IMPLINT )
2900  ++propdata->nmovedimplintpermvars;
2901  else
2902  ++propdata->nmovedcontpermvars;
2903  }
2904 
2905  /* Only catch binary variables, since integer variables should be fixed pointwise; implicit integer variables
2906  * are not branched on. */
2907  if ( SCIPvarGetType(propdata->permvars[v]) == SCIP_VARTYPE_BINARY )
2908  {
2909  /* catch whether binary variables are globally fixed; also store filter position */
2911  propdata->eventhdlr, (SCIP_EVENTDATA*) propdata, &propdata->permvarsevents[v]) );
2912  }
2913  }
2914  assert( propdata->nbg1 == 0 );
2915  }
2916 
2917  /* set up data for Schreier Sims constraints or subgroup detection */
2918  if ( (propdata->sstenabled || propdata->detectsubgroups) && ! propdata->ofenabled )
2919  {
2920  int v;
2921 
2922  /* transpose symmetries matrix here if necessary */
2923  assert( propdata->permstrans == NULL );
2924  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->permstrans, propdata->npermvars) );
2925  for (v = 0; v < propdata->npermvars; ++v)
2926  {
2927  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->permstrans[v]), propdata->nmaxperms) );
2928  for (p = 0; p < propdata->nperms; ++p)
2929  propdata->permstrans[v][p] = propdata->perms[p][v];
2930  }
2931 
2932  /* create hashmap for storing the indices of variables */
2933  assert( propdata->permvarmap == NULL );
2934  SCIP_CALL( SCIPhashmapCreate(&propdata->permvarmap, SCIPblkmem(scip), propdata->npermvars) );
2935 
2936  /* insert variables into hashmap */
2937  for (v = 0; v < propdata->npermvars; ++v)
2938  {
2939  SCIP_CALL( SCIPhashmapInsertInt(propdata->permvarmap, propdata->permvars[v], v) );
2940  }
2941  }
2942 
2943  /* handle several general aspects */
2944 #ifndef NDEBUG
2945  /* store objective coefficients for debug purposes */
2946  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->permvarsobj, propdata->npermvars) );
2947  for (j = 0; j < propdata->npermvars; ++j)
2948  propdata->permvarsobj[j] = SCIPvarGetObj(propdata->permvars[j]);
2949 #endif
2950 
2951  /* capture symmetric variables and forbid multi aggregation */
2952 
2953  /* binary symmetries are always handled
2954  *
2955  * note: binary variables are in the beginning of permvars
2956  */
2957  if ( propdata->binvaraffected )
2958  {
2959  for (j = 0; j < propdata->nbinpermvars; ++j)
2960  {
2961  SCIP_CALL( SCIPcaptureVar(scip, propdata->permvars[j]) );
2962 
2963  if ( propdata->compressed )
2964  {
2965  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, propdata->permvars[j]) );
2966  }
2967  else
2968  {
2969  for (p = 0; p < propdata->nperms; ++p)
2970  {
2971  if ( propdata->perms[p][j] != j )
2972  {
2973  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, propdata->permvars[j]) );
2974  break;
2975  }
2976  }
2977  }
2978  }
2979  }
2980 
2981  /* if Schreier-Sims constraints are enabled, also capture symmetric variables and forbid multi aggregation of handable vars */
2982  if ( propdata->sstenabled && propdata->sstleadervartype != (int) SCIP_SSTTYPE_BINARY )
2983  {
2984  int cnt;
2985 
2986  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->nonbinpermvarcaptured,
2987  propdata->npermvars - propdata->nbinpermvars) );
2988  for (j = propdata->nbinpermvars, cnt = 0; j < propdata->npermvars; ++j, ++cnt)
2989  {
2990  if ( ! isLeadervartypeCompatible(propdata->permvars[j], propdata->sstleadervartype) )
2991  {
2992  propdata->nonbinpermvarcaptured[cnt] = FALSE;
2993  continue;
2994  }
2995 
2996  SCIP_CALL( SCIPcaptureVar(scip, propdata->permvars[j]) );
2997  propdata->nonbinpermvarcaptured[cnt] = TRUE;
2998 
2999  if ( propdata->compressed )
3000  {
3001  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, propdata->permvars[j]) );
3002  }
3003  else
3004  {
3005  for (p = 0; p < propdata->nperms; ++p)
3006  {
3007  if ( propdata->perms[p][j] != j )
3008  {
3009  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, propdata->permvars[j]) );
3010  break;
3011  }
3012  }
3013  }
3014  }
3015  }
3016 
3017  /* free original perms matrix if no symmetry constraints are added */
3018  if ( ! propdata->symconsenabled && ! propdata->sstenabled )
3019  {
3020  for (p = 0; p < propdata->nperms; ++p)
3021  {
3022  SCIPfreeBlockMemoryArray(scip, &(propdata->perms)[p], propdata->npermvars);
3023  }
3024  SCIPfreeBlockMemoryArrayNull(scip, &propdata->perms, propdata->nmaxperms);
3025  }
3026 
3027  return SCIP_OKAY;
3028 }
3029 
3030 
3031 /*
3032  * Functions for symmetry constraints
3033  */
3034 
3035 
3036 /** Checks whether given set of 2-cycle permutations forms an orbitope and if so, builds the variable index matrix.
3037  *
3038  * If @p activevars == NULL, then the function assumes all permutations of the component are active and therefore all
3039  * moved vars are considered.
3040  *
3041  * We need to keep track of the number of generatored columns, because we might not be able to detect all orbitopes.
3042  * 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
3043  * in our construction need shape (1,2), (2,3), (3,4), (4,5).
3044  *
3045  * @pre @p orbitopevaridx has to be an initialized 2D array of size @p ntwocycles x @p nperms
3046  * @pre @p columnorder has to be an initialized array of size nperms
3047  * @pre @p nusedelems has to be an initialized array of size npermvars
3048  */
3049 static
3051  SCIP* scip, /**< SCIP instance */
3052  SCIP_VAR** permvars, /**< array of all permutation variables */
3053  int npermvars, /**< number of permutation variables */
3054  int** perms, /**< array of all permutations of the symmety group */
3055  int* activeperms, /**< indices of the relevant permutations in perms */
3056  int ntwocycles, /**< number of 2-cycles in the permutations */
3057  int nactiveperms, /**< number of active permutations */
3058  int** orbitopevaridx, /**< pointer to store variable index matrix */
3059  int* columnorder, /**< pointer to store column order */
3060  int* nusedelems, /**< pointer to store how often each element was used */
3061  int* nusedcols, /**< pointer to store numer of columns used in orbitope (or NULL) */
3062  SCIP_Shortbool* rowisbinary, /**< pointer to store which rows are binary (or NULL) */
3063  SCIP_Bool* isorbitope, /**< buffer to store result */
3064  SCIP_Shortbool* activevars /**< bitset to store whether a variable is active (or NULL) */
3065  )
3066 { /*lint --e{571}*/
3067  SCIP_Bool* usedperm;
3068  SCIP_Bool foundperm = FALSE;
3069  int nusedperms = 0;
3070  int nfilledcols;
3071  int coltoextend;
3072  int ntestedperms = 0;
3073  int row = 0;
3074  int j;
3075 
3076  assert( scip != NULL );
3077  assert( permvars != NULL );
3078  assert( perms != NULL );
3079  assert( activeperms != NULL );
3080  assert( orbitopevaridx != NULL );
3081  assert( columnorder != NULL );
3082  assert( nusedelems != NULL );
3083  assert( isorbitope != NULL );
3084  assert( nactiveperms > 0 );
3085  assert( ntwocycles > 0 );
3086  assert( npermvars > 0 );
3087  assert( activevars == NULL || (0 <= nactiveperms && nactiveperms < npermvars) );
3088 
3089  *isorbitope = TRUE;
3090  if ( nusedcols != NULL )
3091  *nusedcols = 0;
3092 
3093  /* whether a permutation was considered to contribute to orbitope */
3094  SCIP_CALL( SCIPallocClearBufferArray(scip, &usedperm, nactiveperms) );
3095 
3096  /* fill first two columns of orbitopevaridx matrix */
3097 
3098  /* look for the first active permutation which moves an active variable */
3099  while ( ! foundperm )
3100  {
3101  int permidx;
3102 
3103  assert( ntestedperms < nactiveperms );
3104 
3105  permidx = activeperms[ntestedperms];
3106 
3107  for (j = 0; j < npermvars; ++j)
3108  {
3109  if ( activevars != NULL && ! activevars[j] )
3110  continue;
3111 
3112  assert( activevars == NULL || activevars[perms[permidx][j]] );
3113 
3114  /* avoid adding the same 2-cycle twice */
3115  if ( perms[permidx][j] > j )
3116  {
3117  assert( SCIPvarIsBinary(permvars[j]) == SCIPvarIsBinary(permvars[perms[permidx][j]]) );
3118 
3119  if ( rowisbinary != NULL && SCIPvarIsBinary(permvars[j]) )
3120  rowisbinary[row] = TRUE;
3121 
3122  orbitopevaridx[row][0] = j;
3123  orbitopevaridx[row++][1] = perms[permidx][j];
3124  ++(nusedelems[j]);
3125  ++(nusedelems[perms[permidx][j]]);
3126 
3127  foundperm = TRUE;
3128  }
3129 
3130  if ( row == ntwocycles )
3131  break;
3132  }
3133 
3134  ++ntestedperms;
3135  }
3136 
3137  /* in the subgroup case it might happen that a generator has less than ntwocycles many 2-cyles */
3138  if ( row != ntwocycles )
3139  {
3140  *isorbitope = FALSE;
3141  SCIPfreeBufferArray(scip, &usedperm);
3142  return SCIP_OKAY;
3143  }
3144 
3145  usedperm[ntestedperms - 1] = TRUE;
3146  ++nusedperms;
3147  columnorder[0] = 0;
3148  columnorder[1] = 1;
3149  nfilledcols = 2;
3150 
3151  /* extend orbitopevaridx matrix to the left, i.e., iteratively find new permutations that
3152  * intersect the last added left column in each row in exactly one entry, starting with
3153  * column 0 */
3154  coltoextend = 0;
3155  for (j = ntestedperms; j < nactiveperms; ++j)
3156  { /* lint --e{850} */
3157  SCIP_Bool success = FALSE;
3158  SCIP_Bool infeasible = FALSE;
3159 
3160  if ( nusedperms == nactiveperms )
3161  break;
3162 
3163  if ( usedperm[j] )
3164  continue;
3165 
3166  SCIP_CALL( SCIPextendSubOrbitope(orbitopevaridx, ntwocycles, nfilledcols, coltoextend,
3167  perms[activeperms[j]], TRUE, &nusedelems, permvars, NULL, &success, &infeasible) );
3168 
3169  if ( infeasible )
3170  {
3171  *isorbitope = FALSE;
3172  break;
3173  }
3174  else if ( success )
3175  {
3176  usedperm[j] = TRUE;
3177  ++nusedperms;
3178  coltoextend = nfilledcols;
3179  columnorder[nfilledcols++] = -1; /* mark column to be filled from the left */
3180  j = 0; /*lint !e850*/ /* reset j since previous permutations can now intersect with the latest added column */
3181  }
3182  }
3183 
3184  if ( ! *isorbitope ) /*lint !e850*/
3185  {
3186  SCIPfreeBufferArray(scip, &usedperm);
3187  return SCIP_OKAY;
3188  }
3189 
3190  coltoextend = 1;
3191  for (j = ntestedperms; j < nactiveperms; ++j)
3192  { /*lint --e(850)*/
3193  SCIP_Bool success = FALSE;
3194  SCIP_Bool infeasible = FALSE;
3195 
3196  if ( nusedperms == nactiveperms )
3197  break;
3198 
3199  if ( usedperm[j] )
3200  continue;
3201 
3202  SCIP_CALL( SCIPextendSubOrbitope(orbitopevaridx, ntwocycles, nfilledcols, coltoextend,
3203  perms[activeperms[j]], FALSE, &nusedelems, permvars, NULL, &success, &infeasible) );
3204 
3205  if ( infeasible )
3206  {
3207  *isorbitope = FALSE;
3208  break;
3209  }
3210  else if ( success )
3211  {
3212  usedperm[j] = TRUE;
3213  ++nusedperms;
3214  coltoextend = nfilledcols;
3215  columnorder[nfilledcols] = 1; /* mark column to be filled from the right */
3216  ++nfilledcols;
3217  j = 0; /*lint !e850*/ /* reset j since previous permutations can now intersect with the latest added column */
3218  }
3219  }
3220 
3221  if ( activevars == NULL && nusedperms < nactiveperms ) /*lint !e850*/
3222  *isorbitope = FALSE;
3223 
3224  if ( nusedcols != NULL )
3225  *nusedcols = nfilledcols;
3226  assert( ! *isorbitope || activevars == NULL || nusedperms < nfilledcols );
3227 
3228  SCIPfreeBufferArray(scip, &usedperm);
3229 
3230  return SCIP_OKAY;
3231 }
3232 
3233 /** choose an order in which the generators should be added for subgroup detection */
3234 static
3236  SCIP* scip, /**< SCIP instance */
3237  SCIP_PROPDATA* propdata, /**< pointer to data of symmetry propagator */
3238  int compidx, /**< index of component */
3239  int** genorder, /**< (initialized) buffer to store the resulting order of generator */
3240  int* ntwocycleperms /**< pointer to store the number of 2-cycle permutations in component compidx */
3241  )
3242 {
3243  int** perms;
3244  int* components;
3245  int* componentbegins;
3246  int* ntwocycles;
3247  int npermvars;
3248  int npermsincomp;
3249  int i;
3250 
3251  assert( scip != NULL );
3252  assert( propdata != NULL );
3253  assert( compidx >= 0 );
3254  assert( compidx < propdata->ncomponents );
3255  assert( genorder != NULL );
3256  assert( *genorder != NULL );
3257  assert( ntwocycleperms != NULL );
3258  assert( propdata->computedsymmetry );
3259  assert( propdata->nperms > 0 );
3260  assert( propdata->perms != NULL );
3261  assert( propdata->npermvars > 0 );
3262  assert( propdata->ncomponents > 0 );
3263  assert( propdata->components != NULL );
3264  assert( propdata->componentbegins != NULL );
3265 
3266  perms = propdata->perms;
3267  npermvars = propdata->npermvars;
3268  components = propdata->components;
3269  componentbegins = propdata->componentbegins;
3270  npermsincomp = componentbegins[compidx + 1] - componentbegins[compidx];
3271  *ntwocycleperms = npermsincomp;
3272 
3273  SCIP_CALL( SCIPallocBufferArray(scip, &ntwocycles, npermsincomp) );
3274 
3275  for (i = 0; i < npermsincomp; ++i)
3276  {
3277  int* perm;
3278  int nbincycles;
3279 
3280  perm = perms[components[componentbegins[compidx] + i]];
3281 
3282  SCIP_CALL( SCIPisInvolutionPerm(perm, propdata->permvars, npermvars, &(ntwocycles[i]), &nbincycles, FALSE) );
3283 
3284  /* we skip permutations which do not purely consist of 2-cycles */
3285  if ( ntwocycles[i] == 0 )
3286  {
3287  /* we change the number of two cycles for this perm so that it will be sorted to the end */
3288  if ( propdata->preferlessrows )
3289  ntwocycles[i] = npermvars;
3290  else
3291  ntwocycles[i] = 0;
3292  --(*ntwocycleperms);
3293  }
3294  else if ( ! propdata->preferlessrows )
3295  ntwocycles[i] = - ntwocycles[i];
3296  }
3297 
3298  SCIPsortIntInt(ntwocycles, *genorder, npermsincomp);
3299 
3300  SCIPfreeBufferArray(scip, &ntwocycles);
3301 
3302  return SCIP_OKAY;
3303 }
3304 
3305 
3306 /** builds the graph for symmetric subgroup detection from the given permutation of generators
3307  *
3308  * After execution, @p graphcomponents contains all permvars sorted by their color and component,
3309  * @p graphcompbegins points to the indices where new components in @p graphcomponents start and
3310  * @p compcolorbegins points to the indices where new colors in @p graphcompbegins start.
3311 */
3312 static
3314  SCIP* scip, /**< SCIP instance */
3315  SCIP_PROPDATA* propdata, /**< pointer to data of symmetry propagator */
3316  int* genorder, /**< order in which the generators should be considered */
3317  int ntwocycleperms, /**< number of 2-cycle permutations in this component */
3318  int compidx, /**< index of the component */
3319  int** graphcomponents, /**< buffer to store the components of the graph (ordered var indices) */
3320  int** graphcompbegins, /**< buffer to store the indices of each new graph component */
3321  int** compcolorbegins, /**< buffer to store at which indices a new color begins */
3322  int* ngraphcomponents, /**< pointer to store the number of graph components */
3323  int* ncompcolors, /**< pointer to store the number of different colors */
3324  int** usedperms, /**< buffer to store the indices of permutations that were used */
3325  int* nusedperms, /**< pointer to store the number of used permutations in the graph */
3326  int usedpermssize, /**< initial size of usedperms */
3327  SCIP_Shortbool* permused /**< initialized buffer to store which permutations have been used
3328  * (identified by index in component) */
3329  )
3330 {
3331  SCIP_DISJOINTSET* vartocomponent;
3332  SCIP_DISJOINTSET* comptocolor;
3333  int** perms;
3334  int* components;
3335  int* componentbegins;
3336  int* componentslastperm;
3337  SYM_SORTGRAPHCOMPVARS graphcompvartype;
3338  int npermvars;
3339  int nextcolor;
3340  int nextcomp;
3341  int j;
3342  int k;
3343 
3344  assert( scip != NULL );
3345  assert( propdata != NULL );
3346  assert( graphcomponents != NULL );
3347  assert( graphcompbegins != NULL );
3348  assert( compcolorbegins != NULL );
3349  assert( ngraphcomponents != NULL );
3350  assert( ncompcolors != NULL );
3351  assert( genorder != NULL );
3352  assert( usedperms != NULL );
3353  assert( nusedperms != NULL );
3354  assert( usedpermssize > 0 );
3355  assert( permused != NULL );
3356  assert( ntwocycleperms >= 0 );
3357  assert( compidx >= 0 );
3358  assert( compidx < propdata->ncomponents );
3359  assert( propdata->computedsymmetry );
3360  assert( propdata->nperms > 0 );
3361  assert( propdata->perms != NULL );
3362  assert( propdata->npermvars > 0 );
3363  assert( propdata->ncomponents > 0 );
3364  assert( propdata->components != NULL );
3365  assert( propdata->componentbegins != NULL );
3366  assert( !propdata->componentblocked[compidx] );
3367 
3368  perms = propdata->perms;
3369  npermvars = propdata->npermvars;
3370  components = propdata->components;
3371  componentbegins = propdata->componentbegins;
3372  *nusedperms = 0;
3373 
3374  assert( ntwocycleperms <= componentbegins[compidx + 1] - componentbegins[compidx] );
3375 
3376  SCIP_CALL( SCIPcreateDisjointset(scip, &vartocomponent, npermvars) );
3377  SCIP_CALL( SCIPcreateDisjointset(scip, &comptocolor, npermvars) );
3378  SCIP_CALL( SCIPallocBufferArray( scip, &componentslastperm, npermvars) );
3379 
3380  for (k = 0; k < npermvars; ++k)
3381  componentslastperm[k] = -1;
3382 
3383  for (j = 0; j < ntwocycleperms; ++j)
3384  {
3385  int* perm;
3386  int firstcolor = -1;
3387 
3388  /* use given order of generators */
3389  perm = perms[components[componentbegins[compidx] + genorder[j]]];
3390  assert( perm != NULL );
3391 
3392  /* iteratively handle each swap of perm until an invalid one is found or all edges have been added */
3393  for (k = 0; k < npermvars; ++k)
3394  {
3395  int comp1;
3396  int comp2;
3397  int color1;
3398  int color2;
3399  int img;
3400 
3401  img = perm[k];
3402  assert( perm[img] == k );
3403 
3404  if ( img <= k )
3405  continue;
3406 
3407  comp1 = SCIPdisjointsetFind(vartocomponent, k);
3408  comp2 = SCIPdisjointsetFind(vartocomponent, img);
3409 
3410  if ( comp1 == comp2 )
3411  {
3412  /* another permutation has already merged these variables into one component; store its color */
3413  if ( firstcolor < 0 )
3414  {
3415  assert( SCIPdisjointsetFind(comptocolor, comp1) == SCIPdisjointsetFind(comptocolor, comp2) );
3416  firstcolor = SCIPdisjointsetFind(comptocolor, comp1);
3417  }
3418  componentslastperm[comp1] = j;
3419  continue;
3420  }
3421 
3422  /* if it is the second time that the component is used for this generator,
3423  * it is not guaranteed that the group acts like the symmetric group, so skip it
3424  */
3425  if ( componentslastperm[comp1] == j || componentslastperm[comp2] == j )
3426  break;
3427 
3428  color1 = SCIPdisjointsetFind(comptocolor, comp1);
3429  color2 = SCIPdisjointsetFind(comptocolor, comp2);
3430 
3431  /* a generator is not allowed to connect two components of the same color, since they depend on each other */
3432  if ( color1 == color2 )
3433  break;
3434 
3435  componentslastperm[comp1] = j;
3436  componentslastperm[comp2] = j;
3437 
3438  if ( firstcolor < 0 )
3439  firstcolor = color1;
3440  }
3441 
3442  /* if the generator is invalid, delete the newly added edges, go to next generator */
3443  if ( k < npermvars )
3444  continue;
3445 
3446  /* if the generator only acts on already existing components, we don't have to store it */
3447  if ( firstcolor == -1 )
3448  continue;
3449 
3450  /* check whether we need to resize */
3451  if ( *nusedperms >= usedpermssize )
3452  {
3453  int newsize = SCIPcalcMemGrowSize(scip, (*nusedperms) + 1);
3454  assert( newsize > usedpermssize );
3455 
3456  SCIP_CALL( SCIPreallocBufferArray(scip, usedperms, newsize) );
3457 
3458  usedpermssize = newsize;
3459  }
3460 
3461  (*usedperms)[*nusedperms] = components[componentbegins[compidx] + genorder[j]];
3462  ++(*nusedperms);
3463  permused[genorder[j]] = TRUE;
3464 
3465  /* if the generator can be added, update the datastructures for graph components and colors */
3466  for (k = 0; k < npermvars; ++k)
3467  {
3468  int comp1;
3469  int comp2;
3470  int color1;
3471  int color2;
3472  int img;
3473 
3474  img = perm[k];
3475  assert( perm[img] == k );
3476 
3477  if ( img <= k )
3478  continue;
3479 
3480  comp1 = SCIPdisjointsetFind(vartocomponent, k);
3481  comp2 = SCIPdisjointsetFind(vartocomponent, img);
3482 
3483  /* components and colors don't have to be updated if the components are the same */
3484  if ( comp1 == comp2 )
3485  continue;
3486 
3487  color1 = SCIPdisjointsetFind(comptocolor, comp1);
3488  color2 = SCIPdisjointsetFind(comptocolor, comp2);
3489 
3490  if ( color1 != color2 )
3491  {
3492  SCIPdisjointsetUnion(comptocolor, firstcolor, color1, TRUE);
3493  SCIPdisjointsetUnion(comptocolor, firstcolor, color2, TRUE);
3494  }
3495 
3496  SCIPdisjointsetUnion(vartocomponent, comp1, comp2, FALSE);
3497 
3498  assert( SCIPdisjointsetFind(vartocomponent, k) == SCIPdisjointsetFind(vartocomponent, img) );
3499  assert( SCIPdisjointsetFind(comptocolor, SCIPdisjointsetFind(vartocomponent, k)) == firstcolor );
3500  assert( SCIPdisjointsetFind(comptocolor, SCIPdisjointsetFind(vartocomponent, img)) == firstcolor );
3501  }
3502  }
3503 
3504  SCIP_CALL( SCIPallocBlockMemoryArray(scip, graphcomponents, npermvars) );
3505  SCIP_CALL( SCIPallocBufferArray(scip, &(graphcompvartype.components), npermvars) );
3506  SCIP_CALL( SCIPallocBufferArray(scip, &(graphcompvartype.colors), npermvars) );
3507 
3508  /*
3509  * At this point, we have built the colored graph. Now we transform the information in the
3510  * disjoint sets to the arrays graphcomponents, graphcompbegins, and compcolorbegins (see above).
3511  */
3512 
3513  /* build the struct graphcompvartype which is used to sort the graphcomponents array */
3514  for (j = 0; j < npermvars; ++j)
3515  {
3516  int comp;
3517 
3518  comp = SCIPdisjointsetFind(vartocomponent, j);
3519 
3520  graphcompvartype.components[j] = comp;
3521  graphcompvartype.colors[j] = SCIPdisjointsetFind(comptocolor, comp);
3522 
3523  (*graphcomponents)[j] = j;
3524  }
3525 
3526  /* sort graphcomponents first by color, then by component */
3527  SCIPsort(*graphcomponents, SYMsortGraphCompVars, (void*) &graphcompvartype, npermvars);
3528 
3529  *ngraphcomponents = SCIPdisjointsetGetComponentCount(vartocomponent);
3530  *ncompcolors = SCIPdisjointsetGetComponentCount(comptocolor);
3531  SCIP_CALL( SCIPallocBlockMemoryArray(scip, graphcompbegins, (*ngraphcomponents) + 1) );
3532  SCIP_CALL( SCIPallocBlockMemoryArray(scip, compcolorbegins, (*ncompcolors) + 1) );
3533 
3534  nextcolor = 1;
3535  nextcomp = 1;
3536  (*graphcompbegins)[0] = 0;
3537  (*compcolorbegins)[0] = 0;
3538 
3539  /* find the starting indices of new components and new colors */
3540  for (j = 1; j < npermvars; ++j)
3541  {
3542  int idx1;
3543  int idx2;
3544 
3545  idx1 = (*graphcomponents)[j];
3546  idx2 = (*graphcomponents)[j-1];
3547 
3548  assert( graphcompvartype.colors[idx1] >= graphcompvartype.colors[idx2] );
3549 
3550  if ( graphcompvartype.components[idx1] != graphcompvartype.components[idx2] )
3551  {
3552  (*graphcompbegins)[nextcomp] = j;
3553 
3554  if ( graphcompvartype.colors[idx1] > graphcompvartype.colors[idx2] )
3555  {
3556  (*compcolorbegins)[nextcolor] = nextcomp;
3557  ++nextcolor;
3558  }
3559 
3560  ++nextcomp;
3561  }
3562  }
3563  assert( nextcomp == *ngraphcomponents );
3564  assert( nextcolor == *ncompcolors );
3565 
3566  (*compcolorbegins)[nextcolor] = *ngraphcomponents;
3567  (*graphcompbegins)[nextcomp] = npermvars;
3568 
3569  SCIPfreeBufferArray(scip, &(graphcompvartype.colors));
3570  SCIPfreeBufferArray(scip, &(graphcompvartype.components));
3571  SCIPfreeBufferArray(scip, &componentslastperm);
3572  SCIPfreeDisjointset(scip, &comptocolor);
3573  SCIPfreeDisjointset(scip, &vartocomponent);
3574 
3575  return SCIP_OKAY;
3576 }
3577 
3578 /** adds an orbitope constraint for a suitable color of the subgroup graph */
3579 static
3581  SCIP* scip, /**< SCIP instance */
3582  SCIP_PROPDATA* propdata, /**< pointer to data of symmetry propagator */
3583  int* usedperms, /**< array of the permutations that build the orbitope */
3584  int nusedperms, /**< number of permutations in usedperms */
3585  int* compcolorbegins, /**< array indicating where a new graphcolor begins */
3586  int* graphcompbegins, /**< array indicating where a new graphcomponent begins */
3587  int* graphcomponents, /**< array of all variable indices sorted by color and comp */
3588  int graphcoloridx, /**< index of the graph color */
3589  int nrows, /**< number of rows in the orbitope */
3590  int ncols, /**< number of columns in the orbitope */
3591  int* firstvaridx, /**< buffer to store the index of the largest variable (or NULL) */
3592  int* compidxfirstrow, /**< buffer to store the comp index for the first row (or NULL) */
3593  int** lexorder, /**< pointer to array storing lexicographic order defined by sub orbitopes */
3594  int* nvarslexorder, /**< number of variables in lexicographic order */
3595  int* maxnvarslexorder, /**< maximum number of variables in lexicographic order */
3596  SCIP_Bool mayinteract, /**< whether orbitope's symmetries might interact with other symmetries */
3597  SCIP_Bool* success /**< whether the orbitpe could be added */
3598  )
3599 { /*lint --e{571}*/
3600  char name[SCIP_MAXSTRLEN];
3601  SCIP_VAR*** orbitopevarmatrix;
3602  SCIP_Shortbool* activevars;
3603  int** orbitopevaridx;
3604  int* columnorder;
3605  int* nusedelems;
3606  SCIP_CONS* cons;
3607  SCIP_Bool isorbitope;
3608  SCIP_Bool infeasible = FALSE;
3609 #ifndef NDEBUG
3610  int nactivevars = 0;
3611 #endif
3612  int ngencols = 0;
3613  int k;
3614 
3615  assert( scip != NULL );
3616  assert( propdata != NULL );
3617  assert( usedperms != NULL );
3618  assert( compcolorbegins != NULL );
3619  assert( graphcompbegins != NULL );
3620  assert( graphcomponents != NULL );
3621  assert( nusedperms > 0 );
3622  assert( nrows > 0 );
3623  assert( ncols > 0 );
3624  assert( lexorder != NULL );
3625  assert( nvarslexorder != NULL );
3626  assert( maxnvarslexorder != NULL );
3627 
3628  *success = FALSE;
3629 
3630  /* create hashset to mark variables */
3631  SCIP_CALL( SCIPallocClearBufferArray(scip, &activevars, propdata->npermvars) );
3632 
3633  /* orbitope matrix for indices of variables in permvars array */
3634  SCIP_CALL( SCIPallocBufferArray(scip, &orbitopevaridx, nrows) );
3635  for (k = 0; k < nrows; ++k)
3636  {
3637  SCIP_CALL( SCIPallocBufferArray(scip, &orbitopevaridx[k], ncols) ); /*lint !e866*/
3638  }
3639 
3640  /* order of columns of orbitopevaridx */
3641  SCIP_CALL( SCIPallocBufferArray(scip, &columnorder, ncols) );
3642  for (k = 0; k < ncols; ++k)
3643  columnorder[k] = ncols + 1;
3644 
3645  /* count how often an element was used in the potential orbitope */
3646  SCIP_CALL( SCIPallocClearBufferArray(scip, &nusedelems, propdata->npermvars) );
3647 
3648  /* mark variables in this subgroup orbitope */
3649  for (k = compcolorbegins[graphcoloridx]; k < compcolorbegins[graphcoloridx+1]; ++k)
3650  {
3651  SCIP_VAR* firstvar;
3652  int compstart;
3653  int l;
3654 
3655  compstart = graphcompbegins[k];
3656  firstvar = propdata->permvars[graphcomponents[compstart]];
3657 
3658  if ( ! SCIPvarIsBinary(firstvar) )
3659  continue;
3660 
3661  for (l = 0; l < ncols; ++l)
3662  {
3663  int varidx;
3664 
3665  varidx = graphcomponents[compstart + l];
3666  assert( ! activevars[varidx] );
3667 
3668  activevars[varidx] = TRUE;
3669 #ifndef NDEBUG
3670  ++nactivevars;
3671 #endif
3672  }
3673  }
3674  assert( nactivevars == nrows * ncols );
3675 
3676  /* build the variable index matrix for the orbitope
3677  *
3678  * It is possible that we find an orbitope, but not using all possible columns. For example
3679  * (1,2), (2,3), (3,4), (3,5) defines the symmetric group on {1,2,3,4,5}, but the generators
3680  * we expect in our construction need shape (1,2), (2,3), (3,4), (4,5). For this reason,
3681  * we need to store how many columns have been generated.
3682  *
3683  * @todo ensure compatibility with more general generators
3684  */
3685  SCIP_CALL( checkTwoCyclePermsAreOrbitope(scip, propdata->permvars, propdata->npermvars,
3686  propdata->perms, usedperms, nrows, nusedperms, orbitopevaridx, columnorder,
3687  nusedelems, &ngencols, NULL, &isorbitope, activevars) );
3688 
3689  /* it might happen that we cannot detect the orbitope if it is generated by permutations with different
3690  * number of 2-cycles.
3691  */
3692  if ( ! isorbitope )
3693  {
3694  SCIPfreeBufferArray(scip, &nusedelems);
3695  SCIPfreeBufferArray(scip, &columnorder);
3696  for (k = nrows - 1; k >= 0; --k)
3697  {
3698  SCIPfreeBufferArray(scip, &orbitopevaridx[k]);
3699  }
3700  SCIPfreeBufferArray(scip, &orbitopevaridx);
3701  SCIPfreeBufferArray(scip, &activevars);
3702 
3703  return SCIP_OKAY;
3704  }
3705 
3706  /* There are three possibilities for the structure of columnorder:
3707  * 1) [0, 1, -1, -1, ..., -1]
3708  * 2) [0, 1, 1, 1, ..., 1]
3709  * 3) [0, 1, -1, -1, ...., -1, 1, 1, ..., 1]
3710  *
3711  * The '1'-columns will be added to the matrix first and in the last 2
3712  * cases the method starts from the right. So to store the variable index
3713  * that will be in the upper-left corner, we need either the entryin the
3714  * second column (case 1) or the entry in the last column (cases 2 and 3).
3715  */
3716  if ( firstvaridx != NULL )
3717  {
3718  if ( columnorder[ngencols-1] > -1 )
3719  *firstvaridx = orbitopevaridx[0][ngencols-1];
3720  else
3721  *firstvaridx = orbitopevaridx[0][1];
3722  }
3723 
3724  /* find corresponding graphcomponent of first variable (needed for weak sbcs) */
3725  if ( compidxfirstrow != NULL && firstvaridx != NULL )
3726  {
3727  *compidxfirstrow = -1;
3728 
3729  for (k = compcolorbegins[graphcoloridx]; k < compcolorbegins[graphcoloridx+1] && (*compidxfirstrow) < 0; ++k)
3730  {
3731  SCIP_VAR* firstvar;
3732  int compstart;
3733  int l;
3734 
3735  compstart = graphcompbegins[k];
3736  firstvar = propdata->permvars[graphcomponents[compstart]];
3737 
3738  if ( ! SCIPvarIsBinary(firstvar) )
3739  continue;
3740 
3741  /* iterate over all columns (elements in orbit), because we cannot see from ngencols which columns
3742  * have been left out
3743  */
3744  for (l = 0; l < ncols; ++l)
3745  {
3746  if ( graphcomponents[compstart + l] == *firstvaridx )
3747  {
3748  *compidxfirstrow = k;
3749  break;
3750  }
3751  }
3752  }
3753  assert( *compidxfirstrow > -1 );
3754  }
3755 
3756  /* prepare orbitope variable matrix */
3757  SCIP_CALL( SCIPallocBufferArray(scip, &orbitopevarmatrix, nrows) );
3758  for (k = 0; k < nrows; ++k)
3759  {
3760  SCIP_CALL( SCIPallocBufferArray(scip, &orbitopevarmatrix[k], ngencols) );
3761  }
3762 
3763  /* build the matrix containing the actual variables of the orbitope */
3764  SCIP_CALL( SCIPgenerateOrbitopeVarsMatrix(scip, &orbitopevarmatrix, nrows, ngencols,
3765  propdata->permvars, propdata->npermvars, orbitopevaridx, columnorder,
3766  nusedelems, NULL, &infeasible, TRUE, lexorder, nvarslexorder, maxnvarslexorder) );
3767 
3768  assert( ! infeasible );
3769  assert( firstvaridx == NULL || propdata->permvars[*firstvaridx] == orbitopevarmatrix[0][0] );
3770 
3771  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "suborbitope_%d_%d", graphcoloridx, propdata->norbitopes);
3772 
3773  SCIP_CALL( SCIPcreateConsOrbitope(scip, &cons, name, orbitopevarmatrix,
3774  SCIP_ORBITOPETYPE_FULL, nrows, ngencols, FALSE, mayinteract, FALSE, FALSE, propdata->conssaddlp,
3775  TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
3776 
3777  SCIP_CALL( SCIPaddCons(scip, cons) );
3778  *success = TRUE;
3779 
3780  /* do not release constraint here - will be done later */
3781  propdata->genorbconss[propdata->ngenorbconss++] = cons;
3782  ++propdata->norbitopes;
3783 
3784  for (k = nrows - 1; k >= 0; --k)
3785  SCIPfreeBufferArray(scip, &orbitopevarmatrix[k]);
3786  SCIPfreeBufferArray(scip, &orbitopevarmatrix);
3787  SCIPfreeBufferArray(scip, &nusedelems);
3788  SCIPfreeBufferArray(scip, &columnorder);
3789  for (k = nrows - 1; k >= 0; --k)
3790  SCIPfreeBufferArray(scip, &orbitopevaridx[k]);
3791  SCIPfreeBufferArray(scip, &orbitopevaridx);
3792  SCIPfreeBufferArray(scip, &activevars);
3793 
3794  return SCIP_OKAY;
3795 }
3796 
3797 /** adds strong SBCs for a suitable color of the subgroup graph */
3798 static
3800  SCIP* scip, /**< SCIP instance */
3801  SCIP_PROPDATA* propdata, /**< pointer to data of symmetry propagator */
3802  int* graphcompbegins, /**< array indicating where a new graphcomponent begins */
3803  int* graphcomponents, /**< array of all variable indices sorted by color and comp */
3804  int graphcompidx, /**< index of the graph component */
3805  SCIP_Bool storelexorder, /**< whether the lexicographic order induced by the orbitope shall be stored */
3806  int** lexorder, /**< pointer to array storing lexicographic order defined by sub orbitopes */
3807  int* nvarsorder, /**< number of variables in lexicographic order */
3808  int* maxnvarsorder /**< maximum number of variables in lexicographic order */
3809  )
3810 {
3811  int k;
3812 
3813  assert( scip != NULL );
3814  assert( propdata != NULL );
3815  assert( graphcompbegins != NULL );
3816  assert( graphcomponents != NULL );
3817  assert( graphcompidx >= 0 );
3818  assert( ! storelexorder || lexorder != NULL );
3819  assert( ! storelexorder || nvarsorder != NULL );
3820  assert( ! storelexorder || maxnvarsorder != NULL );
3821 
3822  /* possibly store lexicographic order defined by strong SBCs */
3823  if ( storelexorder )
3824  {
3825  if ( *maxnvarsorder == 0 )
3826  {
3827  *maxnvarsorder = graphcompbegins[graphcompidx + 1] - graphcompbegins[graphcompidx + 1];
3828  *nvarsorder = 0;
3829 
3830  SCIP_CALL( SCIPallocBlockMemoryArray(scip, lexorder, *maxnvarsorder) );
3831  }
3832  else
3833  {
3834  assert( *nvarsorder == *maxnvarsorder );
3835 
3836  *maxnvarsorder += graphcompbegins[graphcompidx + 1] - graphcompbegins[graphcompidx + 1];
3837 
3838  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, lexorder, *nvarsorder, *maxnvarsorder) );
3839  }
3840 
3841  (*lexorder)[*nvarsorder++] = graphcomponents[graphcompbegins[graphcompidx]];
3842  }
3843 
3844  /* add strong SBCs (lex-max order) for chosen graph component */
3845  for (k = graphcompbegins[graphcompidx]+1; k < graphcompbegins[graphcompidx+1]; ++k)
3846  {
3847  char name[SCIP_MAXSTRLEN];
3848  SCIP_CONS* cons;
3849  SCIP_VAR* vars[2];
3850  SCIP_Real vals[2] = {1, -1};
3851 
3852  vars[0] = propdata->permvars[graphcomponents[k-1]];
3853  vars[1] = propdata->permvars[graphcomponents[k]];
3854 
3855  if ( storelexorder )
3856  (*lexorder)[*nvarsorder++] = graphcomponents[k];
3857 
3858  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "strong_sbcs_%s_%s", SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]));
3859 
3860  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, 2, vars, vals, 0.0,
3861  SCIPinfinity(scip), propdata->conssaddlp, propdata->conssaddlp, TRUE,
3862  FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
3863 
3864  SCIP_CALL( SCIPaddCons(scip, cons) );
3865 
3866 #ifdef SCIP_MORE_DEBUG
3867  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
3868  SCIPinfoMessage(scip, NULL, "\n");
3869 #endif
3870 
3871  /* check whether we need to resize */
3872  if ( propdata->ngenlinconss >= propdata->genlinconsssize )
3873  {
3874  int newsize;
3875 
3876  newsize = SCIPcalcMemGrowSize(scip, propdata->ngenlinconss + 1);
3877  assert( newsize > propdata->ngenlinconss );
3878 
3879  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &propdata->genlinconss, propdata->genlinconsssize, newsize) );
3880 
3881  propdata->genlinconsssize = newsize;
3882  }
3883 
3884  propdata->genlinconss[propdata->ngenlinconss] = cons;
3885  ++propdata->ngenlinconss;
3886  }
3887 
3888  return SCIP_OKAY;
3889 }
3890 
3891 /** adds weak SBCs for a suitable color of the subgroup graph */
3892 static
3894  SCIP* scip, /**< SCIP instance */
3895  SCIP_PROPDATA* propdata, /**< pointer to data of symmetry propagator */
3896  int* compcolorbegins, /**< array indicating where a new graphcolor begins */
3897  int* graphcompbegins, /**< array indicating where a new graphcomponent begins */
3898  int* graphcomponents, /**< array of all variable indices sorted by color and comp */
3899  int ncompcolors, /**< number of colors in the graph */
3900  int* chosencomppercolor, /**< array indicating which comp was handled per color */
3901  int* firstvaridxpercolor,/**< array indicating the largest variable per color */
3902  int symgrpcompidx, /**< index of the component of the symmetry group */
3903  int* naddedconss, /**< buffer to store the number of added constraints */
3904  SCIP_Bool storelexorder, /**< whether the lexicographic order induced by the orbitope shall be stored */
3905  int** lexorder, /**< pointer to array storing lexicographic order defined by sub orbitopes */
3906  int* nvarsorder, /**< number of variables in lexicographic order */
3907  int* maxnvarsorder /**< maximum number of variables in lexicographic order */
3908  )
3909 { /*lint --e{571}*/
3910  SCIP_HASHMAP* varsinlexorder;
3911  SCIP_Shortbool* usedvars;
3912  SCIP_VAR* vars[2];
3913  SCIP_Real vals[2] = {1, -1};
3914  SCIP_Shortbool* varfound;
3915  int* orbit[2];
3916  int orbitsize[2] = {1, 1};
3917  int activeorb = 0;
3918  int chosencolor = -1;
3919  int j;
3920  int k;
3921 
3922  assert( scip != NULL );
3923  assert( propdata != NULL );
3924  assert( compcolorbegins != NULL );
3925  assert( graphcompbegins != NULL );
3926  assert( graphcomponents != NULL );
3927  assert( firstvaridxpercolor != NULL );
3928  assert( chosencomppercolor != NULL );
3929  assert( naddedconss != NULL );
3930  assert( symgrpcompidx >= 0 );
3931  assert( symgrpcompidx < propdata->ncomponents );
3932  assert( ! storelexorder || lexorder != NULL );
3933  assert( ! storelexorder || nvarsorder != NULL );
3934  assert( ! storelexorder || maxnvarsorder != NULL );
3935 
3936  *naddedconss = 0;
3937 
3938  SCIP_CALL( SCIPallocCleanBufferArray(scip, &usedvars, propdata->npermvars) );
3939  SCIP_CALL( SCIPallocClearBufferArray(scip, &varfound, propdata->npermvars) );
3940  SCIP_CALL( SCIPallocBufferArray(scip, &orbit[0], propdata->npermvars) );
3941  SCIP_CALL( SCIPallocBufferArray(scip, &orbit[1], propdata->npermvars) );
3942 
3943  /* Store the entries in lexorder in a hashmap, for fast lookups. */
3944  if ( lexorder == NULL || *lexorder == NULL )
3945  {
3946  /* Lexorder does not exist, so do not create hashmap. */
3947  varsinlexorder = NULL;
3948  }
3949  else
3950  {
3951  assert( *maxnvarsorder >= 0 );
3952  assert( *nvarsorder >= 0 );
3953 
3954  SCIP_CALL( SCIPhashmapCreate(&varsinlexorder, SCIPblkmem(scip), *maxnvarsorder) );
3955 
3956  for (k = 0; k < *nvarsorder; ++k)
3957  {
3958  /* add element from lexorder to hashmap.
3959  * Use insert, as duplicate entries in lexorder is not permitted. */
3960  assert((*lexorder)[k] >= 0);
3961  assert( ! SCIPhashmapExists(varsinlexorder, (void*) (size_t) (*lexorder)[k]) ); /* Use int as pointer */
3962  SCIP_CALL( SCIPhashmapInsertInt(varsinlexorder, (void*) (size_t) (*lexorder)[k], k) );
3963  }
3964  }
3965 
3966  /* We will store the newest and the largest orbit and activeorb will be used to mark at which entry of the array
3967  * orbit the newly computed one will be stored. */
3968  for (j = 0; j < ncompcolors; ++j)
3969  {
3970  int graphcomp;
3971  int graphcompsize;
3972  int varidx;
3973 
3974  /* skip color for which we did not add anything */
3975  if ( chosencomppercolor[j] < 0 )
3976  continue;
3977 
3978  assert( firstvaridxpercolor[j] >= 0 );
3979 
3980  graphcomp = chosencomppercolor[j];
3981  graphcompsize = graphcompbegins[graphcomp+1] - graphcompbegins[graphcomp];
3982  varidx = firstvaridxpercolor[j];
3983  assert(varidx >= 0);
3984 
3985  /* if the first variable was already contained in another orbit or if there are no variables left anyway, skip the
3986  * component */
3987  if ( varfound[varidx] || graphcompsize == propdata->npermvars )
3988  continue;
3989 
3990  /* If varidx is in lexorder, then it must be the first entry of lexorder. */
3991  if ( varsinlexorder != NULL
3992  && SCIPhashmapExists(varsinlexorder, (void*) (size_t) varidx)
3993  && lexorder != NULL && *lexorder != NULL && *maxnvarsorder > 0 && *nvarsorder > 0
3994  && (*lexorder)[0] != varidx )
3995  continue;
3996 
3997  /* mark all variables that have been used in strong SBCs */
3998  for (k = graphcompbegins[graphcomp]; k < graphcompbegins[graphcomp+1]; ++k)
3999  {
4000  assert( 0 <= graphcomponents[k] && graphcomponents[k] < propdata->npermvars );
4001 
4002  usedvars[graphcomponents[k]] = TRUE;
4003  }
4004 
4005  SCIP_CALL( SCIPcomputeOrbitVar(scip, propdata->npermvars, propdata->perms,
4006  propdata->permstrans, propdata->components, propdata->componentbegins,
4007  usedvars, varfound, varidx, symgrpcompidx,
4008  orbit[activeorb], &orbitsize[activeorb]) );
4009 
4010  assert( orbit[activeorb][0] == varidx );
4011 
4012  if ( orbitsize[activeorb] > orbitsize[1 - activeorb] ) /*lint !e514*/
4013  {
4014  /* if the new orbit is larger then the old largest one, flip activeorb */
4015  activeorb = 1 - activeorb;
4016  chosencolor = j;
4017  }
4018 
4019  /* reset array */
4020  for (k = graphcompbegins[graphcomp]; k < graphcompbegins[graphcomp+1]; ++k)
4021  usedvars[graphcomponents[k]] = FALSE;
4022  }
4023 
4024  /* check if we have found at least one non-empty orbit */
4025  if ( chosencolor > -1 )
4026  {
4027  /* flip activeorb again to avoid confusion, it is then at the largest orbit */
4028  activeorb = 1 - activeorb;
4029 
4030  assert( orbit[activeorb][0] == firstvaridxpercolor[chosencolor] );
4031  vars[0] = propdata->permvars[orbit[activeorb][0]];
4032 
4033  assert( chosencolor > -1 );
4034  SCIPdebugMsg(scip, " adding %d weak sbcs for enclosing orbit of color %d.\n", orbitsize[activeorb]-1, chosencolor);
4035 
4036  *naddedconss = orbitsize[activeorb] - 1;
4037 
4038  /* add weak SBCs for rest of enclosing orbit */
4039  for (j = 1; j < orbitsize[activeorb]; ++j)
4040  {
4041  SCIP_CONS* cons;
4042  char name[SCIP_MAXSTRLEN];
4043 
4044  vars[1] = propdata->permvars[orbit[activeorb][j]];
4045 
4046  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "weak_sbcs_%d_%s_%s", symgrpcompidx, SCIPvarGetName(vars[0]), SCIPvarGetName(vars[1]));
4047 
4048  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, 2, vars, vals, 0.0,
4049  SCIPinfinity(scip), propdata->conssaddlp, propdata->conssaddlp, TRUE,
4050  FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
4051 
4052  SCIP_CALL( SCIPaddCons(scip, cons) );
4053 
4054 #ifdef SCIP_MORE_DEBUG
4055  SCIP_CALL( SCIPprintCons(scip, cons, NULL) );
4056  SCIPinfoMessage(scip, NULL, "\n");
4057 #endif
4058 
4059  /* check whether we need to resize */
4060  if ( propdata->ngenlinconss >= propdata->genlinconsssize )
4061  {
4062  int newsize;
4063 
4064  newsize = SCIPcalcMemGrowSize(scip, propdata->ngenlinconss + 1);
4065  assert( newsize > propdata->ngenlinconss );
4066 
4067  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &propdata->genlinconss, propdata->genlinconsssize, newsize) );
4068 
4069  propdata->genlinconsssize = newsize;
4070  }
4071 
4072  propdata->genlinconss[propdata->ngenlinconss] = cons;
4073  ++propdata->ngenlinconss;
4074  }
4075 
4076  /* possibly store lexicographic order defined by weak SBCs */
4077  if ( storelexorder )
4078  {
4079  int varidx;
4080 
4081  varidx = orbit[activeorb][0];
4082  assert(varidx >= 0);
4083 
4084  if ( *maxnvarsorder == 0 )
4085  {
4086  *maxnvarsorder = 1;
4087  *nvarsorder = 0;
4088 
4089  SCIP_CALL( SCIPallocBlockMemoryArray(scip, lexorder, *maxnvarsorder) );
4090  (*lexorder)[(*nvarsorder)++] = varidx;
4091  }
4092  else
4093  {
4094  assert( *nvarsorder == *maxnvarsorder );
4095  assert( varsinlexorder != NULL );
4096  assert( lexorder != NULL );
4097  assert( *lexorder != NULL );
4098 
4099  /* the leader of the weak inequalities has to be the first element in the lexicographic order */
4100  if ( varidx == (*lexorder)[0] )
4101  {
4102  /* lexorder is already ok!! */
4103  assert( SCIPhashmapExists(varsinlexorder, (void*) (size_t) varidx) );
4104  }
4105  else
4106  {
4107  /* Then varidx must not be in the lexorder,
4108  * We must add it at the front of the array, and maintain the current order. */
4109  assert( ! SCIPhashmapExists(varsinlexorder, (void*) (size_t) varidx) );
4110 
4111  ++(*maxnvarsorder);
4112  ++(*nvarsorder);
4113 
4114  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, lexorder, *nvarsorder, *maxnvarsorder) );
4115 
4116  /* Shift array by one position to the right */
4117  for (k = *maxnvarsorder - 1; k >= 1; --k)
4118  (*lexorder)[k] = (*lexorder)[k - 1];
4119 
4120  (*lexorder)[0] = varidx;
4121  }
4122  }
4123  }
4124  }
4125  else
4126  SCIPdebugMsg(scip, " no further weak sbcs are valid\n");
4127 
4128  SCIPfreeBufferArray(scip, &orbit[1]);
4129  SCIPfreeBufferArray(scip, &orbit[0]);
4130  if ( varsinlexorder != NULL )
4131  SCIPhashmapFree(&varsinlexorder);
4132  SCIPfreeBufferArray(scip, &varfound);
4133  SCIPfreeCleanBufferArray(scip, &usedvars);
4134 
4135  return SCIP_OKAY;
4136 }
4137 
4138 
4139 /** temporarily adapt symmetry data to new variable order given by Schreier Sims */
4140 static
4142  SCIP* scip, /**< SCIP instance */
4143  int** origperms, /**< permutation matrix w.r.t. original variable ordering */
4144  int** modifiedperms, /**< memory for permutation matrix w.r.t. new variable ordering */
4145  int nperms, /**< number of permutations */
4146  SCIP_VAR** origpermvars, /**< array of permutation vars w.r.t. original variable ordering */
4147  SCIP_VAR** modifiedpermvars, /**< memory for array of permutation vars w.r.t. new variable ordering */
4148  int npermvars, /**< length or modifiedpermvars array */
4149  int* leaders, /**< leaders of Schreier Sims constraints */
4150  int nleaders /**< number of leaders */
4151  )
4152 {
4153  int* permvaridx;
4154  int* posinpermvar;
4155  int leader;
4156  int curposleader;
4157  int varidx;
4158  int lidx;
4159  int i;
4160  int l;
4161  int p;
4162 
4163  assert( scip != NULL );
4164  assert( origperms != NULL );
4165  assert( modifiedperms != NULL );
4166  assert( nperms > 0 );
4167  assert( origpermvars != NULL );
4168  assert( modifiedpermvars != NULL );
4169  assert( npermvars > 0 );
4170  assert( leaders != NULL );
4171  assert( nleaders > 0 );
4172 
4173  /* initialize map from position in lexicographic order to index of original permvar */
4174  SCIP_CALL( SCIPallocBufferArray(scip, &permvaridx, npermvars) );
4175  for (i = 0; i < npermvars; ++i)
4176  permvaridx[i] = i;
4177 
4178  /* initialize map from permvaridx to its current position in the reordered permvars array */
4179  SCIP_CALL( SCIPallocBufferArray(scip, &posinpermvar, npermvars) );
4180  for (i = 0; i < npermvars; ++i)
4181  posinpermvar[i] = i;
4182 
4183  /* Iterate over leaders and put the l-th leader to the l-th position of the lexicographic order.
4184  * We do this by swapping the l-th leader with the element at position l of the current permvars array. */
4185  for (l = 0; l < nleaders; ++l)
4186  {
4187  leader = leaders[l];
4188  curposleader = posinpermvar[leader];
4189  varidx = permvaridx[curposleader];
4190  lidx = permvaridx[l];
4191 
4192  /* swap the permvar at position l with the l-th leader */
4193  permvaridx[curposleader] = lidx;
4194  permvaridx[l] = varidx;
4195 
4196  /* update the position map */
4197  posinpermvar[lidx] = curposleader;
4198  posinpermvar[leader] = l;
4199  }
4200 
4201  /* update the permvars array to new variable order */
4202  for (i = 0; i < npermvars; ++i)
4203  modifiedpermvars[i] = origpermvars[permvaridx[i]];
4204 
4205  /* update the permutation to the new variable order */
4206  for (p = 0; p < nperms; ++p)
4207  {
4208  for (i = 0; i < npermvars; ++i)
4209  modifiedperms[p][i] = posinpermvar[origperms[p][permvaridx[i]]];
4210  }
4211 
4212  SCIPfreeBufferArray(scip, &permvaridx);
4213  SCIPfreeBufferArray(scip, &posinpermvar);
4214 
4215  return SCIP_OKAY;
4216 }
4217 
4218 
4219 /* returns the number of found orbitopes with at least three columns per graph component or 0
4220  * if the found orbitopes do not satisfy certain criteria for being used
4221  */
4222 static
4224  SCIP_VAR** permvars, /**< array of variables affected by symmetry */
4225  int* graphcomponents, /**< array of graph components */
4226  int* graphcompbegins, /**< array indicating starting position of graph components */
4227  int* compcolorbegins, /**< array indicating starting positions of potential orbitopes */
4228  int ncompcolors, /**< number of components encoded in compcolorbegins */
4229  int symcompsize /**< size of symmetry component for that we detect suborbitopes */
4230  )
4231 {
4232  SCIP_Bool oneorbitopecriterion = FALSE;
4233  SCIP_Bool multorbitopecriterion = FALSE;
4234  int norbitopes = 0;
4235  int j;
4236 
4237  assert( graphcompbegins != NULL );
4238  assert( compcolorbegins != NULL );
4239  assert( ncompcolors >= 0 );
4240  assert( symcompsize > 0 );
4241 
4242  for (j = 0; j < ncompcolors; ++j)
4243  {
4244  SCIP_VAR* firstvar;
4245  int largestcompsize = 0;
4246  int nbinrows= 0;
4247  int k;
4248 
4249  /* skip trivial components */
4250  if ( graphcompbegins[compcolorbegins[j+1]] - graphcompbegins[compcolorbegins[j]] < 2 )
4251  continue;
4252 
4253  /* check whether components of this color build an orbitope (with > 2 columns) */
4254  for (k = compcolorbegins[j]; k < compcolorbegins[j+1]; ++k)
4255  {
4256  int compsize;
4257 
4258  compsize = graphcompbegins[k+1] - graphcompbegins[k];
4259 
4260  /* the first component that we are looking at for this color */
4261  if ( largestcompsize < 1 )
4262  {
4263  if ( compsize < 3 )
4264  break;
4265 
4266  largestcompsize = compsize;
4267  }
4268  else if ( compsize != largestcompsize )
4269  break;
4270 
4271  firstvar = permvars[graphcomponents[graphcompbegins[k]]];
4272 
4273  /* count number of binary orbits (comps) */
4274  if ( SCIPvarIsBinary(firstvar) )
4275  ++nbinrows;
4276  }
4277 
4278  /* we have found an orbitope */
4279  if ( k == compcolorbegins[j+1] )
4280  {
4281  SCIP_Real threshold;
4282  int ncols;
4283 
4284  ++norbitopes;
4285  ncols = graphcompbegins[compcolorbegins[j] + 1] - graphcompbegins[compcolorbegins[j]];
4286 
4287  threshold = 0.7 * (SCIP_Real) symcompsize;
4288 
4289  /* check whether criteria for adding orbitopes are satisfied */
4290  if ( nbinrows <= 2 * ncols || (nbinrows <= 8 * ncols && nbinrows < 100) )
4291  multorbitopecriterion = TRUE;
4292  else if ( nbinrows <= 3 * ncols || (SCIP_Real) nbinrows * ncols >= threshold )
4293  oneorbitopecriterion = TRUE;
4294  }
4295  }
4296 
4297  if ( (norbitopes == 1 && oneorbitopecriterion) || (norbitopes >= 2 && multorbitopecriterion) )
4298  return norbitopes;
4299 
4300  return 0;
4301 }
4302 
4303 
4304 /** checks whether subgroups of the components are symmetric groups and adds SBCs for them */
4305 static
4307  SCIP* scip, /**< SCIP instance */
4308  SCIP_PROPDATA* propdata /**< pointer to data of symmetry propagator */
4309  )
4310 {
4311  int* genorder;
4312  int i;
4313 #ifdef SCIP_DEBUG
4314  int norbitopes = 0;
4315  int nstrongsbcs = 0;
4316  int nweaksbcs = 0;
4317 #endif
4318  int** modifiedperms;
4319  SCIP_VAR** modifiedpermvars;
4320  int* nvarsincomponent;
4321 
4322  assert( scip != NULL );
4323  assert( propdata != NULL );
4324  assert( propdata->computedsymmetry );
4325  assert( propdata->components != NULL );
4326  assert( propdata->componentbegins != NULL );
4327  assert( propdata->ncomponents > 0 );
4328  assert( propdata->nperms >= 0 );
4329 
4330  /* exit if no symmetry is present */
4331  if ( propdata->nperms == 0 )
4332  return SCIP_OKAY;
4333 
4334  /* exit if instance is too large */
4335  if ( SCIPgetNConss(scip) > propdata->maxnconsssubgroup )
4336  return SCIP_OKAY;
4337 
4338  assert( propdata->nperms > 0 );
4339  assert( propdata->perms != NULL );
4340  assert( propdata->npermvars > 0 );
4341  assert( propdata->permvars != NULL );
4342 
4343  /* create array for permutation order */
4344  SCIP_CALL( SCIPallocBufferArray(scip, &genorder, propdata->nperms) );
4345 
4346  /* create arrays for modified permutations in case we adapt the lexicographic order because of suborbitopes */
4347  SCIP_CALL( SCIPallocBufferArray(scip, &modifiedperms, propdata->nperms) );
4348  for (i = 0; i < propdata->nperms; ++i)
4349  {
4350  SCIP_CALL( SCIPallocBufferArray(scip, &modifiedperms[i], propdata->npermvars) );
4351  }
4352  SCIP_CALL( SCIPallocBufferArray(scip, &modifiedpermvars, propdata->npermvars) );
4353 
4354  SCIP_CALL( SCIPallocClearBufferArray(scip, &nvarsincomponent, propdata->npermvars) );
4355  for (i = 0; i < propdata->npermvars; ++i)
4356  {
4357  if ( propdata->vartocomponent[i] >= 0 )
4358  ++nvarsincomponent[propdata->vartocomponent[i]];
4359  }
4360 
4361  SCIPdebugMsg(scip, "starting subgroup detection routine for %d components\n", propdata->ncomponents);
4362 
4363  /* iterate over components */
4364  for (i = 0; i < propdata->ncomponents; ++i)
4365  {
4366  int* graphcomponents;
4367  int* graphcompbegins;
4368  int* compcolorbegins;
4369  int* chosencomppercolor = NULL;
4370  int* firstvaridxpercolor = NULL;
4371  int* usedperms;
4372  int usedpermssize;
4373  int ngraphcomponents;
4374  int ncompcolors;
4375  int ntwocycleperms;
4376  int npermsincomp;
4377  int nusedperms;
4378  int ntrivialcolors = 0;
4379  int j;
4380  int* lexorder = NULL;
4381  int nvarslexorder = 0;
4382  int maxnvarslexorder = 0;
4383  SCIP_Shortbool* permused;
4384  SCIP_Bool allpermsused = FALSE;
4385  SCIP_Bool handlednonbinarysymmetry = FALSE;
4386  int norbitopesincomp;
4387 
4388  /* if component is blocked, skip it */
4389  if ( propdata->componentblocked[i] )
4390  {
4391  SCIPdebugMsg(scip, "component %d has already been handled and will be skipped\n", i);
4392  continue;
4393  }
4394 
4395  npermsincomp = propdata->componentbegins[i + 1] - propdata->componentbegins[i];
4396 
4397  /* set the first npermsincomp entries of genorder; the others are not used for this component */
4398  for (j = 0; j < npermsincomp; ++j)
4399  genorder[j] = j;
4400 
4401  SCIP_CALL( chooseOrderOfGenerators(scip, propdata, i, &genorder, &ntwocycleperms) );
4402 
4403  assert( ntwocycleperms >= 0 );
4404  assert( ntwocycleperms <= npermsincomp );
4405 
4406  SCIPdebugMsg(scip, "component %d has %d permutations consisting of 2-cycles\n", i, ntwocycleperms);
4407 
4408 #ifdef SCIP_MORE_DEBUG
4409  SCIP_Bool* used;
4410  int perm;
4411  int p;
4412  int k;
4413 
4414  SCIP_CALL( SCIPallocBufferArray(scip, &used, propdata->npermvars) );
4415  for (p = propdata->componentbegins[i]; p < propdata->componentbegins[i+1]; ++p)
4416  {
4417  perm = propdata->components[p];
4418 
4419  for (k = 0; k < propdata->npermvars; ++k)
4420  used[k] = FALSE;
4421 
4422  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "permutation %d\n", perm);
4423 
4424  for (k = 0; k < propdata->npermvars; ++k)
4425  {
4426  if ( used[k] )
4427  continue;
4428 
4429  j = propdata->perms[perm][k];
4430 
4431  if ( k == j )
4432  continue;
4433 
4434  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "(%s,", SCIPvarGetName(propdata->permvars[k]));
4435  used[k] = TRUE;
4436  while (j != k)
4437  {
4438  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "%s,", SCIPvarGetName(propdata->permvars[j]));
4439  used[j] = TRUE;
4440 
4441  j = propdata->perms[perm][j];
4442  }
4444  }
4446  }
4447 
4448  SCIPfreeBufferArray(scip, &used);
4449 #endif
4450 
4451  if ( ntwocycleperms < 2 )
4452  {
4453  SCIPdebugMsg(scip, " --> skip\n");
4454  continue;
4455  }
4456 
4457  usedpermssize = ntwocycleperms / 2;
4458  SCIP_CALL( SCIPallocBufferArray(scip, &usedperms, usedpermssize) );
4459  SCIP_CALL( SCIPallocClearBufferArray(scip, &permused, npermsincomp) );
4460 
4461  SCIP_CALL( buildSubgroupGraph(scip, propdata, genorder, ntwocycleperms, i,
4462  &graphcomponents, &graphcompbegins, &compcolorbegins, &ngraphcomponents,
4463  &ncompcolors, &usedperms, &nusedperms, usedpermssize, permused) );
4464 
4465  SCIPdebugMsg(scip, " created subgroup detection graph using %d of the permutations\n", nusedperms);
4466 
4467  if ( nusedperms == npermsincomp )
4468  allpermsused = TRUE;
4469 
4470  assert( graphcomponents != NULL );
4471  assert( graphcompbegins != NULL );
4472  assert( compcolorbegins != NULL );
4473  assert( ngraphcomponents > 0 );
4474  assert( ncompcolors > 0 );
4475  assert( nusedperms <= ntwocycleperms );
4476  assert( ncompcolors < propdata->npermvars );
4477 
4478  if ( nusedperms == 0 )
4479  {
4480  SCIPdebugMsg(scip, " -> skipping component, since less no permutation was used\n");
4481 
4482  SCIPfreeBufferArray(scip, &permused);
4483  SCIPfreeBufferArray(scip, &usedperms);
4484 
4485  continue;
4486  }
4487 
4488  SCIPdebugMsg(scip, " number of different colors in the graph: %d\n", ncompcolors);
4489 
4490  if ( propdata->addstrongsbcs || propdata->addweaksbcs )
4491  {
4492  SCIP_CALL( SCIPallocBufferArray(scip, &chosencomppercolor, ncompcolors) );
4493  SCIP_CALL( SCIPallocBufferArray(scip, &firstvaridxpercolor, ncompcolors) );
4494 
4495  /* Initialize the arrays with -1 to encode that we have not added orbitopes/strong SBCs
4496  * yet. In case we do not modify this entry, no weak inequalities are added based on
4497  * this component.
4498  */
4499  for (j = 0; j < ncompcolors; ++j)
4500  {
4501  chosencomppercolor[j] = -1;
4502  firstvaridxpercolor[j] = -1;
4503  }
4504  }
4505 
4506  norbitopesincomp = getNOrbitopesInComp(propdata->permvars, graphcomponents, graphcompbegins, compcolorbegins,
4507  ncompcolors, nvarsincomponent[i]);
4508 
4509  /* if there is just one orbitope satisfying the requirements, handle the full component by symresacks */
4510  if ( norbitopesincomp == 1 )
4511  {
4512  int k;
4513 
4514  for (k = 0; k < npermsincomp; ++k)
4515  {
4516  SCIP_CONS* cons;
4517  char name[SCIP_MAXSTRLEN];
4518 
4519  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "symresack_comp%d_perm%d", i, k);
4520 
4521  SCIP_CALL( SCIPcreateSymbreakCons(scip, &cons, name, propdata->perms[propdata->components[propdata->componentbegins[i] + k]],
4522  propdata->permvars, propdata->npermvars, FALSE,
4523  propdata->conssaddlp, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
4524  SCIP_CALL( SCIPaddCons(scip, cons));
4525 
4526  /* do not release constraint here - will be done later */
4527  propdata->genorbconss[propdata->ngenorbconss++] = cons;
4528  ++propdata->nsymresacks;
4529 
4530  if ( ! propdata->componentblocked[i] )
4531  {
4532  propdata->componentblocked[i] |= SYM_HANDLETYPE_SYMBREAK;
4533  ++propdata->ncompblocked;
4534  }
4535 
4536  SCIPdebugMsg(scip, " add symresack for permutation %d of component %d\n", k, i);
4537  }
4538 
4539  goto FREELOOPMEMORY;
4540  }
4541 
4542  for (j = 0; j < ncompcolors; ++j)
4543  {
4544  int nbinarycomps = 0;
4545  int largestcolorcomp = -1;
4546  int largestcompsize = 0;
4547  int k;
4548  SCIP_Bool isorbitope = TRUE;
4549  SCIP_Bool orbitopeadded = FALSE;
4550  SCIP_Bool useorbitope;
4551 #ifdef SCIP_DEBUG
4552  SCIP_Bool binaffected = FALSE;
4553  SCIP_Bool intaffected = FALSE;
4554  SCIP_Bool contaffected = FALSE;
4555 #endif
4556 
4557  /* skip trivial components */
4558  if ( graphcompbegins[compcolorbegins[j+1]] - graphcompbegins[compcolorbegins[j]] < 2 )
4559  {
4560  if( chosencomppercolor != NULL )
4561  chosencomppercolor[j] = -1;
4562 
4563  ++ntrivialcolors;
4564  continue;
4565  }
4566 
4567  SCIPdebugMsg(scip, " color %d has %d components with overall %d variables\n", j, compcolorbegins[j+1] - compcolorbegins[j],
4568  graphcompbegins[compcolorbegins[j+1]] - graphcompbegins[compcolorbegins[j]]);
4569 
4570  /* check whether components of this color might build an orbitope (with > 2 columns) */
4571  for (k = compcolorbegins[j]; k < compcolorbegins[j+1]; ++k)
4572  {
4573  SCIP_VAR* firstvar;
4574  int compsize;
4575 
4576  compsize = graphcompbegins[k+1] - graphcompbegins[k];
4577 
4578  /* the first component that we are looking at for this color */
4579  if ( largestcompsize < 1 )
4580  {
4581  if ( compsize < 3 )
4582  {
4583  isorbitope = FALSE;
4584  break;
4585  }
4586 
4587  largestcompsize = compsize;
4588  largestcolorcomp = k;
4589  }
4590  else if ( compsize != largestcompsize )
4591  {
4592  /* variable orbits (compsize) have not the same size, cannot define orbitope */
4593  isorbitope = FALSE;
4594  break;
4595  }
4596 
4597  firstvar = propdata->permvars[graphcomponents[graphcompbegins[k]]];
4598 
4599  /* count number of binary orbits (comps) */
4600  if ( SCIPvarIsBinary(firstvar) )
4601  ++nbinarycomps;
4602  }
4603 
4604 #ifdef SCIP_DEBUG
4605  for (k = compcolorbegins[j]; k < compcolorbegins[j+1]; ++k)
4606  {
4607  SCIP_VAR* firstvar;
4608 
4609  firstvar = propdata->permvars[graphcomponents[graphcompbegins[k]]];
4610 
4611  if ( SCIPvarIsBinary(firstvar) )
4612  binaffected = TRUE;
4613  else if (SCIPvarIsIntegral(firstvar) )
4614  intaffected = TRUE;
4615  else
4616  contaffected = TRUE;
4617  }
4618 
4619  SCIPdebugMsg(scip, " affected types (bin,int,cont): (%d,%d,%d)\n", binaffected, intaffected, contaffected);
4620 #endif
4621 
4622  /* only use the orbitope if there are binary rows */
4623  useorbitope = FALSE;
4624  if ( norbitopesincomp > 0 && nbinarycomps > 0 )
4625  useorbitope = TRUE;
4626 
4627  if ( isorbitope && useorbitope )
4628  {
4629  int firstvaridx;
4630  int chosencomp;
4631 
4632  SCIPdebugMsg(scip, " detected an orbitope with %d rows and %d columns\n", nbinarycomps, largestcompsize);
4633 
4634  assert( nbinarycomps > 0 );
4635  assert( largestcompsize > 2 );
4636 
4637  /* add the orbitope constraint for this color
4638  *
4639  * It might happen that we cannot generate the orbitope matrix if the orbitope is not generated by permutations
4640  * all having the same number of 2-cycles, e.g., the orbitope generated by (1,2)(4,5), (2,3), (5,6).
4641  */
4642  SCIP_CALL( addOrbitopeSubgroup(scip, propdata, usedperms, nusedperms, compcolorbegins,
4643  graphcompbegins, graphcomponents, j, nbinarycomps, largestcompsize, &firstvaridx, &chosencomp,
4644  &lexorder, &nvarslexorder, &maxnvarslexorder, allpermsused, &orbitopeadded) );
4645 
4646  if ( orbitopeadded )
4647  {
4648  if ( propdata->addstrongsbcs || propdata->addweaksbcs )
4649  {
4650  assert( chosencomppercolor != NULL );
4651  assert( firstvaridxpercolor != NULL );
4652 
4653  /* adapt the first variable per color to be compatible with the created orbiope (upper left variable) */
4654  assert( compcolorbegins[j] <= chosencomp && chosencomp < compcolorbegins[j+1] );
4655  assert( 0 <= firstvaridx && firstvaridx < propdata->npermvars );
4656 
4657  chosencomppercolor[j] = chosencomp;
4658  firstvaridxpercolor[j] = firstvaridx;
4659  }
4660 
4661  if ( ! propdata->componentblocked[i] )
4662  {
4663  propdata->componentblocked[i] |= SYM_HANDLETYPE_SYMBREAK;
4664  ++propdata->ncompblocked;
4665  }
4666 
4667 #ifdef SCIP_DEBUG
4668  ++norbitopes;
4669 #endif
4670  }
4671  }
4672 
4673  /* if no (useable) orbitope was found, possibly add strong SBCs */
4674  if ( propdata->addstrongsbcs && ! orbitopeadded )
4675  {
4676  assert( largestcolorcomp >= 0 );
4677  assert( largestcolorcomp < ngraphcomponents );
4678  assert( largestcompsize > 0 );
4679 
4680  if( propdata->addweaksbcs )
4681  {
4682  assert( chosencomppercolor != NULL );
4683  assert( firstvaridxpercolor != NULL );
4684 
4685  chosencomppercolor[j] = largestcolorcomp;
4686  firstvaridxpercolor[j] = graphcomponents[graphcompbegins[largestcolorcomp]];
4687  }
4688 
4689  SCIPdebugMsg(scip, " choosing component %d with %d variables and adding strong SBCs\n",
4690  largestcolorcomp, graphcompbegins[largestcolorcomp+1] - graphcompbegins[largestcolorcomp]);
4691 
4692  /* add the strong SBCs for the corresponding component */
4693  SCIP_CALL( addStrongSBCsSubgroup(scip, propdata, graphcompbegins, graphcomponents, largestcolorcomp,
4694  propdata->addsymresacks, &lexorder, &nvarslexorder, &maxnvarslexorder) );
4695 
4696  /* store whether symmetries on non-binary symmetries have been handled */
4697  if ( ! SCIPvarIsBinary(propdata->permvars[graphcomponents[graphcompbegins[largestcolorcomp]]]) )
4698  handlednonbinarysymmetry = TRUE;
4699 
4700  if ( ! propdata->componentblocked[i] )
4701  {
4702  propdata->componentblocked[i] |= SYM_HANDLETYPE_SYMBREAK;
4703  ++propdata->ncompblocked;
4704  }
4705 
4706 #ifdef SCIP_DEBUG
4707  nstrongsbcs += graphcompbegins[largestcolorcomp+1] - graphcompbegins[largestcolorcomp] - 1;
4708 #endif
4709  }
4710  else if ( ! orbitopeadded )
4711  {
4712  SCIPdebugMsg(scip, " no useable orbitope found and no SBCs added\n");
4713 
4714  /* mark the color as not handled */
4715  if ( propdata->addweaksbcs )
4716  {
4717  assert( chosencomppercolor != NULL );
4718  chosencomppercolor[j] = -1; /*lint !e613*/
4719  }
4720  }
4721  }
4722 
4723  SCIPdebugMsg(scip, " skipped %d trivial colors\n", ntrivialcolors);
4724 
4725  /* possibly add weak SBCs for enclosing orbit of first component */
4726  if ( propdata->addweaksbcs && propdata->componentblocked[i] && nusedperms < npermsincomp )
4727  {
4728  int naddedconss;
4729 
4730  assert( firstvaridxpercolor != NULL );
4731  assert( chosencomppercolor != NULL );
4732 
4733  SCIP_CALL( addWeakSBCsSubgroup(scip, propdata, compcolorbegins, graphcompbegins,
4734  graphcomponents, ncompcolors, chosencomppercolor, firstvaridxpercolor,
4735  i, &naddedconss, propdata->addsymresacks, &lexorder, &nvarslexorder, &maxnvarslexorder) );
4736 
4737  assert( naddedconss < propdata->npermvars );
4738 
4739 #ifdef SCIP_DEBUG
4740  nweaksbcs += naddedconss;
4741 #endif
4742  }
4743  else
4744  SCIPdebugMsg(scip, " don't add weak sbcs because all generators were used or the settings forbid it\n");
4745 
4746  /* if suborbitopes or strong group actions have been found, potentially add symresacks adapted to
4747  * variable order given by lexorder if no symmetries on non-binary variables have been handled
4748  */
4749  if ( nvarslexorder > 0 && propdata->addsymresacks && ! handlednonbinarysymmetry )
4750  {
4751  int k;
4752 
4753  SCIP_CALL( adaptSymmetryDataSST(scip, propdata->perms, modifiedperms, propdata->nperms,
4754  propdata->permvars, modifiedpermvars, propdata->npermvars, lexorder, nvarslexorder) );
4755 
4756  for (k = 0; k < npermsincomp; ++k)
4757  {
4758  SCIP_CONS* cons;
4759  char name[SCIP_MAXSTRLEN];
4760 
4761  /* skip permutations that have been used to build an orbitope */
4762  if ( permused[k] )
4763  continue;
4764 
4765  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "symresack_comp%d_perm%d", i, k);
4766 
4767  SCIP_CALL( SCIPcreateSymbreakCons(scip, &cons, name, modifiedperms[propdata->components[propdata->componentbegins[i] + k]],
4768  modifiedpermvars, propdata->npermvars, FALSE,
4769  propdata->conssaddlp, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
4770  SCIP_CALL( SCIPaddCons(scip, cons));
4771 
4772  /* do not release constraint here - will be done later */
4773  propdata->genorbconss[propdata->ngenorbconss++] = cons;
4774  ++propdata->nsymresacks;
4775 
4776  if ( ! propdata->componentblocked[i] )
4777  {
4778  propdata->componentblocked[i] |= SYM_HANDLETYPE_SYMBREAK;
4779  ++propdata->ncompblocked;
4780  }
4781 
4782  SCIPdebugMsg(scip, " add symresack for permutation %d of component %d adapted to suborbitope lexorder\n", k, i);
4783  }
4784  }
4785 
4786  FREELOOPMEMORY:
4787  SCIPfreeBlockMemoryArrayNull(scip, &lexorder, maxnvarslexorder);
4788 
4789  SCIPfreeBufferArrayNull(scip, &firstvaridxpercolor);
4790  SCIPfreeBufferArrayNull(scip, &chosencomppercolor);
4791  SCIPfreeBlockMemoryArrayNull(scip, &compcolorbegins, ncompcolors + 1);
4792  SCIPfreeBlockMemoryArrayNull(scip, &graphcompbegins, ngraphcomponents + 1);
4793  SCIPfreeBlockMemoryArrayNull(scip, &graphcomponents, propdata->npermvars);
4794  SCIPfreeBufferArrayNull(scip, &permused);
4795  SCIPfreeBufferArrayNull(scip, &usedperms);
4796  }
4797 
4798 #ifdef SCIP_DEBUG
4799  SCIPdebugMsg(scip, "total number of added (sub-)orbitopes: %d\n", norbitopes);
4800  SCIPdebugMsg(scip, "total number of added strong sbcs: %d\n", nstrongsbcs);
4801  SCIPdebugMsg(scip, "total number of added weak sbcs: %d\n", nweaksbcs);
4802 #endif
4803 
4804  SCIPfreeBufferArray(scip, &nvarsincomponent);
4805 
4806  SCIPfreeBufferArray(scip, &modifiedpermvars);
4807  for (i = propdata->nperms - 1; i >= 0; --i)
4808  {
4809  SCIPfreeBufferArray(scip, &modifiedperms[i]);
4810  }
4811  SCIPfreeBufferArray(scip, &modifiedperms);
4812  SCIPfreeBufferArray(scip, &genorder);
4813 
4814  return SCIP_OKAY;
4815 }
4816 
4817 
4818 /*
4819  * Functions for symmetry constraints
4820  */
4821 
4822 
4823 /** sorts orbitope vars matrix such that rows are sorted increasingly w.r.t. minimum variable index in row;
4824  * columns are sorted such that first row is sorted increasingly w.r.t. variable indices
4825  */
4826 static
4828  SCIP* scip, /**< SCIP instance */
4829  int** orbitopevaridx, /**< variable index matrix of orbitope */
4830  SCIP_VAR*** vars, /**< variable matrix of orbitope */
4831  int nrows, /**< number of binary rows of orbitope */
4832  int ncols /**< number of columns of orbitope */
4833  )
4834 {
4835  SCIP_VAR** sortedrow;
4836  int* colorder;
4837  int* idcs;
4838  int arrlen;
4839  int minrowidx = INT_MAX;
4840  int minrow = INT_MAX;
4841  int i;
4842  int j;
4843 
4844  assert( scip != NULL );
4845  assert( orbitopevaridx != NULL );
4846  assert( vars != NULL );
4847  assert( nrows > 0 );
4848  assert( ncols > 0 );
4849 
4850  arrlen = MAX(nrows, ncols);
4851  SCIP_CALL( SCIPallocBufferArray(scip, &idcs, arrlen) );
4852 
4853  /* detect minimum index per row */
4854  for (i = 0; i < nrows; ++i)
4855  {
4856  int idx;
4857 
4858  idcs[i] = INT_MAX;
4859 
4860  for (j = 0; j < ncols; ++j)
4861  {
4862  idx = orbitopevaridx[i][j];
4863 
4864  if ( idx < idcs[i] )
4865  idcs[i] = idx;
4866 
4867  if ( idx < minrowidx )
4868  {
4869  minrowidx = idx;
4870  minrow = i;
4871  }
4872  }
4873  }
4874 
4875  /* sort rows increasingly w.r.t. minimum variable indices */
4876  SCIPsortIntPtr(idcs, (void**) vars, nrows);
4877 
4878  /* sort columns increasingly w.r.t. variable indices of first row */
4879  SCIP_CALL( SCIPallocBufferArray(scip, &colorder, ncols) );
4880  for (j = 0; j < ncols; ++j)
4881  {
4882  idcs[j] = orbitopevaridx[minrow][j];
4883  colorder[j] = j;
4884  }
4885 
4886  /* sort columns of first row and store new column order */
4887  SCIPsortIntIntPtr(idcs, colorder, (void**) vars[0], ncols);
4888 
4889  /* adapt rows 1, ..., nrows - 1 to new column order*/
4890  SCIP_CALL( SCIPallocBufferArray(scip, &sortedrow, ncols) );
4891  for (i = 1; i < nrows; ++i)
4892  {
4893  for (j = 0; j < ncols; ++j)
4894  sortedrow[j] = vars[i][colorder[j]];
4895  for (j = 0; j < ncols; ++j)
4896  vars[i][j] = sortedrow[j];
4897  }
4898 
4899  SCIPfreeBufferArray(scip, &sortedrow);
4900  SCIPfreeBufferArray(scip, &colorder);
4901  SCIPfreeBufferArray(scip, &idcs);
4902 
4903  return SCIP_OKAY;
4904 }
4905 
4906 
4907 /** checks whether components of the symmetry group can be completely handled by orbitopes */
4908 static
4910  SCIP* scip, /**< SCIP instance */
4911  SCIP_PROPDATA* propdata, /**< pointer to data of symmetry propagator */
4912  int* components, /**< array containing components of symmetry group */
4913  int* componentbegins, /**< array containing begin positions of components in components array */
4914  int ncomponents /**< number of components */
4915  )
4916 {
4917  SCIP_VAR** permvars;
4918  int** perms;
4919  int npermvars;
4920  int i;
4921 
4922  assert( scip != NULL );
4923  assert( propdata != NULL );
4924  assert( components != NULL );
4925  assert( componentbegins != NULL );
4926  assert( ncomponents > 0 );
4927  assert( propdata->nperms >= 0 );
4928 
4929  /* exit if no symmetry is present */
4930  if ( propdata->nperms == 0 )
4931  return SCIP_OKAY;
4932 
4933  assert( propdata->nperms > 0 );
4934  assert( propdata->perms != NULL );
4935  assert( propdata->nbinpermvars >= 0 );
4936  assert( propdata->npermvars >= 0 );
4937  assert( propdata->permvars != NULL );
4938 
4939  /* exit if no symmetry on binary variables is present */
4940  if ( propdata->nbinpermvars == 0 )
4941  {
4942  assert( ! propdata->binvaraffected );
4943  return SCIP_OKAY;
4944  }
4945 
4946  perms = propdata->perms;
4947  npermvars = propdata->npermvars;
4948  permvars = propdata->permvars;
4949 
4950  /* iterate over components */
4951  for (i = 0; i < ncomponents; ++i)
4952  {
4953  SCIP_VAR*** vars;
4954  SCIP_VAR*** varsallocorder;
4955  SCIP_CONS* cons;
4956  SCIP_Shortbool* rowisbinary;
4957  SCIP_Bool isorbitope = TRUE;
4958  SCIP_Bool infeasibleorbitope;
4959  int** orbitopevaridx;
4960  int* columnorder;
4961  int npermsincomponent;
4962  int ntwocyclescomp = INT_MAX;
4963  int nbincyclescomp = INT_MAX;
4964  int* nusedelems;
4965  int j;
4966  int cnt;
4967 
4968  /* orbitopes are detected first, so no component should be blocked */
4969  assert( ! propdata->componentblocked[i] );
4970 
4971  /* get properties of permutations */
4972  npermsincomponent = componentbegins[i + 1] - componentbegins[i];
4973  assert( npermsincomponent > 0 );
4974  for (j = componentbegins[i]; j < componentbegins[i + 1]; ++j)
4975  {
4976  int ntwocyclesperm = 0;
4977  int nbincyclesperm = 0;
4978 
4979  SCIP_CALL( SCIPisInvolutionPerm(perms[components[j]], permvars, npermvars,
4980  &ntwocyclesperm, &nbincyclesperm, FALSE) );
4981 
4982  if ( ntwocyclesperm == 0 )
4983  {
4984  isorbitope = FALSE;
4985  break;
4986  }
4987 
4988  /* if we are checking the first permutation */
4989  if ( ntwocyclescomp == INT_MAX )
4990  {
4991  ntwocyclescomp = ntwocyclesperm;
4992  nbincyclescomp = nbincyclesperm;
4993 
4994  /* if there are no binary rows */
4995  if ( nbincyclescomp == 0 )
4996  {
4997  isorbitope = FALSE;
4998  break;
4999  }
5000  }
5001 
5002  /* no or different number of 2-cycles or not all vars binary: permutations cannot generate orbitope */
5003  if ( ntwocyclescomp != ntwocyclesperm || nbincyclesperm != nbincyclescomp )
5004  {
5005  isorbitope = FALSE;
5006  break;
5007  }
5008  }
5009 
5010  /* if no orbitope was detected */
5011  if ( ! isorbitope )
5012  continue;
5013  assert( ntwocyclescomp > 0 );
5014  assert( ntwocyclescomp < INT_MAX );
5015 
5016  /* iterate over permutations and check whether for each permutation there exists
5017  * another permutation whose 2-cycles intersect pairwise in exactly one element */
5018 
5019  /* orbitope matrix for indices of variables in permvars array */
5020  SCIP_CALL( SCIPallocBufferArray(scip, &orbitopevaridx, ntwocyclescomp) );
5021  for (j = 0; j < ntwocyclescomp; ++j)
5022  {
5023  SCIP_CALL( SCIPallocBufferArray(scip, &orbitopevaridx[j], npermsincomponent + 1) ); /*lint !e866*/
5024  }
5025 
5026  /* order of columns of orbitopevaridx */
5027  SCIP_CALL( SCIPallocBufferArray(scip, &columnorder, npermsincomponent + 1) );
5028  for (j = 0; j < npermsincomponent + 1; ++j)
5029  columnorder[j] = npermsincomponent + 2;
5030 
5031  /* count how often an element was used in the potential orbitope */
5032  SCIP_CALL( SCIPallocClearBufferArray(scip, &nusedelems, npermvars) );
5033 
5034  /* store whether a row of the potential orbitope contains only binary variables */
5035  SCIP_CALL( SCIPallocClearBufferArray(scip, &rowisbinary, ntwocyclescomp) );
5036 
5037  /* check if the permutations fulfill properties of an orbitope */
5038  SCIP_CALL( checkTwoCyclePermsAreOrbitope(scip, permvars, npermvars, perms,
5039  &(components[componentbegins[i]]), ntwocyclescomp, npermsincomponent,
5040  orbitopevaridx, columnorder, nusedelems, NULL, rowisbinary, &isorbitope, NULL) );
5041 
5042  if ( ! isorbitope )
5043  goto FREEDATASTRUCTURES;
5044 
5045  /* we have found a potential orbitope, prepare data for orbitope conshdlr */
5046  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nbincyclescomp) );
5047  SCIP_CALL( SCIPallocBufferArray(scip, &varsallocorder, nbincyclescomp) );
5048  cnt = 0;
5049  for (j = 0; j < ntwocyclescomp; ++j)
5050  {
5051  if ( ! rowisbinary[j] )
5052  continue;
5053 
5054  SCIP_CALL( SCIPallocBufferArray(scip, &vars[cnt], npermsincomponent + 1) ); /*lint !e866*/
5055  varsallocorder[cnt] = vars[cnt]; /* to ensure that we can free the buffer in reverse order */
5056  ++cnt;
5057  }
5058  assert( cnt == nbincyclescomp );
5059 
5060  /* prepare variable matrix (reorder columns of orbitopevaridx) */
5061  infeasibleorbitope = FALSE;
5062  SCIP_CALL( SCIPgenerateOrbitopeVarsMatrix(scip, &vars, ntwocyclescomp, npermsincomponent + 1, permvars,
5063  npermvars, orbitopevaridx, columnorder, nusedelems, rowisbinary, &infeasibleorbitope, FALSE, NULL, NULL, NULL) );
5064 
5065  if ( ! infeasibleorbitope )
5066  {
5067  char name[SCIP_MAXSTRLEN];
5068 
5069  SCIPdebugMsg(scip, "found an orbitope of size %d x %d in component %d\n", ntwocyclescomp, npermsincomponent + 1, i);
5070 
5071  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "orbitope_component%d", i);
5072 
5073  /* to ensure same orbitope is added if different sets of generators are found */
5074  SCIP_CALL( SCIPsortOrbitope(scip, orbitopevaridx, vars, nbincyclescomp, npermsincomponent + 1) );
5075 
5076  SCIP_CALL( SCIPcreateConsOrbitope(scip, &cons, name, vars, SCIP_ORBITOPETYPE_FULL,
5077  nbincyclescomp, npermsincomponent + 1, propdata->usedynamicprop, FALSE, FALSE, FALSE,
5078  propdata->conssaddlp, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
5079 
5080  SCIP_CALL( SCIPaddCons(scip, cons) );
5081 
5082  /* do not release constraint here - will be done later */
5083  propdata->genorbconss[propdata->ngenorbconss++] = cons;
5084  ++propdata->norbitopes;
5085 
5086  propdata->componentblocked[i] |= SYM_HANDLETYPE_SYMBREAK;
5087  }
5088 
5089  /* free data structures */
5090  for (j = nbincyclescomp - 1; j >= 0; --j)
5091  {
5092  SCIPfreeBufferArray(scip, &varsallocorder[j]);
5093  }
5094  SCIPfreeBufferArray(scip, &varsallocorder);
5095  SCIPfreeBufferArray(scip, &vars);
5096 
5097  FREEDATASTRUCTURES:
5098  SCIPfreeBufferArray(scip, &rowisbinary);
5099  SCIPfreeBufferArray(scip, &nusedelems);
5100  SCIPfreeBufferArray(scip, &columnorder);
5101  for (j = ntwocyclescomp - 1; j >= 0; --j)
5102  {
5103  SCIPfreeBufferArray(scip, &orbitopevaridx[j]);
5104  }
5105  SCIPfreeBufferArray(scip, &orbitopevaridx);
5106  }
5107 
5108  return SCIP_OKAY;
5109 }
5110 
5111 
5112 /** update symmetry information of conflict graph */
5113 static
5115  SCIP* scip, /**< SCIP instance */
5116  SCIP_DIGRAPH* conflictgraph, /**< conflict graph */
5117  SCIP_VAR** graphvars, /**< variables encoded in conflict graph (either all vars or permvars) */
5118  int ngraphvars, /**< number of nodes/vars in conflict graph */
5119  SCIP_VAR** permvars, /**< variables considered in permutations */
5120  int npermvars, /**< number of permvars */
5121  SCIP_Bool onlypermvars, /**< whether conflict graph contains only permvars */
5122  SCIP_HASHMAP* varmap, /**< map from graphvar to node label in conflict graph
5123  * (or NULL if onlypermvars == TRUE) */
5124  int* orbits, /**< array of non-trivial orbits */
5125  int* orbitbegins, /**< array containing begin positions of new orbits in orbits array */
5126  int norbits /**< number of non-trivial orbits */
5127  )
5128 {
5129  int i;
5130  int j;
5131 
5132  assert( scip != NULL );
5133  assert( conflictgraph != NULL );
5134  assert( graphvars != NULL );
5135  assert( ngraphvars > 0 );
5136  assert( permvars != NULL );
5137  assert( npermvars > 0 );
5138  assert( onlypermvars || varmap != NULL );
5139  assert( orbits != NULL );
5140  assert( orbitbegins != NULL );
5141  assert( norbits >= 0 );
5142 
5143  /* initialize/reset variable information of nodes in conflict graph */
5144  for (i = 0; i < ngraphvars; ++i)
5145  {
5146  SCIP_NODEDATA* nodedata;
5147 
5148  nodedata = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(conflictgraph, i);
5149 
5150  /* possibly create node data */
5151  if ( nodedata == NULL )
5152  {
5153  SCIP_CALL( SCIPallocBlockMemory(scip, &nodedata) );
5154  nodedata->var = graphvars[i];
5155  nodedata->active = TRUE;
5156  }
5157 
5158  /* (re-)set node data */
5159  nodedata->orbitidx = -1;
5160  nodedata->nconflictinorbit = 0;
5161  nodedata->orbitsize = -1;
5162  nodedata->posinorbit = -1;
5163 
5164  /* set node data */
5165  SCIPdigraphSetNodeData(conflictgraph, (void*) nodedata, i);
5166  }
5167 
5168  /* add orbit information to nodes of conflict graph */
5169  for (j = 0; j < norbits; ++j)
5170  {
5171  int posinorbit = 0;
5172  int orbitsize;
5173 
5174  orbitsize = orbitbegins[j + 1] - orbitbegins[j];
5175  assert( orbitsize >= 0 );
5176 
5177  for (i = orbitbegins[j]; i < orbitbegins[j + 1]; ++i)
5178  {
5179  SCIP_NODEDATA* nodedata;
5180  SCIP_VAR* var;
5181  int pos;
5182 
5183  /* get variable and position in conflict graph */
5184  if ( onlypermvars )
5185  {
5186  pos = orbits[i];
5187  var = permvars[pos];
5188  }
5189  else
5190  {
5191  var = permvars[orbits[i]];
5192  assert( var != NULL );
5193 
5194  assert( SCIPhashmapExists(varmap, var) );
5195  pos = SCIPhashmapGetImageInt(varmap, var);
5196  assert( pos != INT_MAX );
5197  }
5198 
5199  /* get node data */
5200  nodedata = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(conflictgraph, pos);
5201  assert( nodedata != NULL );
5202  assert( nodedata->var == var );
5203 
5204  nodedata->orbitidx = j;
5205  nodedata->orbitsize = orbitsize;
5206  nodedata->posinorbit = posinorbit++;
5207  }
5208  }
5209 
5210  /* add information on number of conflicts within orbit to conflict graph */
5211  for (i = 0; i < ngraphvars; ++i)
5212  {
5213  SCIP_NODEDATA* nodedata;
5214  SCIP_NODEDATA* nodedataconflict;
5215  int* conflictvaridx;
5216  int nconflictinorbit = 0;
5217  int curorbit;
5218 
5219  nodedata = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(conflictgraph, i);
5220  conflictvaridx = SCIPdigraphGetSuccessors(conflictgraph, i);
5221 
5222  assert( nodedata != NULL );
5223  assert( nodedata->nconflictinorbit == 0 );
5224  assert( conflictvaridx != NULL || SCIPdigraphGetNSuccessors(conflictgraph, i) == 0 );
5225 
5226  curorbit = nodedata->orbitidx;
5227 
5228  /* i-th variable is fixed by all permutations */
5229  if ( curorbit == -1 )
5230  {
5231  nodedata->nconflictinorbit = 0;
5232  continue;
5233  }
5234 
5235  /* get conflicts in orbit by couting the active neighbors of i in the same orbit */
5236  for (j = 0; j < SCIPdigraphGetNSuccessors(conflictgraph, i); ++j)
5237  {
5238  assert( conflictvaridx != NULL );
5239  nodedataconflict = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(conflictgraph, conflictvaridx[j]);
5240  assert( nodedataconflict != NULL );
5241 
5242  if ( nodedataconflict->active && nodedataconflict->orbitidx == curorbit )
5243  ++nconflictinorbit;
5244  }
5245 
5246  nodedata->nconflictinorbit = nconflictinorbit;
5247  }
5248 
5249  return SCIP_OKAY;
5250 }
5251 
5252 
5253 /** create conflict graph either for symmetric or for all variables
5254  *
5255  * This routine just creates the graph, but does not add (symmetry) information to its nodes.
5256  * This has to be done separately by the routine updateSymInfoConflictGraphSST().
5257  */
5258 static
5260  SCIP* scip, /**< SCIP instance */
5261  SCIP_DIGRAPH** conflictgraph, /**< pointer to store conflict graph */
5262  SCIP_VAR** graphvars, /**< variables encoded in conflict graph */
5263  int ngraphvars, /**< number of vars encoded in conflict graph */
5264  SCIP_Bool onlypermvars, /**< whether conflict graph contains only permvars */
5265  SCIP_HASHMAP* permvarmap, /**< map of variables to indices in permvars array (or NULL) */
5266  SCIP_Bool* success /**< pointer to store whether conflict graph could be created successfully */
5267  )
5268 {
5269  SCIP_CONSHDLR* setppcconshdlr;
5270  SCIP_CONS** setppcconss;
5271  SCIP_VAR** setppcvars;
5272  SCIP_CONS* cons;
5273  int nsetppcconss;
5274  int nsetppcvars;
5275  int nodei;
5276  int nodej;
5277  int c;
5278  int i;
5279  int j;
5280  int nedges = 0;
5281 
5282  assert( scip != NULL );
5283  assert( conflictgraph != NULL );
5284  assert( graphvars != NULL );
5285  assert( ngraphvars > 0 );
5286  assert( success != NULL );
5287 
5288  *success = FALSE;
5289 
5290  /* get setppcconss for creating conflict graph */
5291  setppcconshdlr = SCIPfindConshdlr(scip, "setppc");
5292  if ( setppcconshdlr == NULL )
5293  {
5294  SCIPdebugMsg(scip, "Could not find setppc conshdlr --> construction of conflict graph aborted.\n");
5295  return SCIP_OKAY;
5296  }
5297  assert( setppcconshdlr != NULL );
5298 
5299  setppcconss = SCIPconshdlrGetConss(setppcconshdlr);
5300  nsetppcconss = SCIPconshdlrGetNConss(setppcconshdlr);
5301  if ( nsetppcconss == 0 )
5302  {
5303  SCIPdebugMsg(scip, "No setppc constraints present --> construction of conflict graph aborted.\n");
5304  return SCIP_OKAY;
5305  }
5306 
5307  /* construct conflict graph */
5308  SCIP_CALL( SCIPcreateDigraph(scip, conflictgraph, ngraphvars) );
5309  *success = TRUE;
5310 
5311  SCIPdebugMsg(scip, "Construction of conflict graph:\n");
5312 
5313  for (c = 0; c < nsetppcconss; ++c)
5314  {
5315  cons = setppcconss[c];
5316  assert( cons != NULL );
5317 
5318  /* skip covering constraints */
5319  if ( SCIPgetTypeSetppc(scip, cons) == SCIP_SETPPCTYPE_COVERING )
5320  continue;
5321 
5322  setppcvars = SCIPgetVarsSetppc(scip, cons);
5323  nsetppcvars = SCIPgetNVarsSetppc(scip, cons);
5324  assert( setppcvars != NULL );
5325  assert( nsetppcvars > 0 );
5326 
5327  SCIPdebugMsg(scip, "\tAdd edges for constraint %s.\n", SCIPconsGetName(cons));
5328 
5329  /* iterate over pairs of variables in constraint and add bidirected arc
5330  * if both are affected by a symmetry or active */
5331  for (i = 0; i < nsetppcvars; ++i)
5332  {
5333  if ( onlypermvars )
5334  {
5335  nodei = SCIPhashmapGetImageInt(permvarmap, setppcvars[i]);
5336 
5337  /* skip variables that are not affected by symmetry */
5338  if ( nodei == INT_MAX )
5339  continue;
5340  }
5341  else
5342  {
5343  nodei = SCIPvarGetProbindex(setppcvars[i]);
5344 
5345  /* skip inactive variables */
5346  if ( nodei < 0 )
5347  continue;
5348  }
5349 
5350  for (j = i + 1; j < nsetppcvars; ++j)
5351  {
5352  if ( onlypermvars )
5353  {
5354  nodej = SCIPhashmapGetImageInt(permvarmap, setppcvars[j]);
5355 
5356  /* skip variables that are not affected by symmetyr */
5357  if ( nodej == INT_MAX )
5358  continue;
5359  }
5360  else
5361  {
5362  nodej = SCIPvarGetProbindex(setppcvars[j]);
5363 
5364  /* skip inactive variables */
5365  if ( nodej < 0 )
5366  continue;
5367  }
5368 
5369  SCIP_CALL( SCIPdigraphAddArcSafe(*conflictgraph, nodei, nodej, NULL) );
5370  SCIP_CALL( SCIPdigraphAddArcSafe(*conflictgraph, nodej, nodei, NULL) );
5371  ++nedges;
5372  }
5373  }
5374  }
5375  SCIPdebugMsg(scip, "Construction of conflict graph terminated; %d conflicts detected.\n", nedges);
5376 
5377  return SCIP_OKAY;
5378 }
5379 
5380 
5381 /** frees conflict graph */
5382 static
5384  SCIP* scip, /**< SCIP instance */
5385  SCIP_DIGRAPH** conflictgraph, /**< conflict graph */
5386  int nnodes /**< number of nodes in conflict graph */
5387  )
5388 {
5389  int i;
5390 
5391  assert( scip != NULL );
5392  assert( conflictgraph != NULL );
5393  assert( *conflictgraph != NULL );
5394  assert( nnodes > 0 );
5395 
5396  /* free node data */
5397  for (i = 0; i < nnodes; ++i)
5398  {
5399  SCIP_NODEDATA* nodedata;
5400 
5401  /* get node data */
5402  nodedata = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(*conflictgraph, i);
5403 
5404  /* free node data (might not have been allocated if all components are already blocked) */
5405  if ( nodedata != NULL )
5406  {
5407  SCIPfreeBlockMemory(scip, &nodedata);
5408  }
5409  }
5410 
5411  /* free conflict graph */
5412  SCIPdigraphFree(conflictgraph);
5413 
5414  return SCIP_OKAY;
5415 }
5416 
5417 
5418 /** adds symresack constraints */
5419 static
5421  SCIP* scip, /**< SCIP instance */
5422  SCIP_PROP* prop, /**< symmetry breaking propagator */
5423  int* components, /**< array containing components of symmetry group */
5424  int* componentbegins, /**< array containing begin positions of components in components array */
5425  int ncomponents /**< number of components */
5426  )
5427 { /*lint --e{641}*/
5428  SCIP_PROPDATA* propdata;
5429  SCIP_VAR** permvars;
5430  SCIP_Bool conssaddlp;
5431  int** modifiedperms = NULL;
5432  SCIP_VAR** modifiedpermvars = NULL;
5433  int** perms;
5434  int nsymresackcons = 0;
5435  int npermvars;
5436  int nperms;
5437  int i;
5438  int p;
5439 
5440  assert( scip != NULL );
5441  assert( prop != NULL );
5442 
5443  propdata = SCIPpropGetData(prop);
5444  assert( propdata != NULL );
5445  assert( propdata->npermvars >= 0 );
5446  assert( propdata->nbinpermvars >= 0 );
5447 
5448  /* if no symmetries on binary variables are present */
5449  if ( propdata->nbinpermvars == 0 )
5450  {
5451  assert( propdata->binvaraffected == 0 );
5452  return SCIP_OKAY;
5453  }
5454 
5455  perms = propdata->perms;
5456  nperms = propdata->nperms;
5457  permvars = propdata->permvars;
5458  npermvars = propdata->npermvars;
5459  conssaddlp = propdata->conssaddlp;
5460 
5461  assert( nperms <= 0 || perms != NULL );
5462  assert( permvars != NULL );
5463  assert( npermvars > 0 );
5464 
5465  /* adapt natural variable order to a variable order that is compatible with Schreier Sims constraints */
5466  if ( propdata->nleaders > 0 && ISSSTBINACTIVE(propdata->sstleadervartype) )
5467  {
5468  SCIP_CALL( SCIPallocBufferArray(scip, &modifiedperms, nperms) );
5469  for (p = 0; p < nperms; ++p)
5470  {
5471  SCIP_CALL( SCIPallocBufferArray(scip, &modifiedperms[p], npermvars) );
5472  }
5473  SCIP_CALL( SCIPallocBufferArray(scip, &modifiedpermvars, npermvars) );
5474 
5475  for (i = 0; i < npermvars; ++i)
5476  modifiedpermvars[i] = permvars[i];
5477 
5478  SCIP_CALL( adaptSymmetryDataSST(scip, perms, modifiedperms, nperms, permvars, modifiedpermvars, npermvars,
5479  propdata->leaders, propdata->nleaders) );
5480  }
5481 
5482  /* if components have not been computed */
5483  if ( ncomponents == -1 )
5484  {
5485  assert( ! propdata->ofenabled );
5486  assert( ! propdata->detectorbitopes );
5487  assert( ! propdata->sstenabled );
5488 
5489  /* loop through perms and add symresack constraints */
5490  for (p = 0; p < propdata->nperms; ++p)
5491  {
5492  SCIP_CONS* cons;
5493  char name[SCIP_MAXSTRLEN];
5494 
5495  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "symbreakcons_perm%d", p);
5496 
5497  SCIP_CALL( SCIPcreateSymbreakCons(scip, &cons, name, perms[p], permvars, npermvars, FALSE,
5498  conssaddlp, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
5499 
5500  SCIP_CALL( SCIPaddCons(scip, cons) );
5501 
5502  /* do not release constraint here - will be done later */
5503  propdata->genorbconss[propdata->ngenorbconss++] = cons;
5504  ++propdata->nsymresacks;
5505  ++nsymresackcons;
5506  }
5507  }
5508  else
5509  {
5510  /* loop through components */
5511  for (i = 0; i < ncomponents; ++i)
5512  {
5513  SCIP_Bool sstcompatible = TRUE;
5514 
5515  if ( ISSSTINTACTIVE(propdata->sstleadervartype)
5516  || ISSSTIMPLINTACTIVE(propdata->sstleadervartype)
5517  || ISSSTCONTACTIVE(propdata->sstleadervartype) )
5518  sstcompatible = FALSE;
5519 
5520  /* skip components that were treated by incompatible symmetry handling techniques */
5521  if ( (propdata->componentblocked[i] & SYM_HANDLETYPE_SYMBREAK) != 0
5522  || (propdata->componentblocked[i] & SYM_HANDLETYPE_ORBITALFIXING) != 0
5523  || ((propdata->componentblocked[i] & SYM_HANDLETYPE_SST) != 0 && ! sstcompatible) )
5524  continue;
5525 
5526  /* loop through perms in component i and add symresack constraints */
5527  for (p = componentbegins[i]; p < componentbegins[i + 1]; ++p)
5528  {
5529  SCIP_CONS* cons;
5530  int permidx;
5531  char name[SCIP_MAXSTRLEN];
5532 
5533  permidx = components[p];
5534 
5535  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "symbreakcons_component%d_perm%d", i, permidx);
5536 
5537  /* adapt permutation to leader */
5538  if ( propdata->nleaders > 0 && ISSSTBINACTIVE(propdata->sstleadervartype) )
5539  {
5540  assert( (propdata->componentblocked[i] & SYM_HANDLETYPE_SST) != 0 );
5541  assert( modifiedperms != NULL );
5542  assert( modifiedpermvars != NULL );
5543 
5544  SCIP_CALL( SCIPcreateSymbreakCons(scip, &cons, name, modifiedperms[permidx], modifiedpermvars, npermvars, FALSE,
5545  conssaddlp, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
5546  }
5547  else
5548  {
5549  SCIP_CALL( SCIPcreateSymbreakCons(scip, &cons, name, perms[permidx], permvars, npermvars, FALSE,
5550  conssaddlp, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
5551  }
5552  propdata->componentblocked[i] |= SYM_HANDLETYPE_SYMBREAK;
5553  SCIP_CALL( SCIPaddCons(scip, cons) );
5554 
5555  /* do not release constraint here - will be done later */
5556  propdata->genorbconss[propdata->ngenorbconss++] = cons;
5557  ++propdata->nsymresacks;
5558  ++nsymresackcons;
5559  }
5560  }
5561  }
5562 
5563  if ( propdata->nleaders > 0 && ISSSTBINACTIVE(propdata->sstleadervartype) )
5564  {
5565  assert( modifiedperms != NULL );
5566  assert( modifiedpermvars != NULL );
5567 
5568  SCIPfreeBufferArray(scip, &modifiedpermvars);
5569  for (p = nperms - 1; p >= 0; --p)
5570  {
5571  SCIPfreeBufferArray(scip, &modifiedperms[p]);
5572  }
5573  SCIPfreeBufferArray(scip, &modifiedperms);
5574  }
5575 
5576  SCIPdebugMsg(scip, "Added %d symresack constraints.\n", nsymresackcons);
5577 
5578  return SCIP_OKAY;
5579 }
5580 
5581 
5582 /** add Schreier Sims constraints for a specific orbit and update Schreier Sims table */
5583 static
5585  SCIP* scip, /**< SCIP instance */
5586  SCIP_DIGRAPH* conflictgraph, /**< conflict graph or NULL if useconflictgraph == FALSE */
5587  SCIP_PROPDATA* propdata, /**< data of symmetry propagator */
5588  SCIP_VAR** permvars, /**< permvars array */
5589  int* orbits, /**< symmetry orbits */
5590  int* orbitbegins, /**< array storing begin position for each orbit */
5591  int orbitidx, /**< index of orbit for Schreier Sims constraints */
5592  int orbitleaderidx, /**< index of leader variable for Schreier Sims constraints */
5593  SCIP_Shortbool* orbitvarinconflict, /**< indicator whether orbitvar is in conflict with orbit leader */
5594  int norbitvarinconflict, /**< number of variables in conflict with orbit leader */
5595  int* nchgbds, /**< pointer to store number of bound changes (or NULL) */
5596  SCIP_Bool useconflictgraph /**< whether conflict graph shall be used */
5597  )
5598 { /*lint --e{613,641}*/
5599  SCIP_CONS* cons;
5600  char name[SCIP_MAXSTRLEN];
5601  SCIP_VAR* vars[2];
5602  SCIP_Real vals[2];
5603  int orbitsize;
5604  int posleader;
5605  int poscur;
5606  int ncuts = 0;
5607  SCIP_Bool addcuts = FALSE;
5608  int i;
5609 #ifndef NDEBUG
5610  int j;
5611 #endif
5612 
5613  assert( scip != NULL );
5614  assert( conflictgraph != NULL || ! useconflictgraph );
5615  assert( propdata != NULL );
5616  assert( permvars != NULL );
5617  assert( orbits != NULL );
5618  assert( orbitbegins != NULL );
5619  assert( orbitidx >= 0 );
5620  assert( orbitleaderidx >= 0 );
5621  assert( orbitvarinconflict != NULL || ! useconflictgraph );
5622  assert( norbitvarinconflict >= 0 );
5623  assert( nchgbds != NULL );
5624 
5625  orbitsize = orbitbegins[orbitidx + 1] - orbitbegins[orbitidx];
5626 
5627  /* variables in conflict with leader are fixed and not treated by a cut; trailing -1 to not count the leader */
5628  if ( propdata->sstaddcuts )
5629  addcuts = TRUE;
5630  else if ( propdata->sstleaderrule == SCIP_LEADERRULE_MAXCONFLICTSINORBIT
5631  || propdata->sstleaderrule == SCIP_LEADERRULE_MAXCONFLICTS
5632  || propdata->ssttiebreakrule == SCIP_LEADERTIEBREAKRULE_MAXCONFLICTSINORBIT )
5633  addcuts = propdata->addconflictcuts;
5634 
5635  if ( addcuts )
5636  ncuts = orbitsize - norbitvarinconflict - 1;
5637 
5638  /* (re-)allocate memory for Schreier Sims constraints and leaders */
5639  if ( ncuts > 0 )
5640  {
5641  if ( propdata->nsstconss == 0 )
5642  {
5643  assert( propdata->sstconss == NULL );
5644  assert( propdata->maxnsstconss == 0 );
5645  propdata->maxnsstconss = 2 * ncuts;
5646  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->sstconss), propdata->maxnsstconss) );
5647  }
5648  else if ( propdata->nsstconss + ncuts > propdata->maxnsstconss )
5649  {
5650  int newsize;
5651 
5652  newsize = SCIPcalcMemGrowSize(scip, propdata->maxnsstconss + 2 * ncuts);
5653  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(propdata->sstconss),
5654  propdata->maxnsstconss, newsize) );
5655  propdata->maxnsstconss = newsize;
5656  }
5657  }
5658 
5659  if ( propdata->nleaders == 0 )
5660  {
5661  propdata->maxnleaders = MIN(propdata->nperms, propdata->npermvars);
5662  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(propdata->leaders), propdata->maxnleaders) );
5663  }
5664  assert( propdata->nleaders < propdata->maxnleaders );
5665 
5666  /* add Schreier Sims constraints vars[0] >= vars[1], where vars[0] is always the leader */
5667  posleader = orbitbegins[orbitidx] + orbitleaderidx;
5668  vars[0] = permvars[orbits[posleader]];
5669  vals[0] = -1.0;
5670  vals[1] = 1.0;
5671  propdata->leaders[propdata->nleaders++] = orbits[posleader];
5672  *nchgbds = 0;
5673  for (i = 0, poscur = orbitbegins[orbitidx]; i < orbitsize; ++i, ++poscur)
5674  {
5675  if ( i == orbitleaderidx )
5676  {
5677  assert( orbitvarinconflict == NULL || ! orbitvarinconflict[i] );
5678  continue;
5679  }
5680 
5681  vars[1] = permvars[orbits[poscur]];
5682 #ifndef NDEBUG
5683  for (j = 0; j < propdata->nleaders - 1; ++j)
5684  {
5685  assert( propdata->leaders[j] != orbits[poscur] );
5686  }
5687 #endif
5688 
5689  /* if the i-th variable in the orbit is in a conflict with the leader, fix it to 0 */
5690  if ( useconflictgraph )
5691  {
5692  if ( orbitvarinconflict[i] )
5693  {
5694  assert( SCIPvarIsBinary(vars[1]) );
5695  assert( SCIPvarGetLbLocal(vars[1]) < 0.5 );
5696  assert( useconflictgraph );
5697 
5698  /* if variable is fixed */
5699  if ( SCIPvarGetUbLocal(vars[1]) > 0.5 )
5700  {
5701  SCIP_NODEDATA* nodedata;
5702 
5703  SCIP_CALL( SCIPchgVarUb(scip, vars[1], 0.0) );
5704  ++(*nchgbds);
5705 
5706  /* deactivate the fixed variable (cannot contribute to a conflict anymore) */
5707  nodedata = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(conflictgraph, orbits[poscur]);
5708  assert( nodedata != NULL );
5709  assert( nodedata->active );
5710 
5711  nodedata->active = FALSE;
5712  }
5713 
5714  /* reset value */
5715  orbitvarinconflict[i] = FALSE;
5716  }
5717  else if ( addcuts )
5718  {
5719  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "SSTcut_%d_%d", orbits[posleader], orbits[poscur]);
5720  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, 2, vars, vals, - SCIPinfinity(scip), 0.0,
5722 
5723  SCIP_CALL( SCIPaddCons(scip, cons) );
5724  propdata->sstconss[propdata->nsstconss++] = cons;
5725  }
5726  }
5727  else if ( addcuts )
5728  {
5729  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "SSTcut_%d_%d", orbits[posleader], orbits[poscur]);
5730  SCIP_CALL( SCIPcreateConsLinear(scip, &cons, name, 2, vars, vals, - SCIPinfinity(scip), 0.0,
5732 
5733  SCIP_CALL( SCIPaddCons(scip, cons) );
5734  propdata->sstconss[propdata->nsstconss++] = cons;
5735  }
5736  }
5737 
5738  return SCIP_OKAY;
5739 }
5740 
5741 
5742 /** selection rule of next orbit/leader in orbit for Schreier Sims constraints */
5743 static
5745  SCIP* scip, /**< SCIP instance */
5746  SCIP_DIGRAPH* conflictgraph, /**< conflict graph or NULL if useconflictgraph == FALSE */
5747  SCIP_VAR** graphvars, /**< variables encoded in conflict graph */
5748  int ngraphvars, /**< number of variables encoded in conflict graph */
5749  SCIP_HASHMAP* varmap, /**< map from variable to node label in conflict graph or NULL if useconflictgraph == FALSE */
5750  SCIP_VAR** permvars, /**< vars encoded in a permutation */
5751  int npermvars, /**< number of vars in a permutation */
5752  int* orbits, /**< orbits of stabilizer subgroup */
5753  int* orbitbegins, /**< array storing the begin position of each orbit in orbits */
5754  int norbits, /**< number of orbits */
5755  int leaderrule, /**< rule to select leader */
5756  int tiebreakrule, /**< tie break rule to select leader */
5757  SCIP_VARTYPE leadervartype, /**< variable type of leader */
5758  int* orbitidx, /**< pointer to index of selected orbit */
5759  int* leaderidx, /**< pointer to leader in orbit */
5760  SCIP_Shortbool* orbitvarinconflict, /**< array to store whether a var in the orbit is conflicting with leader */
5761  int* norbitvarinconflict, /**< pointer to store number of vars in the orbit in conflict with leader */
5762  SCIP_Bool useconflictgraph, /**< whether conflict graph shall be used */
5763  SCIP_Bool* success /**< pointer to store whether orbit cut be selected successfully */
5764  )
5765 {
5766  SCIP_NODEDATA* nodedata;
5767  int* conflictvars;
5768  int nconflictvars = 0;
5769  int varidx;
5770  int orbitcriterion;
5771  int curcriterion = INT_MIN;
5772  int orbitsize;
5773  int i;
5774  SCIP_NODEDATA* neighbordata;
5775  int leader = -1;
5776  int j;
5777 
5778  assert( scip != NULL );
5779  assert( conflictgraph != NULL || ! useconflictgraph );
5780  assert( graphvars != NULL );
5781  assert( ngraphvars > 0 );
5782  assert( varmap != NULL || ! useconflictgraph );
5783  assert( permvars != NULL );
5784  assert( npermvars > 0 );
5785  assert( orbits != NULL );
5786  assert( orbitbegins != NULL );
5787  assert( norbits > 0 );
5788  assert( orbitidx != NULL );
5789  assert( leaderidx != NULL );
5790  assert( orbitvarinconflict != NULL || ! useconflictgraph );
5791  assert( norbitvarinconflict != NULL );
5792  assert( success != NULL );
5793 
5794  *orbitidx = 0;
5795  *leaderidx = 0;
5796  *norbitvarinconflict = 0;
5797  *success = FALSE;
5798 
5799  /* terminate if leader or tiebreak rule cannot be checked */
5800  if ( ! useconflictgraph && (leaderrule == (int) SCIP_LEADERRULE_MAXCONFLICTS
5801  || leaderrule == (int) SCIP_LEADERRULE_MAXCONFLICTSINORBIT
5802  || tiebreakrule == (int) SCIP_LEADERTIEBREAKRULE_MAXCONFLICTSINORBIT) )
5803  return SCIP_OKAY;
5804 
5805  /* select the leader and its orbit */
5806  if ( leaderrule == (int) SCIP_LEADERRULE_FIRSTINORBIT || leaderrule == (int) SCIP_LEADERRULE_LASTINORBIT )
5807  {
5808  orbitcriterion = INT_MIN;
5809 
5810  /* iterate over orbits and select the first one that meets the tiebreak rule */
5811  for (i = 0; i < norbits; ++i)
5812  {
5813  /* skip orbits containing vars different to the leader's vartype */
5814  if ( SCIPvarGetType(permvars[orbits[orbitbegins[i]]]) != leadervartype )
5815  continue;
5816 
5817  if ( tiebreakrule == (int) SCIP_LEADERTIEBREAKRULE_MINORBIT )
5818  curcriterion = orbitbegins[i] - orbitbegins[i + 1];
5819  else if ( tiebreakrule == (int) SCIP_LEADERTIEBREAKRULE_MAXORBIT )
5820  curcriterion = orbitbegins[i + 1] - orbitbegins[i];
5821  else
5822  {
5823  /* get first or last active variable in orbit */
5824  if ( leaderrule == (int) SCIP_LEADERRULE_FIRSTINORBIT )
5825  {
5826  int cnt = orbitbegins[i];
5827 
5828  do
5829  {
5830  varidx = SCIPvarGetProbindex(permvars[orbits[cnt++]]);
5831  }
5832  while ( varidx == -1 && cnt < orbitbegins[i + 1]);
5833  }
5834  else
5835  {
5836  int cnt = orbitbegins[i + 1] - 1;
5837 
5838  do
5839  {
5840  varidx = SCIPvarGetProbindex(permvars[orbits[cnt--]]);
5841  }
5842  while ( varidx == -1 && cnt >= orbitbegins[i]);
5843  }
5844 
5845  /* skip inactive variables */
5846  if ( varidx == -1 )
5847  continue;
5848 
5849  nodedata = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(conflictgraph, varidx);
5850  assert( nodedata != NULL );
5851  assert( nodedata->orbitidx == i );
5852 
5853  if ( nodedata->nconflictinorbit > 0 )
5854  curcriterion = nodedata->nconflictinorbit;
5855  }
5856 
5857  /* update selected orbit */
5858  if ( curcriterion > orbitcriterion )
5859  {
5860  orbitcriterion = curcriterion;
5861  *orbitidx = i;
5862  *success = TRUE;
5863 
5864  if ( leaderrule == (int) SCIP_LEADERRULE_FIRSTINORBIT )
5865  *leaderidx = 0;
5866  else
5867  *leaderidx = orbitbegins[i + 1] - orbitbegins[i] - 1;
5868  }
5869  }
5870 
5871  /* store variables in conflict with leader */
5872  if ( useconflictgraph )
5873  {
5874  leader = SCIPhashmapGetImageInt(varmap, permvars[orbits[orbitbegins[*orbitidx] + *leaderidx]]);
5875  assert( leader < SCIPdigraphGetNNodes(conflictgraph) );
5876 
5877  nconflictvars = SCIPdigraphGetNSuccessors(conflictgraph, leader);
5878  }
5879 
5880  if ( *success && tiebreakrule == (int) SCIP_LEADERTIEBREAKRULE_MAXCONFLICTSINORBIT && nconflictvars > 0 )
5881  {
5882  SCIP_VAR* var;
5883  orbitsize = orbitbegins[*orbitidx + 1] - orbitbegins[*orbitidx];
5884  assert( useconflictgraph );
5885  assert( leader >= 0 && leader < npermvars );
5886 
5887  conflictvars = SCIPdigraphGetSuccessors(conflictgraph, leader);
5888  assert( conflictvars != NULL );
5889  assert( orbitvarinconflict != NULL );
5890 
5891  for (i = 0; i < orbitsize; ++i)
5892  {
5893  /* skip the leader */
5894  if ( i == *leaderidx )
5895  continue;
5896 
5897  var = permvars[orbits[orbitbegins[*orbitidx] + i]];
5898 
5899  for (j = 0; j < nconflictvars; ++j)
5900  {
5901  neighbordata = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(conflictgraph, conflictvars[j]);
5902 
5903  assert( neighbordata != NULL );
5904 
5905  if ( neighbordata->var == var && neighbordata->active )
5906  {
5907  orbitvarinconflict[i] = TRUE;
5908  *norbitvarinconflict += 1;
5909  break;
5910  }
5911  }
5912  }
5913  }
5914  }
5915  else if ( useconflictgraph )
5916  {
5917  orbitcriterion = 0;
5918 
5919  /* iterate over variables and select the first one that meets the tiebreak rule */
5920  for (i = 0; i < ngraphvars; ++i)
5921  {
5922  /* skip vars different to the leader's vartype */
5923  if ( SCIPvarGetType(graphvars[i]) != leadervartype )
5924  continue;
5925 
5926  nodedata = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(conflictgraph, i);
5927  assert( nodedata != NULL );
5928 
5929  /* skip variables not affected by symmetry */
5930  if ( nodedata->orbitidx == -1 )
5931  continue;
5932 
5933  if ( leaderrule == (int) SCIP_LEADERRULE_MAXCONFLICTSINORBIT )
5934  curcriterion = nodedata->nconflictinorbit;
5935  else
5936  curcriterion = SCIPdigraphGetNSuccessors(conflictgraph, i);
5937 
5938  if ( curcriterion > orbitcriterion )
5939  {
5940  orbitcriterion = curcriterion;
5941  *orbitidx = nodedata->orbitidx;
5942  *leaderidx = nodedata->posinorbit;
5943  *success = TRUE;
5944  }
5945  }
5946 
5947  /* store variables in conflict with leader */
5948  leader = SCIPhashmapGetImageInt(varmap, permvars[orbits[orbitbegins[*orbitidx] + *leaderidx]]);
5949  assert( leader < SCIPdigraphGetNNodes(conflictgraph) );
5950  assert( norbitvarinconflict != NULL );
5951 
5952  nconflictvars = SCIPdigraphGetNSuccessors(conflictgraph, leader);
5953  if ( *success && nconflictvars > 0 )
5954  {
5955  SCIP_VAR* var;
5956  assert( orbitvarinconflict != NULL );
5957 
5958  orbitsize = orbitbegins[*orbitidx + 1] - orbitbegins[*orbitidx];
5959 
5960  conflictvars = SCIPdigraphGetSuccessors(conflictgraph, leader);
5961  assert( conflictvars != NULL );
5962 
5963  for (i = 0; i < orbitsize; ++i)
5964  {
5965  /* skip the leader */
5966  if ( i == *leaderidx )
5967  continue;
5968 
5969  var = permvars[orbits[orbitbegins[*orbitidx] + i]];
5970 
5971  for (j = 0; j < nconflictvars; ++j)
5972  {
5973  neighbordata = (SCIP_NODEDATA*) SCIPdigraphGetNodeData(conflictgraph, conflictvars[j]);
5974  assert( neighbordata != NULL );
5975 
5976  if ( neighbordata->var == var && neighbordata->active )
5977  {
5978  orbitvarinconflict[i] = TRUE;
5979  *norbitvarinconflict += 1;
5980  break;
5981  }
5982  }
5983  }
5984  }
5985  }
5986 
5987  return SCIP_OKAY;
5988 }
5989 
5990 
5991 /** add Schreier Sims constraints to the problem */
5992 static
5994  SCIP* scip, /**< SCIP instance */
5995  SCIP_PROPDATA* propdata, /**< datas of symmetry propagator */
5996  int* nchgbds /**< pointer to store number of bound changes (or NULL) */
5997  )
5998 { /*lint --e{641}*/
5999  SCIP_DIGRAPH* conflictgraph = NULL;
6000  SCIP_HASHMAP* varmap = NULL;
6001  SCIP_VAR** vars;
6002  int nvars;
6003 
6004  SCIP_HASHMAP* permvarmap;
6005  SCIP_VAR** permvars;
6006  int** permstrans;
6007  int npermvars;
6008  int nmovedpermvars;
6009  int nmovedbinpermvars;
6010  int nmovedintpermvars;
6011  int nmovedimplintpermvars;
6012  int nmovedcontpermvars;
6013  int nperms;
6014 
6015  int* orbits;
6016  int* orbitbegins;
6017  int norbits;
6018  int* components;
6019  int* componentbegins;
6020  int* vartocomponent;
6021  int ncomponents;
6022  unsigned* componentblocked;
6023 
6024  int orbitidx;
6025  int orbitleaderidx;
6026  SCIP_Shortbool* orbitvarinconflict = NULL;
6027  int norbitvarinconflict;
6028  SCIP_Shortbool* inactiveperms;
6029  int ninactiveperms;
6030  int posleader;
6031  int leaderrule;
6032  int tiebreakrule;
6033  int leadervartype;
6034  SCIP_VARTYPE selectedtype = SCIP_VARTYPE_CONTINUOUS;
6035  int nvarsselectedtype;
6036  SCIP_Bool conflictgraphcreated = FALSE;
6037  SCIP_Bool mixedcomponents;
6038  int* norbitleadercomponent;
6039 
6040  int c;
6041  int v;
6042  int p;
6043 
6044  assert( scip != NULL );
6045  assert( propdata != NULL );
6046 
6047  permvars = propdata->permvars;
6048  npermvars = propdata->npermvars;
6049  permvarmap = propdata->permvarmap;
6050  permstrans = propdata->permstrans;
6051  nperms = propdata->nperms;
6052  components = propdata->components;
6053  componentbegins = propdata->componentbegins;
6054  componentblocked = propdata->componentblocked;
6055  vartocomponent = propdata->vartocomponent;
6056  ncomponents = propdata->ncomponents;
6057  nmovedpermvars = propdata->nmovedpermvars;
6058  nmovedbinpermvars = propdata->nmovedbinpermvars;
6059  nmovedintpermvars = propdata->nmovedintpermvars;
6060  nmovedimplintpermvars = propdata->nmovedimplintpermvars;
6061  nmovedcontpermvars = propdata->nmovedcontpermvars;
6062 
6063  assert( permvars != NULL );
6064  assert( npermvars > 0 );
6065  assert( permvarmap != NULL );
6066  assert( permstrans != NULL );
6067  assert( nperms > 0 );
6068  assert( components != NULL );
6069  assert( componentbegins != NULL );
6070  assert( vartocomponent != NULL );
6071  assert( ncomponents > 0 );
6072  assert( nmovedpermvars > 0 || ! propdata->ofenabled );
6073  assert( nmovedbinpermvars > 0 || ! propdata->ofenabled );
6074 
6075  leaderrule = propdata->sstleaderrule;
6076  tiebreakrule = propdata->ssttiebreakrule;
6077  leadervartype = propdata->sstleadervartype;
6078  mixedcomponents = propdata->sstmixedcomponents;
6079 
6080  /* if not already computed, get number of affected vars */
6081  if ( nmovedpermvars == -1 )
6082  {
6083  nmovedpermvars = 0;
6084 
6085  for (v = 0; v < npermvars; ++v)
6086  {
6087  for (p = 0; p < nperms; ++p)
6088  {
6089  if ( permstrans[v][p] != v )
6090  {
6091  ++nmovedpermvars;
6092 
6093  switch ( SCIPvarGetType(permvars[v]) )
6094  {
6095  case SCIP_VARTYPE_BINARY:
6096  ++nmovedbinpermvars;
6097  break;
6098  case SCIP_VARTYPE_INTEGER:
6099  ++nmovedintpermvars;
6100  break;
6101  case SCIP_VARTYPE_IMPLINT:
6102  ++nmovedimplintpermvars;
6103  break;
6105  default:
6106  ++nmovedcontpermvars;
6107  }
6108  }
6109  }
6110  }
6111  }
6112  propdata->nmovedbinpermvars = nmovedbinpermvars;
6113  propdata->nmovedintpermvars = nmovedintpermvars;
6114  propdata->nmovedimplintpermvars = nmovedimplintpermvars;
6115  propdata->nmovedcontpermvars = nmovedcontpermvars;
6116 
6117  vars = SCIPgetVars(scip);
6118  nvars = SCIPgetNVars(scip);
6119 
6120  /* determine the leader's vartype */
6121  nvarsselectedtype = 0;
6122  if ( ISSSTBINACTIVE(leadervartype) && nmovedbinpermvars > nvarsselectedtype )
6123  {
6124  selectedtype = SCIP_VARTYPE_BINARY;
6125  nvarsselectedtype = nmovedbinpermvars;
6126  }
6127 
6128  if ( ISSSTINTACTIVE(leadervartype) && nmovedintpermvars > nvarsselectedtype )
6129  {
6130  selectedtype = SCIP_VARTYPE_INTEGER;
6131  nvarsselectedtype = nmovedintpermvars;
6132  }
6133 
6134  if ( ISSSTIMPLINTACTIVE(leadervartype) && nmovedimplintpermvars > nvarsselectedtype )
6135  {
6136  selectedtype = SCIP_VARTYPE_IMPLINT;
6137  nvarsselectedtype = nmovedimplintpermvars;
6138  }
6139 
6140  if ( ISSSTCONTACTIVE(leadervartype) && nmovedcontpermvars > nvarsselectedtype )
6141  {
6142  selectedtype = SCIP_VARTYPE_CONTINUOUS;
6143  nvarsselectedtype = nmovedcontpermvars;
6144  }
6145 
6146  /* terminate if no variables of a possible leader type is affected */
6147  if ( nvarsselectedtype == 0 )
6148  return SCIP_OKAY;
6149 
6150  /* possibly create conflict graph; graph is not created if no setppc conss are present */
6151  if ( selectedtype == SCIP_VARTYPE_BINARY && (leaderrule == SCIP_LEADERRULE_MAXCONFLICTSINORBIT
6152  || leaderrule == SCIP_LEADERRULE_MAXCONFLICTS
6153  || tiebreakrule == SCIP_LEADERTIEBREAKRULE_MAXCONFLICTSINORBIT) )
6154  {
6155  SCIP_CALL( createConflictGraphSST(scip, &conflictgraph, vars, nvars, FALSE,
6156  permvarmap, &conflictgraphcreated) );
6157  }
6158 
6159  /* allocate data structures necessary for orbit computations and conflict graph */
6160  SCIP_CALL( SCIPallocBufferArray(scip, &inactiveperms, nperms) );
6161  SCIP_CALL( SCIPallocBufferArray(scip, &orbits, npermvars) );
6162  SCIP_CALL( SCIPallocBufferArray(scip, &orbitbegins, npermvars) );
6163 
6164  if ( conflictgraphcreated )
6165  {
6166  SCIP_CALL( SCIPallocClearBufferArray(scip, &orbitvarinconflict, npermvars) );
6167  SCIP_CALL( SCIPhashmapCreate(&varmap, SCIPblkmem(scip), nvars) );
6168  for (v = 0; v < nvars; ++v)
6169  {
6170  assert( ! SCIPhashmapExists(varmap, vars[v]) );
6171  SCIP_CALL( SCIPhashmapInsertInt(varmap, vars[v], v) );
6172  }
6173  }
6174 
6175  SCIPdebugMsg(scip, "Start selection of orbits and leaders for Schreier Sims constraints.\n");
6176  SCIPdebugMsg(scip, "orbitidx\tleaderidx\torbitsize\n");
6177 
6178  if ( nchgbds != NULL )
6179  *nchgbds = 0;
6180 
6181  /* initialize array indicating whether permutations shall not be considered for orbit permutations */
6182  for (p = 0; p < nperms; ++p)
6183  inactiveperms[p] = TRUE;
6184 
6185  SCIP_CALL( SCIPallocBufferArray(scip, &norbitleadercomponent, ncomponents) );
6186  for (c = 0; c < ncomponents; ++c)
6187  norbitleadercomponent[c] = 0;
6188 
6189  /* iterate over components and compute orbits */
6190  for (c = 0; c < ncomponents; ++c)
6191  {
6192  SCIP_Bool success = TRUE;
6193 
6194  if ( componentblocked[c] )
6195  continue;
6196 
6197  for (p = componentbegins[c]; p < componentbegins[c + 1]; ++p)
6198  inactiveperms[components[p]] = FALSE;
6199  ninactiveperms = nperms - componentbegins[c + 1] + componentbegins[c];
6200 
6201  /* as long as the stabilizer is non-trivial, add Schreier Sims constraints */
6202  while ( ninactiveperms < nperms )
6203  {
6204  int nchanges = 0;
6205 
6206  /* compute orbits w.r.t. active perms */
6207  SCIP_CALL( SCIPcomputeOrbitsFilterSym(scip, npermvars, permstrans, nperms, inactiveperms,
6208  orbits, orbitbegins, &norbits, components, componentbegins, vartocomponent,
6209  componentblocked, ncomponents, nmovedpermvars) );
6210 
6211  /* stop if we require pure components and a component contains variables of different types */
6212  if ( ! mixedcomponents )
6213  {
6214  for (p = 0; p < norbits; ++p)
6215  {
6216  /* stop if the first element of an orbits has the wrong vartype */
6217  if ( SCIPvarGetType(permvars[orbits[orbitbegins[p]]]) != selectedtype )
6218  {
6219  success = FALSE;
6220  break;
6221  }
6222  }
6223  }
6224 
6225  if ( ! success )
6226  break;
6227 
6228  /* update symmetry information of conflict graph */
6229  if ( conflictgraphcreated )
6230  {
6231  assert( conflictgraph != NULL );
6232  SCIP_CALL( updateSymInfoConflictGraphSST(scip, conflictgraph, vars, nvars, permvars, npermvars, FALSE,
6233  varmap, orbits, orbitbegins, norbits) );
6234  }
6235 
6236  /* possibly adapt the leader and tie-break rule */
6237  if ( (leaderrule == SCIP_LEADERRULE_MAXCONFLICTSINORBIT || leaderrule == SCIP_LEADERRULE_MAXCONFLICTS)
6238  && ! conflictgraphcreated )
6239  leaderrule = SCIP_LEADERRULE_FIRSTINORBIT;
6240  if ( (leaderrule == SCIP_LEADERRULE_MAXCONFLICTSINORBIT || leaderrule == SCIP_LEADERRULE_MAXCONFLICTS)
6241  && selectedtype != SCIP_VARTYPE_BINARY )
6242  leaderrule = SCIP_LEADERRULE_FIRSTINORBIT;
6243  if ( tiebreakrule == SCIP_LEADERTIEBREAKRULE_MAXCONFLICTSINORBIT && ! conflictgraphcreated )
6244  tiebreakrule = SCIP_LEADERTIEBREAKRULE_MAXORBIT;
6245  if ( tiebreakrule == SCIP_LEADERTIEBREAKRULE_MAXCONFLICTSINORBIT && selectedtype != SCIP_VARTYPE_BINARY )
6246  tiebreakrule = SCIP_LEADERTIEBREAKRULE_MAXORBIT;
6247 
6248  /* select orbit and leader */
6249  SCIP_CALL( selectOrbitLeaderSSTConss(scip, conflictgraph, vars, nvars, varmap,
6250  permvars, npermvars, orbits, orbitbegins, norbits, propdata->sstleaderrule, propdata->ssttiebreakrule, selectedtype,
6251  &orbitidx, &orbitleaderidx, orbitvarinconflict, &norbitvarinconflict, conflictgraphcreated, &success) );
6252 
6253  if ( ! success )
6254  break;
6255 
6256  assert( 0 <= orbitidx && orbitidx < norbits );
6257  assert( 0 <= orbitleaderidx && orbitleaderidx < orbitbegins[orbitidx + 1] - orbitbegins[orbitidx] );
6258  SCIPdebugMsg(scip, "%d\t\t%d\t\t%d\n", orbitidx, orbitleaderidx, orbitbegins[orbitidx + 1] - orbitbegins[orbitidx]);
6259 
6260  /* add Schreier Sims constraints for the selected orbit and update Schreier Sims table */
6261  SCIP_CALL( addSSTConssOrbitAndUpdateSST(scip, conflictgraph, propdata, permvars,
6262  orbits, orbitbegins, orbitidx, orbitleaderidx, orbitvarinconflict, norbitvarinconflict, &nchanges, conflictgraphcreated) );
6263 
6264  ++norbitleadercomponent[propdata->vartocomponent[orbits[orbitbegins[orbitidx] + orbitleaderidx]]];
6265 
6266  if ( nchgbds != NULL )
6267  *nchgbds += nchanges;
6268 
6269  /* deactivate permutations that move the orbit leader */
6270  posleader = orbits[orbitbegins[orbitidx] + orbitleaderidx];
6271  for (p = 0; p < nperms; ++p)
6272  {
6273  if ( inactiveperms[p] )
6274  continue;
6275 
6276  if ( permstrans[posleader][p] != posleader )
6277  {
6278  inactiveperms[p] = TRUE;
6279  ++ninactiveperms;
6280  }
6281  }
6282  }
6283 
6284  for (p = componentbegins[c]; p < componentbegins[c + 1]; ++p)
6285  inactiveperms[components[p]] = TRUE;
6286  }
6287 
6288  /* if Schreier Sims constraints have been added, store that Schreier Sims has been used for this component */
6289  for (c = 0; c < ncomponents; ++c)
6290  {
6291  if ( norbitleadercomponent[c] > 0 )
6292  componentblocked[c] |= SYM_HANDLETYPE_SST;
6293  }
6294  SCIPfreeBufferArray(scip, &norbitleadercomponent);
6295 
6296  if ( conflictgraphcreated )
6297  {
6298  SCIPhashmapFree(&varmap);
6299  SCIPfreeBufferArray(scip, &orbitvarinconflict);
6300  }
6301  SCIPfreeBufferArray(scip, &orbitbegins);
6302  SCIPfreeBufferArray(scip, &orbits);
6303  if ( conflictgraphcreated )
6304  {
6305  assert( conflictgraph != NULL );
6306  SCIP_CALL( freeConflictGraphSST(scip, &conflictgraph, nvars) );
6307  }
6308  SCIPfreeBufferArray(scip, &inactiveperms);
6309 
6310  return SCIP_OKAY;
6311 }
6312 
6313 
6314 /** finds problem symmetries */
6315 static
6317  SCIP* scip, /**< SCIP instance */
6318  SCIP_PROP* prop, /**< symmetry breaking propagator */
6319  int* nchgbds, /**< pointer to store number of bound changes (or NULL)*/
6320  SCIP_Bool* earlyterm /**< pointer to store whether we terminated early (or NULL) */
6321  )
6322 {
6323  SCIP_PROPDATA* propdata;
6324 
6325  assert( prop != NULL );
6326  assert( scip != NULL );
6327 
6328  propdata = SCIPpropGetData(prop);
6329  assert( propdata != NULL );
6330  assert( propdata->symconsenabled || propdata->sstenabled );
6331 
6332  /* if constraints have already been added */
6333  if ( propdata->triedaddconss )
6334  {
6335  assert( propdata->nperms > 0 );
6336 
6337  if ( earlyterm != NULL )
6338  *earlyterm = TRUE;
6339 
6340  return SCIP_OKAY;
6341  }
6342 
6343  /* possibly compute symmetry */
6344  if ( propdata->ofenabled && SCIPgetNBinVars(scip) > 1 )
6345  {
6346  SCIP_Bool oldsymconsenabled;
6347 
6348  oldsymconsenabled = propdata->symconsenabled;
6349 
6350  /* in the nonlinear case, all non-binary variables have to be fixed
6351  (fix non-binary potential branching variables)
6352  */
6353  if ( hasNonlinearConstraints(propdata) || propdata->symfixnonbinaryvars )
6354  {
6356  }
6357  else
6358  {
6360  }
6361 
6362  /* if there is no symmetry compatible with OF, check whether there are more general symmetries */
6363  if ( propdata->nperms == 0 && SCIPgetNIntVars(scip) + SCIPgetNImplVars(scip) > 1 )
6364  {
6365  SCIP_CALL( freeSymmetryData(scip, propdata) );
6366  propdata->symconsenabled = oldsymconsenabled;
6367  propdata->ofenabled = FALSE;
6368  propdata->sstenabled = FALSE;
6369 
6371  }
6372  }
6373  else
6374  {
6376  }
6377  assert( propdata->binvaraffected || ! propdata->ofenabled || ! propdata->symconsenabled );
6378 
6379  if ( propdata->nperms <= 0 || (! propdata->symconsenabled && ! propdata->sstenabled) )
6380  return SCIP_OKAY;
6381 
6382  if ( ! propdata->binvaraffected )
6383  {
6384  SCIPdebugMsg(scip, "Symmetry propagator: problem is linear and no symmetry on binary variables has been found, turning symretope constraints off.\n");
6385  propdata->symconsenabled = FALSE;
6386  }
6387  assert( propdata->nperms > 0 );
6388  assert( hasNonlinearConstraints(propdata) || propdata->binvaraffected || propdata->sstenabled );
6389 
6390  propdata->triedaddconss = TRUE;
6391 
6392  if ( propdata->symconsenabled )
6393  {
6394  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->genorbconss, propdata->nperms) );
6395 
6396  if ( propdata->detectorbitopes )
6397  {
6398  SCIP_CALL( detectOrbitopes(scip, propdata, propdata->components, propdata->componentbegins, propdata->ncomponents) );
6399  }
6400  }
6401 
6402  /* disable orbital fixing if all components are handled by orbitopes */
6403  if ( propdata->ncomponents == propdata->norbitopes )
6404  propdata->ofenabled = FALSE;
6405 
6406  /* possibly stop */
6407  if ( SCIPisStopped(scip) )
6408  {
6409  if ( propdata->ngenorbconss == 0 )
6410  {
6411  SCIPfreeBlockMemoryArrayNull(scip, &propdata->genorbconss, propdata->nperms);
6412  }
6413  return SCIP_OKAY;
6414  }
6415 
6416  if ( propdata->ncompblocked < propdata->ncomponents && propdata->detectsubgroups && propdata->symconsenabled )
6417  {
6418  /* @TODO: create array only when needed */
6419  propdata->genlinconsssize = propdata->nperms;
6420  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &propdata->genlinconss, propdata->genlinconsssize) );
6421 
6422  SCIP_CALL( detectAndHandleSubgroups(scip, propdata) );
6423  }
6424 
6425  if ( propdata->sstenabled )
6426  {
6427  SCIP_CALL( addSSTConss(scip, propdata, nchgbds) );
6428  }
6429 
6430  /* possibly stop */
6431  if ( SCIPisStopped(scip) || ! propdata->symconsenabled )
6432  return SCIP_OKAY;
6433 
6434  /* add symmetry breaking constraints if orbital fixing is not used outside orbitopes */
6435  if ( ! propdata->ofenabled )
6436  {
6437  /* exit if no or only trivial symmetry group is available */
6438  if ( propdata->nperms < 1 || ! propdata->binvaraffected )
6439  return SCIP_OKAY;
6440 
6441  if ( propdata->addsymresacks )
6442  {
6443  SCIP_CALL( addSymresackConss(scip, prop, propdata->components, propdata->componentbegins, propdata->ncomponents) );
6444  }
6445 
6446  /* free symmetry conss if no orbitope/symresack constraints have been found (may happen if Schreier-Sims constraints are active) */
6447  if ( propdata->ngenorbconss == 0 )
6448  SCIPfreeBlockMemoryArrayNull(scip, &propdata->genorbconss, propdata->nperms);
6449  }
6450 
6451  return SCIP_OKAY;
6452 }
6453 
6454 
6455 
6456 /*
6457  * Local methods for orbital fixing
6458  */
6459 
6460 
6461 /** performs orbital fixing
6462  *
6463  * Note that we do not have to distinguish between variables that have been fixed or branched to 1, since the
6464  * stabilizer is with respect to the variables that have been branched to 1. Thus, if an orbit contains a variable that
6465  * has been branched to 1, the whole orbit only contains variables that have been branched to 1 - and nothing can be
6466  * fixed.
6467  */
6468 static
6470  SCIP* scip, /**< SCIP pointer */
6471  SCIP_VAR** permvars, /**< variables */
6472  int npermvars, /**< number of variables */
6473  int* orbits, /**< array of non-trivial orbits */
6474  int* orbitbegins, /**< array containing begin positions of new orbits in orbits array */
6475  int norbits, /**< number of orbits */
6476  SCIP_Bool* infeasible, /**< pointer to store whether problem is infeasible */
6477  int* nfixedzero, /**< pointer to store number of variables fixed to 0 */
6478  int* nfixedone /**< pointer to store number of variables fixed to 1 */
6479  )
6480 {
6481  SCIP_Bool tightened;
6482  int i;
6483 
6484  assert( scip != NULL );
6485  assert( permvars != NULL );
6486  assert( orbits != NULL );
6487  assert( orbitbegins != NULL );
6488  assert( infeasible != NULL );
6489  assert( nfixedzero != NULL );
6490  assert( nfixedone != NULL );
6491  assert( norbits > 0 );
6492  assert( orbitbegins[0] == 0 );
6493 
6494  *infeasible = FALSE;
6495  *nfixedzero = 0;
6496  *nfixedone = 0;
6497 
6498  /* check all orbits */
6499  for (i = 0; i < norbits; ++i)
6500  {
6501  SCIP_Bool havefixedone = FALSE;
6502  SCIP_Bool havefixedzero = FALSE;
6503  SCIP_VAR* var;
6504  int j;
6505 
6506  /* we only have nontrivial orbits */
6507  assert( orbitbegins[i+1] - orbitbegins[i] >= 2 );
6508 
6509  /* check all variables in the orbit */
6510  for (j = orbitbegins[i]; j < orbitbegins[i+1]; ++j)
6511  {
6512  assert( 0 <= orbits[j] && orbits[j] < npermvars );
6513  var = permvars[orbits[j]];
6514  assert( var != NULL );
6515 
6516  /* check whether variable is not binary (and not implicit integer!) */
6517  if ( SCIPvarGetType(var) != SCIP_VARTYPE_BINARY )
6518  {
6519  /* skip orbit if there are non-binary variables */
6520  havefixedone = FALSE;
6521  havefixedzero = FALSE;
6522  break;
6523  }
6524 
6525  /* if variable is fixed to 1 -> can fix all variables in orbit to 1 */
6526  if ( SCIPvarGetLbLocal(var) > 0.5 )
6527  havefixedone = TRUE;
6528 
6529  /* check for zero-fixed variables */
6530  if ( SCIPvarGetUbLocal(var) < 0.5 )
6531  havefixedzero = TRUE;
6532  }
6533 
6534  /* check consistency */
6535  if ( havefixedone && havefixedzero )
6536  {
6537  *infeasible = TRUE;
6538  return SCIP_OKAY;
6539  }
6540 
6541  /* fix all variables to 0 if there is one variable fixed to 0 */
6542  if ( havefixedzero )
6543  {
6544  assert( ! havefixedone );
6545 
6546  for (j = orbitbegins[i]; j < orbitbegins[i+1]; ++j)
6547  {
6548  assert( 0 <= orbits[j] && orbits[j] < npermvars );
6549  var = permvars[orbits[j]];
6550  assert( var != NULL );
6551 
6552  /* only variables that are not yet fixed to 0 */
6553  if ( SCIPvarGetUbLocal(var) > 0.5 )
6554  {
6555  SCIPdebugMsg(scip, "can fix <%s> (index %d) to 0.\n", SCIPvarGetName(var), orbits[j]);
6556  assert( SCIPvarGetType(var) == SCIP_VARTYPE_BINARY );
6557  /* due to aggregation, var might already be fixed to 1, so do not put assert here */
6558 
6559  /* do not use SCIPinferBinvarProp(), since conflict analysis is not valid */
6560  SCIP_CALL( SCIPtightenVarUb(scip, var, 0.0, FALSE, infeasible, &tightened) );
6561  if ( *infeasible )
6562  return SCIP_OKAY;
6563  if ( tightened )
6564  ++(*nfixedzero);
6565  }
6566  }
6567  }
6568 
6569  /* fix all variables to 1 if there is one variable fixed to 1 */
6570  if ( havefixedone )
6571  {
6572  assert( ! havefixedzero );
6573 
6574  for (j = orbitbegins[i]; j < orbitbegins[i+1]; ++j)
6575  {
6576  assert( 0 <= orbits[j] && orbits[j] < npermvars );
6577  var = permvars[orbits[j]];
6578  assert( var != NULL );
6579 
6580  /* only variables that are not yet fixed to 1 */
6581  if ( SCIPvarGetLbLocal(var) < 0.5)
6582  {
6583  SCIPdebugMsg(scip, "can fix <%s> (index %d) to 1.\n", SCIPvarGetName(var), orbits[j]);
6584  assert( SCIPvarGetType(var) == SCIP_VARTYPE_BINARY );
6585  /* due to aggregation, var might already be fixed to 0, so do not put assert here */
6586 
6587  /* do not use SCIPinferBinvarProp(), since conflict analysis is not valid */
6588  SCIP_CALL( SCIPtightenVarLb(scip, var, 1.0, FALSE, infeasible, &tightened) );
6589  if ( *infeasible )
6590  return SCIP_OKAY;
6591  if ( tightened )
6592  ++(*nfixedone);
6593  }
6594  }
6595  }
6596  }
6597 
6598  return SCIP_OKAY;
6599 }
6600 
6601 
6602 /** Gets branching variables on the path to root
6603  *
6604  * The variables are added to bg1 and bg1list, which are prefilled with the variables globally fixed to 1.
6605  */
6606 static
6608  SCIP* scip, /**< SCIP pointer */
6609  int nvars, /**< number of variables */
6610  SCIP_HASHMAP* varmap, /**< map of variables to indices in vars array */
6611  SCIP_Shortbool* bg1, /**< bitset marking the variables globally fixed or branched to 1 */
6612  int* bg1list, /**< array to store the variable indices globally fixed or branched to 1 */
6613  int* nbg1 /**< pointer to store the number of variables in bg1 and bg1list */
6614  )
6615 {
6616  SCIP_NODE* node;
6617 
6618  assert( scip != NULL );
6619  assert( varmap != NULL );
6620  assert( bg1 != NULL );
6621  assert( bg1list != NULL );
6622  assert( nbg1 != NULL );
6623  assert( *nbg1 >= 0 );
6624 
6625  /* get current node */
6626  node = SCIPgetCurrentNode(scip);
6627 
6628 #ifdef SCIP_OUTPUT
6629  SCIP_CALL( SCIPprintNodeRootPath(scip, node, NULL) );
6630 #endif
6631 
6632  /* follow path to the root (in the root no domains were changed due to branching) */
6633  while ( SCIPnodeGetDepth(node) != 0 )
6634  {
6635  SCIP_BOUNDCHG* boundchg;
6636  SCIP_DOMCHG* domchg;
6637  SCIP_VAR* branchvar;
6638  int nboundchgs;
6639  int i;
6640 
6641  /* get domain changes of current node */
6642  domchg = SCIPnodeGetDomchg(node);
6643 
6644  /* If we stopped due to a solving limit, it might happen that a non-root node has no domain changes, in all other
6645  * cases domchg should not be NULL. */
6646  if ( domchg != NULL )
6647  {
6648  /* loop through all bound changes */
6649  nboundchgs = SCIPdomchgGetNBoundchgs(domchg);
6650  for (i = 0; i < nboundchgs; ++i)
6651  {
6652  /* get bound change info */
6653  boundchg = SCIPdomchgGetBoundchg(domchg, i);
6654  assert( boundchg != NULL );
6655 
6656  /* branching decisions have to be in the beginning of the bound change array */
6658  break;
6659 
6660  /* get corresponding branching variable */
6661  branchvar = SCIPboundchgGetVar(boundchg);
6662 
6663  /* we only consider binary variables */
6664  if ( SCIPvarGetType(branchvar) == SCIP_VARTYPE_BINARY )
6665  {
6666  /* if branching variable is not known (may have been created meanwhile,
6667  * e.g., by prop_inttobinary; may have been removed from symmetry data
6668  * due to compression), continue with parent node */
6669  if ( ! SCIPhashmapExists(varmap, (void*) branchvar) )
6670  break;
6671 
6672  if ( SCIPvarGetLbLocal(branchvar) > 0.5 )
6673  {
6674  int branchvaridx;
6675 
6676  branchvaridx = SCIPhashmapGetImageInt(varmap, (void*) branchvar);
6677  assert( branchvaridx < nvars );
6678 
6679  /* the variable might already be fixed to 1 */
6680  if ( ! bg1[branchvaridx] )
6681  {
6682  bg1[branchvaridx] = TRUE;
6683  bg1list[(*nbg1)++] = branchvaridx;
6684  }
6685  }
6686  }
6687  }
6688  }
6689 
6690  node = SCIPnodeGetParent(node);
6691  }
6692 
6693  return SCIP_OKAY;
6694 }
6695 
6696 
6697 /** propagates orbital fixing */
6698 static
6700  SCIP* scip, /**< SCIP pointer */
6701  SCIP_PROPDATA* propdata, /**< data of symmetry breaking propagator */
6702  SCIP_Bool* infeasible, /**< pointer to store whether the node is detected to be infeasible */
6703  int* nprop /**< pointer to store the number of propagations */
6704  )
6705 {
6706  SCIP_Shortbool* inactiveperms;
6707  SCIP_Shortbool* bg0;
6708  SCIP_Shortbool* bg1;
6709  SCIP_VAR** permvars;
6710  int* orbitbegins;
6711  int* orbits;
6712  int* components;
6713  int* componentbegins;
6714  int* vartocomponent;
6715  int ncomponents;
6716  int* bg0list;
6717  int nbg0;
6718  int* bg1list;
6719  int nbg1;
6720  int nactiveperms;
6721  int norbits;
6722  int npermvars;
6723  int nbinpermvars;
6724  int** permstrans;
6725  int nperms;
6726  int p;
6727  int v;
6728  int j;
6729  int componentidx;
6730 
6731  assert( scip != NULL );
6732  assert( propdata != NULL );
6733  assert( propdata->ofenabled );
6734  assert( infeasible != NULL );
6735  assert( nprop != NULL );
6736 
6737  *infeasible = FALSE;
6738  *nprop = 0;
6739 
6740  /* possibly compute symmetry; fix non-binary potential branching variables */
6741  if ( hasNonlinearConstraints(propdata) || propdata->symfixnonbinaryvars )
6742  {
6744  }
6745  else
6746  {
6748  }
6749  assert( hasNonlinearConstraints(propdata) || propdata->binvaraffected || ! propdata->ofenabled );
6750 
6751  /* return if there is no symmetry available */
6752  nperms = propdata->nperms;
6753  if ( nperms <= 0 || ! propdata->ofenabled )
6754  return SCIP_OKAY;
6755 
6756  assert( propdata->permvars != NULL );
6757  assert( propdata->npermvars > 0 );
6758  assert( propdata->permvarmap != NULL );
6759  assert( propdata->permstrans != NULL );
6760  assert( propdata->inactiveperms != NULL );
6761  assert( propdata->components != NULL );
6762  assert( propdata->componentbegins != NULL );
6763  assert( propdata->vartocomponent != NULL );
6764  assert( propdata->ncomponents > 0 );
6765 
6766  permvars = propdata->permvars;
6767  npermvars = propdata->npermvars;
6768  nbinpermvars = propdata->nbinpermvars;
6769  permstrans = propdata->permstrans;
6770  inactiveperms = propdata->inactiveperms;
6771  components = propdata->components;
6772  componentbegins = propdata->componentbegins;
6773  vartocomponent = propdata->vartocomponent;
6774  ncomponents = propdata->ncomponents;
6775 
6776  /* init bitset for marking variables (globally fixed or) branched to 1 */
6777  assert( propdata->bg1 != NULL );
6778  assert( propdata->bg1list != NULL );
6779  assert( propdata->nbg1 >= 0 );
6780  assert( propdata->nbg1 <= npermvars );
6781 
6782  bg1 = propdata->bg1;
6783  bg1list = propdata->bg1list;
6784  nbg1 = propdata->nbg1;
6785 
6786  /* get branching variables */
6787  SCIP_CALL( computeBranchingVariables(scip, npermvars, propdata->permvarmap, bg1, bg1list, &nbg1) );
6788  assert( nbg1 >= propdata->nbg1 );
6789 
6790  /* reset inactive permutations */
6791  nactiveperms = nperms;
6792  for (p = 0; p < nperms; ++p)
6793  propdata->inactiveperms[p] = FALSE;
6794 
6795  /* get pointers for bg0 */
6796  assert( propdata->bg0 != NULL );
6797  assert( propdata->bg0list != NULL );
6798  assert( propdata->nbg0 >= 0 );
6799  assert( propdata->nbg0 <= npermvars );
6800 
6801  bg0 = propdata->bg0;
6802  bg0list = propdata->bg0list;
6803  nbg0 = propdata->nbg0;
6804 
6805  /* filter out permutations that move variables that are fixed to 0 */
6806  for (j = 0; j < nbg0 && nactiveperms > 0; ++j)
6807  {
6808  int* pt;
6809 
6810  v = bg0list[j];
6811  assert( 0 <= v && v < npermvars );
6812  assert( bg0[v] );
6813 
6814  componentidx = vartocomponent[v];
6815 
6816  /* skip unaffected variables and blocked components */
6817  if ( componentidx < 0 || propdata->componentblocked[componentidx] )
6818  continue;
6819 
6820  pt = permstrans[v];
6821  assert( pt != NULL );
6822 
6823  for (p = componentbegins[componentidx]; p < componentbegins[componentidx + 1]; ++p)
6824  {
6825  int img;
6826  int perm;
6827 
6828  perm = components[p];
6829 
6830  /* skip inactive permutations */
6831  if ( inactiveperms[perm] )
6832  continue;
6833 
6834  img = pt[perm];
6835 
6836  if ( img != v )
6837  {
6838 #ifndef NDEBUG
6839  SCIP_VAR* varv = permvars[v];
6840  SCIP_VAR* varimg = permvars[img];
6841 
6842  /* check whether moved variables have the same type (might have been aggregated in the meanwhile) */
6843  assert( SCIPvarGetType(varv) == SCIPvarGetType(varimg) ||
6844  (SCIPvarIsBinary(varv) && SCIPvarIsBinary(varimg)) ||
6846  SCIPisEQ(scip, SCIPvarGetLbGlobal(varv), SCIPvarGetLbGlobal(varimg)) &&
6847  SCIPisEQ(scip, SCIPvarGetUbGlobal(varv), SCIPvarGetUbGlobal(varimg))) ||
6849  SCIPisEQ(scip, SCIPvarGetLbGlobal(varv), SCIPvarGetLbGlobal(varimg)) &&
6850  SCIPisEQ(scip, SCIPvarGetUbGlobal(varv), SCIPvarGetUbGlobal(varimg))) );
6851  assert( SCIPisEQ(scip, propdata->permvarsobj[v], propdata->permvarsobj[img]) );
6852 #endif
6853 
6854  /* we are moving a variable globally fixed to 0 to a variable not of this type */
6855  if ( ! bg0[img] )
6856  {
6857  inactiveperms[perm] = TRUE; /* mark as inactive */
6858  --nactiveperms;
6859  }
6860  }
6861  }
6862  }
6863 
6864  /* filter out permutations that move variables that are fixed to different values */
6865  for (j = 0; j < nbg1 && nactiveperms > 0; ++j)
6866  {
6867  int* pt;
6868 
6869  v = bg1list[j];
6870  assert( 0 <= v && v < npermvars );
6871  assert( bg1[v] );
6872 
6873  componentidx = vartocomponent[v];
6874 
6875  /* skip unaffected variables and blocked components */
6876  if ( componentidx < 0 || propdata->componentblocked[componentidx] )
6877  continue;
6878 
6879  pt = permstrans[v];
6880  assert( pt != NULL );
6881 
6882  for (p = componentbegins[componentidx]; p < componentbegins[componentidx + 1]; ++p)
6883  {
6884  int img;
6885  int perm;
6886 
6887  perm = components[p];
6888 
6889  /* skip inactive permutations */
6890  if ( inactiveperms[perm] )
6891  continue;
6892 
6893  img = pt[perm];
6894 
6895  if ( img != v )
6896  {
6897 #ifndef NDEBUG
6898  SCIP_VAR* varv = permvars[v];
6899  SCIP_VAR* varimg = permvars[img];
6900 
6901  /* check whether moved variables have the same type (might have been aggregated in the meanwhile) */
6902  assert( SCIPvarGetType(varv) == SCIPvarGetType(varimg) ||
6903  (SCIPvarIsBinary(varv) && SCIPvarIsBinary(varimg)) ||
6905  SCIPisEQ(scip, SCIPvarGetLbGlobal(varv), SCIPvarGetLbGlobal(varimg)) &&
6906  SCIPisEQ(scip, SCIPvarGetUbGlobal(varv), SCIPvarGetUbGlobal(varimg))) ||
6908  SCIPisEQ(scip, SCIPvarGetLbGlobal(varv), SCIPvarGetLbGlobal(varimg)) &&
6909  SCIPisEQ(scip, SCIPvarGetUbGlobal(varv), SCIPvarGetUbGlobal(varimg))) );
6910  assert( SCIPisEQ(scip, propdata->permvarsobj[v], propdata->permvarsobj[img]) );
6911 #endif
6912 
6913  /* we are moving a variable globally fixed or branched to 1 to a variable not of this type */
6914  if ( ! bg1[img] )
6915  {
6916  inactiveperms[perm] = TRUE; /* mark as inactive */
6917  --nactiveperms;
6918  }
6919  }
6920  }
6921  }
6922 
6923  /* Clean bg1 list - need to do this after the main loop! (Not needed for bg0.)
6924  * Note that variables globally fixed to 1 are not resetted, since the loop starts at propdata->nbg1. */
6925  for (j = propdata->nbg1; j < nbg1; ++j)
6926  bg1[bg1list[j]] = FALSE;
6927 
6928  /* exit if no active permuations left */
6929  if ( nactiveperms == 0 )
6930  return SCIP_OKAY;
6931 
6932  /* compute orbits of binary variables */
6933  SCIP_CALL( SCIPallocBufferArray(scip, &orbits, nbinpermvars) );
6934  SCIP_CALL( SCIPallocBufferArray(scip, &orbitbegins, nbinpermvars) );
6935  SCIP_CALL( SCIPcomputeOrbitsFilterSym(scip, nbinpermvars, permstrans, nperms, inactiveperms,
6936  orbits, orbitbegins, &norbits, components, componentbegins, vartocomponent, propdata->componentblocked, ncomponents, propdata->nmovedpermvars) );
6937 
6938  if ( norbits > 0 )
6939  {
6940  int nfixedzero = 0;
6941  int nfixedone = 0;
6942 
6943  SCIPdebugMsg(scip, "Perform orbital fixing on %d orbits (%d active perms).\n", norbits, nactiveperms);
6944  SCIP_CALL( performOrbitalFixing(scip, permvars, nbinpermvars, orbits, orbitbegins, norbits, infeasible, &nfixedzero, &nfixedone) );
6945 
6946  propdata->nfixedzero += nfixedzero;
6947  propdata->nfixedone += nfixedone;
6948  *nprop = nfixedzero + nfixedone;
6949 
6950  SCIPdebugMsg(scip, "Orbital fixings: %d 0s, %d 1s.\n", nfixedzero, nfixedone);
6951  }
6952 
6953  SCIPfreeBufferArray(scip, &orbitbegins);
6954  SCIPfreeBufferArray(scip, &orbits);
6955 
6956  return SCIP_OKAY;
6957 }
6958 
6959 
6960 
6961 /*
6962  * Callback methods of propagator
6963  */
6964 
6965 /** presolving initialization method of propagator (called when presolving is about to begin) */
6966 static
6967 SCIP_DECL_PROPINITPRE(propInitpreSymmetry)
6968 { /*lint --e{715}*/
6969  SCIP_PROPDATA* propdata;
6970 
6971  assert( scip != NULL );
6972  assert( prop != NULL );
6973 
6974  propdata = SCIPpropGetData(prop);
6975  assert( propdata != NULL );
6976 
6977  /* get nonlinear conshdlr for future checks on whether there are nonlinear constraints */
6978  propdata->conshdlr_nonlinear = SCIPfindConshdlr(scip, "nonlinear");
6979 
6980  /* check whether we should run */
6981  if ( propdata->usesymmetry < 0 )
6982  {
6983  SCIP_CALL( SCIPgetIntParam(scip, "misc/usesymmetry", &propdata->usesymmetry) );
6985  }
6986 
6987  /* add symmetry handling constraints if required */
6988  if ( (propdata->symconsenabled || propdata->sstenabled) && propdata->addconsstiming == 0 )
6989  {
6990  SCIPdebugMsg(scip, "Try to add symmetry handling constraints before presolving.");
6991 
6993  }
6994  else if ( propdata->ofenabled && propdata->ofsymcomptiming == 0 )
6995  {
6996  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "Symmetry computation before presolving:\n");
6997 
6998  /* otherwise compute symmetry if timing requests it; fix non-binary potential branching variables */
6999  if ( hasNonlinearConstraints(propdata) || propdata->symfixnonbinaryvars )
7000  {
7002  }
7003  else
7004  {
7006  }
7007  assert( propdata->binvaraffected || ! propdata->ofenabled );
7008  }
7009 
7010  return SCIP_OKAY;
7011 }
7012 
7013 
7014 /** presolving deinitialization method of propagator (called after presolving has been finished) */
7015 static
7016 SCIP_DECL_PROPEXITPRE(propExitpreSymmetry)
7017 { /*lint --e{715}*/
7018  SCIP_PROPDATA* propdata;
7019 
7020  assert( scip != NULL );
7021  assert( prop != NULL );
7022  assert( strcmp(SCIPpropGetName(prop), PROP_NAME) == 0 );
7023 
7024  SCIPdebugMsg(scip, "Exitpre method of propagator <%s> ...\n", PROP_NAME);
7025 
7026  propdata = SCIPpropGetData(prop);
7027  assert( propdata != NULL );
7028  assert( propdata->usesymmetry >= 0 );
7029 
7030  /* guarantee that symmetries are computed (and handled) if the solving process has not been interrupted
7031  * and even if presolving has been disabled */
7032  if ( (propdata->symconsenabled || propdata->sstenabled) && SCIPgetStatus(scip) == SCIP_STATUS_UNKNOWN )
7033  {
7035  }
7036 
7037  /* if timing requests it, guarantee that symmetries are computed even if presolving is disabled */
7038  if ( propdata->ofenabled && propdata->ofsymcomptiming <= 1 && SCIPgetStatus(scip) == SCIP_STATUS_UNKNOWN )
7039  {
7040  /* fix non-binary potential branching variables */
7041  if ( hasNonlinearConstraints(propdata) || propdata->symfixnonbinaryvars )
7042  {
7044  }
7045  else
7046  {
7048  }
7049  assert( propdata->binvaraffected || ! propdata->ofenabled );
7050  }
7051 
7052  return SCIP_OKAY;
7053 }
7054 
7055 
7056 /** presolving method of propagator */
7057 static
7058 SCIP_DECL_PROPPRESOL(propPresolSymmetry)
7059 { /*lint --e{715}*/
7060  SCIP_PROPDATA* propdata;
7061  int i;
7062 
7063  assert( scip != NULL );
7064  assert( prop != NULL );
7065  assert( result != NULL );
7066  assert( SCIPgetStage(scip) == SCIP_STAGE_PRESOLVING );
7067 
7068  *result = SCIP_DIDNOTRUN;
7069 
7070  propdata = SCIPpropGetData(prop);
7071  assert( propdata != NULL );
7072  assert( propdata->usesymmetry >= 0 );
7073 
7074  /* possibly create symmetry handling constraints */
7075  if ( propdata->symconsenabled || propdata->sstenabled )
7076  {
7077  int noldngenconns;
7078  int nchanges = 0;
7079  SCIP_Bool earlyterm = FALSE;
7080 
7081  /* skip presolving if we are not at the end if addconsstiming == 2 */
7082  assert( 0 <= propdata->addconsstiming && propdata->addconsstiming <= SYM_COMPUTETIMING_AFTERPRESOL );
7083  if ( propdata->addconsstiming > SYM_COMPUTETIMING_DURINGPRESOL && ! SCIPisPresolveFinished(scip) )
7084  return SCIP_OKAY;
7085 
7086  /* possibly stop */
7087  if ( SCIPisStopped(scip) )
7088  return SCIP_OKAY;
7089 
7090  noldngenconns = propdata->ngenorbconss + propdata->nsstconss + propdata->ngenlinconss;
7091 
7092  SCIP_CALL( tryAddSymmetryHandlingConss(scip, prop, &nchanges, &earlyterm) );
7093 
7094  /* if we actually tried to add symmetry handling constraints */
7095  if ( ! earlyterm ) /*lint !e774*/
7096  {
7097  *result = SCIP_DIDNOTFIND;
7098 
7099  if ( nchanges > 0 )
7100  {
7101  *result = SCIP_SUCCESS;
7102  *nchgbds += nchanges;
7103  }
7104 
7105  /* if symmetry handling constraints have been added, presolve each */
7106  if ( propdata->ngenorbconss > 0 || propdata->ngenlinconss > 0 || propdata->nsstconss > 0 )
7107  {
7108  /* at this point, the symmetry group should be computed and nontrivial */
7109  assert( propdata->nperms > 0 );
7110  assert( propdata->triedaddconss );
7111 
7112  /* we have added at least one symmetry handling constraints, i.e., we were successful */
7113  *result = SCIP_SUCCESS;
7114 
7115  *naddconss += propdata->ngenorbconss + propdata->ngenlinconss + propdata->nsstconss - noldngenconns;
7116  SCIPdebugMsg(scip, "Added symmetry breaking constraints: %d.\n", *naddconss);
7117 
7118  /* if constraints have been added, loop through generated constraints and presolve each */
7119  for (i = 0; i < propdata->ngenorbconss; ++i)
7120  {
7121  SCIP_CALL( SCIPpresolCons(scip, propdata->genorbconss[i], nrounds, SCIP_PROPTIMING_ALWAYS, nnewfixedvars, nnewaggrvars, nnewchgvartypes,
7122  nnewchgbds, nnewholes, nnewdelconss, nnewaddconss, nnewupgdconss, nnewchgcoefs, nnewchgsides, nfixedvars, naggrvars,
7123  nchgvartypes, nchgbds, naddholes, ndelconss, naddconss, nupgdconss, nchgcoefs, nchgsides, result) );
7124 
7125  /* exit if cutoff or unboundedness has been detected */
7126  if ( *result == SCIP_CUTOFF || *result == SCIP_UNBOUNDED )
7127  {
7128  SCIPdebugMsg(scip, "Presolving constraint <%s> detected cutoff or unboundedness.\n", SCIPconsGetName(propdata->genorbconss[i]));
7129  return SCIP_OKAY;
7130  }
7131  }
7132 
7133  for (i = 0; i < propdata->ngenlinconss; ++i)
7134  {
7135  SCIP_CALL( SCIPpresolCons(scip, propdata->genlinconss[i], nrounds, SCIP_PROPTIMING_ALWAYS, nnewfixedvars, nnewaggrvars, nnewchgvartypes,
7136  nnewchgbds, nnewholes, nnewdelconss, nnewaddconss, nnewupgdconss, nnewchgcoefs, nnewchgsides, nfixedvars, naggrvars,
7137  nchgvartypes, nchgbds, naddholes, ndelconss, naddconss, nupgdconss, nchgcoefs, nchgsides, result) );
7138 
7139  /* exit if cutoff or unboundedness has been detected */
7140  if ( *result == SCIP_CUTOFF || *result == SCIP_UNBOUNDED )
7141  {
7142  SCIPdebugMsg(scip, "Presolving constraint <%s> detected cutoff or unboundedness.\n", SCIPconsGetName(propdata->genlinconss[i]));
7143  return SCIP_OKAY;
7144  }
7145  }
7146  SCIPdebugMsg(scip, "Presolved %d generated constraints.\n",
7147  propdata->ngenorbconss + propdata->ngenlinconss);
7148 
7149  for (i = 0; i < propdata->nsstconss; ++i)
7150  {
7151  SCIP_CALL( SCIPpresolCons(scip, propdata->sstconss[i], nrounds, SCIP_PROPTIMING_ALWAYS, nnewfixedvars, nnewaggrvars, nnewchgvartypes,
7152  nnewchgbds, nnewholes, nnewdelconss, nnewaddconss, nnewupgdconss, nnewchgcoefs, nnewchgsides, nfixedvars, naggrvars,
7153  nchgvartypes, nchgbds, naddholes, ndelconss, naddconss, nupgdconss, nchgcoefs, nchgsides, result) );
7154 
7155  /* exit if cutoff or unboundedness has been detected */
7156  if ( *result == SCIP_CUTOFF || *result == SCIP_UNBOUNDED )
7157  {
7158  SCIPdebugMsg(scip, "Presolving constraint <%s> detected cutoff or unboundedness.\n", SCIPconsGetName(propdata->sstconss[i]));
7159  return SCIP_OKAY;
7160  }
7161  }
7162  SCIPdebugMsg(scip, "Presolved %d generated Schreier Sims constraints.\n", propdata->nsstconss);
7163  }
7164  }
7165  }
7166 
7167  /* run OF presolving */
7168  assert( 0 <= propdata->ofsymcomptiming && propdata->ofsymcomptiming <= SYM_COMPUTETIMING_AFTERPRESOL );
7169  if ( propdata->ofenabled && propdata->performpresolving && propdata->ofsymcomptiming <= SYM_COMPUTETIMING_DURINGPRESOL )
7170  {
7171  SCIP_Bool infeasible;
7172  int nprop;
7173 
7174  /* if we have not tried to add symmetry handling constraints */
7175  if ( *result == SCIP_DIDNOTRUN )
7176  *result = SCIP_DIDNOTFIND;
7177 
7178  SCIPdebugMsg(scip, "Presolving <%s>.\n", PROP_NAME);
7179 
7180  SCIP_CALL( propagateOrbitalFixing(scip, propdata, &infeasible, &nprop) );
7181 
7182  if ( infeasible )
7183  {
7184  *result = SCIP_CUTOFF;
7185  propdata->offoundreduction = TRUE;
7186  }
7187  else if ( nprop > 0 )
7188  {
7189  *result = SCIP_SUCCESS;
7190  *nfixedvars += nprop;
7191  propdata->offoundreduction = TRUE;
7192  }
7193  }
7194  else if ( propdata->ofenabled && propdata->ofsymcomptiming == SYM_COMPUTETIMING_DURINGPRESOL )
7195  {
7196  /* otherwise compute symmetry early if timing requests it; fix non-binary potential branching variables */
7197  if ( hasNonlinearConstraints(propdata) || propdata->symfixnonbinaryvars )
7198  {
7200  }
7201  else
7202  {
7204  }
7205  assert( propdata->binvaraffected || ! propdata->ofenabled );
7206  }
7207 
7208  return SCIP_OKAY;
7209 }
7210 
7211 
7212 /** execution method of propagator */
7213 static
7214 SCIP_DECL_PROPEXEC(propExecSymmetry)
7215 { /*lint --e{715}*/
7216  SCIP_PROPDATA* propdata;
7217  SCIP_Bool infeasible = FALSE;
7218  SCIP_Longint nodenumber;
7219  int nprop = 0;
7220 
7221  assert( scip != NULL );
7222  assert( result != NULL );
7223 
7224  *result = SCIP_DIDNOTRUN;
7225 
7226  /* do not run if we are in the root or not yet solving */
7227  if ( SCIPgetDepth(scip) <= 0 || SCIPgetStage(scip) < SCIP_STAGE_SOLVING )
7228  return SCIP_OKAY;
7229 
7230  /* do nothing if we are in a probing node */
7231  if ( SCIPinProbing(scip) )
7232  return SCIP_OKAY;
7233 
7234  /* do not run again in repropagation, since the path to the root might have changed */
7235  if ( SCIPinRepropagation(scip) )
7236  return SCIP_OKAY;
7237 
7238  /* get data */
7239  propdata = SCIPpropGetData(prop);
7240  assert( propdata != NULL );
7241 
7242  /* if usesymmetry has not been read so far */
7243  if ( propdata->usesymmetry < 0 )
7244  {
7245  SCIP_CALL( SCIPgetIntParam(scip, "misc/usesymmetry", &propdata->usesymmetry) );
7247  }
7248 
7249  /* do not propagate if orbital fixing is not enabled */
7250  if ( ! propdata->ofenabled )
7251  return SCIP_OKAY;
7252 
7253  /* return if there is no symmetry available */
7254  if ( propdata->nperms == 0 )
7255  return SCIP_OKAY;
7256 
7257  /* return if we already ran in this node */
7258  nodenumber = SCIPnodeGetNumber(SCIPgetCurrentNode(scip));
7259  if ( nodenumber == propdata->nodenumber )
7260  return SCIP_OKAY;
7261  propdata->nodenumber = nodenumber;
7262 
7263  /* propagate */
7264  *result = SCIP_DIDNOTFIND;
7265 
7266  SCIPdebugMsg(scip, "Propagating <%s>.\n", SCIPpropGetName(prop));
7267 
7268  SCIP_CALL( propagateOrbitalFixing(scip, propdata, &infeasible, &nprop) );
7269 
7270  if ( infeasible )
7271  {
7272  *result = SCIP_CUTOFF;
7273  propdata->offoundreduction = TRUE;
7274  }
7275  else if ( nprop > 0 )
7276  {
7277  *result = SCIP_REDUCEDDOM;
7278  propdata->offoundreduction = TRUE;
7279  }
7280 
7281  return SCIP_OKAY;
7282 }
7283 
7284 
7285 /** deinitialization method of propagator (called before transformed problem is freed) */
7286 static
7287 SCIP_DECL_PROPEXIT(propExitSymmetry)
7289  SCIP_PROPDATA* propdata;
7290 
7291  assert( scip != NULL );
7292  assert( prop != NULL );
7293  assert( strcmp(SCIPpropGetName(prop), PROP_NAME) == 0 );
7294 
7295  SCIPdebugMsg(scip, "Exiting propagator <%s>.\n", PROP_NAME);
7296 
7297  propdata = SCIPpropGetData(prop);
7298  assert( propdata != NULL );
7299 
7300  SCIP_CALL( freeSymmetryData(scip, propdata) );
7301 
7302  /* reset basic data */
7303  propdata->usesymmetry = -1;
7304  propdata->symconsenabled = FALSE;
7305  propdata->triedaddconss = FALSE;
7306  propdata->nsymresacks = 0;
7307  propdata->norbitopes = 0;
7308  propdata->ofenabled = FALSE;
7309  propdata->sstenabled = FALSE;
7310  propdata->lastrestart = 0;
7311  propdata->nfixedzero = 0;
7312  propdata->nfixedone = 0;
7313  propdata->nodenumber = -1;
7314  propdata->offoundreduction = FALSE;
7315 
7316  return SCIP_OKAY;
7317 }
7318 
7319 
7320 /** propagation conflict resolving method of propagator
7321  *
7322  * @todo Implement reverse propagation.
7323  *
7324  * Note that this is relatively difficult to obtain: One needs to include all bounds of variables that are responsible
7325  * for creating the orbit in which the variables that was propagated lies. This includes all variables that are moved
7326  * by the permutations which are involved in creating the orbit.
7327  */
7328 static
7329 SCIP_DECL_PROPRESPROP(propRespropSymmetry)
7330 { /*lint --e{715,818}*/
7331  assert( result != NULL );
7332 
7333  *result = SCIP_DIDNOTFIND;
7334 
7335  return SCIP_OKAY;
7336 }
7337 
7338 
7339 /** destructor of propagator to free user data (called when SCIP is exiting) */
7340 static
7341 SCIP_DECL_PROPFREE(propFreeSymmetry)
7342 { /*lint --e{715}*/
7343  SCIP_PROPDATA* propdata;
7344 
7345  assert( scip != NULL );
7346  assert( prop != NULL );
7347  assert( strcmp(SCIPpropGetName(prop), PROP_NAME) == 0 );
7348 
7349  SCIPdebugMsg(scip, "Freeing symmetry propagator.\n");
7350 
7351  propdata = SCIPpropGetData(prop);
7352  assert( propdata != NULL );
7353 
7354  SCIPfreeBlockMemory(scip, &propdata);
7355 
7356  return SCIP_OKAY;
7357 }
7358 
7359 
7360 /*
7361  * External methods
7362  */
7363 
7364 /** include symmetry propagator */
7366  SCIP* scip /**< SCIP data structure */
7367  )
7368 {
7369  SCIP_TABLEDATA* tabledata;
7370  SCIP_PROPDATA* propdata = NULL;
7371  SCIP_PROP* prop = NULL;
7372 
7373  SCIP_CALL( SCIPallocBlockMemory(scip, &propdata) );
7374  assert( propdata != NULL );
7375 
7376  propdata->npermvars = 0;
7377  propdata->nbinpermvars = 0;
7378  propdata->permvars = NULL;
7379 #ifndef NDEBUG
7380  propdata->permvarsobj = NULL;
7381 #endif
7382  propdata->nperms = -1;
7383  propdata->nmaxperms = 0;
7384  propdata->perms = NULL;
7385  propdata->permstrans = NULL;
7386  propdata->permvarmap = NULL;
7387  propdata->nonbinpermvarcaptured = NULL;
7388 
7389  propdata->ncomponents = -1;
7390  propdata->ncompblocked = 0;
7391  propdata->components = NULL;
7392  propdata->componentbegins = NULL;
7393  propdata->vartocomponent = NULL;
7394  propdata->componentblocked = NULL;
7395 
7396  propdata->log10groupsize = -1.0;
7397  propdata->nmovedvars = -1;
7398  propdata->binvaraffected = FALSE;
7399  propdata->computedsymmetry = FALSE;
7400  propdata->conshdlr_nonlinear = NULL;
7401 
7402  propdata->usesymmetry = -1;
7403  propdata->symconsenabled = FALSE;
7404  propdata->triedaddconss = FALSE;
7405  propdata->genorbconss = NULL;
7406  propdata->genlinconss = NULL;
7407  propdata->ngenorbconss = 0;
7408  propdata->ngenlinconss = 0;
7409  propdata->genlinconsssize = 0;
7410  propdata->nsymresacks = 0;
7411  propdata->norbitopes = 0;
7412  propdata->isnonlinvar = NULL;
7413 
7414  propdata->ofenabled = FALSE;
7415  propdata->bg0 = NULL;
7416  propdata->bg0list = NULL;
7417  propdata->nbg0 = 0;
7418  propdata->bg1 = NULL;
7419  propdata->bg1list = NULL;
7420  propdata->nbg1 = 0;
7421  propdata->permvarsevents = NULL;
7422  propdata->inactiveperms = NULL;
7423  propdata->nmovedpermvars = -1;
7424  propdata->nmovedbinpermvars = 0;
7425  propdata->nmovedintpermvars = 0;
7426  propdata->nmovedimplintpermvars = 0;
7427  propdata->nmovedcontpermvars = 0;
7428  propdata->lastrestart = 0;
7429  propdata->nfixedzero = 0;
7430  propdata->nfixedone = 0;
7431  propdata->nodenumber = -1;
7432  propdata->offoundreduction = FALSE;
7433 
7434  propdata->sstenabled = FALSE;
7435  propdata->sstconss = NULL;
7436  propdata->nsstconss = 0;
7437  propdata->maxnsstconss = 0;
7438  propdata->leaders = NULL;
7439  propdata->nleaders = 0;
7440  propdata->maxnleaders = 0;
7441 
7442  /* create event handler */
7443  propdata->eventhdlr = NULL;
7445  eventExecSymmetry, NULL) );
7446  assert( propdata->eventhdlr != NULL );
7447 
7448  /* include constraint handler */
7450  PROP_PRIORITY, PROP_FREQ, PROP_DELAY, PROP_TIMING, propExecSymmetry, propdata) );
7451  assert( prop != NULL );
7452 
7453  SCIP_CALL( SCIPsetPropFree(scip, prop, propFreeSymmetry) );
7454  SCIP_CALL( SCIPsetPropExit(scip, prop, propExitSymmetry) );
7455  SCIP_CALL( SCIPsetPropInitpre(scip, prop, propInitpreSymmetry) );
7456  SCIP_CALL( SCIPsetPropExitpre(scip, prop, propExitpreSymmetry) );
7457  SCIP_CALL( SCIPsetPropResprop(scip, prop, propRespropSymmetry) );
7459 
7460  /* include table */
7461  SCIP_CALL( SCIPallocBlockMemory(scip, &tabledata) );
7462  tabledata->propdata = propdata;
7464  NULL, tableFreeOrbitalfixing, NULL, NULL, NULL, NULL, tableOutputOrbitalfixing,
7466 
7467  /* add parameters for computing symmetry */
7468  SCIP_CALL( SCIPaddIntParam(scip,
7469  "propagating/" PROP_NAME "/maxgenerators",
7470  "limit on the number of generators that should be produced within symmetry detection (0 = no limit)",
7471  &propdata->maxgenerators, TRUE, DEFAULT_MAXGENERATORS, 0, INT_MAX, NULL, NULL) );
7472 
7474  "propagating/" PROP_NAME "/checksymmetries",
7475  "Should all symmetries be checked after computation?",
7476  &propdata->checksymmetries, TRUE, DEFAULT_CHECKSYMMETRIES, NULL, NULL) );
7477 
7479  "propagating/" PROP_NAME "/displaynorbitvars",
7480  "Should the number of variables affected by some symmetry be displayed?",
7481  &propdata->displaynorbitvars, TRUE, DEFAULT_DISPLAYNORBITVARS, NULL, NULL) );
7482 
7484  "propagating/" PROP_NAME "/doubleequations",
7485  "Double equations to positive/negative version?",
7486  &propdata->doubleequations, TRUE, DEFAULT_DOUBLEEQUATIONS, NULL, NULL) );
7487 
7488  /* add parameters for adding symmetry handling constraints */
7490  "propagating/" PROP_NAME "/conssaddlp",
7491  "Should the symmetry breaking constraints be added to the LP?",
7492  &propdata->conssaddlp, TRUE, DEFAULT_CONSSADDLP, NULL, NULL) );
7493 
7495  "propagating/" PROP_NAME "/addsymresacks",
7496  "Add inequalities for symresacks for each generator?",
7497  &propdata->addsymresacks, TRUE, DEFAULT_ADDSYMRESACKS, NULL, NULL) );
7498 
7500  "propagating/" PROP_NAME "/detectorbitopes",
7501  "Should we check whether the components of the symmetry group can be handled by orbitopes?",
7502  &propdata->detectorbitopes, TRUE, DEFAULT_DETECTORBITOPES, NULL, NULL) );
7503 
7505  "propagating/" PROP_NAME "/detectsubgroups",
7506  "Should we try to detect symmetric subgroups of the symmetry group on binary variables?",
7507  &propdata->detectsubgroups, TRUE, DEFAULT_DETECTSUBGROUPS, NULL, NULL) );
7508 
7510  "propagating/" PROP_NAME "/addweaksbcs",
7511  "Should we add weak SBCs for enclosing orbit of symmetric subgroups?",
7512  &propdata->addweaksbcs, TRUE, DEFAULT_ADDWEAKSBCS, NULL, NULL) );
7513 
7514  SCIP_CALL( SCIPaddIntParam(scip,
7515  "propagating/" PROP_NAME "/addconsstiming",
7516  "timing of adding constraints (0 = before presolving, 1 = during presolving, 2 = after presolving)",
7517  &propdata->addconsstiming, TRUE, DEFAULT_ADDCONSSTIMING, 0, 2, NULL, NULL) );
7518 
7519  /* add parameters for orbital fixing */
7520  SCIP_CALL( SCIPaddIntParam(scip,
7521  "propagating/" PROP_NAME "/ofsymcomptiming",
7522  "timing of symmetry computation for orbital fixing (0 = before presolving, 1 = during presolving, 2 = at first call)",
7523  &propdata->ofsymcomptiming, TRUE, DEFAULT_OFSYMCOMPTIMING, 0, 2, NULL, NULL) );
7524 
7526  "propagating/" PROP_NAME "/performpresolving",
7527  "run orbital fixing during presolving?",
7528  &propdata->performpresolving, TRUE, DEFAULT_PERFORMPRESOLVING, NULL, NULL) );
7529 
7530  SCIP_CALL( SCIPaddIntParam(scip,
7531  "propagating/" PROP_NAME "/recomputerestart",
7532  "recompute symmetries after a restart has occured? (0 = never)",
7533  &propdata->recomputerestart, TRUE, DEFAULT_RECOMPUTERESTART, 0, 0, NULL, NULL) );
7534 
7536  "propagating/" PROP_NAME "/compresssymmetries",
7537  "Should non-affected variables be removed from permutation to save memory?",
7538  &propdata->compresssymmetries, TRUE, DEFAULT_COMPRESSSYMMETRIES, NULL, NULL) );
7539 
7541  "propagating/" PROP_NAME "/compressthreshold",
7542  "Compression is used if percentage of moved vars is at most the threshold.",
7543  &propdata->compressthreshold, TRUE, DEFAULT_COMPRESSTHRESHOLD, 0.0, 1.0, NULL, NULL) );
7544 
7546  "propagating/" PROP_NAME "/usecolumnsparsity",
7547  "Should the number of conss a variable is contained in be exploited in symmetry detection?",
7548  &propdata->usecolumnsparsity, TRUE, DEFAULT_USECOLUMNSPARSITY, NULL, NULL) );
7549 
7550  SCIP_CALL( SCIPaddIntParam(scip,
7551  "propagating/" PROP_NAME "/maxnconsssubgroup",
7552  "maximum number of constraints up to which subgroup structures are detected",
7553  &propdata->maxnconsssubgroup, TRUE, DEFAULT_MAXNCONSSSUBGROUP, 0, INT_MAX, NULL, NULL) );
7554 
7556  "propagating/" PROP_NAME "/usedynamicprop",
7557  "whether dynamic propagation should be used for full orbitopes",
7558  &propdata->usedynamicprop, TRUE, DEFAULT_USEDYNAMICPROP, NULL, NULL) );
7559 
7561  "propagating/" PROP_NAME "/addstrongsbcs",
7562  "Should strong SBCs for enclosing orbit of symmetric subgroups be added if orbitopes are not used?",
7563  &propdata->addstrongsbcs, TRUE, DEFAULT_ADDSTRONGSBCS, NULL, NULL) );
7564 
7565  SCIP_CALL( SCIPaddIntParam(scip,
7566  "propagating/" PROP_NAME "/ssttiebreakrule",
7567  "rule to select the orbit in Schreier Sims inequalities (variable in 0: minimum size orbit; 1: maximum size orbit; 2: orbit with most variables in conflict with leader)",
7568  &propdata->ssttiebreakrule, TRUE, DEFAULT_SSTTIEBREAKRULE, 0, 2, NULL, NULL) );
7569 
7570  SCIP_CALL( SCIPaddIntParam(scip,
7571  "propagating/" PROP_NAME "/sstleaderrule",
7572  "rule to select the leader in an orbit (0: first var; 1: last var; 2: var having most conflicting vars in orbit; 3: var having most conflicting vars in problem)",
7573  &propdata->sstleaderrule, TRUE, DEFAULT_SSTLEADERRULE, 0, 3, NULL, NULL) );
7574 
7575  SCIP_CALL( SCIPaddIntParam(scip,
7576  "propagating/" PROP_NAME "/sstleadervartype",
7577  "bitset encoding which variable types can be leaders (1: binary; 2: integer; 4: impl. int; 8: continuous);" \
7578  "if multiple types are allowed, take the one with most affected vars",
7579  &propdata->sstleadervartype, TRUE, DEFAULT_SSTLEADERVARTYPE, 1, 15, NULL, NULL) );
7580 
7582  "propagating/" PROP_NAME "/addconflictcuts",
7583  "Should Schreier Sims constraints be added if we use a conflict based rule?",
7584  &propdata->addconflictcuts, TRUE, DEFAULT_ADDCONFLICTCUTS, NULL, NULL) );
7585 
7587  "propagating/" PROP_NAME "/sstaddcuts",
7588  "Should Schreier Sims constraints be added?",
7589  &propdata->sstaddcuts, TRUE, DEFAULT_SSTADDCUTS, NULL, NULL) );
7590 
7592  "propagating/" PROP_NAME "/sstmixedcomponents",
7593  "Should Schreier Sims constraints be added if a symmetry component contains variables of different types?",
7594  &propdata->sstmixedcomponents, TRUE, DEFAULT_SSTMIXEDCOMPONENTS, NULL, NULL) );
7595 
7597  "propagating/" PROP_NAME "/symfixnonbinaryvars",
7598  "Whether all non-binary variables shall be not affected by symmetries if OF is active?",
7599  &propdata->symfixnonbinaryvars, TRUE, DEFAULT_SYMFIXNONBINARYVARS, NULL, NULL) );
7600 
7602  "propagating/" PROP_NAME "/onlybinarysymmetry",
7603  "Is only symmetry on binary variables used?",
7604  &propdata->onlybinarysymmetry, TRUE, DEFAULT_ONLYBINARYSYMMETRY, NULL, NULL) );
7605 
7607  "propagating/" PROP_NAME "/preferlessrows",
7608  "Shall orbitopes with less rows be preferred in detection?",
7609  &propdata->preferlessrows, TRUE, DEFAULT_PREFERLESSROWS, NULL, NULL) );
7610 
7611  /* possibly add description */
7612  if ( SYMcanComputeSymmetry() )
7613  {
7615  if ( SYMsymmetryGetAddName() != NULL )
7616  {
7618  }
7619  }
7620 
7621  return SCIP_OKAY;
7622 }
7623 
7624 
7625 /** return currently available symmetry group information */
7627  SCIP* scip, /**< SCIP data structure */
7628  int* npermvars, /**< pointer to store number of variables for permutations */
7629  SCIP_VAR*** permvars, /**< pointer to store variables on which permutations act */
7630  SCIP_HASHMAP** permvarmap, /**< pointer to store hash map of permvars (or NULL) */
7631  int* nperms, /**< pointer to store number of permutations */
7632  int*** perms, /**< pointer to store permutation generators as (nperms x npermvars) matrix (or NULL)*/
7633  int*** permstrans, /**< pointer to store permutation generators as (npermvars x nperms) matrix (or NULL)*/
7634  SCIP_Real* log10groupsize, /**< pointer to store log10 of group size (or NULL) */
7635  SCIP_Bool* binvaraffected, /**< pointer to store whether binary variables are affected (or NULL) */
7636  int** components, /**< pointer to store components of symmetry group (or NULL) */
7637  int** componentbegins, /**< pointer to store begin positions of components in components array (or NULL) */
7638  int** vartocomponent, /**< pointer to store assignment from variable to its component (or NULL) */
7639  int* ncomponents /**< pointer to store number of components (or NULL) */
7640  )
7641 {
7642  SCIP_PROPDATA* propdata;
7643  SCIP_PROP* prop;
7644 
7645  assert( scip != NULL );
7646  assert( npermvars != NULL );
7647  assert( permvars != NULL );
7648  assert( nperms != NULL );
7649  assert( perms != NULL || permstrans != NULL );
7650  assert( ncomponents != NULL || (components == NULL && componentbegins == NULL && vartocomponent == NULL) );
7651 
7652  /* find symmetry propagator */
7653  prop = SCIPfindProp(scip, "symmetry");
7654  if ( prop == NULL )
7655  {
7656  SCIPerrorMessage("Could not find symmetry propagator.\n");
7657  return SCIP_PLUGINNOTFOUND;
7658  }
7659  assert( prop != NULL );
7660  assert( strcmp(SCIPpropGetName(prop), PROP_NAME) == 0 );
7661 
7662  propdata = SCIPpropGetData(prop);
7663  assert( propdata != NULL );
7664 
7665  *npermvars = propdata->npermvars;
7666  *permvars = propdata->permvars;
7667 
7668  if ( permvarmap != NULL )
7669  *permvarmap = propdata->permvarmap;
7670 
7671  *nperms = propdata->nperms;
7672  if ( perms != NULL )
7673  {
7674  *perms = propdata->perms;
7675  assert( *perms != NULL || *nperms <= 0 );
7676  }
7677 
7678  if ( permstrans != NULL )
7679  {
7680  *permstrans = propdata->permstrans;
7681  assert( *permstrans != NULL || *nperms <= 0 );
7682  }
7683 
7684  if ( log10groupsize != NULL )
7685  *log10groupsize = propdata->log10groupsize;
7686 
7687  if ( binvaraffected != NULL )
7688  *binvaraffected = propdata->binvaraffected;
7689 
7690  if ( components != NULL )
7691  *components = propdata->components;
7692 
7693  if ( componentbegins != NULL )
7694  *componentbegins = propdata->componentbegins;
7695 
7696  if ( vartocomponent )
7697  *vartocomponent = propdata->vartocomponent;
7698 
7699  if ( ncomponents )
7700  *ncomponents = propdata->ncomponents;
7701 
7702  return SCIP_OKAY;
7703 }
7704 
7705 /** return whether orbital fixing is enabled */
7707  SCIP* scip /**< SCIP data structure */
7708  )
7709 {
7710  SCIP_PROP* prop;
7711  SCIP_PROPDATA* propdata;
7712 
7713  assert( scip != NULL );
7714 
7715  prop = SCIPfindProp(scip, PROP_NAME);
7716  if ( prop == NULL )
7717  return FALSE;
7718 
7719  propdata = SCIPpropGetData(prop);
7720  assert( propdata != NULL );
7721 
7722  return propdata->ofenabled;
7723 }
7724 
7725 /** return number of the symmetry group's generators */
7727  SCIP* scip /**< SCIP data structure */
7728  )
7729 {
7730  SCIP_PROP* prop;
7731  SCIP_PROPDATA* propdata;
7732 
7733  assert( scip != NULL );
7734 
7735  prop = SCIPfindProp(scip, PROP_NAME);
7736  if ( prop == NULL )
7737  return 0;
7738 
7739  propdata = SCIPpropGetData(prop);
7740  assert( propdata != NULL );
7741 
7742  if ( propdata->nperms < 0 )
7743  return 0;
7744  else
7745  return propdata->nperms;
7746 }
SCIP_RETCODE SCIPcomputeComponentsSym(SCIP *scip, 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:766
SCIP_RETCODE SCIPsetPropPresol(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPPRESOL((*proppresol)), int presolpriority, int presolmaxrounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_prop.c:279
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:59
int SCIPgetNIntVars(SCIP *scip)
Definition: scip_prob.c:2082
static SCIP_RETCODE addSSTConssOrbitAndUpdateSST(SCIP *scip, SCIP_DIGRAPH *conflictgraph, SCIP_PROPDATA *propdata, SCIP_VAR **permvars, int *orbits, int *orbitbegins, int orbitidx, int orbitleaderidx, SCIP_Shortbool *orbitvarinconflict, int norbitvarinconflict, int *nchgbds, SCIP_Bool useconflictgraph)
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:99
SCIP_Bool SCIPinRepropagation(SCIP *scip)
Definition: scip_tree.c:146
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
Definition: scip_timing.c:378
void SCIPsortIntIntPtr(int *intarray1, int *intarray2, void **ptrarray, int len)
#define DEFAULT_COMPRESSTHRESHOLD
SCIP_RETCODE SCIPexpriterInit(SCIP_EXPRITER *iterator, SCIP_EXPR *expr, SCIP_EXPRITER_TYPE type, SCIP_Bool allowrevisit)
Definition: expriter.c:500
static SCIP_RETCODE propagateOrbitalFixing(SCIP *scip, SCIP_PROPDATA *propdata, SCIP_Bool *infeasible, int *nprop)
#define DEFAULT_SSTMIXEDCOMPONENTS
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5203
SCIP_Real * matcoef
SCIP_RETCODE SCIPsimplifyExpr(SCIP *scip, SCIP_EXPR *rootexpr, SCIP_EXPR **simplified, SCIP_Bool *changed, SCIP_Bool *infeasible, SCIP_DECL_EXPR_OWNERCREATE((*ownercreate)), void *ownercreatedata)
Definition: scip_expr.c:1763
SCIP_RETCODE SCIPincludeTable(SCIP *scip, const char *name, const char *desc, SCIP_Bool active, SCIP_DECL_TABLECOPY((*tablecopy)), SCIP_DECL_TABLEFREE((*tablefree)), SCIP_DECL_TABLEINIT((*tableinit)), SCIP_DECL_TABLEEXIT((*tableexit)), SCIP_DECL_TABLEINITSOL((*tableinitsol)), SCIP_DECL_TABLEEXITSOL((*tableexitsol)), SCIP_DECL_TABLEOUTPUT((*tableoutput)), SCIP_TABLEDATA *tabledata, int position, SCIP_STAGE earlieststage)
Definition: scip_table.c:56
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip_tree.c:91
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:365
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8349
void SCIPdisjointsetUnion(SCIP_DISJOINTSET *djset, int p, int q, SCIP_Bool forcerepofp)
Definition: misc.c:11208
#define DEFAULT_CHECKSYMMETRIES
Constraint handler for variable bound constraints .
static SCIP_RETCODE addSymresackConss(SCIP *scip, SCIP_PROP *prop, int *components, int *componentbegins, int ncomponents)
static SCIP_DECL_EVENTEXEC(eventExecSymmetry)
#define DEFAULT_SSTADDCUTS
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2497
static SCIP_RETCODE updateSymInfoConflictGraphSST(SCIP *scip, SCIP_DIGRAPH *conflictgraph, SCIP_VAR **graphvars, int ngraphvars, SCIP_VAR **permvars, int npermvars, SCIP_Bool onlypermvars, SCIP_HASHMAP *varmap, int *orbits, int *orbitbegins, int norbits)
static SCIP_DECL_PROPPRESOL(propPresolSymmetry)
static SCIP_Bool isLeadervartypeCompatible(SCIP_VAR *var, int leadervartype)
SCIP_RETCODE SCIPcatchVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int *filterpos)
Definition: scip_event.c:354
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:886
#define DEFAULT_CONSSADDLP
int SCIPexprGetNChildren(SCIP_EXPR *expr)
Definition: expr.c:3801
static SCIP_DECL_PROPEXEC(propExecSymmetry)
int SCIPgetNVarsSetppc(SCIP *scip, SCIP_CONS *cons)
Definition: cons_setppc.c:9415
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip_mem.h:126
static SCIP_DECL_TABLEFREE(tableFreeOrbitalfixing)
SCIP_EXPR * SCIPexpriterGetParentDFS(SCIP_EXPRITER *iterator)
Definition: expriter.c:739
int SCIPgetNVarsBounddisjunction(SCIP *scip, SCIP_CONS *cons)
SCIP_PROP * SCIPfindProp(SCIP *scip, const char *name)
Definition: scip_prop.c:329
SCIP_Real SCIPgetLhsVarbound(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17901
int SCIPgetNVarsLogicor(SCIP *scip, SCIP_CONS *cons)
#define SCIP_MAXSTRLEN
Definition: def.h:302
SCIP_RETCODE SCIPgetSymmetry(SCIP *scip, int *npermvars, SCIP_VAR ***permvars, SCIP_HASHMAP **permvarmap, int *nperms, int ***perms, int ***permstrans, SCIP_Real *log10groupsize, SCIP_Bool *binvaraffected, int **components, int **componentbegins, int **vartocomponent, int *ncomponents)
SCIP_RETCODE SCIPcreateSymbreakCons(SCIP *scip, SCIP_CONS **cons, const char *name, int *perm, SCIP_VAR **vars, int nvars, SCIP_Bool ismodelcons, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
#define ISSSTIMPLINTACTIVE(x)
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:97
static SCIP_RETCODE addSSTConss(SCIP *scip, SCIP_PROPDATA *propdata, int *nchgbds)
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:139
SCIP_Bool SCIPisPositive(SCIP *scip, SCIP_Real val)
SCIP_VAR ** SCIPgetVarsBounddisjunction(SCIP *scip, SCIP_CONS *cons)
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17957
int * SCIPdigraphGetSuccessors(SCIP_DIGRAPH *digraph, int node)
Definition: misc.c:7731
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Real * SCIPgetBoundsBounddisjunction(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE freeSymmetryData(SCIP *scip, SCIP_PROPDATA *propdata)
SCIP_RETCODE SCIPincludeEventhdlrBasic(SCIP *scip, SCIP_EVENTHDLR **eventhdlrptr, const char *name, const char *desc, SCIP_DECL_EVENTEXEC((*eventexec)), SCIP_EVENTHDLRDATA *eventhdlrdata)
Definition: scip_event.c:104
SCIP_Real SCIPgetRhsNonlinear(SCIP_CONS *cons)
SCIP_NODE * SCIPnodeGetParent(SCIP_NODE *node)
Definition: tree.c:7724
SCIP_RETCODE SYMcomputeSymmetryGenerators(SCIP *scip, int maxgenerators, SYM_MATRIXDATA *matrixdata, SYM_EXPRDATA *exprdata, int *nperms, int *nmaxperms, int ***perms, SCIP_Real *log10groupsize, SCIP_Real *symcodetime)
#define PROP_TIMING
static SCIP_DECL_PROPRESPROP(propRespropSymmetry)
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1248
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:17422
static SCIP_RETCODE detectOrbitopes(SCIP *scip, SCIP_PROPDATA *propdata, int *components, int *componentbegins, int ncomponents)
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:163
#define DEFAULT_DISPLAYNORBITVARS
#define ISSSTINTACTIVE(x)
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4554
#define FALSE
Definition: def.h:96
static SCIP_RETCODE freeConflictGraphSST(SCIP *scip, SCIP_DIGRAPH **conflictgraph, int nnodes)
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3024
const char * SCIPeventhdlrGetName(SCIP_EVENTHDLR *eventhdlr)
Definition: event.c:324
int SCIPgetNActivePricers(SCIP *scip)
Definition: scip_pricer.c:348
SCIP_Real SCIPinfinity(SCIP *scip)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10788
#define TRUE
Definition: def.h:95
SCIP_RETCODE SCIPhashsetCreate(SCIP_HASHSET **hashset, BMS_BLKMEM *blkmem, int size)
Definition: misc.c:3709
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8369
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3142
#define SYM_HANDLETYPE_SYMBREAK
Definition: type_symmetry.h:69
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17591
SCIP_Bool SCIPhashsetExists(SCIP_HASHSET *hashset, void *element)
Definition: misc.c:3767
int SCIPgetSymmetryNGenerators(SCIP *scip)
#define SCIP_EVENTTYPE_GLBCHANGED
Definition: type_event.h:75
#define DEFAULT_RECOMPUTERESTART
static SCIP_RETCODE SCIPsortOrbitope(SCIP *scip, int **orbitopevaridx, SCIP_VAR ***vars, int nrows, int ncols)
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8399
int SCIPgetNActiveConss(SCIP *scip)
#define ISSSTBINACTIVE(x)
static GRAPHNODE ** active
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5320
SCIP_VAR ** SCIPgetVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
static SCIP_RETCODE computeSymmetryGroup(SCIP *scip, SCIP_Bool doubleequations, SCIP_Bool compresssymmetries, SCIP_Real compressthreshold, int maxgenerators, SYM_SPEC fixedtype, SCIP_Bool local, SCIP_Bool checksymmetries, SCIP_Bool usecolumnsparsity, SCIP_CONSHDLR *conshdlr_nonlinear, int *npermvars, int *nbinpermvars, SCIP_VAR ***permvars, int *nperms, int *nmaxperms, int ***perms, SCIP_Real *log10groupsize, int *nmovedvars, SCIP_Bool **isnonlinvar, SCIP_Bool *binvaraffected, SCIP_Bool *compressed, SCIP_Real *symcodetime, SCIP_Bool *success)
Constraint handler for AND constraints, .
static SCIP_RETCODE detectAndHandleSubgroups(SCIP *scip, SCIP_PROPDATA *propdata)
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip_mem.h:132
SCIP_CONS ** SCIPgetConss(SCIP *scip)
Definition: scip_prob.c:3088
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPnodeGetDepth(SCIP_NODE *node)
Definition: tree.c:7454
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
SCIP_VAR * SCIPgetVarVarbound(SCIP *scip, SCIP_CONS *cons)
Constraint handler for the set partitioning / packing / covering constraints .
#define DEFAULT_DETECTSUBGROUPS
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
static SCIP_RETCODE determineSymmetry(SCIP *scip, SCIP_PROPDATA *propdata, SYM_SPEC symspecrequire, SYM_SPEC symspecrequirefixed)
SCIP_VAR ** permvars
#define SCIP_EXPRITER_ENTEREXPR
Definition: type_expr.h:676
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8359
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:120
static SCIP_RETCODE checkSymmetriesAreSymmetries(SCIP *scip, SYM_SPEC fixedtype, SYM_MATRIXDATA *matrixdata, int nperms, int **perms)
#define DEFAULT_SSTLEADERRULE
#define SCIPdebugMsg
Definition: scip_message.h:78
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:83
SCIP_Real SCIPgetRhsLinear(SCIP *scip, SCIP_CONS *cons)
#define TABLE_DESC_ORBITALFIXING
SCIP_EXPR * SCIPexpriterGetCurrent(SCIP_EXPRITER *iterator)
Definition: expriter.c:682
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8151
static SCIP_DECL_PROPINITPRE(propInitpreSymmetry)
static SCIP_RETCODE getActiveVariables(SCIP *scip, SCIP_VAR ***vars, SCIP_Real **scalars, int *nvars, SCIP_Real *constant, SCIP_Bool transformed)
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:208
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2172
SCIP_RETCODE SCIPcreateDigraph(SCIP *scip, SCIP_DIGRAPH **digraph, int nnodes)
#define DEFAULT_MAXNCONSSSUBGROUP
#define DEFAULT_COMPRESSSYMMETRIES
int SCIPgetNActiveBenders(SCIP *scip)
Definition: scip_benders.c:532
SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
Definition: misc.c:2246
static SCIP_RETCODE addWeakSBCsSubgroup(SCIP *scip, SCIP_PROPDATA *propdata, int *compcolorbegins, int *graphcompbegins, int *graphcomponents, int ncompcolors, int *chosencomppercolor, int *firstvaridxpercolor, int symgrpcompidx, int *naddedconss, SCIP_Bool storelexorder, int **lexorder, int *nvarsorder, int *maxnvarsorder)
public functions to work with algebraic expressions
interface for symmetry computations
SCIP_Bool SCIPisReoptEnabled(SCIP *scip)
Definition: scip_solve.c:3628
int SCIPcompareExpr(SCIP *scip, SCIP_EXPR *expr1, SCIP_EXPR *expr2)
Definition: scip_expr.c:1724
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3373
#define DEFAULT_ADDWEAKSBCS
void SCIPsortIntPtr(int *intarray, void **ptrarray, int len)
int SCIPdigraphGetNNodes(SCIP_DIGRAPH *digraph)
Definition: misc.c:7658
constraint handler for (partitioning/packing/full) orbitope constraints w.r.t. the full symmetric gro...
constraint handler for symresack constraints
static SCIP_RETCODE checkTwoCyclePermsAreOrbitope(SCIP *scip, SCIP_VAR **permvars, int npermvars, int **perms, int *activeperms, int ntwocycles, int nactiveperms, int **orbitopevaridx, int *columnorder, int *nusedelems, int *nusedcols, SCIP_Shortbool *rowisbinary, SCIP_Bool *isorbitope, SCIP_Shortbool *activevars)
int SCIPgetNFixedVars(SCIP *scip)
Definition: scip_prob.c:2309
Constraint handler for "or" constraints, .
#define SCIPallocCleanBufferArray(scip, ptr, num)
Definition: scip_mem.h:142
static int getNSymhandableConss(SCIP *scip, SCIP_CONSHDLR *conshdlr_nonlinear)
SCIP_Longint SCIPnodeGetNumber(SCIP_NODE *node)
Definition: tree.c:7444
#define DEFAULT_USEDYNAMICPROP
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17911
#define SYM_SPEC_BINARY
Definition: type_symmetry.h:43
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:105
Constraint handler for knapsack constraints of the form , x binary and .
SCIP_RETCODE SCIPsetPropExitpre(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPEXITPRE((*propexitpre)))
Definition: scip_prop.c:263
SCIP_Real ub
#define TABLE_EARLIEST_ORBITALFIXING
SCIP_Real SCIPeventGetNewbound(SCIP_EVENT *event)
Definition: event.c:1242
static const NodeData nodedata[]
Definition: gastrans.c:83
static SCIP_RETCODE chooseOrderOfGenerators(SCIP *scip, SCIP_PROPDATA *propdata, int compidx, int **genorder, int *ntwocycleperms)
SCIP_Real SCIPgetRhsVarbound(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisPresolveFinished(SCIP *scip)
Definition: scip_general.c:612
SCIP_VAR ** SCIPgetVarsAnd(SCIP *scip, SCIP_CONS *cons)
Definition: cons_and.c:5151
#define ISSSTCONTACTIVE(x)
#define ISORBITALFIXINGACTIVE(x)
const char * SYMsymmetryGetAddName(void)
#define SCIPhashFour(a, b, c, d)
Definition: pub_misc.h:524
SYM_RHSSENSE * rhssense
SCIP_Real * SCIPgetValsLinking(SCIP *scip, SCIP_CONS *cons)
#define SCIPerrorMessage
Definition: pub_message.h:64
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4182
SCIP_RETCODE SCIPgetConsNVars(SCIP *scip, SCIP_CONS *cons, int *nvars, SCIP_Bool *success)
Definition: scip_cons.c:2567
SCIP_RETCODE SCIPaddCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2770
SCIP_Bool SCIPisOrbitalfixingEnabled(SCIP *scip)
SCIP_VAR * SCIPgetResultantAnd(SCIP *scip, SCIP_CONS *cons)
Definition: cons_and.c:5176
void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
static SCIP_RETCODE computeBranchingVariables(SCIP *scip, int nvars, SCIP_HASHMAP *varmap, SCIP_Shortbool *bg1, int *bg1list, int *nbg1)
static SCIP_DECL_TABLEOUTPUT(tableOutputOrbitalfixing)
#define SYM_SPEC_INTEGER
Definition: type_symmetry.h:42
SCIP_VAR * SCIPgetVarExprVar(SCIP_EXPR *expr)
Definition: expr_var.c:416
void * SCIPdigraphGetNodeData(SCIP_DIGRAPH *digraph, int node)
Definition: misc.c:7668
Constraint handler for logicor constraints (equivalent to set covering, but algorithms are suited fo...
#define ISSSTACTIVE(x)
SCIP_RETCODE SCIPpresolCons(SCIP *scip, SCIP_CONS *cons, int nrounds, SCIP_PRESOLTIMING presoltiming, int nnewfixedvars, int nnewaggrvars, int nnewchgvartypes, int nnewchgbds, int nnewholes, int nnewdelconss, int nnewaddconss, int nnewupgdconss, int nnewchgcoefs, int nnewchgsides, int *nfixedvars, int *naggrvars, int *nchgvartypes, int *nchgbds, int *naddholes, int *ndelconss, int *naddconss, int *nupgdconss, int *nchgcoefs, int *nchgsides, SCIP_RESULT *result)
Definition: scip_cons.c:2352
void SCIPhashsetFree(SCIP_HASHSET **hashset, BMS_BLKMEM *blkmem)
Definition: misc.c:3740
static INLINE uint32_t SCIPrealHashCode(double x)
Definition: pub_misc.h:544
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:137
SCIP_STATUS SCIPgetStatus(SCIP *scip)
Definition: scip_general.c:483
void SCIPdigraphSetNodeData(SCIP_DIGRAPH *digraph, void *dataptr, int node)
Definition: misc.c:7684
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:57
SYM_RHSSENSE * senses
SCIP_RETCODE SCIPincludePropSymmetry(SCIP *scip)
#define DEFAULT_PERFORMPRESOLVING
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8090
SCIP_RETCODE SCIPchgVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound)
Definition: scip_var.c:4766
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:8715
static SCIP_DECL_PROPEXIT(propExitSymmetry)
SCIP_Bool SCIPisExprValue(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1432
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8309
SCIP_VAR ** SCIPgetVarsLogicor(SCIP *scip, SCIP_CONS *cons)
#define PROP_PRESOL_MAXROUNDS
static SCIP_DECL_HASHGETKEY(SYMhashGetKeyVartype)
struct SCIP_EventData SCIP_EVENTDATA
Definition: type_event.h:173
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17242
static SCIP_RETCODE addOrbitopeSubgroup(SCIP *scip, SCIP_PROPDATA *propdata, int *usedperms, int nusedperms, int *compcolorbegins, int *graphcompbegins, int *graphcomponents, int graphcoloridx, int nrows, int ncols, int *firstvaridx, int *compidxfirstrow, int **lexorder, int *nvarslexorder, int *maxnvarslexorder, SCIP_Bool mayinteract, SCIP_Bool *success)
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3058
SCIP_EXPR * SCIPgetExprNonlinear(SCIP_CONS *cons)
SCIP_DOMCHG * SCIPnodeGetDomchg(SCIP_NODE *node)
Definition: tree.c:7539
#define DEFAULT_ADDCONFLICTCUTS
#define DEFAULT_ADDSYMRESACKS
internal miscellaneous methods
#define PROP_PRESOL_PRIORITY
#define NULL
Definition: lpi_spx1.cpp:164
#define SCIP_Shortbool
Definition: def.h:101
#define EVENTHDLR_SYMMETRY_NAME
static SCIP_DECL_HASHKEYEQ(SYMhashKeyEQVartype)
SCIP_RETCODE SCIPgetIntParam(SCIP *scip, const char *name, int *value)
Definition: scip_param.c:269
int SCIPdisjointsetFind(SCIP_DISJOINTSET *djset, int element)
Definition: misc.c:11181
#define SCIP_PROPTIMING_ALWAYS
Definition: type_timing.h:73
#define PROP_FREQ
static SCIP_RETCODE addStrongSBCsSubgroup(SCIP *scip, SCIP_PROPDATA *propdata, int *graphcompbegins, int *graphcomponents, int graphcompidx, SCIP_Bool storelexorder, int **lexorder, int *nvarsorder, int *maxnvarsorder)
SCIP_Bool SCIPisExprSum(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1443
#define SCIP_CALL(x)
Definition: def.h:394
#define TABLE_POSITION_ORBITALFIXING
#define DEFAULT_OFSYMCOMPTIMING
SCIP_RETCODE SCIPgetProbvarLinearSum(SCIP *scip, SCIP_VAR **vars, SCIP_Real *scalars, int *nvars, int varssize, SCIP_Real *constant, int *requiredsize, SCIP_Bool mergemultiples)
Definition: scip_var.c:1738
#define SCIP_SPECIALVAL
SCIP_VAR ** SCIPgetVarsOr(SCIP *scip, SCIP_CONS *cons)
Definition: cons_or.c:2232
propagator for symmetry handling
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:225
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8329
static SCIP_RETCODE selectOrbitLeaderSSTConss(SCIP *scip, SCIP_DIGRAPH *conflictgraph, SCIP_VAR **graphvars, int ngraphvars, SCIP_HASHMAP *varmap, SCIP_VAR **permvars, int npermvars, int *orbits, int *orbitbegins, int norbits, int leaderrule, int tiebreakrule, SCIP_VARTYPE leadervartype, int *orbitidx, int *leaderidx, SCIP_Shortbool *orbitvarinconflict, int *norbitvarinconflict, SCIP_Bool useconflictgraph, SCIP_Bool *success)
static SCIP_RETCODE createConflictGraphSST(SCIP *scip, SCIP_DIGRAPH **conflictgraph, SCIP_VAR **graphvars, int ngraphvars, SCIP_Bool onlypermvars, SCIP_HASHMAP *permvarmap, SCIP_Bool *success)
SCIP_RETCODE SCIPcreateDisjointset(SCIP *scip, SCIP_DISJOINTSET **djset, int ncomponents)
SCIP_Real * vals
int SCIPdisjointsetGetComponentCount(SCIP_DISJOINTSET *djset)
Definition: misc.c:11278
static int getNOrbitopesInComp(SCIP_VAR **permvars, int *graphcomponents, int *graphcompbegins, int *compcolorbegins, int ncompcolors, int symcompsize)
SCIP_RETCODE SCIPgetConsVars(SCIP *scip, SCIP_CONS *cons, SCIP_VAR **vars, int varssize, SCIP_Bool *success)
Definition: scip_cons.c:2523
#define TABLE_NAME_ORBITALFIXING
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4597
SCIP_RETCODE SCIPcreateExpriter(SCIP *scip, SCIP_EXPRITER **iterator)
Definition: scip_expr.c:2296
const char * SYMsymmetryGetAddDesc(void)
SCIP_Longint SCIPgetCapacityKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPgetConsCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_CONS *sourcecons, SCIP_CONS **targetcons, SCIP_CONSHDLR *sourceconshdlr, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, const char *name, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode, SCIP_Bool global, SCIP_Bool *valid)
Definition: scip_copy.c:1591
SCIP_VAR * SCIPgetVbdvarVarbound(SCIP *scip, SCIP_CONS *cons)
constraint handler for linking binary variables to a linking (continuous or integer) variable ...
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
SCIP_RETCODE SCIPdigraphAddArcSafe(SCIP_DIGRAPH *digraph, int startnode, int endnode, void *data)
Definition: misc.c:7605
int SCIPdigraphGetNSuccessors(SCIP_DIGRAPH *digraph, int node)
Definition: misc.c:7716
SCIP_VAR * SCIPeventGetVar(SCIP_EVENT *event)
Definition: event.c:1053
SCIP_RETCODE SCIPdetermineNVarsAffectedSym(SCIP *scip, int **perms, int nperms, SCIP_VAR **permvars, int npermvars, int *nvarsaffected)
Definition: symmetry.c:584
#define SCIP_Bool
Definition: def.h:93
static SCIP_RETCODE setSymmetryData(SCIP *scip, SCIP_VAR **vars, int nvars, int nbinvars, SCIP_VAR ***permvars, int *npermvars, int *nbinpermvars, int **perms, int nperms, int *nmovedvars, SCIP_Bool *binvaraffected, SCIP_Bool usecompression, SCIP_Real compressthreshold, SCIP_Bool *compressed)
#define DEFAULT_PREFERLESSROWS
int SCIPgetNImplVars(SCIP *scip)
Definition: scip_prob.c:2127
SCIP_EVENTTYPE SCIPeventGetType(SCIP_EVENT *event)
Definition: event.c:1030
SCIP_BOUNDCHGTYPE SCIPboundchgGetBoundchgtype(SCIP_BOUNDCHG *boundchg)
Definition: var.c:17159
uint32_t SYM_SPEC
Definition: type_symmetry.h:46
int SCIPgetNVarsOr(SCIP *scip, SCIP_CONS *cons)
Definition: cons_or.c:2209
#define DEFAULT_SSTTIEBREAKRULE
SCIP_RETCODE SCIPhashmapRemoveAll(SCIP_HASHMAP *hashmap)
Definition: misc.c:3583
int SCIPgetDepth(SCIP *scip)
Definition: scip_tree.c:670
SCIP_RETCODE SCIPreleaseExpr(SCIP *scip, SCIP_EXPR **expr)
Definition: scip_expr.c:1407
SCIP_SETPPCTYPE SCIPgetTypeSetppc(SCIP *scip, SCIP_CONS *cons)
Definition: cons_setppc.c:9461
constraint handler for nonlinear constraints specified by algebraic expressions
static SCIP_Bool checkSymmetryDataFree(SCIP_PROPDATA *propdata)
SCIP_RETCODE SCIPisInvolutionPerm(int *perm, SCIP_VAR **vars, int nvars, int *ntwocyclesperm, int *nbincyclesperm, SCIP_Bool earlytermination)
Definition: symmetry.c:533
SCIP_RETCODE SCIPprintCons(SCIP *scip, SCIP_CONS *cons, FILE *file)
Definition: scip_cons.c:2482
#define MAX(x, y)
Definition: tclique_def.h:92
SCIP_Bool SYMcanComputeSymmetry(void)
SCIP_VAR * SCIPboundchgGetVar(SCIP_BOUNDCHG *boundchg)
Definition: var.c:17149
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8110
SCIP_BOUNDCHG * SCIPdomchgGetBoundchg(SCIP_DOMCHG *domchg, int pos)
Definition: var.c:17197
SCIP_Real lb
#define DEFAULT_ONLYBINARYSYMMETRY
static SCIP_RETCODE adaptSymmetryDataSST(SCIP *scip, int **origperms, int **modifiedperms, int nperms, SCIP_VAR **origpermvars, SCIP_VAR **modifiedpermvars, int npermvars, int *leaders, int nleaders)
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8289
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8259
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17749
SCIP_RETCODE SCIPdropVarEvent(SCIP *scip, SCIP_VAR *var, SCIP_EVENTTYPE eventtype, SCIP_EVENTHDLR *eventhdlr, SCIP_EVENTDATA *eventdata, int filterpos)
Definition: scip_event.c:400
SCIP_EXPR * SCIPexpriterGetNext(SCIP_EXPRITER *iterator)
Definition: expriter.c:857
SCIP_Real SCIPgetVbdcoefVarbound(SCIP *scip, SCIP_CONS *cons)
SCIP_VARTYPE type
int SCIPgetNRuns(SCIP *scip)
Constraint handler for linear constraints in their most general form, .
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2558
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPgetRhsXor(SCIP *scip, SCIP_CONS *cons)
Definition: cons_xor.c:6025
SCIP_RETCODE SCIPvarGetOrigvarSum(SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: var.c:12764
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:970
#define DEFAULT_MAXGENERATORS
#define PROP_NAME
int SCIPgetNBinVars(SCIP *scip)
Definition: scip_prob.c:2037
int SCIPconshdlrGetNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4631
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:97
const char * SCIPpropGetName(SCIP_PROP *prop)
Definition: prop.c:941
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:636
SCIP_VAR ** SCIPgetVarsSetppc(SCIP *scip, SCIP_CONS *cons)
Definition: cons_setppc.c:9438
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2296
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1992
void SCIPexpriterSetStagesDFS(SCIP_EXPRITER *iterator, SCIP_EXPRITER_STAGE stopstages)
Definition: expriter.c:663
void SCIPfreeExpriter(SCIP_EXPRITER **iterator)
Definition: scip_expr.c:2310
SCIP_VAR ** SCIPgetVarsXor(SCIP *scip, SCIP_CONS *cons)
Definition: cons_xor.c:5979
enum SYM_Rhssense SYM_RHSSENSE
Definition: type_symmetry.h:65
SCIP_RETCODE SCIPcreateConsLinear(SCIP *scip, SCIP_CONS **cons, const char *name, int nvars, SCIP_VAR **vars, SCIP_Real *vals, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
#define COMPRESSNVARSLB
Constraint handler for XOR constraints, .
int SCIPgetNVarsXor(SCIP *scip, SCIP_CONS *cons)
Definition: cons_xor.c:5956
#define DEFAULT_DOUBLEEQUATIONS
SCIP_RETCODE SCIPprintNodeRootPath(SCIP *scip, SCIP_NODE *node, FILE *file)
Definition: scip_tree.c:529
#define DEFAULT_ADDSTRONGSBCS
#define PROP_PRIORITY
#define SYM_HANDLETYPE_ORBITALFIXING
Definition: type_symmetry.h:70
SCIP_RETCODE SCIPsetPropResprop(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPRESPROP((*propresprop)))
Definition: scip_prop.c:312
#define PROP_DELAY
void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition: misc.c:5450
#define PROP_DESC
static const SCIP_Real scalars[]
Definition: lp.c:5743
SCIP_VAR ** SCIPgetVarsLinear(SCIP *scip, SCIP_CONS *cons)
methods for handling symmetries
int SCIPdomchgGetNBoundchgs(SCIP_DOMCHG *domchg)
Definition: var.c:17189
SCIP_RETCODE SCIPgetBinvarsLinking(SCIP *scip, SCIP_CONS *cons, SCIP_VAR ***binvars, int *nbinvars)
const char * SYMsymmetryGetName(void)
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:311
SCIP_VAR * SCIPgetResultantOr(SCIP *scip, SCIP_CONS *cons)
Definition: cons_or.c:2255
int SCIPgetNConss(SCIP *scip)
Definition: scip_prob.c:3042
SCIP_RETCODE SCIPreleaseCons(SCIP *scip, SCIP_CONS **cons)
Definition: scip_cons.c:1119
SCIP_EXPRITER_STAGE SCIPexpriterGetStageDFS(SCIP_EXPRITER *iterator)
Definition: expriter.c:695
SCIP_BOUNDTYPE * SCIPgetBoundtypesBounddisjunction(SCIP *scip, SCIP_CONS *cons)
#define MAXGENNUMERATOR
#define SYM_SPEC_REAL
Definition: type_symmetry.h:44
SCIP_Real SCIPeventGetOldbound(SCIP_EVENT *event)
Definition: event.c:1218
#define ISSYMRETOPESACTIVE(x)
SCIP_VAR * SCIPgetLinkvarLinking(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisExprVar(SCIP *scip, SCIP_EXPR *expr)
Definition: scip_expr.c:1421
SCIP_RETCODE SCIPhashsetInsert(SCIP_HASHSET *hashset, BMS_BLKMEM *blkmem, void *element)
Definition: misc.c:3750
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1947
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1214
#define SCIP_Real
Definition: def.h:186
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8339
#define DEFAULT_SSTLEADERVARTYPE
#define SCIPfreeCleanBufferArray(scip, ptr)
Definition: scip_mem.h:146
struct SCIP_PropData SCIP_PROPDATA
Definition: type_prop.h:52
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:703
#define SYM_COMPUTETIMING_AFTERPRESOL
Definition: type_symmetry.h:51
int SCIPgetNVarsAnd(SCIP *scip, SCIP_CONS *cons)
Definition: cons_and.c:5127
SCIP_TABLEDATA * SCIPtableGetData(SCIP_TABLE *table)
Definition: table.c:288
#define SYM_HANDLETYPE_SST
Definition: type_symmetry.h:71
int SCIPgetNVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8279
#define DEFAULT_SYMFIXNONBINARYVARS
public methods for data structures
#define SCIP_INVALID
Definition: def.h:206
#define DEFAULT_ADDCONSSTIMING
SCIP_RETCODE SCIPsetPropFree(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPFREE((*propfree)))
Definition: scip_prop.c:167
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8269
SCIP_PROPDATA * SCIPpropGetData(SCIP_PROP *prop)
Definition: prop.c:789
#define SCIP_Longint
Definition: def.h:171
const char * SYMsymmetryGetDesc(void)
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17407
SCIP_Bool SCIPhashtableExists(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2609
static SCIP_RETCODE performOrbitalFixing(SCIP *scip, SCIP_VAR **permvars, int npermvars, int *orbits, int *orbitbegins, int norbits, SCIP_Bool *infeasible, int *nfixedzero, int *nfixedone)
static SCIP_RETCODE collectCoefficients(SCIP *scip, SCIP_Bool doubleequations, SCIP_VAR **linvars, SCIP_Real *linvals, int nlinvars, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool istransformed, SYM_RHSSENSE rhssense, SYM_MATRIXDATA *matrixdata, int *nconssforvar)
static SCIP_Bool hasNonlinearConstraints(SCIP_PROPDATA *propdata)
SCIP_RETCODE SCIPincludeExternalCodeInformation(SCIP *scip, const char *name, const char *description)
Definition: scip_general.c:713
SCIP_RETCODE SCIPcreateConsOrbitope(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR ***vars, SCIP_ORBITOPETYPE orbitopetype, int nspcons, int nblocks, SCIP_Bool usedynamicprop, SCIP_Bool mayinteract, SCIP_Bool resolveprop, SCIP_Bool ismodelcons, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Real * SCIPgetValsLinear(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPisLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
enum SCIP_Vartype SCIP_VARTYPE
Definition: type_var.h:73
#define EVENTHDLR_SYMMETRY_DESC
#define PROP_PRESOLTIMING
static SCIP_DECL_SORTINDCOMP(SYMsortRhsTypes)
SCIP_Bool SCIPconsIsConflict(SCIP_CONS *cons)
Definition: cons.c:8239
#define nnodes
Definition: gastrans.c:74
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17967
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:111
static SCIP_RETCODE setSymmetryMethodEnabledValues(SCIP_PROPDATA *propdata)
SCIP_VAR * SCIPgetExprAuxVarNonlinear(SCIP_EXPR *expr)
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:3106
SCIP_Bool SCIPexpriterIsEnd(SCIP_EXPRITER *iterator)
Definition: expriter.c:968
#define SCIP_EVENTTYPE_GUBCHANGED
Definition: type_event.h:76
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3231
SCIP_RETCODE SCIPsetPropInitpre(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPINITPRE((*propinitpre)))
Definition: scip_prop.c:247
constraint handler for bound disjunction constraints
void SCIPfreeDisjointset(SCIP *scip, SCIP_DISJOINTSET **djset)
static SCIP_Bool SymmetryFixVar(SYM_SPEC fixedtype, SCIP_VAR *var)
void SCIPdigraphFree(SCIP_DIGRAPH **digraph)
Definition: misc.c:7480
SCIP_Longint * SCIPgetWeightsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPsetPropExit(SCIP *scip, SCIP_PROP *prop, SCIP_DECL_PROPEXIT((*propexit)))
Definition: scip_prop.c:199
#define SCIPABORT()
Definition: def.h:366
SCIP_Real obj
SCIP_Real * rhscoef
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:17433
SCIP_Real SCIPgetLhsNonlinear(SCIP_CONS *cons)
static SCIP_DECL_PROPEXITPRE(propExitpreSymmetry)
int SCIPgetNVarsLinear(SCIP *scip, SCIP_CONS *cons)
static SCIP_DECL_HASHKEYVAL(SYMhashKeyValVartype)
#define DEFAULT_USECOLUMNSPARSITY
static SCIP_RETCODE tryAddSymmetryHandlingConss(SCIP *scip, SCIP_PROP *prop, int *nchgbds, SCIP_Bool *earlyterm)
#define DEFAULT_DETECTORBITOPES
SCIP_Real SCIPgetLhsLinear(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:139
SCIP_VAR * SCIPgetIntVarXor(SCIP *scip, SCIP_CONS *cons)
Definition: cons_xor.c:6002
static SCIP_RETCODE buildSubgroupGraph(SCIP *scip, SCIP_PROPDATA *propdata, int *genorder, int ntwocycleperms, int compidx, int **graphcomponents, int **graphcompbegins, int **compcolorbegins, int *ngraphcomponents, int *ncompcolors, int **usedperms, int *nusedperms, int usedpermssize, SCIP_Shortbool *permused)
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:57
#define SYM_COMPUTETIMING_DURINGPRESOL
Definition: type_symmetry.h:50
struct SCIP_TableData SCIP_TABLEDATA
Definition: type_table.h:58
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:128
SCIP_RETCODE SCIPincludePropBasic(SCIP *scip, SCIP_PROP **propptr, const char *name, const char *desc, int priority, int freq, SCIP_Bool delay, SCIP_PROPTIMING timingmask, SCIP_DECL_PROPEXEC((*propexec)), SCIP_PROPDATA *propdata)
Definition: scip_prop.c:114
static SCIP_DECL_PROPFREE(propFreeSymmetry)