Scippy

SCIP

Solving Constraint Integer Programs

presol_symmetry.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2019 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scip.zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file presol_symmetry.c
17  * @brief presolver for storing symmetry information about current problem
18  * @author Marc Pfetsch
19  * @author Thomas Rehn
20  *
21  * This presolver computes symmetries of the problem and stores this information in adequate form. It does not
22  * perform additional actions. The symmetry information can be accessed through external functions. However, the user
23  * has to declare the type of symmetry that is needed before execution, see SYMsetSpecRequirement().
24  *
25  * @note We treat implict integer variables as if they were continuous/real variables. The reason is that there is
26  * currently no distinction between implicit integer and implicit binary. Moreover, currently implicit integer variables
27  * hurt our code more than continuous/real variables (we basically do not handle integral variables at all).
28  *
29  * @note We do not copy symmetry information, since it is not clear how this information transfers. Moreover, copying
30  * symmetry might inhibit heuristics. But note that solving the a sub-SCIP might then happen without symmetry
31  * information!
32  */
33 
34 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
35 
36 #include <scip/cons_linear.h>
37 #include <scip/cons_knapsack.h>
38 #include <scip/cons_varbound.h>
39 #include <scip/cons_setppc.h>
40 #include <scip/cons_and.h>
41 #include <scip/cons_logicor.h>
42 #include <scip/cons_or.h>
43 #include <scip/cons_xor.h>
44 #include <scip/cons_linking.h>
46 
47 #include <scip/presol_symmetry.h>
49 
50 #include <string.h>
51 
52 /* presolver properties */
53 #define PRESOL_NAME "symmetry"
54 #define PRESOL_DESC "presolver for computing and storing symmetry information about current problem"
55 #define PRESOL_PRIORITY 0 /**< priority of the presolver (>= 0: before, < 0: after constraint handlers) */
56 #define PRESOL_MAXROUNDS -1 /**< maximal number of presolving rounds the presolver participates in (-1: no limit) */
57 #define PRESOL_TIMING SCIP_PRESOLTIMING_EXHAUSTIVE /* timing of the presolver (fast, medium, or exhaustive) */
58 
59 /* default parameter values */
60 #define DEFAULT_MAXGENERATORS 1500 /**< limit on the number of generators that should be produced within symmetry detection (0 = no limit) */
61 #define DEFAULT_CHECKSYMMETRIES FALSE /**< Should all symmetries be checked after computation? */
62 #define DEFAULT_DISPLAYNORBITVARS FALSE /**< Should the number of variables affected by some symmetry be displayed? */
63 
64 /* other defines */
65 #define MAXGENNUMERATOR 64000000 /**< determine maximal number of generators by dividing this number by the number of variables */
66 #define SCIP_SPECIALVAL 1.12345678912345e+19 /**< special floating point value for handling zeros in bound disjunctions */
67 
68 
69 /** presolver data */
70 struct SCIP_PresolData
71 {
72  int maxgenerators; /**< limit on the number of generators that should be produced within symmetry detection (0 = no limit) */
73  SCIP_Bool checksymmetries; /**< Should all symmetries be checked after computation? */
74  SCIP_Bool displaynorbitvars; /**< Whether the number of variables in non-trivial orbits shall be computed */
75  int npermvars; /**< number of variables for permutations */
76  SCIP_VAR** permvars; /**< variables on which permutations act */
77  SCIP_Real* permvarsobj; /**< objective values of permuted variables (for debugging) */
78  int nperms; /**< number of permutations */
79  int nmaxperms; /**< maximal number of permutations (needed for freeing storage) */
80  int** perms; /**< permutation generators as (nperms x npermvars) matrix */
81  SCIP_Real log10groupsize; /**< log10 of size of symmetry group */
82  int norbitvars; /**< number of vars that are contained in a non-trivial orbit */
83  SCIP_Bool binvaraffected; /**< whether binary variables are affected by some symmetry */
84  SCIP_Bool computedsym; /**< Have we already tried to compute symmetries? */
85  SCIP_Bool successful; /**< Was the computation of symmetries successful? */
86  int oldmaxroundsdomcol; /**< original value of parameter presolving/maxrounds/domcol */
87  SCIP_Bool changeddefaultparams; /**< whether default parameters were changed */
88 };
89 
90 
91 /*
92  * local data structures
93  */
94 
95 /* ------------------- map for variable types ------------------- */
96 
97 /** gets the key of the given element */
98 static
99 SCIP_DECL_HASHGETKEY(SYMhashGetKeyVartype)
100 { /*lint --e{715}*/
101  return elem;
102 }
103 
104 /** returns TRUE iff both keys are equal
105  *
106  * Compare the types of two variables according to objective, lower and upper bound, and variable type.
107  */
108 static
109 SCIP_DECL_HASHKEYEQ(SYMhashKeyEQVartype)
110 {
111  SCIP* scip;
112  SYM_VARTYPE* k1;
113  SYM_VARTYPE* k2;
114 
115  scip = (SCIP*) userptr;
116  k1 = (SYM_VARTYPE*) key1;
117  k2 = (SYM_VARTYPE*) key2;
118 
119  /* first check objective coefficients */
120  if ( ! SCIPisEQ(scip, k1->obj, k2->obj) )
121  return FALSE;
122 
123  /* if still undecided, take lower bound */
124  if ( ! SCIPisEQ(scip, k1->lb, k2->lb) )
125  return FALSE;
126 
127  /* if still undecided, take upper bound */
128  if ( ! SCIPisEQ(scip, k1->ub, k2->ub) )
129  return FALSE;
130 
131  /* if still undecided, take variable type */
132  if ( k1->type != k2->type )
133  return FALSE;
134 
135  return TRUE;
136 }
137 
138 /** returns the hash value of the key */
139 static
140 SCIP_DECL_HASHKEYVAL(SYMhashKeyValVartype)
141 { /*lint --e{715}*/
142  SYM_VARTYPE* k;
143 
144  k = (SYM_VARTYPE*) key;
145 
147 }
148 
149 
150 /* ------------------- sorting function for rhs types ------------------- */
151 
152 /** data struct to store arrays used for sorting rhs types */
154 {
155  SCIP_Real* vals; /**< array of values */
156  SYM_RHSSENSE* senses; /**< array of senses of rhs */
157  int nrhscoef; /**< size of arrays (for debugging) */
158 };
160 
161 /** sort rhs types - first by sense, then by value
162  *
163  * Due to numerical issues, we first sort by sense, then by value.
164  *
165  * result:
166  * < 0: ind1 comes before (is better than) ind2
167  * = 0: both indices have the same value
168  * > 0: ind2 comes after (is worse than) ind2
169  */
170 static
171 SCIP_DECL_SORTINDCOMP(SYMsortRhsTypes)
172 {
173  SYM_SORTRHSTYPE* data;
174  SCIP_Real diffvals;
175 
176  data = (SYM_SORTRHSTYPE*) dataptr;
177  assert( 0 <= ind1 && ind1 < data->nrhscoef );
178  assert( 0 <= ind2 && ind2 < data->nrhscoef );
179 
180  /* first sort by senses */
181  if ( data->senses[ind1] < data->senses[ind2] )
182  return -1;
183  else if ( data->senses[ind1] > data->senses[ind2] )
184  return 1;
185 
186  /* senses are equal, use values */
187  diffvals = data->vals[ind1] - data->vals[ind2];
188 
189  if ( diffvals < 0.0 )
190  return -1;
191  else if ( diffvals > 0.0 )
192  return 1;
193 
194  return 0;
195 }
196 
197 /** sort matrix coefficients
198  *
199  * result:
200  * < 0: ind1 comes before (is better than) ind2
201  * = 0: both indices have the same value
202  * > 0: ind2 comes after (is worse than) ind2
203  */
204 static
205 SCIP_DECL_SORTINDCOMP(SYMsortMatCoef)
206 {
207  SCIP_Real diffvals;
208  SCIP_Real* vals;
209 
210  vals = (SCIP_Real*) dataptr;
211  diffvals = vals[ind1] - vals[ind2];
212 
213  if ( diffvals < 0.0 )
214  return -1;
215  else if ( diffvals > 0.0 )
216  return 1;
217 
218  return 0;
219 }
220 
221 
222 /*
223  * Local methods
224  */
225 
226 /** determines whether variable should be fixed by permutations */
227 static
229  SYM_SPEC fixedtype, /**< bitset of variable types that should be fixed */
230  SCIP_VAR* var /**< variable to be considered */
231  )
232 {
233  if ( (fixedtype & SYM_SPEC_INTEGER) && SCIPvarGetType(var) == SCIP_VARTYPE_INTEGER )
234  return TRUE;
235  if ( (fixedtype & SYM_SPEC_BINARY) && SCIPvarGetType(var) == SCIP_VARTYPE_BINARY )
236  return TRUE;
237  if ( (fixedtype & SYM_SPEC_REAL) &&
239  return TRUE;
240  return FALSE;
241 }
242 
243 
244 /** Transforms given variables, scalars, and constant to the corresponding active variables, scalars, and constant.
245  *
246  * @note @p constant needs to be initialized!
247  */
248 static
250  SCIP* scip, /**< SCIP data structure */
251  SCIP_VAR*** vars, /**< pointer to vars array to get active variables for */
252  SCIP_Real** scalars, /**< pointer to scalars a_1, ..., a_n in linear sum a_1*x_1 + ... + a_n*x_n + c */
253  int* nvars, /**< pointer to number of variables and values in vars and vals array */
254  SCIP_Real* constant, /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c */
255  SCIP_Bool transformed /**< transformed constraint? */
256  )
257 {
258  int requiredsize;
259  int v;
260 
261  assert( scip != NULL );
262  assert( vars != NULL );
263  assert( scalars != NULL );
264  assert( *vars != NULL );
265  assert( *scalars != NULL );
266  assert( nvars != NULL );
267  assert( constant != NULL );
268 
269  if ( transformed )
270  {
271  SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *nvars, constant, &requiredsize, TRUE) );
272 
273  if ( requiredsize > *nvars )
274  {
275  SCIP_CALL( SCIPreallocBufferArray(scip, vars, requiredsize) );
276  SCIP_CALL( SCIPreallocBufferArray(scip, scalars, requiredsize) );
277 
278  SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, requiredsize, constant, &requiredsize, TRUE) );
279  assert( requiredsize <= *nvars );
280  }
281  }
282  else
283  {
284  for (v = 0; v < *nvars; ++v)
285  {
286  SCIP_CALL( SCIPvarGetOrigvarSum(&(*vars)[v], &(*scalars)[v], constant) );
287  }
288  }
289  return SCIP_OKAY;
290 }
291 
292 
293 /** fill in matrix elements into coefficient arrays */
294 static
296  SCIP* scip, /**< SCIP data structure */
297  SCIP_VAR** linvars, /**< array of linear variables */
298  SCIP_Real* linvals, /**< array of linear coefficients values (or NULL if all linear coefficient values are 1) */
299  int nlinvars, /**< number of linear variables */
300  SCIP_Real lhs, /**< left hand side */
301  SCIP_Real rhs, /**< right hand side */
302  SCIP_Bool istransformed, /**< whether the constraint is transformed */
303  SYM_RHSSENSE rhssense, /**< identifier of constraint type */
304  SYM_MATRIXDATA* matrixdata /**< matrix data to be filled in */
305  )
306 {
307  SCIP_VAR** vars;
308  SCIP_Real* vals;
309  SCIP_Real constant = 0.0;
310  int nrhscoef;
311  int nmatcoef;
312  int nvars;
313  int j;
314 
315  assert( scip != NULL );
316  assert( nlinvars == 0 || linvars != NULL );
317  assert( lhs <= rhs );
318 
319  /* do nothing if constraint is empty */
320  if ( nlinvars == 0 )
321  return SCIP_OKAY;
322 
323  /* ignore redundant constraints */
324  if ( SCIPisInfinity(scip, -lhs) && SCIPisInfinity(scip, rhs) )
325  return SCIP_OKAY;
326 
327  /* duplicate variable and value array */
328  nvars = nlinvars;
329  SCIP_CALL( SCIPduplicateBufferArray(scip, &vars, linvars, nvars) );
330  if ( linvals != NULL )
331  {
332  SCIP_CALL( SCIPduplicateBufferArray(scip, &vals, linvals, nvars) );
333  }
334  else
335  {
336  SCIP_CALL( SCIPallocBufferArray(scip, &vals, nvars) );
337  for (j = 0; j < nvars; ++j)
338  vals[j] = 1.0;
339  }
340  assert( vars != NULL );
341  assert( vals != NULL );
342 
343  /* get active variables */
344  SCIP_CALL( getActiveVariables(scip, &vars, &vals, &nvars, &constant, istransformed) );
345 
346  /* check whether constraint is empty after transformation to active variables */
347  if ( nvars <= 0 )
348  {
349  SCIPfreeBufferArray(scip, &vals);
350  SCIPfreeBufferArray(scip, &vars);
351  return SCIP_OKAY;
352  }
353 
354  /* handle constant */
355  if ( ! SCIPisInfinity(scip, -lhs) )
356  lhs -= constant;
357  if ( ! SCIPisInfinity(scip, rhs) )
358  rhs -= constant;
359 
360  /* check whether we have to resize; note that we have to add 2 * nvars since two inequalities may be added */
361  if ( matrixdata->nmatcoef + 2 * nvars > matrixdata->nmaxmatcoef )
362  {
363  int newsize;
364 
365  newsize = SCIPcalcMemGrowSize(scip, matrixdata->nmatcoef + 2 * nvars);
366  assert( newsize >= 0 );
367  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(matrixdata->matidx), matrixdata->nmaxmatcoef, newsize) );
368  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(matrixdata->matrhsidx), matrixdata->nmaxmatcoef, newsize) );
369  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(matrixdata->matvaridx), matrixdata->nmaxmatcoef, newsize) );
370  SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &(matrixdata->matcoef), matrixdata->nmaxmatcoef, newsize) );
371  SCIPdebugMsg(scip, "Resized matrix coefficients from %u to %d.\n", matrixdata->nmaxmatcoef, newsize);
372  matrixdata->nmaxmatcoef = newsize;
373  }
374 
375  nrhscoef = matrixdata->nrhscoef;
376  nmatcoef = matrixdata->nmatcoef;
377 
378  /* check lhs/rhs */
379  if ( SCIPisEQ(scip, lhs, rhs) )
380  {
381  assert( ! SCIPisInfinity(scip, rhs) );
382 
383  /* equality constraint */
384  matrixdata->rhscoef[nrhscoef] = rhs;
385 
386  /* if we deal with special constraints */
387  if ( (int) rhssense >= (int) SYM_SENSE_XOR )
388  matrixdata->rhssense[nrhscoef] = rhssense;
389  else
390  matrixdata->rhssense[nrhscoef] = SYM_SENSE_EQUATION;
391  matrixdata->rhsidx[nrhscoef] = nrhscoef;
392 
393  for (j = 0; j < nvars; ++j)
394  {
395  assert( nmatcoef < matrixdata->nmaxmatcoef );
396 
397  matrixdata->matidx[nmatcoef] = nmatcoef;
398  matrixdata->matrhsidx[nmatcoef] = nrhscoef;
399 
400  assert( 0 <= SCIPvarGetProbindex(vars[j]) && SCIPvarGetProbindex(vars[j]) < SCIPgetNVars(scip) );
401 
402  matrixdata->matvaridx[nmatcoef] = SCIPvarGetProbindex(vars[j]);
403  matrixdata->matcoef[nmatcoef++] = vals[j];
404  }
405  nrhscoef++;
406  }
407  else
408  {
409 #ifndef NDEBUG
410  if ( rhssense == SYM_SENSE_BOUNDIS_TYPE_2 )
411  {
412  assert( ! SCIPisInfinity(scip, -lhs) );
413  assert( ! SCIPisInfinity(scip, rhs) );
414  }
415 #endif
416 
417  if ( ! SCIPisInfinity(scip, -lhs) )
418  {
419  matrixdata->rhscoef[nrhscoef] = -lhs;
420  if ( rhssense >= SYM_SENSE_XOR )
421  {
422  assert( rhssense == SYM_SENSE_BOUNDIS_TYPE_2 );
423  matrixdata->rhssense[nrhscoef] = rhssense;
424  }
425  else
426  matrixdata->rhssense[nrhscoef] = SYM_SENSE_INEQUALITY;
427 
428  matrixdata->rhsidx[nrhscoef] = nrhscoef;
429 
430  for (j = 0; j < nvars; ++j)
431  {
432  assert( nmatcoef < matrixdata->nmaxmatcoef );
433  matrixdata->matidx[nmatcoef] = nmatcoef;
434  matrixdata->matrhsidx[nmatcoef] = nrhscoef;
435  matrixdata->matvaridx[nmatcoef] = SCIPvarGetProbindex(vars[j]);
436 
437  assert( 0 <= SCIPvarGetProbindex(vars[j]) && SCIPvarGetProbindex(vars[j]) < SCIPgetNVars(scip) );
438 
439  matrixdata->matcoef[nmatcoef++] = -vals[j];
440  }
441  nrhscoef++;
442  }
443 
444  if ( ! SCIPisInfinity(scip, rhs) )
445  {
446  matrixdata->rhscoef[nrhscoef] = rhs;
447  if ( rhssense >= SYM_SENSE_XOR )
448  {
449  assert( rhssense == SYM_SENSE_BOUNDIS_TYPE_2 );
450  matrixdata->rhssense[nrhscoef] = rhssense;
451  }
452  else
453  matrixdata->rhssense[nrhscoef] = SYM_SENSE_INEQUALITY;
454 
455  matrixdata->rhsidx[nrhscoef] = nrhscoef;
456 
457  for (j = 0; j < nvars; ++j)
458  {
459  assert( nmatcoef < matrixdata->nmaxmatcoef );
460  matrixdata->matidx[nmatcoef] = nmatcoef;
461  matrixdata->matrhsidx[nmatcoef] = nrhscoef;
462 
463  assert( 0 <= SCIPvarGetProbindex(vars[j]) && SCIPvarGetProbindex(vars[j]) < SCIPgetNVars(scip) );
464 
465  matrixdata->matvaridx[nmatcoef] = SCIPvarGetProbindex(vars[j]);
466  matrixdata->matcoef[nmatcoef++] = vals[j];
467  }
468  nrhscoef++;
469  }
470  }
471  matrixdata->nrhscoef = nrhscoef;
472  matrixdata->nmatcoef = nmatcoef;
473 
474  SCIPfreeBufferArray(scip, &vals);
475  SCIPfreeBufferArray(scip, &vars);
476 
477  return SCIP_OKAY;
478 }
479 
480 
481 /** checks whether given permutations form a symmetry of a MIP
482  *
483  * We need the matrix and rhs in the original order in order to speed up the comparison process. The matrix is needed
484  * in the right order to easily check rows. The rhs is used because of cache effects.
485  */
486 static
488  SCIP* scip, /**< SCIP data structure */
489  SYM_SPEC fixedtype, /**< variable types that must be fixed by symmetries */
490  SYM_MATRIXDATA* matrixdata, /**< matrix data */
491  int nperms, /**< number of permutations */
492  int** perms /**< permutations */
493  )
494 {
495  SCIP_Real* permrow = 0;
496  int* rhsmatbeg = 0;
497  int oldrhs;
498  int j;
499  int p;
500 
501  SCIPdebugMsg(scip, "Checking whether symmetries are symmetries (generators: %u).\n", nperms);
502 
503  /* set up dense arrow for permuted row */
504  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &permrow, matrixdata->npermvars) );
505 
506  /* set up map between rows and first entry in matcoef array */
507  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &rhsmatbeg, matrixdata->nrhscoef) );
508  for (j = 0; j < matrixdata->nrhscoef; ++j)
509  rhsmatbeg[j] = -1;
510 
511  /* build map from rhs into matrix */
512  oldrhs = -1;
513  for (j = 0; j < matrixdata->nmatcoef; ++j)
514  {
515  int rhs;
516 
517  rhs = matrixdata->matrhsidx[j];
518  if ( rhs != oldrhs )
519  {
520  assert( 0 <= rhs && rhs < matrixdata->nrhscoef );
521  rhsmatbeg[rhs] = j;
522  oldrhs = rhs;
523  }
524  }
525 
526  /* create row */
527  for (j = 0; j < matrixdata->npermvars; ++j)
528  permrow[j] = 0.0;
529 
530  /* check all generators */
531  for (p = 0; p < nperms; ++p)
532  {
533  int* P;
534  int r1;
535  int r2;
536 
537  SCIPdebugMsg(scip, "Verifying automorphism group generator #%d ...\n", p);
538  P = perms[p];
539  assert( P != NULL );
540 
541  for (j = 0; j < matrixdata->npermvars; ++j)
542  {
543  if ( SymmetryFixVar(fixedtype, matrixdata->permvars[j]) && P[j] != j )
544  {
545  SCIPdebugMsg(scip, "Permutation does not fix types %u, moving variable %d.\n", fixedtype, j);
546  return SCIP_ERROR;
547  }
548  }
549 
550  /* check all constraints == rhs */
551  for (r1 = 0; r1 < matrixdata->nrhscoef; ++r1)
552  {
553  int npermuted = 0;
554 
555  /* fill row into permrow (dense) */
556  j = rhsmatbeg[r1];
557  assert( 0 <= j && j < matrixdata->nmatcoef );
558  assert( matrixdata->matrhsidx[j] == r1 ); /* note: row cannot be empty by construction */
559 
560  /* loop through row */
561  while ( j < matrixdata->nmatcoef && matrixdata->matrhsidx[j] == r1 )
562  {
563  int varidx;
564 
565  assert( matrixdata->matvaridx[j] < matrixdata->npermvars );
566  varidx = P[matrixdata->matvaridx[j]];
567  assert( 0 <= varidx && varidx < matrixdata->npermvars );
568  if ( varidx != matrixdata->matvaridx[j] )
569  ++npermuted;
570  assert( SCIPisZero(scip, permrow[varidx]) );
571  permrow[varidx] = matrixdata->matcoef[j];
572  ++j;
573  }
574 
575  /* if row is not affected by permutation, we do not have to check it */
576  if ( npermuted > 0 )
577  {
578  /* check other rows (sparse) */
579  SCIP_Bool found = FALSE;
580  for (r2 = 0; r2 < matrixdata->nrhscoef; ++r2)
581  {
582  /* a permutation must map constraints of the same type and respect rhs coefficients */
583  if ( matrixdata->rhssense[r1] == matrixdata->rhssense[r2] && SCIPisEQ(scip, matrixdata->rhscoef[r1], matrixdata->rhscoef[r2]) )
584  {
585  j = rhsmatbeg[r2];
586  assert( 0 <= j && j < matrixdata->nmatcoef );
587  assert( matrixdata->matrhsidx[j] == r2 );
588  assert( matrixdata->matvaridx[j] < matrixdata->npermvars );
589 
590  /* loop through row r2 and check whether it is equal to permuted row r */
591  while (j < matrixdata->nmatcoef && matrixdata->matrhsidx[j] == r2 && SCIPisEQ(scip, permrow[matrixdata->matvaridx[j]], matrixdata->matcoef[j]) )
592  ++j;
593 
594  /* check whether rows are completely equal */
595  if ( j >= matrixdata->nmatcoef || matrixdata->matrhsidx[j] != r2 )
596  {
597  /* perm[p] is indeed a symmetry */
598  found = TRUE;
599  break;
600  }
601  }
602  }
603 
604  assert( found );
605  if ( ! found ) /*lint !e774*/
606  {
607  SCIPerrorMessage("Found permutation that is not a symmetry.\n");
608  return SCIP_ERROR;
609  }
610  }
611 
612  /* reset permrow */
613  j = rhsmatbeg[r1];
614  while ( j < matrixdata->nmatcoef && matrixdata->matrhsidx[j] == r1 )
615  {
616  int varidx;
617  varidx = P[matrixdata->matvaridx[j]];
618  permrow[varidx] = 0.0;
619  ++j;
620  }
621  }
622  }
623 
624  SCIPfreeBlockMemoryArray(scip, &rhsmatbeg, matrixdata->nrhscoef);
625  SCIPfreeBlockMemoryArray(scip, &permrow, matrixdata->npermvars);
626 
627  return SCIP_OKAY;
628 }
629 
630 
631 /** returns the number of active constraints that can be handled by symmetry */
632 static
634  SCIP* scip /**< SCIP instance */
635  )
636 {
637  SCIP_CONSHDLR* conshdlr;
638  int nhandleconss = 0;
639 
640  assert( scip != NULL );
641 
642  conshdlr = SCIPfindConshdlr(scip, "linear");
643  nhandleconss += SCIPconshdlrGetNActiveConss(conshdlr);
644  conshdlr = SCIPfindConshdlr(scip, "linking");
645  nhandleconss += SCIPconshdlrGetNActiveConss(conshdlr);
646  conshdlr = SCIPfindConshdlr(scip, "setppc");
647  nhandleconss += SCIPconshdlrGetNActiveConss(conshdlr);
648  conshdlr = SCIPfindConshdlr(scip, "xor");
649  nhandleconss += SCIPconshdlrGetNActiveConss(conshdlr);
650  conshdlr = SCIPfindConshdlr(scip, "and");
651  nhandleconss += SCIPconshdlrGetNActiveConss(conshdlr);
652  conshdlr = SCIPfindConshdlr(scip, "or");
653  nhandleconss += SCIPconshdlrGetNActiveConss(conshdlr);
654  conshdlr = SCIPfindConshdlr(scip, "logicor");
655  nhandleconss += SCIPconshdlrGetNActiveConss(conshdlr);
656  conshdlr = SCIPfindConshdlr(scip, "knapsack");
657  nhandleconss += SCIPconshdlrGetNActiveConss(conshdlr);
658  conshdlr = SCIPfindConshdlr(scip, "varbound");
659  nhandleconss += SCIPconshdlrGetNActiveConss(conshdlr);
660  conshdlr = SCIPfindConshdlr(scip, "bounddisjunction");
661  nhandleconss += SCIPconshdlrGetNActiveConss(conshdlr);
662 
663  return nhandleconss;
664 }
665 
666 
667 /** compute symmetry group of MIP */
668 static
670  SCIP* scip, /**< SCIP pointer */
671  int maxgenerators, /**< maximal number of generators constructed (= 0 if unlimited) */
672  SYM_SPEC fixedtype, /**< variable types that must be fixed by symmetries */
673  SCIP_Bool local, /**< Use local variable bounds? */
674  SCIP_Bool checksymmetries, /**< Should all symmetries be checked after computation? */
675  int* npermvars, /**< pointer to store number of variables for permutations */
676  SCIP_VAR*** permvars, /**< pointer to store variables on which permutations act */
677  SCIP_Real** permvarsobj, /**< objective values of permuted variables */
678  int* nperms, /**< pointer to store number of permutations */
679  int* nmaxperms, /**< pointer to store maximal number of permutations (needed for freeing storage) */
680  int*** perms, /**< pointer to store permutation generators as (nperms x npermvars) matrix */
681  SCIP_Real* log10groupsize, /**< pointer to store log10 of size of group */
682  SCIP_Bool* success /**< pointer to store whether symmetry computation was successful */
683  )
684 {
685  SCIP_CONSHDLR* conshdlr;
686  SYM_MATRIXDATA matrixdata;
687  SCIP_HASHTABLE* vartypemap;
688  SCIP_VAR** consvars;
689  SCIP_Real* consvals;
690  SCIP_CONS** conss;
691  SCIP_VAR** vars;
692  SYM_VARTYPE* uniquevararray;
693  SYM_RHSSENSE oldsense = SYM_SENSE_UNKOWN;
694  SYM_SORTRHSTYPE sortrhstype;
695  SCIP_Real oldcoef = SCIP_INVALID;
696  SCIP_Real val;
697  int nuniquevararray = 0;
698  int nhandleconss;
699  int nactiveconss;
700  int nconss;
701  int nvars;
702  int nallvars;
703  int c;
704  int j;
705 
706  assert( scip != NULL );
707  assert( npermvars != NULL );
708  assert( permvars != NULL );
709  assert( permvarsobj != NULL );
710  assert( nperms != NULL );
711  assert( nmaxperms != NULL );
712  assert( perms != NULL );
713  assert( log10groupsize != NULL );
714  assert( success != NULL );
715 
716  /* init */
717  *npermvars = 0;
718  *permvars = NULL;
719  *permvarsobj = NULL;
720  *nperms = 0;
721  *nmaxperms = 0;
722  *perms = NULL;
723  *log10groupsize = 0;
724  *success = FALSE;
725 
726  /* skip if no symmetry can be computed */
727  if ( ! SYMcanComputeSymmetry() )
728  return SCIP_OKAY;
729 
730  nconss = SCIPgetNConss(scip);
731  nvars = SCIPgetNVars(scip);
732 
733  /* exit if no constraints or no variables are available */
734  if ( nconss == 0 || nvars == 0 )
735  {
736  *success = TRUE;
737  return SCIP_OKAY;
738  }
739 
740  conss = SCIPgetConss(scip);
741  assert( conss != NULL );
742 
743  /* compute the number of active constraints */
744  nactiveconss = SCIPgetNActiveConss(scip);
745 
746  /* exit if no active constraints are available */
747  if ( nactiveconss == 0 )
748  {
749  *success = TRUE;
750  return SCIP_OKAY;
751  }
752 
753  /* before we set up the matrix, check whether we can handle all constraints */
754  nhandleconss = getNSymhandableConss(scip);
755  assert( nhandleconss <= nactiveconss );
756  if ( nhandleconss < nactiveconss )
757  {
758  /* In this case we found unkown constraints and we exit, since we cannot handle them. */
759  *success = FALSE;
760  return SCIP_OKAY;
761  }
762 
763  SCIPdebugMsg(scip, "Detecting %ssymmetry on %d variables and %d constraints.\n", local ? "local " : "", nvars, nactiveconss);
764 
765  /* copy variables */
766  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &vars, SCIPgetVars(scip), nvars) ); /*lint !e666*/
767  assert( vars != NULL );
768 
769  /* fill matrixdata */
770  matrixdata.nmaxmatcoef = 100 * nvars;
771  matrixdata.nmatcoef = 0;
772  matrixdata.nrhscoef = 0;
773  matrixdata.nuniquemat = 0;
774  matrixdata.nuniquevars = 0;
775  matrixdata.nuniquerhs = 0;
776  matrixdata.npermvars = nvars;
777  matrixdata.permvars = vars;
778  matrixdata.permvarcolors = NULL;
779  matrixdata.matcoefcolors = NULL;
780  matrixdata.rhscoefcolors = NULL;
781 
782  /* prepare matrix data (use block memory, since this can become large) */
783  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &matrixdata.matcoef, matrixdata.nmaxmatcoef) );
784  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &matrixdata.matidx, matrixdata.nmaxmatcoef) );
785  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &matrixdata.matrhsidx, matrixdata.nmaxmatcoef) );
786  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &matrixdata.matvaridx, matrixdata.nmaxmatcoef) );
787  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &matrixdata.rhscoef, 2 * nactiveconss) );
788  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &matrixdata.rhssense, 2 * nactiveconss) );
789  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &matrixdata.rhsidx, 2 * nactiveconss) );
790 
791  /* prepare temporary constraint data (use block memory, since this can become large);
792  * also allocate memory for fixed vars since some vars might have been deactivated meanwhile */
793  nallvars = nvars + SCIPgetNFixedVars(scip);
794  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consvars, nallvars) );
795  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consvals, nallvars) );
796 
797  /* loop through all constraints */
798  for (c = 0; c < nconss; ++c)
799  {
800  const char* conshdlrname;
801  SCIP_CONS* cons;
802  SCIP_VAR** linvars;
803  int nconsvars;
804 
805  /* get constraint */
806  cons = conss[c];
807  assert( cons != NULL );
808 
809  /* skip non-active constraints */
810  if ( ! SCIPconsIsActive(cons) )
811  continue;
812 
813  /* Skip conflict constraints if we are late in the solving process */
814  if ( SCIPgetStage(scip) == SCIP_STAGE_SOLVING && SCIPconsIsConflict(cons) )
815  continue;
816 
817  /* get constraint handler */
818  conshdlr = SCIPconsGetHdlr(cons);
819  assert( conshdlr != NULL );
820 
821  conshdlrname = SCIPconshdlrGetName(conshdlr);
822  assert( conshdlrname != NULL );
823 
824  /* check type of constraint */
825  if ( strcmp(conshdlrname, "linear") == 0 )
826  {
827  SCIP_CALL( collectCoefficients(scip, SCIPgetVarsLinear(scip, cons), SCIPgetValsLinear(scip, cons),
828  SCIPgetNVarsLinear(scip, cons), SCIPgetLhsLinear(scip, cons), SCIPgetRhsLinear(scip, cons),
829  SCIPconsIsTransformed(cons), SYM_SENSE_UNKOWN, &matrixdata) );
830  }
831  else if ( strcmp(conshdlrname, "linking") == 0 )
832  {
833  SCIP_VAR** curconsvars;
834  int* curconsvals;
835  int i;
836 
837  /* get constraint variables and their amount */
838  curconsvals = SCIPgetValsLinking(scip, cons);
839  SCIP_CALL( SCIPgetBinvarsLinking(scip, cons, &curconsvars, &nconsvars) );
840  /* SCIPgetBinVarsLinking returns the number of binary variables, but we also need the integer variable */
841  nconsvars++;
842 
843  /* copy vars and vals for binary variables */
844  for( i = 0; i < nconsvars - 1; i++ )
845  {
846  consvars[i] = curconsvars[i];
847  consvals[i] = (SCIP_Real) curconsvals[i];
848  }
849 
850  /* set final entry of vars and vals to the linking variable and its coefficient, respectively */
851  consvars[nconsvars - 1] = SCIPgetIntvarLinking(scip, cons);
852  consvals[nconsvars - 1] = -1;
853 
854  SCIP_CALL( collectCoefficients(scip, consvars, consvals, nconsvars, 0.0, 0.0,
855  SCIPconsIsTransformed(cons), SYM_SENSE_UNKOWN, &matrixdata) );
856  SCIP_CALL( collectCoefficients(scip, consvars, NULL, nconsvars - 1, 1.0, 1.0,
857  SCIPconsIsTransformed(cons), SYM_SENSE_UNKOWN, &matrixdata) );
858  }
859  else if ( strcmp(conshdlrname, "setppc") == 0 )
860  {
861  linvars = SCIPgetVarsSetppc(scip, cons);
862  nconsvars = SCIPgetNVarsSetppc(scip, cons);
863 
864  switch ( SCIPgetTypeSetppc(scip, cons) )
865  {
867  SCIP_CALL( collectCoefficients(scip, linvars, 0, nconsvars, 1.0, 1.0, SCIPconsIsTransformed(cons), SYM_SENSE_EQUATION, &matrixdata) );
868  break;
870  SCIP_CALL( collectCoefficients(scip, linvars, 0, nconsvars, -SCIPinfinity(scip), 1.0, SCIPconsIsTransformed(cons), SYM_SENSE_INEQUALITY, &matrixdata) );
871  break;
873  SCIP_CALL( collectCoefficients(scip, linvars, 0, nconsvars, 1.0, SCIPinfinity(scip), SCIPconsIsTransformed(cons), SYM_SENSE_INEQUALITY, &matrixdata) );
874  break;
875  default:
876  SCIPerrorMessage("Unknown setppc type %d.\n", SCIPgetTypeSetppc(scip, cons));
877  return SCIP_ERROR;
878  }
879  }
880  else if ( strcmp(conshdlrname, "xor") == 0 )
881  {
882  SCIP_VAR** curconsvars;
883  SCIP_VAR* var;
884 
885  /* get number of variables of XOR constraint (without integer variable) */
886  nconsvars = SCIPgetNVarsXor(scip, cons);
887 
888  /* get variables of XOR constraint */
889  curconsvars = SCIPgetVarsXor(scip, cons);
890  for (j = 0; j < nconsvars; ++j)
891  {
892  assert( curconsvars[j] != NULL );
893  consvars[j] = curconsvars[j];
894  consvals[j] = 1.0;
895  }
896 
897  /* intVar of xor constraint might have been removed */
898  var = SCIPgetIntVarXor(scip, cons);
899  if ( var != NULL )
900  {
901  consvars[nconsvars] = var;
902  consvals[nconsvars++] = 2.0;
903  }
904  assert( nconsvars <= nallvars );
905 
906  SCIP_CALL( collectCoefficients(scip, consvars, consvals, nconsvars, (SCIP_Real) SCIPgetRhsXor(scip, cons),
907  (SCIP_Real) SCIPgetRhsXor(scip, cons), SCIPconsIsTransformed(cons), SYM_SENSE_XOR, &matrixdata) );
908  }
909  else if ( strcmp(conshdlrname, "and") == 0 )
910  {
911  SCIP_VAR** curconsvars;
912 
913  /* get number of variables of AND constraint (without resultant) */
914  nconsvars = SCIPgetNVarsAnd(scip, cons);
915 
916  /* get variables of AND constraint */
917  curconsvars = SCIPgetVarsAnd(scip, cons);
918 
919  for (j = 0; j < nconsvars; ++j)
920  {
921  assert( curconsvars[j] != NULL );
922  consvars[j] = curconsvars[j];
923  consvals[j] = 1.0;
924  }
925 
926  assert( SCIPgetResultantAnd(scip, cons) != NULL );
927  consvars[nconsvars] = SCIPgetResultantAnd(scip, cons);
928  consvals[nconsvars++] = 2.0;
929  assert( nconsvars <= nallvars );
930 
931  SCIP_CALL( collectCoefficients(scip, consvars, consvals, nconsvars, 0.0, 0.0,
932  SCIPconsIsTransformed(cons), SYM_SENSE_AND, &matrixdata) );
933  }
934  else if ( strcmp(conshdlrname, "or") == 0 )
935  {
936  SCIP_VAR** curconsvars;
937 
938  /* get number of variables of OR constraint (without resultant) */
939  nconsvars = SCIPgetNVarsOr(scip, cons);
940 
941  /* get variables of OR constraint */
942  curconsvars = SCIPgetVarsOr(scip, cons);
943 
944  for (j = 0; j < nconsvars; ++j)
945  {
946  assert( curconsvars[j] != NULL );
947  consvars[j] = curconsvars[j];
948  consvals[j] = 1.0;
949  }
950 
951  assert( SCIPgetResultantOr(scip, cons) != NULL );
952  consvars[nconsvars] = SCIPgetResultantOr(scip, cons);
953  consvals[nconsvars++] = 2.0;
954  assert( nconsvars <= nallvars );
955 
956  SCIP_CALL( collectCoefficients(scip, consvars, consvals, nconsvars, 0.0, 0.0,
957  SCIPconsIsTransformed(cons), SYM_SENSE_OR, &matrixdata) );
958  }
959  else if ( strcmp(conshdlrname, "logicor") == 0 )
960  {
961  SCIP_CALL( collectCoefficients(scip, SCIPgetVarsLogicor(scip, cons), 0, SCIPgetNVarsLogicor(scip, cons),
962  1.0, SCIPinfinity(scip), SCIPconsIsTransformed(cons), SYM_SENSE_INEQUALITY, &matrixdata) );
963  }
964  else if ( strcmp(conshdlrname, "knapsack") == 0 )
965  {
966  SCIP_Longint* weights;
967 
968  nconsvars = SCIPgetNVarsKnapsack(scip, cons);
969 
970  /* copy Longint array to SCIP_Real array and get active variables of constraint */
971  weights = SCIPgetWeightsKnapsack(scip, cons);
972  for (j = 0; j < nconsvars; ++j)
973  consvals[j] = (SCIP_Real) weights[j];
974  assert( nconsvars <= nallvars );
975 
976  SCIP_CALL( collectCoefficients(scip, SCIPgetVarsKnapsack(scip, cons), consvals, nconsvars, -SCIPinfinity(scip),
977  (SCIP_Real) SCIPgetCapacityKnapsack(scip, cons), SCIPconsIsTransformed(cons), SYM_SENSE_INEQUALITY, &matrixdata) );
978  }
979  else if ( strcmp(conshdlrname, "varbound") == 0 )
980  {
981  consvars[0] = SCIPgetVarVarbound(scip, cons);
982  consvals[0] = 1.0;
983 
984  consvars[1] = SCIPgetVbdvarVarbound(scip, cons);
985  consvals[1] = SCIPgetVbdcoefVarbound(scip, cons);
986 
987  SCIP_CALL( collectCoefficients(scip, consvars, consvals, 2, SCIPgetLhsVarbound(scip, cons),
988  SCIPgetRhsVarbound(scip, cons), SCIPconsIsTransformed(cons), SYM_SENSE_INEQUALITY, &matrixdata) );
989  }
990  else if ( strcmp(conshdlrname, "bounddisjunction") == 0 )
991  {
992  /* To model bound disjunctions, we normalize each constraint
993  * \f[
994  * (x_1 \{\leq,\geq\} b_1) \vee \ldots \vee (x_n \{\leq,\geq\} b_n)
995  * \f]
996  * to a constraint of type
997  * \f[
998  * (x_1 \leq b'_1 \vee \ldots \vee (x_n \leq b'_n).
999  * \f]
1000  *
1001  * If no variable appears twice in such a normalized constraint, we say this bound disjunction
1002  * is of type 1. If the bound disjunction has length two and both disjunctions contain the same variable,
1003  * we say the bound disjunction is of type 2. Further bound disjunctions are possible, but can currently
1004  * not be handled.
1005  *
1006  * Bound disjunctions of type 1 are modeled as the linear constraint
1007  * \f[
1008  * b'_1 \cdot x_1 + \ldots + b'_n \cdot x_n = 0
1009  * \f]
1010  * and bound disjunctions of type 2 are modeled as the linear constraint
1011  * \f[
1012  * \min\{b'_1, b'_2\} \leq x_1 \leq \max\{b'_1, b'_2\}.
1013  * \f]
1014  * Note that problems arise if \fb'_i = 0\f for some variable \fx_i\f, because its coefficient in the
1015  * linear constraint is 0. To avoid this, we replace 0 by a special number.
1016  */
1017  SCIP_VAR** bounddisjvars;
1018  SCIP_BOUNDTYPE* boundtypes;
1019  SCIP_Real* bounds;
1020  SCIP_Bool repetition = FALSE;
1021  int nbounddisjvars;
1022  int k;
1023 
1024  /* collect coefficients for normalized constraint */
1025  nbounddisjvars = SCIPgetNVarsBounddisjunction(scip, cons);
1026  bounddisjvars = SCIPgetVarsBounddisjunction(scip, cons);
1027  boundtypes = SCIPgetBoundtypesBounddisjunction(scip, cons);
1028  bounds = SCIPgetBoundsBounddisjunction(scip, cons);
1029 
1030  /* copy data */
1031  for (j = 0; j < nbounddisjvars; ++j)
1032  {
1033  consvars[j] = bounddisjvars[j];
1034 
1035  /* normalize bounddisjunctions to SCIP_BOUNDTYPE_LOWER */
1036  if ( boundtypes[j] == SCIP_BOUNDTYPE_LOWER )
1037  consvals[j] = - bounds[j];
1038  else
1039  consvals[j] = bounds[j];
1040 
1041  /* special treatment of 0 values */
1042  if ( SCIPisZero(scip, consvals[j]) )
1043  consvals[j] = SCIP_SPECIALVAL;
1044 
1045  /* detect whether a variable appears in two literals */
1046  for (k = 0; k < j && ! repetition; ++k)
1047  {
1048  if ( consvars[j] == consvars[k] )
1049  repetition = TRUE;
1050  }
1051 
1052  /* stop, we cannot handle bounddisjunctions with more than two variables that contain a variable twice */
1053  if ( repetition && nbounddisjvars > 2 )
1054  {
1055  *success = FALSE;
1056 
1058  " Deactivated symmetry handling methods, there exist constraints that cannot be handled by symmetry methods.\n");
1059 
1060  SCIPfreeBlockMemoryArrayNull(scip, &consvals, nallvars);
1061  SCIPfreeBlockMemoryArrayNull(scip, &consvars, nallvars);
1062  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.rhsidx, 2 * nactiveconss);
1063  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.rhssense, 2 * nactiveconss);
1064  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.rhscoef, 2 * nactiveconss);
1065  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matvaridx, matrixdata.nmaxmatcoef);
1066  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matrhsidx, matrixdata.nmaxmatcoef);
1067  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matidx, matrixdata.nmaxmatcoef);
1068  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matcoef, matrixdata.nmaxmatcoef);
1069  SCIPfreeBlockMemoryArrayNull(scip, &vars, nvars);
1070 
1071  return SCIP_OKAY;
1072  }
1073  }
1074  assert( ! repetition || nbounddisjvars == 2 );
1075 
1076  /* if no variable appears twice */
1077  if ( ! repetition )
1078  {
1079  /* add information for bounddisjunction of type 1 */
1080  SCIP_CALL( collectCoefficients(scip, consvars, consvals, nbounddisjvars, 0.0, 0.0,
1081  SCIPconsIsTransformed(cons), SYM_SENSE_BOUNDIS_TYPE_1, &matrixdata) );
1082  }
1083  else
1084  {
1085  /* add information for bounddisjunction of type 2 */
1086  SCIP_Real lhs;
1087  SCIP_Real rhs;
1088 
1089  lhs = MIN(consvals[0], consvals[1]);
1090  rhs = MAX(consvals[0], consvals[1]);
1091 
1092  consvals[0] = 1.0;
1093 
1094  SCIP_CALL( collectCoefficients(scip, consvars, consvals, 1, lhs, rhs,
1095  SCIPconsIsTransformed(cons), SYM_SENSE_BOUNDIS_TYPE_2, &matrixdata) );
1096  }
1097  }
1098  else
1099  {
1100  SCIPerrorMessage("Cannot determine symmetries for constraint <%s> of constraint handler <%s>.\n",
1101  SCIPconsGetName(cons), SCIPconshdlrGetName(conshdlr) );
1102  return SCIP_ERROR;
1103  }
1104  }
1105  assert( matrixdata.nrhscoef <= 2 * nactiveconss );
1106  assert( matrixdata.nrhscoef > 0 ); /* cannot have empty rows! */
1107 
1108  SCIPfreeBlockMemoryArray(scip, &consvals, nallvars);
1109  SCIPfreeBlockMemoryArray(scip, &consvars, nallvars);
1110 
1111  /* sort matrix coefficients (leave matrix array intact) */
1112  SCIPsort(matrixdata.matidx, SYMsortMatCoef, (void*) matrixdata.matcoef, matrixdata.nmatcoef);
1113 
1114  /* sort rhs types (first by sense, then by value, leave rhscoef intact) */
1115  sortrhstype.vals = matrixdata.rhscoef;
1116  sortrhstype.senses = matrixdata.rhssense;
1117  sortrhstype.nrhscoef = matrixdata.nrhscoef;
1118  SCIPsort(matrixdata.rhsidx, SYMsortRhsTypes, (void*) &sortrhstype, matrixdata.nrhscoef);
1119 
1120  /* create map for variables to indices */
1121  SCIP_CALL( SCIPhashtableCreate(&vartypemap, SCIPblkmem(scip), 5 * nvars, SYMhashGetKeyVartype, SYMhashKeyEQVartype, SYMhashKeyValVartype, (void*) scip) );
1122  assert( vartypemap != NULL );
1123 
1124  /* allocate space for mappings to colors */
1125  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &matrixdata.permvarcolors, nvars) );
1126  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &matrixdata.matcoefcolors, matrixdata.nmatcoef) );
1127  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &matrixdata.rhscoefcolors, matrixdata.nrhscoef) );
1128  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &uniquevararray, nvars) );
1129 
1130  /* determine number of different coefficents */
1131 
1132  /* find non-equivalent variables: same objective, lower and upper bounds, and variable type */
1133  for (j = 0; j < nvars; ++j)
1134  {
1135  SCIP_VAR* var;
1136 
1137  var = vars[j];
1138  assert( var != NULL );
1139 
1140  /* if the variable type should be fixed just increase the color */
1141  if ( SymmetryFixVar(fixedtype, var) )
1142  {
1143  matrixdata.permvarcolors[j] = matrixdata.nuniquevars++;
1144 #ifdef SCIP_OUTPUT
1145  SCIPdebugMsg(scip, "Detected variable <%s> of fixed type %d - color %d.\n", SCIPvarGetName(var), SCIPvarGetType(var), matrixdata.nuniquevars - 1);
1146 #endif
1147  }
1148  else
1149  {
1150  SYM_VARTYPE* vt;
1151 
1152  vt = &uniquevararray[nuniquevararray];
1153  assert( nuniquevararray <= matrixdata.nuniquevars );
1154 
1155  vt->obj = SCIPvarGetObj(var);
1156  if ( local )
1157  {
1158  vt->lb = SCIPvarGetLbLocal(var);
1159  vt->ub = SCIPvarGetUbLocal(var);
1160  }
1161  else
1162  {
1163  vt->lb = SCIPvarGetLbGlobal(var);
1164  vt->ub = SCIPvarGetUbGlobal(var);
1165  }
1166  vt->type = SCIPvarGetType(var);
1167 
1168  if ( ! SCIPhashtableExists(vartypemap, (void*) vt) )
1169  {
1170  SCIP_CALL( SCIPhashtableInsert(vartypemap, (void*) vt) );
1171  vt->color = matrixdata.nuniquevars;
1172  matrixdata.permvarcolors[j] = matrixdata.nuniquevars++;
1173  ++nuniquevararray;
1174 #ifdef SCIP_OUTPUT
1175  SCIPdebugMsg(scip, "Detected variable <%s> of new type (probindex: %d, obj: %g, lb: %g, ub: %g, type: %d) - color %d.\n",
1176  SCIPvarGetName(var), SCIPvarGetProbindex(var), vt->obj, vt->lb, vt->ub, vt->type, matrixdata.nuniquevars - 1);
1177 #endif
1178  }
1179  else
1180  {
1181  SYM_VARTYPE* vtr;
1182 
1183  vtr = (SYM_VARTYPE*) SCIPhashtableRetrieve(vartypemap, (void*) vt);
1184  matrixdata.permvarcolors[j] = vtr->color;
1185  }
1186  }
1187  }
1188 
1189  /* find non-equivalent matrix entries (use sorting to avoid too many map calls) */
1190  for (j = 0; j < matrixdata.nmatcoef; ++j)
1191  {
1192  int idx;
1193 
1194  idx = matrixdata.matidx[j];
1195  assert( 0 <= idx && idx < matrixdata.nmatcoef );
1196 
1197  val = matrixdata.matcoef[idx];
1198  assert( oldcoef == SCIP_INVALID || oldcoef <= val ); /*lint !e777*/
1199 
1200  if ( ! SCIPisEQ(scip, val, oldcoef) )
1201  {
1202 #ifdef SCIP_OUTPUT
1203  SCIPdebugMsg(scip, "Detected new matrix entry type %f - color: %d\n.", val, matrixdata.nuniquemat);
1204 #endif
1205  matrixdata.matcoefcolors[idx] = matrixdata.nuniquemat++;
1206  oldcoef = val;
1207  }
1208  else
1209  {
1210  assert( matrixdata.nuniquemat > 0 );
1211  matrixdata.matcoefcolors[idx] = matrixdata.nuniquemat - 1;
1212  }
1213  }
1214 
1215  /* find non-equivalent rhs */
1216  oldcoef = SCIP_INVALID;
1217  for (j = 0; j < matrixdata.nrhscoef; ++j)
1218  {
1219  SYM_RHSSENSE sense;
1220  int idx;
1221 
1222  idx = matrixdata.rhsidx[j];
1223  assert( 0 <= idx && idx < matrixdata.nrhscoef );
1224  sense = matrixdata.rhssense[idx];
1225  val = matrixdata.rhscoef[idx];
1226 
1227  /* make sure that new senses are treated with new color */
1228  if ( sense != oldsense )
1229  oldcoef = SCIP_INVALID;
1230  oldsense = sense;
1231  assert( oldcoef == SCIP_INVALID || oldcoef <= val ); /*lint !e777*/
1232 
1233  /* assign new color to new type */
1234  if ( ! SCIPisEQ(scip, val, oldcoef) )
1235  {
1236 #ifdef SCIP_OUTPUT
1237  SCIPdebugMsg(scip, "Detected new rhs type %f, type: %u - color: %d\n", val, sense, matrixdata.nuniquerhs);
1238 #endif
1239  matrixdata.rhscoefcolors[idx] = matrixdata.nuniquerhs++;
1240  oldcoef = val;
1241  }
1242  else
1243  {
1244  assert( matrixdata.nuniquerhs > 0 );
1245  matrixdata.rhscoefcolors[idx] = matrixdata.nuniquerhs - 1;
1246  }
1247  }
1248  assert( 0 < matrixdata.nuniquevars && matrixdata.nuniquevars <= nvars );
1249  assert( 0 < matrixdata.nuniquerhs && matrixdata.nuniquerhs <= matrixdata.nrhscoef );
1250  assert( 0 < matrixdata.nuniquemat && matrixdata.nuniquemat <= matrixdata.nmatcoef );
1251 
1252  SCIPdebugMsg(scip, "Number of detected different variables: %d (total: %d).\n", matrixdata.nuniquevars, nvars);
1253  SCIPdebugMsg(scip, "Number of detected different rhs types: %d (total: %d).\n", matrixdata.nuniquerhs, matrixdata.nrhscoef);
1254  SCIPdebugMsg(scip, "Number of detected different matrix coefficients: %d (total: %d).\n", matrixdata.nuniquemat, matrixdata.nmatcoef);
1255 
1256  /* do not compute symmetry if all variables are non-equivalent (unique) or if all matrix coefficients are different */
1257  if ( matrixdata.nuniquevars < nvars && matrixdata.nuniquemat < matrixdata.nmatcoef )
1258  {
1259  /* determine generators */
1260  SCIP_CALL( SYMcomputeSymmetryGenerators(scip, maxgenerators, &matrixdata, nperms, nmaxperms, perms, log10groupsize) );
1261 
1262  /* SCIPisStopped() might call SCIPgetGap() which is only available after initpresolve */
1263  if ( checksymmetries && SCIPgetStage(scip) > SCIP_STAGE_INITPRESOLVE && ! SCIPisStopped(scip) )
1264  {
1265  SCIP_CALL( checkSymmetriesAreSymmetries(scip, fixedtype, &matrixdata, *nperms, *perms) );
1266  }
1267  }
1268  *success = TRUE;
1269 
1270  /* free matrix data */
1271  SCIPfreeBlockMemoryArray(scip, &uniquevararray, nvars);
1272 
1273  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.rhscoefcolors, matrixdata.nrhscoef);
1274  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matcoefcolors, matrixdata.nmatcoef);
1275  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.permvarcolors, nvars);
1276  SCIPhashtableFree(&vartypemap);
1277 
1278  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.rhsidx, 2 * nactiveconss);
1279  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.rhssense, 2 * nactiveconss);
1280  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.rhscoef, 2 * nactiveconss);
1281  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matvaridx, matrixdata.nmaxmatcoef);
1282  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matrhsidx, matrixdata.nmaxmatcoef);
1283  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matidx, matrixdata.nmaxmatcoef);
1284  SCIPfreeBlockMemoryArrayNull(scip, &matrixdata.matcoef, matrixdata.nmaxmatcoef);
1285 
1286  /* copy variables */
1287  *permvars = vars;
1288  *npermvars = nvars;
1289 
1290  /* symmetric variables are not allowed to be multi-aggregated */
1291  for (j = 0; j < nvars; ++j)
1292  {
1293  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, vars[j]) );
1294  }
1295 
1296 #ifndef NDEBUG
1297  SCIP_CALL( SCIPallocBlockMemoryArray(scip, permvarsobj, nvars) );
1298  for (j = 0; j < nvars; ++j)
1299  (*permvarsobj)[j] = SCIPvarGetObj(vars[j]);
1300 #endif
1301 
1302  return SCIP_OKAY;
1303 }
1304 
1305 
1306 /* compute number of variables that are contained in a non-trivial orbit */
1307 static
1309  SCIP* scip, /**< SCIP instance */
1310  SCIP_PRESOLDATA* presoldata, /**< presolver data */
1311  SCIP_Bool completestatistic /**< whether a complete statistic on affected vars should be computed */
1312  )
1313 {
1314  int** perms;
1315  int nperms;
1316  int nvars;
1317  SCIP_Shortbool* affected;
1318  int i;
1319  int p;
1320  int naffected = 0;
1321 
1322  assert( scip != NULL );
1323  assert( presoldata != NULL );
1324  assert( presoldata->perms != NULL );
1325  assert( presoldata->nperms > 0 );
1326  assert( presoldata->npermvars > 0 );
1327 
1328  perms = presoldata->perms;
1329  nperms = presoldata->nperms;
1330  nvars = presoldata->npermvars;
1331 
1332  SCIP_CALL( SCIPallocClearBufferArray(scip, &affected, nvars) );
1333 
1334  /* iterate over permutations and check which variables are affected by some symmetry */
1335  for (p = 0; p < nperms && (completestatistic || ! presoldata->binvaraffected); ++p)
1336  {
1337  for (i = 0; i < nvars; ++i)
1338  {
1339  if ( affected[i] )
1340  continue;
1341 
1342  if ( perms[p][i] != i )
1343  {
1344  if ( SCIPvarIsBinary(presoldata->permvars[i]) )
1345  {
1346  presoldata->binvaraffected = TRUE;
1347 
1348  if ( ! completestatistic )
1349  break;
1350  }
1351 
1352  affected[i] = TRUE;
1353  ++naffected;
1354  }
1355  }
1356  }
1357 
1358  if ( completestatistic )
1359  presoldata->norbitvars = naffected;
1360 
1361  SCIPfreeBufferArray(scip, &affected);
1362 
1363  return SCIP_OKAY;
1364 }
1365 
1366 
1367 /** determine symmetry */
1368 static
1370  SCIP* scip, /**< SCIP instance */
1371  SCIP_PRESOLDATA* presoldata, /**< presolver data */
1372  SYM_SPEC symspecrequire, /**< symmetry specification for which we need to compute symmetries */
1373  SYM_SPEC symspecrequirefixed /**< symmetry specification of variables which must be fixed by symmetries */
1374  )
1375 {
1376  int maxgenerators;
1377  int type = 0;
1378  int nvars;
1379 
1380  assert( scip != NULL );
1381  assert( presoldata != NULL );
1382 
1383  assert( ! presoldata->computedsym );
1384  assert( presoldata->npermvars == 0 );
1385  assert( presoldata->permvars == NULL );
1386  assert( presoldata->permvarsobj == NULL );
1387  assert( presoldata->nperms == 0 );
1388  assert( presoldata->nmaxperms == 0 );
1389  assert( presoldata->perms == NULL );
1390 
1391  presoldata->computedsym = TRUE;
1392 
1393 #ifndef NDEBUG
1394  {
1395  int usesymmetry;
1396  SCIP_CALL( SCIPgetIntParam(scip, "misc/usesymmetry", &usesymmetry) );
1397  assert( usesymmetry );
1398  }
1399 #endif
1400 
1401  /* do not compute symmetry if there are active pricers */
1402  if ( SCIPgetNActivePricers(scip) > 0 )
1403  return SCIP_OKAY;
1404 
1405  /* avoid trivial cases */
1406  nvars = SCIPgetNVars(scip);
1407  if ( nvars <= 0 )
1408  return SCIP_OKAY;
1409 
1410  /* determine symmetry specification */
1411  if ( SCIPgetNBinVars(scip) > 0 )
1412  type |= (int) SYM_SPEC_BINARY;
1413  if ( SCIPgetNIntVars(scip) > 0 )
1414  type |= (int) SYM_SPEC_INTEGER;
1415  /* count implicit integer variables as real variables, since we cannot currently handle integral variables well */
1416  if ( SCIPgetNContVars(scip) > 0 || SCIPgetNImplVars(scip) > 0 )
1417  type |= (int) SYM_SPEC_REAL;
1418 
1419  /* skip symmetry computation if no graph automorphism code was linked */
1420  if ( ! SYMcanComputeSymmetry() )
1421  {
1422  int nconss = SCIPgetNActiveConss(scip);
1423  int nhandleconss = getNSymhandableConss(scip);
1424 
1425  /* print verbMessage only if problem consists of symmetry handable constraints */
1426  assert( nhandleconss <= nconss );
1427  if ( nhandleconss < nconss )
1428  return SCIP_OKAY;
1429 
1431  " Deactivated symmetry handling methods, since SCIP was built without symmetry detector (SYM=none).\n");
1432  return SCIP_OKAY;
1433  }
1434  /* skip symmetry computation if required variables are not present */
1435  else if ( ! (type & symspecrequire) )
1436  {
1438  " (%.1fs) symmetry computation skipped: type (bin %c, int %c, cont %c) does not match requirements (bin %c, int %c, cont %c)\n",
1439  SCIPgetSolvingTime(scip),
1440  SCIPgetNBinVars(scip) > 0 ? '+' : '-',
1441  SCIPgetNIntVars(scip) > 0 ? '+' : '-',
1442  SCIPgetNContVars(scip) + SCIPgetNImplVars(scip) > 0 ? '+' : '-',
1443  (symspecrequire & (int) SYM_SPEC_BINARY) != 0 ? '+' : '-',
1444  (symspecrequire & (int) SYM_SPEC_INTEGER) != 0 ? '+' : '-',
1445  (symspecrequire & (int) SYM_SPEC_REAL) != 0 ? '+' : '-');
1446  return SCIP_OKAY;
1447  }
1448  /* skip symmetry computation if there are constraints that cannot be handled by symmetry */
1449  else if ( getNSymhandableConss(scip) < SCIPgetNActiveConss(scip) )
1450  {
1452  " (%.1fs) symmetry computation skipped: there exist constraints that cannot be handled by symmetry methods\n",
1453  SCIPgetSolvingTime(scip));
1454  return SCIP_OKAY;
1455  }
1456 
1458  " (%.1fs) symmetry computation started: requiring (bin %c, int %c, cont %c), (fixed: bin %c, int %c, cont %c)\n",
1459  SCIPgetSolvingTime(scip),
1460  (symspecrequire & (int) SYM_SPEC_BINARY) != 0 ? '+' : '-',
1461  (symspecrequire & (int) SYM_SPEC_INTEGER) != 0 ? '+' : '-',
1462  (symspecrequire & (int) SYM_SPEC_REAL) != 0 ? '+' : '-',
1463  (symspecrequirefixed & (int) SYM_SPEC_BINARY) != 0 ? '+' : '-',
1464  (symspecrequirefixed & (int) SYM_SPEC_INTEGER) != 0 ? '+' : '-',
1465  (symspecrequirefixed & (int) SYM_SPEC_REAL) != 0 ? '+' : '-');
1466 
1467  if ( symspecrequire & symspecrequirefixed )
1468  SCIPwarningMessage(scip, "Warning: some required symmetries must be fixed.\n");
1469 
1470  /* actually compute (global) symmetry */
1471  /* determine maximal number of generators depending on the number of variables */
1472  maxgenerators = presoldata->maxgenerators;
1473  maxgenerators = MIN(maxgenerators, MAXGENNUMERATOR / nvars);
1474 
1475  SCIP_CALL( computeSymmetryGroup(scip, maxgenerators, symspecrequirefixed, FALSE, presoldata->checksymmetries,
1476  &presoldata->npermvars, &presoldata->permvars, &presoldata->permvarsobj, &presoldata->nperms, &presoldata->nmaxperms, &presoldata->perms,
1477  &presoldata->log10groupsize, &presoldata->successful) );
1478 
1479  /* output statistics */
1480  if ( ! presoldata->successful )
1481  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, " (%.1fs) could not compute symmetry\n", SCIPgetSolvingTime(scip));
1482  else if ( presoldata->nperms == 0 )
1483  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, " (%.1fs) no symmetry present\n", SCIPgetSolvingTime(scip));
1484  else
1485  {
1486  int usesymmetry;
1487 
1488  assert( presoldata->nperms > 0 );
1489 
1490  SCIP_CALL( SCIPgetIntParam(scip, "misc/usesymmetry", &usesymmetry) );
1491 
1492  if ( presoldata->displaynorbitvars )
1493  {
1494  SCIP_CALL( computeNOrbitVars(scip, presoldata, TRUE) );
1495  }
1496  else if ( usesymmetry == 1 )
1497  {
1498  SCIP_CALL( computeNOrbitVars(scip, presoldata, FALSE) );
1499  }
1500 
1501  /* display statistics: number of generators */
1503  " (%.1fs) symmetry computation finished: %d generators found (max: ",
1504  SCIPgetSolvingTime(scip), presoldata->nperms);
1505 
1506  /* display statistics: maximum number of generators*/
1507  if ( maxgenerators == 0 )
1509  else
1510  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "%u", maxgenerators);
1511 
1512  /* display statistics: log10 group size, number of affected vars*/
1513  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, ", log10 of symmetry group size: %.1f", presoldata->log10groupsize);
1514 
1515  /* display statistics: number of affected vars*/
1516  if ( presoldata->displaynorbitvars )
1517  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, ", number of affected variables: %d)\n", presoldata->norbitvars);
1518  else
1519  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, ")\n");
1520 
1521  /* do not deactivate components if no binary variables are affected in the polyhedral setting */
1522  if ( ! presoldata->binvaraffected && usesymmetry == 1 )
1523  {
1524  SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, " (%.1fs) no symmetry on binary variables present\n", SCIPgetSolvingTime(scip));
1525 
1526  return SCIP_OKAY;
1527  }
1528 
1529  /* turn off some other presolving methods in order to be sure that they do not destroy symmetry afterwards */
1531  " (%.1fs) turning off presolver <domcol> for remaining computations in order to avoid conflicts\n",
1532  SCIPgetSolvingTime(scip));
1533 
1534  /* domcol avoids S_2-symmetries and may not be compatible with other symmetry handling methods */
1535  SCIP_CALL( SCIPsetIntParam(scip, "presolving/domcol/maxrounds", 0) );
1536 
1537  presoldata->changeddefaultparams = TRUE;
1538  }
1539 
1540  return SCIP_OKAY;
1541 }
1542 
1543 
1544 /*
1545  * Callback methods of presolver
1546  */
1547 
1548 /** initialization method of presolver (called after problem was transformed) */
1549 static
1550 SCIP_DECL_PRESOLINIT(presolInitSymmetry)
1551 { /*lint --e{715}*/
1552  SCIP_PRESOLDATA* presoldata;
1553 
1554  assert( scip != NULL );
1555  assert( presol != NULL );
1556  assert( strcmp(SCIPpresolGetName(presol), PRESOL_NAME) == 0 );
1557 
1558  presoldata = SCIPpresolGetData(presol);
1559 
1560  /* initialize original values of changed parameters in case we do not enter determineSymmetry() */
1561  SCIP_CALL( SCIPgetIntParam(scip, "presolving/domcol/maxrounds", &(presoldata->oldmaxroundsdomcol)) );
1562 
1563  return SCIP_OKAY;
1564 }
1565 
1566 
1567 /** deinitialization method of presolver (called before transformed problem is freed) */
1568 static
1569 SCIP_DECL_PRESOLEXIT(presolExitSymmetry)
1570 {
1571  SCIP_PRESOLDATA* presoldata;
1572  int i;
1573 
1574  assert( scip != NULL );
1575  assert( presol != NULL );
1576  assert( strcmp(SCIPpresolGetName(presol), PRESOL_NAME) == 0 );
1577 
1578  SCIPdebugMsg(scip, "Exiting symmetry presolver.\n");
1579 
1580  presoldata = SCIPpresolGetData(presol);
1581  assert( presoldata != NULL );
1582 
1583  SCIPfreeBlockMemoryArrayNull(scip, &presoldata->permvars, presoldata->npermvars);
1584  SCIPfreeBlockMemoryArrayNull(scip, &presoldata->permvarsobj, presoldata->npermvars);
1585  for (i = 0; i < presoldata->nperms; ++i)
1586  {
1587  SCIPfreeBlockMemoryArray(scip, &presoldata->perms[i], presoldata->npermvars);
1588  }
1589  SCIPfreeBlockMemoryArrayNull(scip, &presoldata->perms, presoldata->nmaxperms);
1590 
1591  /* reset settings */
1592  presoldata->npermvars = 0;
1593  presoldata->nperms = 0;
1594  presoldata->nmaxperms = 0;
1595  presoldata->norbitvars = 0;
1596  presoldata->binvaraffected = FALSE;
1597  presoldata->computedsym = FALSE;
1598  presoldata->successful = FALSE;
1599 
1600  /* reset changed parameters */
1601  if ( presoldata->changeddefaultparams )
1602  {
1603  SCIP_CALL( SCIPsetIntParam(scip, "presolving/domcol/maxrounds", presoldata->oldmaxroundsdomcol) );
1604 
1605  presoldata->changeddefaultparams = FALSE;
1606  }
1607 
1608  return SCIP_OKAY;
1609 }
1610 
1611 
1612 /** destructor of presolver to free user data (called when SCIP is exiting) */
1613 static
1614 SCIP_DECL_PRESOLFREE(presolFreeSymmetry)
1615 { /*lint --e{715}*/
1616  SCIP_PRESOLDATA* presoldata;
1617 
1618  assert( scip != NULL );
1619  assert( presol != NULL );
1620  assert( strcmp(SCIPpresolGetName(presol), PRESOL_NAME) == 0 );
1621 
1622  SCIPdebugMsg(scip, "Freeing symmetry presolver.\n");
1623 
1624  presoldata = SCIPpresolGetData(presol);
1625  assert( presoldata != NULL );
1626 
1627  SCIPfreeBlockMemory(scip, &presoldata);
1628 
1629  return SCIP_OKAY;
1630 }
1631 
1632 
1633 /** execution method of presolver */
1634 static
1635 SCIP_DECL_PRESOLEXEC(presolExecSymmetry)
1636 { /*lint --e{715}*/
1637  assert( scip != NULL );
1638  assert( presol != NULL );
1639  assert( strcmp(SCIPpresolGetName(presol), PRESOL_NAME) == 0 );
1640  assert( result != NULL );
1641 
1642  /* do nothing */
1643  *result = SCIP_DIDNOTRUN;
1644 
1645  return SCIP_OKAY;
1646 }
1647 
1648 
1649 /*
1650  * External methods
1651  */
1652 
1653 /** include symmetry constraint handler */
1655  SCIP* scip /**< SCIP data structure */
1656  )
1657 {
1658  SCIP_PRESOL* presol = NULL;
1659  SCIP_PRESOLDATA* presoldata = NULL;
1660 
1661  SCIP_CALL( SCIPallocBlockMemory(scip, &presoldata) );
1662  assert( presoldata != NULL );
1663 
1664  presoldata->npermvars = 0;
1665  presoldata->permvars = NULL;
1666  presoldata->permvarsobj = NULL;
1667  presoldata->perms = NULL;
1668  presoldata->nperms = 0;
1669  presoldata->nmaxperms = 0;
1670  presoldata->norbitvars = 0;
1671  presoldata->binvaraffected = FALSE;
1672  presoldata->computedsym = FALSE;
1673  presoldata->successful = FALSE;
1674  presoldata->changeddefaultparams = FALSE;
1675 
1676  /* include constraint handler */
1678  PRESOL_PRIORITY, PRESOL_MAXROUNDS, PRESOL_TIMING, presolExecSymmetry, presoldata) );
1679  assert( presol != NULL );
1680 
1681  SCIP_CALL( SCIPsetPresolFree(scip, presol, presolFreeSymmetry) );
1682  SCIP_CALL( SCIPsetPresolInit(scip, presol, presolInitSymmetry) );
1683  SCIP_CALL( SCIPsetPresolExit(scip, presol, presolExitSymmetry) );
1684 
1685  /* add parameters */
1686  SCIP_CALL( SCIPaddIntParam(scip,
1687  "presolving/" PRESOL_NAME "/maxgenerators",
1688  "limit on the number of generators that should be produced within symmetry detection (0 = no limit)",
1689  &presoldata->maxgenerators, TRUE, DEFAULT_MAXGENERATORS, 0, INT_MAX, NULL, NULL) );
1690 
1692  "presolving/" PRESOL_NAME "/checksymmetries",
1693  "Should all symmetries be checked after computation?",
1694  &presoldata->checksymmetries, TRUE, DEFAULT_CHECKSYMMETRIES, NULL, NULL) );
1695 
1697  "presolving/" PRESOL_NAME "/displaynorbitvars",
1698  "Should the number of variables affected by some symmetry be displayed?",
1699  &presoldata->displaynorbitvars, TRUE, DEFAULT_DISPLAYNORBITVARS, NULL, NULL) );
1700 
1701  /* possibly add description */
1702  if ( SYMcanComputeSymmetry() )
1703  {
1705  }
1706 
1707  return SCIP_OKAY;
1708 }
1709 
1710 
1711 /** return symmetry group generators */
1713  SCIP* scip, /**< SCIP data structure */
1714  SYM_SPEC symspecrequire, /**< symmetry specification for which we need to compute symmetries */
1715  SYM_SPEC symspecrequirefixed,/**< symmetry specification of variables which must be fixed by symmetries */
1716  SCIP_Bool recompute, /**< Have symmetries already been computed? */
1717  int* npermvars, /**< pointer to store number of variables for permutations */
1718  SCIP_VAR*** permvars, /**< pointer to store variables on which permutations act */
1719  int* nperms, /**< pointer to store number of permutations */
1720  int*** perms, /**< pointer to store permutation generators as (nperms x npermvars) matrix */
1721  SCIP_Real* log10groupsize, /**< pointer to store log10 of group size (or NULL) */
1722  SCIP_Bool* binvaraffected /**< pointer to store whether binary variables are affected */
1723  )
1724 {
1725  SCIP_PRESOLDATA* presoldata;
1726  SCIP_PRESOL* presol;
1727 
1728  assert( scip != NULL );
1729  assert( npermvars != NULL );
1730  assert( permvars != NULL );
1731  assert( nperms != NULL );
1732  assert( perms != NULL );
1733 
1734  /* find symmetry presolver */
1735  presol = SCIPfindPresol(scip, "symmetry");
1736  if ( presol == NULL )
1737  {
1738  SCIPerrorMessage("Could not find symmetry presolver.\n");
1739  return SCIP_PLUGINNOTFOUND;
1740  }
1741  assert( presol != NULL );
1742  assert( strcmp(SCIPpresolGetName(presol), PRESOL_NAME) == 0 );
1743 
1744  presoldata = SCIPpresolGetData(presol);
1745  assert( presoldata != NULL );
1746 
1747  /* free symmetry information if we recompute symmetries */
1748  if ( recompute )
1749  {
1750  int i;
1751 
1752  SCIPfreeBlockMemoryArrayNull(scip, &presoldata->permvars, presoldata->npermvars);
1753  SCIPfreeBlockMemoryArrayNull(scip, &presoldata->permvarsobj, presoldata->npermvars);
1754  for (i = 0; i < presoldata->nperms; ++i)
1755  {
1756  SCIPfreeBlockMemoryArray(scip, &presoldata->perms[i], presoldata->npermvars);
1757  }
1758  SCIPfreeBlockMemoryArrayNull(scip, &presoldata->perms, presoldata->nmaxperms);
1759 
1760  /* reset settings */
1761  presoldata->npermvars = 0;
1762  presoldata->nperms = 0;
1763  presoldata->nmaxperms = 0;
1764  presoldata->norbitvars = 0;
1765  presoldata->binvaraffected = FALSE;
1766  presoldata->computedsym = FALSE;
1767  presoldata->successful = FALSE;
1768  }
1769 
1770  /* if not already done before, compute symmetries */
1771  if ( ! presoldata->computedsym )
1772  {
1776  {
1777  SCIPerrorMessage("Cannot call symmetry detection outside of presolving.\n");
1778  return SCIP_INVALIDCALL;
1779  }
1780 
1781  /* determine symmetry here */
1782  SCIP_CALL( determineSymmetry(scip, presoldata, symspecrequire, symspecrequirefixed) );
1783  }
1784 
1785  *npermvars = presoldata->npermvars;
1786  *permvars = presoldata->permvars;
1787  *nperms = presoldata->nperms;
1788  *perms = presoldata->perms;
1789  if ( log10groupsize != NULL )
1790  *log10groupsize = presoldata->log10groupsize;
1791  if ( binvaraffected != NULL )
1792  *binvaraffected = presoldata->binvaraffected;
1793 
1794  return SCIP_OKAY;
1795 }
1796 
1797 
1798 /** return objective coefficients of permuted variables at time of symmetry computation */
1800  SCIP* scip, /**< SCIP data structure */
1801  SCIP_Real** permvarsobj /**< pointer to store objective coefficients of permuted variables (NULL if not available) */
1802  )
1803 {
1804  SCIP_PRESOLDATA* presoldata;
1805  SCIP_PRESOL* presol;
1806 
1807  assert( scip != NULL );
1808  assert( permvarsobj != NULL );
1809 
1810  /* find symmetry presolver */
1811  presol = SCIPfindPresol(scip, "symmetry");
1812  if ( presol == NULL )
1813  {
1814  SCIPerrorMessage("Could not find symmetry presolver.\n");
1815  return SCIP_PLUGINNOTFOUND;
1816  }
1817  assert( presol != NULL );
1818  assert( strcmp(SCIPpresolGetName(presol), PRESOL_NAME) == 0 );
1819 
1820  presoldata = SCIPpresolGetData(presol);
1821  assert( presoldata != NULL );
1822 
1823  *permvarsobj = presoldata->permvarsobj;
1824 
1825  return SCIP_OKAY;
1826 }
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:97
enum SCIP_BoundType SCIP_BOUNDTYPE
Definition: type_lp.h:50
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:86
int SCIPgetNContVars(SCIP *scip)
Definition: scip_prob.c:2167
struct SCIP_PresolData SCIP_PRESOLDATA
Definition: type_presol.h:37
SCIP_VAR * SCIPgetIntVarXor(SCIP *scip, SCIP_CONS *cons)
Definition: cons_xor.c:5939
#define NULL
Definition: def.h:253
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:686
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:80
SCIP_RETCODE SCIPhashtableInsert(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2364
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:876
SCIP_Real * matcoef
SCIP_Real SCIPgetLhsLinear(SCIP *scip, SCIP_CONS *cons)
SCIP_VAR * SCIPgetResultantOr(SCIP *scip, SCIP_CONS *cons)
Definition: cons_or.c:2212
SCIP_VAR ** SCIPgetVarsOr(SCIP *scip, SCIP_CONS *cons)
Definition: cons_or.c:2191
Constraint handler for variable bound constraints .
#define PRESOL_DESC
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip_mem.h:113
SCIP_VAR ** SCIPgetVarsAnd(SCIP *scip, SCIP_CONS *cons)
Definition: cons_and.c:5161
static SCIP_RETCODE checkSymmetriesAreSymmetries(SCIP *scip, SYM_SPEC fixedtype, SYM_MATRIXDATA *matrixdata, int nperms, int **perms)
SCIP_Bool SCIPhashtableExists(SCIP_HASHTABLE *hashtable, void *element)
Definition: misc.c:2476
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:122
void * SCIPhashtableRetrieve(SCIP_HASHTABLE *hashtable, void *key)
Definition: misc.c:2425
SCIP_Real * SCIPgetBoundsBounddisjunction(SCIP *scip, SCIP_CONS *cons)
static SCIP_RETCODE determineSymmetry(SCIP *scip, SCIP_PRESOLDATA *presoldata, SYM_SPEC symspecrequire, SYM_SPEC symspecrequirefixed)
int SCIPgetNVarsBounddisjunction(SCIP *scip, SCIP_CONS *cons)
#define SCIP_SPECIALVAL
int SCIPgetNVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_EXPORT SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:16918
#define DEFAULT_DISPLAYNORBITVARS
int SCIPgetNConss(SCIP *scip)
Definition: scip_prob.c:3037
int SCIPgetNVars(SCIP *scip)
Definition: scip_prob.c:1987
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8137
static int getNSymhandableConss(SCIP *scip)
SCIP_Real SCIPgetSolvingTime(SCIP *scip)
Definition: scip_timing.c:359
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:215
#define FALSE
Definition: def.h:73
SCIP_PRESOL * SCIPfindPresol(SCIP *scip, const char *name)
Definition: scip_presol.c:225
SCIP_EXPORT SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17200
SCIP_EXPORT SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:16903
#define TRUE
Definition: def.h:72
SCIP_CONS ** SCIPgetConss(SCIP *scip)
Definition: scip_prob.c:3083
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:53
static SCIP_RETCODE collectCoefficients(SCIP *scip, SCIP_VAR **linvars, SCIP_Real *linvals, int nlinvars, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool istransformed, SYM_RHSSENSE rhssense, SYM_MATRIXDATA *matrixdata)
SCIP_VAR ** SCIPgetVarsSetppc(SCIP *scip, SCIP_CONS *cons)
Definition: cons_setppc.c:9276
int SCIPgetNImplVars(SCIP *scip)
Definition: scip_prob.c:2122
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:47
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:95
SCIP_RETCODE SCIPsetPresolExit(SCIP *scip, SCIP_PRESOL *presol, SCIP_DECL_PRESOLEXIT((*presolexit)))
Definition: scip_presol.c:177
#define PRESOL_PRIORITY
Constraint handler for AND constraints, .
SCIP_VAR * SCIPgetIntvarLinking(SCIP *scip, SCIP_CONS *cons)
#define SCIPduplicateBufferArray(scip, ptr, source, num)
Definition: scip_mem.h:119
SCIP_Longint * SCIPgetWeightsKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_EXPORT const char * SYMsymmetryGetName(void)
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:123
Constraint handler for the set partitioning / packing / covering constraints .
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:78
SCIP_Real * SCIPgetValsLinear(SCIP *scip, SCIP_CONS *cons)
SCIP_VAR ** permvars
SCIP_VAR ** SCIPgetVarsXor(SCIP *scip, SCIP_CONS *cons)
Definition: cons_xor.c:5918
#define SCIPdebugMsg
Definition: scip_message.h:69
static SCIP_RETCODE computeNOrbitVars(SCIP *scip, SCIP_PRESOLDATA *presoldata, SCIP_Bool completestatistic)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_VAR * SCIPgetResultantAnd(SCIP *scip, SCIP_CONS *cons)
Definition: cons_and.c:5186
int SCIPgetNIntVars(SCIP *scip)
Definition: scip_prob.c:2077
SCIP_RETCODE SCIPhashtableCreate(SCIP_HASHTABLE **hashtable, BMS_BLKMEM *blkmem, int tablesize, SCIP_DECL_HASHGETKEY((*hashgetkey)), SCIP_DECL_HASHKEYEQ((*hashkeyeq)), SCIP_DECL_HASHKEYVAL((*hashkeyval)), void *userptr)
Definition: misc.c:2113
interface for symmetry computations
static SCIP_DECL_PRESOLEXEC(presolExecSymmetry)
#define DEFAULT_MAXGENERATORS
Constraint handler for "or" constraints, .
#define SYM_SPEC_BINARY
Definition: type_symmetry.h:34
SCIP_EXPORT SCIP_RETCODE SYMcomputeSymmetryGenerators(SCIP *scip, int maxgenerators, SYM_MATRIXDATA *matrixdata, int *nperms, int *nmaxperms, int ***perms, SCIP_Real *log10groupsize)
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:92
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:8542
Constraint handler for knapsack constraints of the form , x binary and .
SCIP_Real ub
SCIP_RETCODE SCIPgetProbvarLinearSum(SCIP *scip, SCIP_VAR **vars, SCIP_Real *scalars, int *nvars, int varssize, SCIP_Real *constant, int *requiredsize, SCIP_Bool mergemultiples)
Definition: scip_var.c:1740
#define PRESOL_MAXROUNDS
SCIP_VAR * SCIPgetVarVarbound(SCIP *scip, SCIP_CONS *cons)
int SCIPgetNVarsOr(SCIP *scip, SCIP_CONS *cons)
Definition: cons_or.c:2170
SCIP_EXPORT const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:16738
SCIP_VAR ** SCIPgetVarsBounddisjunction(SCIP *scip, SCIP_CONS *cons)
SYM_RHSSENSE * rhssense
#define SCIPerrorMessage
Definition: pub_message.h:45
SCIP_Real SCIPgetRhsVarbound(SCIP *scip, SCIP_CONS *cons)
SCIP_PRESOLDATA * SCIPpresolGetData(SCIP_PRESOL *presol)
Definition: presol.c:502
#define SYM_SPEC_INTEGER
Definition: type_symmetry.h:33
Constraint handler for logicor constraints (equivalent to set covering, but algorithms are suited fo...
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:1942
SCIP_Real SCIPgetVbdcoefVarbound(SCIP *scip, SCIP_CONS *cons)
static INLINE uint32_t SCIPrealHashCode(double x)
Definition: pub_misc.h:509
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:47
SYM_RHSSENSE * senses
SCIP_Real SCIPgetRhsLinear(SCIP *scip, SCIP_CONS *cons)
#define MAXGENNUMERATOR
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
int SCIPgetNActiveConss(SCIP *scip)
SCIP_RETCODE SCIPgetGeneratorsSymmetry(SCIP *scip, SYM_SPEC symspecrequire, SYM_SPEC symspecrequirefixed, SCIP_Bool recompute, int *npermvars, SCIP_VAR ***permvars, int *nperms, int ***perms, SCIP_Real *log10groupsize, SCIP_Bool *binvaraffected)
int SCIPgetNFixedVars(SCIP *scip)
Definition: scip_prob.c:2304
#define SCIP_Shortbool
Definition: def.h:78
SCIP_RETCODE SCIPincludeExternalCodeInformation(SCIP *scip, const char *name, const char *description)
Definition: scip_general.c:696
SCIP_VAR * SCIPgetVbdvarVarbound(SCIP *scip, SCIP_CONS *cons)
#define SCIP_CALL(x)
Definition: def.h:365
#define SCIPhashTwo(a, b)
Definition: pub_misc.h:493
Definition: grphload.c:88
SCIP_Real * vals
SCIP_Bool SCIPconsIsConflict(SCIP_CONS *cons)
Definition: cons.c:8225
SCIP_BOUNDTYPE * SCIPgetBoundtypesBounddisjunction(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPgetIntParam(SCIP *scip, const char *name, int *value)
Definition: scip_param.c:259
SCIP_VAR ** SCIPgetVarsLogicor(SCIP *scip, SCIP_CONS *cons)
SCIP_EXPORT SCIP_Bool SYMcanComputeSymmetry(void)
constraint handler for linking binary variables to an integer variable
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:111
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:129
SCIP_Real SCIPinfinity(SCIP *scip)
void SCIPhashtableFree(SCIP_HASHTABLE **hashtable)
Definition: misc.c:2163
#define SCIP_Bool
Definition: def.h:70
uint32_t SYM_SPEC
Definition: type_symmetry.h:37
SCIP_RETCODE SCIPsetPresolInit(SCIP *scip, SCIP_PRESOL *presol, SCIP_DECL_PRESOLINIT((*presolinit)))
Definition: scip_presol.c:161
SCIP_EXPORT SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17362
const char * SCIPpresolGetName(SCIP_PRESOL *presol)
Definition: presol.c:589
int SCIPgetNVarsLinear(SCIP *scip, SCIP_CONS *cons)
#define MIN(x, y)
Definition: def.h:223
SCIP_Real lb
void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition: misc.c:5317
SCIP_Bool SCIPconsIsTransformed(SCIP_CONS *cons)
Definition: cons.c:8385
SCIP_VAR ** SCIPgetVarsKnapsack(SCIP *scip, SCIP_CONS *cons)
int SCIPgetNVarsAnd(SCIP *scip, SCIP_CONS *cons)
Definition: cons_and.c:5137
int SCIPconshdlrGetNActiveConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4627
static SCIP_DECL_HASHKEYVAL(SYMhashKeyValVartype)
SCIP_VARTYPE type
Constraint handler for linear constraints in their most general form, .
int * SCIPgetValsLinking(SCIP *scip, SCIP_CONS *cons)
int SCIPgetNActivePricers(SCIP *scip)
Definition: scip_pricer.c:338
static SCIP_DECL_HASHKEYEQ(SYMhashKeyEQVartype)
SCIP_EXPORT SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17408
static SCIP_RETCODE computeSymmetryGroup(SCIP *scip, int maxgenerators, SYM_SPEC fixedtype, SCIP_Bool local, SCIP_Bool checksymmetries, int *npermvars, SCIP_VAR ***permvars, SCIP_Real **permvarsobj, int *nperms, int *nmaxperms, int ***perms, SCIP_Real *log10groupsize, SCIP_Bool *success)
SCIP_RETCODE SCIPsetPresolFree(SCIP *scip, SCIP_PRESOL *presol, SCIP_DECL_PRESOLFREE((*presolfree)))
Definition: scip_presol.c:145
enum SYM_Rhssense SYM_RHSSENSE
Definition: type_symmetry.h:51
SCIP_EXPORT SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17418
Constraint handler for XOR constraints, .
#define MAX(x, y)
Definition: def.h:222
SCIP_RETCODE SCIPgetPermvarsObjSymmetry(SCIP *scip, SCIP_Real **permvarsobj)
static const SCIP_Real scalars[]
Definition: lp.c:5650
static SCIP_DECL_SORTINDCOMP(SYMsortRhsTypes)
int SCIPgetNVarsLogicor(SCIP *scip, SCIP_CONS *cons)
SCIP_Bool SCIPgetRhsXor(SCIP *scip, SCIP_CONS *cons)
Definition: cons_xor.c:5960
#define PRESOL_NAME
SCIP_EXPORT SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17352
static SCIP_DECL_PRESOLINIT(presolInitSymmetry)
presolver for storing symmetry information about current problem
static SCIP_DECL_PRESOLEXIT(presolExitSymmetry)
SCIP_EXPORT const char * SYMsymmetryGetDesc(void)
#define SYM_SPEC_REAL
Definition: type_symmetry.h:35
int SCIPgetNVarsSetppc(SCIP *scip, SCIP_CONS *cons)
Definition: cons_setppc.c:9255
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:73
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8076
#define SCIP_Real
Definition: def.h:164
SCIP_RETCODE SCIPincludePresolBasic(SCIP *scip, SCIP_PRESOL **presolptr, const char *name, const char *desc, int priority, int maxrounds, SCIP_PRESOLTIMING timing, SCIP_DECL_PRESOLEXEC((*presolexec)), SCIP_PRESOLDATA *presoldata)
Definition: scip_presol.c:94
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8096
SCIP_EXPORT SCIP_RETCODE SCIPvarGetOrigvarSum(SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: var.c:12268
#define SCIP_INVALID
Definition: def.h:184
#define PRESOL_TIMING
#define SCIP_Longint
Definition: def.h:149
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4191
int SCIPgetNBinVars(SCIP *scip)
Definition: scip_prob.c:2032
SCIP_SETPPCTYPE SCIPgetTypeSetppc(SCIP *scip, SCIP_CONS *cons)
Definition: cons_setppc.c:9297
SCIP_EXPORT int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17045
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:98
static SCIP_RETCODE getActiveVariables(SCIP *scip, SCIP_VAR ***vars, SCIP_Real **scalars, int *nvars, SCIP_Real *constant, SCIP_Bool transformed)
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:355
constraint handler for bound disjunction constraints
static SCIP_DECL_HASHGETKEY(SYMhashGetKeyVartype)
#define SCIPcombineTwoInt(a, b)
Definition: pub_misc.h:499
int SCIPgetNVarsXor(SCIP *scip, SCIP_CONS *cons)
Definition: cons_xor.c:5897
SCIP_Real SCIPgetLhsVarbound(SCIP *scip, SCIP_CONS *cons)
SCIP_Real obj
static SCIP_DECL_PRESOLFREE(presolFreeSymmetry)
SCIP_Real * rhscoef
static SCIP_Bool SymmetryFixVar(SYM_SPEC fixedtype, SCIP_VAR *var)
SCIP_VAR ** SCIPgetVarsLinear(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPsetIntParam(SCIP *scip, const char *name, int value)
Definition: scip_param.c:496
SCIP_RETCODE SCIPgetBinvarsLinking(SCIP *scip, SCIP_CONS *cons, SCIP_VAR ***binvars, int *nbinvars)
SCIP_Longint SCIPgetCapacityKnapsack(SCIP *scip, SCIP_CONS *cons)
SCIP_RETCODE SCIPincludePresolSymmetry(SCIP *scip)
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:115
#define DEFAULT_CHECKSYMMETRIES