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