Scippy

SCIP

Solving Constraint Integer Programs

cons_symresack.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 2002-2022 Zuse Institute Berlin */
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 cons_symresack.c
26  * @ingroup DEFPLUGINS_CONS
27  * @brief constraint handler for symresack constraints
28  * @author Christopher Hojny
29  * @author Jasper van Doornmalen
30  *
31  * The type of constraints of this constraint handler is described in cons_symresack.h.
32  *
33  * The details of the method implemented here are described in the following papers:
34  *
35  * Fundamental Domains for Integer Programs with Symmetries@n
36  * Eric J. Friedman,@n
37  * Combinatorial Optimization, volume 4616 of LNCS, 146-153 (2007)
38  *
39  * This paper describes an inequality to handle symmetries of a single permutation. This
40  * so-called FD-inequality is the basic for the propagation routine of our implementation.
41  *
42  * Polytopes Associated with Symmetry Handling@n
43  * Christopher Hojny and Marc E. Pfetsch,@n
44  * Mathematical Programming 175, No. 1, 197-240, 2019
45  *
46  * This paper describes an almost linear time separation routine for so-called cover
47  * inequalities of symresacks. A slight modification of this algorithm allows for a linear
48  * running time, which is used in this implementation.
49  *
50  * Packing, Partitioning, and Covering Symresacks@n
51  * Christopher Hojny,@n
52  * (2020), available at https://doi.org/10.1016/j.dam.2020.03.002
53  * Discrete Applied Mathematics, volume 283, 689-717 (2020)
54  *
55  * This paper introduces linearly many inequalities with ternary coefficients that suffice to
56  * characterize the binary points contained in a packing and partitioning symresack completely.
57  */
58 
59 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
60 
61 #include "blockmemshell/memory.h"
62 #include "scip/cons_orbisack.h"
63 #include "scip/cons_setppc.h"
64 #include "scip/cons_symresack.h"
65 #include "scip/pub_cons.h"
66 #include "scip/pub_message.h"
67 #include "scip/pub_misc.h"
68 #include "scip/pub_var.h"
69 #include "scip/scip.h"
70 #include "scip/scip_branch.h"
71 #include "scip/scip_conflict.h"
72 #include "scip/scip_cons.h"
73 #include "scip/scip_cut.h"
74 #include "scip/scip_general.h"
75 #include "scip/scip_lp.h"
76 #include "scip/scip_mem.h"
77 #include "scip/scip_message.h"
78 #include "scip/scip_numerics.h"
79 #include "scip/scip_param.h"
80 #include "scip/scip_prob.h"
81 #include "scip/scip_sol.h"
82 #include "scip/scip_var.h"
83 #include <ctype.h>
84 #include <string.h>
85 
86 /* constraint handler properties */
87 #define CONSHDLR_NAME "symresack"
88 #define CONSHDLR_DESC "symmetry breaking constraint handler relying on symresacks"
89 #define CONSHDLR_SEPAPRIORITY +40100 /**< priority of the constraint handler for separation */
90 #define CONSHDLR_ENFOPRIORITY -1005200 /**< priority of the constraint handler for constraint enforcing */
91 #define CONSHDLR_CHECKPRIORITY -1005200 /**< priority of the constraint handler for checking feasibility */
92 #define CONSHDLR_SEPAFREQ 5 /**< frequency for separating cuts; zero means to separate only in the root node */
93 #define CONSHDLR_PROPFREQ 5 /**< frequency for propagating domains; zero means only preprocessing propagation */
94 #define CONSHDLR_EAGERFREQ -1 /**< frequency for using all instead of only the useful constraints in separation,
95  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
96 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
97 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
98 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
99 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
101 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP
102 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_EXHAUSTIVE
104 #define DEFAULT_PPSYMRESACK TRUE /**< whether we allow upgrading to packing/partitioning symresacks */
105 #define DEFAULT_CHECKMONOTONICITY TRUE /**< check whether permutation is monotone when upgrading to packing/partitioning symresacks */
106 #define DEFAULT_FORCECONSCOPY FALSE /**< whether symresack constraints should be forced to be copied to sub SCIPs */
108 /* Constants to store fixings */
109 #define FIXED0 1 /* When a variable is fixed to 0. */
110 #define FIXED1 2 /* When a variable is fixed to 1. */
111 #define UNFIXED 3 /* When a variable is neither fixed to 0 or to 1. */
112 #define NOINIT 0 /* A dummy entry for non-initialized variables.
113  * Must have value 0 because of SCIPallocCleanBufferArray. */
114 /* A macro for checking if a variable was fixed during a bound change */
115 #define ISFIXED(x, bdchgidx) (SCIPvarGetUbAtIndex(x, bdchgidx, FALSE) - SCIPvarGetLbAtIndex(x, bdchgidx, FALSE) < 0.5)
117 
118 
119 /*
120  * Data structures
121  */
122 
123 /** constraint handler data */
124 struct SCIP_ConshdlrData
125 {
126  SCIP_Bool checkppsymresack; /**< whether we allow upgrading to packing/partitioning symresacks */
127  SCIP_Bool checkmonotonicity; /**< check whether permutation is monotone when upgrading to packing/partitioning symresacks */
128  int maxnvars; /**< maximal number of variables in a symresack constraint */
129  SCIP_Bool forceconscopy; /**< whether symresack constraints should be forced to be copied to sub SCIPs */
130 };
131 
132 
133 /** constraint data for symresack constraints */
134 struct SCIP_ConsData
135 {
136  SCIP_VAR** vars; /**< variables */
137  int nvars; /**< number of variables */
138  int* perm; /**< permutation associated to the symresack */
139  int* invperm; /**< inverse permutation */
140  SCIP_Bool ppupgrade; /**< whether constraint is upgraded to packing/partitioning symresack */
141  SCIP_Bool ismodelcons; /**< whether the symresack is a model constraint */
142 #ifdef SCIP_DEBUG
143  int debugcnt; /**< counter to store number of added cover inequalities */
144 #endif
145 
146  /* data for upgraded symresack constraints */
147  int ncycles; /**< number of cycles in permutation */
148  int** cycledecomposition; /**< cycle decomposition */
149  int ndescentpoints; /**< number of descent points in perm (only used if perm is not monotone) */
150  int* descentpoints; /**< descent points in perm (only used if perm is not monotone) */
151 };
152 
153 
154 /*
155  * Local methods
156  */
157 
158 /** frees a symresack constraint data */
159 static
161  SCIP* scip, /**< SCIP data structure */
162  SCIP_CONSDATA** consdata /**< pointer to symresack constraint data */
163  )
164 {
165  int nvars;
166  int i;
167 
168  assert( consdata != NULL );
169  assert( *consdata != NULL );
170 
171  nvars = (*consdata)->nvars;
172 
173  if ( nvars == 0 )
174  {
175  assert( (*consdata)->vars == NULL );
176  assert( (*consdata)->perm == NULL );
177  assert( (*consdata)->invperm == NULL );
178  assert( (*consdata)->ncycles == 0 );
179  assert( (*consdata)->cycledecomposition == NULL );
180 
181  SCIPfreeBlockMemory(scip, consdata);
182 
183  return SCIP_OKAY;
184  }
185 
186  if ( (*consdata)->ndescentpoints > 0 )
187  {
188  assert( (*consdata)->descentpoints != NULL );
189 
190  SCIPfreeBlockMemoryArray(scip, &((*consdata)->descentpoints), (*consdata)->ndescentpoints);
191  }
192 
193  if ( (*consdata)->ppupgrade )
194  {
195  for (i = 0; i < (*consdata)->ncycles; ++i)
196  {
197  SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->cycledecomposition[i]), nvars + 1);
198  }
199  SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->cycledecomposition), (*consdata)->ncycles);
200  }
201 
202  SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->invperm), nvars);
203  SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->perm), nvars);
204 
205  for (i = 0; i < nvars; ++i)
206  {
207  SCIP_CALL( SCIPreleaseVar(scip, &(*consdata)->vars[i]) );
208  }
209  SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->vars), nvars);
210 
211  SCIPfreeBlockMemory(scip, consdata);
212 
213  return SCIP_OKAY;
214 }
215 
216 
217 /** check whether constraint can be upgraded to packing/partitioning symresack */
218 static
220  SCIP* scip, /**< SCIP data structure */
221  SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
222  int* perm, /**< permutation */
223  SCIP_VAR** vars, /**< variables affected by permutation */
224  int nvars, /**< length of permutation */
225  SCIP_Bool checkmonotonicity, /**< check whether permutation is monotone */
226  SCIP_Bool* upgrade /**< pointer to store whether upgrade was successful */
227  )
228 {
229  SCIP_Bool* covered;
230  SCIP_Bool descent;
231  SCIP_CONSHDLR* setppcconshdlr;
232  SCIP_CONS** setppcconss;
233  SCIP_VAR* var;
234  SCIP_Bool terminated = FALSE;
235  int** cycledecomposition;
236  int* indicesincycle;
237  int nsetppcconss;
238  int curcycle;
239  int maxcyclelength;
240  int ncycles = 0;
241  int c;
242  int i;
243  int j;
244  int ndescentpoints = 0;
245  int* descentpoints;
246 
247  assert( scip != NULL );
248  assert( perm != NULL );
249  assert( vars != NULL );
250  assert( nvars > 0 );
251  assert( upgrade != NULL );
252 
253  *upgrade = FALSE;
254 
255  SCIP_CALL( SCIPallocBufferArray(scip, &covered, nvars) );
256 
257  for (i = 0; i < nvars; ++i)
258  covered[i] = FALSE;
259 
260  /* get number of cycles in permutation */
261  for (i = 0; i < nvars; ++i)
262  {
263  /* skip checked indices */
264  if ( covered[i] )
265  continue;
266 
267  ++ncycles;
268  j = i;
269  descent = FALSE;
270 
271  do
272  {
273  covered[j] = TRUE;
274 
275  if ( perm[j] < j )
276  {
277  ++ndescentpoints;
278 
279  if ( ! descent )
280  descent = TRUE;
281  else if ( checkmonotonicity )
282  break;
283  }
284 
285  j = perm[j];
286  }
287  while ( j != i );
288 
289  /* if cycle is not monotone and we require the cycle to be monotone */
290  if ( j != i )
291  {
292  assert( checkmonotonicity );
293  SCIPfreeBufferArray(scip, &covered);
294 
295  return SCIP_OKAY;
296  }
297  }
298  assert( ncycles <= nvars / 2 );
299 
300  /* check for packing/partitioning type */
301  for (i = 0; i < nvars; ++i)
302  covered[i] = FALSE;
303 
304  /* compute cycle decomposition: row i stores in entry 0 the length of the cycle,
305  * the remaining entries are the coordinates in the cycle;
306  * store descent points as well if permutation is not monotone */
307  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &cycledecomposition, ncycles) );
308  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &descentpoints, ndescentpoints) );
309  for (i = 0; i < ncycles; ++i)
310  {
311  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &cycledecomposition[i], nvars + 1) );
312  }
313 
314  curcycle = 0;
315  maxcyclelength = 0;
316  c = 0;
317  for (i = 0; i < nvars; ++i)
318  {
319  int cyclelength = 0;
320 
321  /* skip checked indices */
322  if ( covered[i] )
323  continue;
324 
325  j = i;
326  do
327  {
328  if ( perm[j] < j )
329  descentpoints[c++] = j;
330 
331  covered[j] = TRUE;
332  cycledecomposition[curcycle][++cyclelength] = j;
333  j = perm[j];
334  }
335  while ( j != i );
336 
337  cycledecomposition[curcycle][0] = cyclelength;
338  ++curcycle;
339 
340  if ( maxcyclelength < cyclelength )
341  maxcyclelength = cyclelength;
342  }
343  assert( c == ndescentpoints );
344 
345  /* permutation can be upgraded -> check whether the symresack is of packing/partitioning type */
346  setppcconshdlr = SCIPfindConshdlr(scip, "setppc");
347  if ( setppcconshdlr == NULL )
348  {
349  SCIPerrorMessage("Setppc constraint handler not found.\n");
350  return SCIP_PLUGINNOTFOUND;
351  }
352  setppcconss = SCIPconshdlrGetConss(setppcconshdlr);
353  nsetppcconss = SCIPconshdlrGetNConss(setppcconshdlr);
354 
355  /* Check whether each cycle of the symresack is contained in a set packing/partitioning constraint.
356  * To this end, we have to guarantee that all affected variables are not negated since permutations
357  * are given w.r.t. original variables. */
358  *upgrade = TRUE;
359 
360  SCIP_CALL( SCIPallocBufferArray(scip, &indicesincycle, maxcyclelength) );
361 
362  for (i = 0; i < ncycles && *upgrade && ! terminated; ++i)
363  {
364  int cyclelength;
365 
366  /* get indices of variables in current cycle */
367  for (j = 0; j < cycledecomposition[i][0]; ++ j)
368  {
369  var = vars[cycledecomposition[i][j + 1]];
370 
371  if ( SCIPvarIsNegated(var) )
372  {
373  terminated = TRUE;
374  break;
375  }
376 
377  indicesincycle[j] = SCIPvarGetProbindex(var);
378  }
379 
380  cyclelength = cycledecomposition[i][0];
381 
382  /* iterate over constraints
383  *
384  * @todo Improve the check by sorting the constraints in the setppcconss array
385  * by type and number of contained variables. */
386  for (c = 0; c < nsetppcconss; ++c)
387  {
388  int nsetppcvars;
389  SCIP_VAR** setppcvars;
390  int varidx;
391  int nfound = 0;
392  int k;
393 
394  /* check type */
395  if ( SCIPgetTypeSetppc(scip, setppcconss[c]) == SCIP_SETPPCTYPE_COVERING )
396  continue;
397  assert( SCIPgetTypeSetppc(scip, setppcconss[c]) == SCIP_SETPPCTYPE_PARTITIONING || SCIPgetTypeSetppc(scip, setppcconss[c]) == SCIP_SETPPCTYPE_PACKING );
398 
399  /* get set packing/partitioning variables */
400  nsetppcvars = SCIPgetNVarsSetppc(scip, setppcconss[c]);
401 
402  /* skip empty constraints (might not have been removed by presolving yet) */
403  if ( nsetppcvars == 0 )
404  continue;
405  assert( nsetppcvars > 0 );
406 
407  setppcvars = SCIPgetVarsSetppc(scip, setppcconss[c]);
408  assert( setppcvars != NULL );
409 
410  /* check whether all variables of the cycle are contained in setppc constraint */
411  for (j = 0; j < nsetppcvars && nfound < cyclelength; ++j)
412  {
413  var = setppcvars[j];
414 
415  if ( SCIPvarIsNegated(var) )
416  continue;
417 
418  varidx = SCIPvarGetProbindex(var);
419 
420  for (k = 0; k < cyclelength; ++k)
421  {
422  if ( varidx == indicesincycle[k] )
423  {
424  ++nfound;
425  break;
426  }
427  }
428  }
429  assert( nfound <= cyclelength );
430 
431  if ( nfound == cyclelength )
432  break;
433  }
434 
435  /* row is not contained in a set packing/partitioning constraint */
436  if ( c >= nsetppcconss )
437  *upgrade = FALSE;
438  }
439 
440  if ( *upgrade )
441  {
442  (*consdata)->ncycles = ncycles;
443  (*consdata)->cycledecomposition = cycledecomposition;
444  (*consdata)->ndescentpoints = ndescentpoints;
445  (*consdata)->descentpoints = descentpoints;
446  SCIPdebugMsg(scip, "added monotone PP symresack.\n");
447 
448  SCIPfreeBufferArray(scip, &indicesincycle);
449  SCIPfreeBufferArray(scip, &covered);
450  }
451  else
452  {
453  SCIPfreeBlockMemoryArray(scip, &descentpoints, ndescentpoints);
454  SCIPfreeBufferArray(scip, &indicesincycle);
455  SCIPfreeBufferArray(scip, &covered);
456  for (i = 0; i < ncycles; ++i)
457  {
458  SCIPfreeBlockMemoryArray(scip, &cycledecomposition[i], nvars + 1);
459  }
460  SCIPfreeBlockMemoryArray(scip, &cycledecomposition, ncycles);
461  }
462 
463  return SCIP_OKAY;
464 }
465 
466 
467 /** creates symresack constraint data
468  *
469  * If the input data contains non-binary variables or fixed
470  * points, we delete these variables in a preprocessing step.
471  */
472 static
474  SCIP* scip, /**< SCIP data structure */
475  SCIP_CONSHDLR* conshdlr, /**< symresack constraint handler */
476  SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
477  SCIP_VAR*const* inputvars, /**< input variables of the constraint handler */
478  int inputnvars, /**< input number of variables of the constraint handler*/
479  int* inputperm, /**< input permutation of the constraint handler */
480  SCIP_Bool ismodelcons /**< whether the symresack is a model constraint */
481  )
482 {
483  SCIP_CONSHDLRDATA* conshdlrdata;
484  SCIP_VAR** vars;
485  SCIP_Bool upgrade;
486  int* indexcorrection;
487  int* invperm;
488  int* perm;
489  int naffectedvariables;
490  int i;
491  int j = 0;
492 
493  assert( consdata != NULL );
494  assert( conshdlr != NULL );
495  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
496 
497  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
498 
499 #ifdef SCIP_DEBUG
500  (*consdata)->debugcnt = 0;
501 #endif
502 
503  (*consdata)->ndescentpoints = 0;
504  (*consdata)->descentpoints = NULL;
505  (*consdata)->ismodelcons = ismodelcons;
506 
507  /* count the number of binary variables which are affected by the permutation */
508  SCIP_CALL( SCIPallocBufferArray(scip, &indexcorrection, inputnvars) );
509  indexcorrection[0] = -1;
510  for (i = 0; i < inputnvars; ++i)
511  {
512  if ( inputperm[i] != i && SCIPvarIsBinary(inputvars[i]) )
513  {
514  if ( i == 0 )
515  indexcorrection[i] = 0;
516  else
517  indexcorrection[i] = indexcorrection[i - 1] + 1;
518  }
519  else
520  {
521  if ( i > 0 )
522  indexcorrection[i] = indexcorrection[i - 1];
523  }
524  }
525  naffectedvariables = indexcorrection[inputnvars - 1] + 1;
526 
527  (*consdata)->nvars = naffectedvariables;
528 
529  /* Stop if we detect that the permutation fixes each binary point. */
530  if ( naffectedvariables == 0 )
531  {
532  SCIPfreeBufferArrayNull(scip, &indexcorrection);
533 
534  (*consdata)->vars = NULL;
535  (*consdata)->perm = NULL;
536  (*consdata)->invperm = NULL;
537  (*consdata)->ppupgrade = FALSE;
538  (*consdata)->ncycles = 0;
539  (*consdata)->cycledecomposition = NULL;
540  return SCIP_OKAY;
541  }
542 
543  /* remove fixed points from permutation representation */
544  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &vars, naffectedvariables) );
545  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &perm, naffectedvariables) );
546  for (i = 0; i < inputnvars; ++i)
547  {
548  if ( i == 0 )
549  {
550  if ( indexcorrection[i] > -1 )
551  {
552  vars[j] = inputvars[i];
553  perm[j++] = indexcorrection[inputperm[i]];
554  }
555  }
556  else
557  {
558  if ( indexcorrection[i] > indexcorrection[i - 1] )
559  {
560  vars[j] = inputvars[i];
561  perm[j++] = indexcorrection[inputperm[i]];
562  }
563  }
564  }
565  SCIPfreeBufferArrayNull(scip, &indexcorrection);
566 
567  (*consdata)->vars = vars;
568  (*consdata)->perm = perm;
569 
570  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &invperm, naffectedvariables) );
571  for (i = 0; i < naffectedvariables; ++i)
572  {
573  SCIP_CALL( SCIPcaptureVar(scip, (*consdata)->vars[i]) );
574  invperm[perm[i]] = i;
575  }
576  (*consdata)->invperm = invperm;
577 
578  /* check for upgrade to packing/partitioning symresacks*/
579  conshdlrdata = SCIPconshdlrGetData(conshdlr);
580  upgrade = FALSE;
581  if ( conshdlrdata->checkppsymresack )
582  {
583  SCIP_CALL( packingUpgrade(scip, consdata, perm, vars, naffectedvariables, conshdlrdata->checkmonotonicity, &upgrade) );
584  }
585 
586  (*consdata)->ppupgrade = upgrade;
587 
588  /* get transformed variables, if we are in the transformed problem */
589  if ( SCIPisTransformed(scip) )
590  {
591  /* Make sure that all variables cannot be multiaggregated (cannot be handled by cons_symresack, since one cannot
592  * easily eliminate single variables from a symresack constraint. */
593  for (i = 0; i < naffectedvariables; ++i)
594  {
595  SCIP_CALL( SCIPgetTransformedVar(scip, (*consdata)->vars[i], &(*consdata)->vars[i]) );
596  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->vars[i]) );
597  }
598  }
599 
600  return SCIP_OKAY;
601 }
602 
603 
604 /** generate initial LP cut
605  *
606  * We generate the ordering inequality for the pair \f$(1, \gamma^{-1}(1))\f$, i.e.,
607  * the inequality \f$-x_{1} + x_{\gamma^{-1}(1)} \leq 0\f$. This inequality is valid,
608  * because we guaranteed in a preprocessing step that all variables are binary.
609  *
610  * Furthermore, we add facet inequalities of packing/partitioning symresacks if
611  * we deal with packing/partitioning symresacks.
612  */
613 static
615  SCIP* scip, /**< SCIP pointer */
616  SCIP_CONS* cons, /**< constraint */
617  SCIP_Bool checkmonotonicity, /**< has it been checked whether permutation is monotone for packing/partitioning symresacks? */
618  SCIP_Bool* infeasible /**< pointer to store whether we detected infeasibility */
619  )
620 {
621  SCIP_CONSDATA* consdata;
622  SCIP_VAR** vars;
623  SCIP_ROW* row;
624  int nvars;
625 #ifdef SCIP_DEBUG
626  char name[SCIP_MAXSTRLEN];
627 #endif
628  int i;
629  int j;
630  int k;
631 
632  assert( scip != NULL );
633  assert( cons != NULL );
634  assert( infeasible != NULL );
635 
636  *infeasible = FALSE;
637 
638  consdata = SCIPconsGetData(cons);
639  assert( consdata != NULL );
640 
641  nvars = consdata->nvars;
642 
643  /* avoid stupid problems */
644  if ( nvars <= 1 )
645  return SCIP_OKAY;
646 
647  assert( consdata->vars != NULL );
648  vars = consdata->vars;
649 
650  /* there are no fixed points */
651  assert( consdata->invperm[0] != 0 );
652 
653  /* add ordering inequality */
654 #ifdef SCIP_DEBUG
655  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "symresack_init_%s", SCIPconsGetName(cons));
656  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), 0.0, FALSE, FALSE, TRUE) );
657 #else
658  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, "", -SCIPinfinity(scip), 0.0, FALSE, FALSE, TRUE) );
659 #endif
660  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[0], -1.0) );
661  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[consdata->invperm[0]], 1.0) );
662 
663  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
664 
665  SCIP_CALL( SCIPreleaseRow(scip, &row) );
666 
667  /* check whether we have a packing/partioning symresack */
668  if ( consdata->ppupgrade && ! *infeasible )
669  {
670  if ( checkmonotonicity )
671  {
672  SCIP_VAR** varsincons;
673  SCIP_Real* coeffs;
674  int** cycledecomposition;
675  int ncycles;
676  int nvarsincons;
677  int nvarsincycle;
678  int firstelemincycle;
679 
680  ncycles = consdata->ncycles;
681  cycledecomposition = consdata->cycledecomposition;
682 
683  SCIP_CALL( SCIPallocBufferArray(scip, &varsincons, nvars) );
684  SCIP_CALL( SCIPallocBufferArray(scip, &coeffs, nvars) );
685 
686  coeffs[0] = 1.0;
687 
688  /* add packing/partitioning symresack constraints */
689  for (i = 0; i < ncycles; ++i)
690  {
691  assert( cycledecomposition[i][0] > 0 );
692 
693  nvarsincycle = cycledecomposition[i][0];
694  varsincons[0] = vars[cycledecomposition[i][nvarsincycle]];
695  firstelemincycle = cycledecomposition[i][1];
696 
697  assert( firstelemincycle == consdata->perm[cycledecomposition[i][nvarsincycle]] );
698 
699  nvarsincons = 1;
700 
701  /* add variables of other cycles to the constraint */
702  for (j = 0; j < i; ++j)
703  {
704  nvarsincycle = cycledecomposition[j][0];
705  for (k = 1; k <= nvarsincycle; ++k)
706  {
707  if ( cycledecomposition[j][k] < firstelemincycle )
708  {
709  varsincons[nvarsincons] = vars[cycledecomposition[j][k]];
710  coeffs[nvarsincons++] = -1.0;
711  }
712  else
713  continue;
714  }
715  }
716 
717 #ifdef SCIP_DEBUG
718  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "ppSymresack_%d_%s", i, SCIPconsGetName(cons));
719  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), 0.0, FALSE, FALSE, TRUE) );
720 #else
721  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, "", -SCIPinfinity(scip), 0.0, FALSE, FALSE, TRUE) );
722 #endif
723  SCIP_CALL( SCIPaddVarsToRow(scip, row, nvarsincons, varsincons, coeffs) );
724 
725  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
726  SCIP_CALL( SCIPreleaseRow(scip, &row) );
727 
728  if ( *infeasible )
729  break;
730  }
731 
732  SCIPfreeBufferArray(scip, &coeffs);
733  SCIPfreeBufferArray(scip, &varsincons);
734  }
735  else
736  {
737  SCIP_Real* coeffs;
738  SCIP_VAR** varsincons;
739  int* imgdescentpoints;
740  int* descentpoints;
741  int* perm;
742  int ndescentpoints;
743  int lastascent = 0;
744  int newlastascent = 0;
745  int nvarsincons = 1;
746 
747  descentpoints = consdata->descentpoints;
748  ndescentpoints = consdata->ndescentpoints;
749  perm = consdata->perm;
750 
751  assert( descentpoints != NULL );
752  assert( ndescentpoints > 0 );
753  assert( perm != NULL );
754  assert( vars != NULL );
755  assert( nvars > 0 );
756 
757  SCIP_CALL( SCIPallocBufferArray(scip, &imgdescentpoints, ndescentpoints) );
758 
759  /* get images of descentpoints */
760  for (j = 0; j < ndescentpoints; ++j)
761  imgdescentpoints[j] = perm[descentpoints[j]];
762 
763  /* sort descent points increasingly w.r.t. the corresponding image */
764  SCIPsortIntInt(imgdescentpoints, descentpoints, ndescentpoints);
765 
766  /* iteratively generate coefficient vector: the first entry is the descent point j and the remaining entries
767  * are the corresponding ascent points less than perm[j]
768  */
769  SCIP_CALL( SCIPallocClearBufferArray(scip, &coeffs, nvars) );
770  SCIP_CALL( SCIPallocClearBufferArray(scip, &varsincons, nvars) );
771  coeffs[0] = 1.0;
772  for (j = 0; j < ndescentpoints; ++j)
773  {
774  varsincons[0] = vars[descentpoints[j]];
775  for (i = lastascent; i < imgdescentpoints[j]; ++i)
776  {
777  if ( perm[i] > i )
778  {
779  coeffs[nvarsincons] = -1.0;
780  varsincons[nvarsincons++] = vars[i];
781  newlastascent = i;
782  }
783  }
784  lastascent = newlastascent;
785 
786 #ifdef SCIP_DEBUG
787  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "ppSymresack_%d_%s", j, SCIPconsGetName(cons));
788  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), 0.0, FALSE, FALSE, TRUE) );
789 #else
790  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, "", -SCIPinfinity(scip), 0.0, FALSE, FALSE, TRUE) );
791 #endif
792  SCIP_CALL( SCIPaddVarsToRow(scip, row, nvarsincons, varsincons, coeffs) );
793 
794  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
795  SCIP_CALL( SCIPreleaseRow(scip, &row) );
796 
797  if ( *infeasible )
798  break;
799  }
800 
801  SCIPfreeBufferArray(scip, &varsincons);
802  SCIPfreeBufferArray(scip, &coeffs);
803  SCIPfreeBufferArray(scip, &imgdescentpoints);
804  }
805  }
806 
807  return SCIP_OKAY;
808 }
809 
810 
811 /** Determines if a vector with additional fixings could exist that is lexicographically larger than its image.
812  *
813  * Given a vector of variables, a permutation, and a set of additional (virtual) fixings.
814  * If a vector adhering to the local variable bounds (local fixings) and to the virtual fixings exists,
815  * then infeasible is FALSE, otherwise TRUE.
816  */
817 static
819  SCIP* scip, /**< SCIP pointer */
820  SCIP_VAR** vars, /**< array of variables affected by permutation */
821  int* invperm, /**< inverse of permutation */
822  int nvars, /**< number of variables */
823  int start, /**< at which position to start (assuming previous positions are equal) */
824  int* tempfixings, /**< array with at entry i the virtual fixing of variable vars[i] */
825  int* tempfixentries, /**< the entries i that are virtually fixed until numfixentriesinit */
826  int numfixentriesinit, /**< the number of virtually fixed entries */
827  SCIP_Bool* infeasible, /**< pointer to store whether infeasibility is detected in these fixings */
828  int* infeasibleentry /**< pointer to store at which entry a (0, 1) pattern is found */
829 )
830 {
831  SCIP_VAR* var1;
832  SCIP_VAR* var2;
833  int var1fix;
834  int var2fix;
835 
836  int i;
837  int numfixentries;
838 
839  /* avoid trivial problems */
840  if ( nvars < 2 )
841  return SCIP_OKAY;
842 
843  assert( scip != NULL );
844  assert( vars != NULL );
845  assert( invperm != NULL );
846  assert( tempfixings != NULL );
847  assert( tempfixentries != NULL );
848  assert( infeasible != NULL );
849 
850  /* A counter for how many virtual fixings we have. */
851  numfixentries = numfixentriesinit;
852 
853  *infeasible = FALSE;
854 
855  for (i = start; i < nvars; ++i)
856  {
857  /* there are no fixed points */
858  assert( invperm[i] != i );
859 
860  /* get variables of first and second column */
861  var1 = vars[i];
862  var2 = vars[invperm[i]];
863 
864  assert( var1 != NULL );
865  assert( var2 != NULL );
866 
867  /* Get virtual fixing of variable in left column */
868  var1fix = tempfixings[i];
869  if ( var1fix == NOINIT )
870  {
871  if ( SCIPvarGetUbLocal(var1) < 0.5 )
872  {
873  var1fix = FIXED0;
874  assert( SCIPvarGetLbLocal(var1) <= 0.5 );
875  }
876  else if ( SCIPvarGetLbLocal(var1) > 0.5 )
877  var1fix = FIXED1;
878  else
879  var1fix = UNFIXED;
880  }
881  assert( var1fix != NOINIT );
882 
883  /* Get virtual fixing of variable in right column */
884  var2fix = tempfixings[invperm[i]];
885  if ( var2fix == NOINIT )
886  {
887  if ( SCIPvarGetUbLocal(var2) < 0.5 )
888  {
889  var2fix = FIXED0;
890  assert( SCIPvarGetLbLocal(var2) <= 0.5 );
891  }
892  else if ( SCIPvarGetLbLocal(var2) > 0.5 )
893  var2fix = FIXED1;
894  else
895  var2fix = UNFIXED;
896  }
897  assert( var2fix != NOINIT );
898 
899  /* Encounter one of (_, _), (_, 0), (1, _), (1, 0). In all cases (1, 0) can be constructed. Thus feasible. */
900  if ( var1fix != FIXED0 && var2fix != FIXED1 )
901  break;
902  /* Encounter (0, 1). Infeasible. */
903  else if ( var1fix == FIXED0 && var2fix == FIXED1 )
904  {
905  *infeasible = TRUE;
906  *infeasibleentry = i;
907  break;
908  }
909  /* Encounter (0, _). Virtually fix var2 to 0. */
910  else if ( var1fix == FIXED0 && var2fix == UNFIXED )
911  {
912  tempfixings[invperm[i]] = FIXED0;
913  /* Mark that we have fixed invperm[i]. */
914  tempfixentries[numfixentries++] = invperm[i];
915  }
916  /* Encounter (_, 1). Virtually fix var1 to 1. */
917  else if(var1fix == UNFIXED && var2fix == FIXED1 )
918  {
919  tempfixings[i] = FIXED0;
920  /* Mark that we have fixed invperm[i]. */
921  tempfixentries[numfixentries++] = i;
922  }
923  /* Remaining cases are (0, 0) and (1, 1). In both cases: continue. */
924  }
925 
926  /* Undo virtual fixings made in this function */
927  for (i = numfixentriesinit; i < numfixentries; ++i)
928  {
929  tempfixings[tempfixentries[i]] = NOINIT;
930  tempfixentries[i] = 0;
931  }
932 
933  return SCIP_OKAY;
934 }
935 
936 
937 /** perform propagation of symresack constraint */
938 static
940  SCIP* scip, /**< SCIP pointer */
941  SCIP_CONS* cons, /**< constraint to be propagated */
942  SCIP_Bool* infeasible, /**< pointer to store whether it was detected that the node is infeasible */
943  int* ngen /**< pointer to store number of generated bound strengthenings */
944  )
945 {
946  SCIP_CONSDATA* consdata;
947  SCIP_VAR** vars;
948  int* invperm;
949  int nvars;
950  int i;
951  int r;
952  SCIP_VAR* var1;
953  SCIP_VAR* var2;
954  int var1fix;
955  int var2fix;
956  SCIP_Bool tightened;
957  SCIP_Bool peekinfeasible;
958  int peekinfeasibleentry;
959  int* tempfixings;
960  int* tempfixentries;
961 
962  assert( scip != NULL );
963  assert( cons != NULL );
964  assert( infeasible != NULL );
965  assert( ngen != NULL );
966 
967  SCIPdebugMsg(scip, "Propagating variables of constraint <%s>.\n", SCIPconsGetName(cons));
968 
969  *ngen = 0;
970  *infeasible = FALSE;
971 
972  /* get data of constraint */
973  consdata = SCIPconsGetData(cons);
974  assert( consdata != NULL );
975  nvars = consdata->nvars;
976 
977  /* avoid trivial problems */
978  if ( nvars < 2 )
979  return SCIP_OKAY;
980 
981  assert( consdata->vars != NULL );
982  assert( consdata->invperm != NULL );
983  vars = consdata->vars;
984  invperm = consdata->invperm;
985 
986  /* loop through all variables */
987  for (i = 0; i < nvars; ++i)
988  {
989  /* there are no fixed points */
990  assert( invperm[i] != i );
991 
992  /* get variables of first and second column */
993  var1 = vars[i];
994  var2 = vars[invperm[i]];
995  assert( var1 != NULL );
996  assert( var2 != NULL );
997 
998  /* Get the fixing status of the left column variable var1 */
999  if ( SCIPvarGetUbLocal(var1) < 0.5 )
1000  {
1001  var1fix = FIXED0;
1002  assert( SCIPvarGetLbLocal(var1) <= 0.5 );
1003  }
1004  else if ( SCIPvarGetLbLocal(var1) > 0.5 )
1005  var1fix = FIXED1;
1006  else
1007  var1fix = UNFIXED;
1008 
1009  /* Get the fixing status of the right column variable var2 */
1010  if ( SCIPvarGetUbLocal(var2) < 0.5 )
1011  {
1012  var2fix = FIXED0;
1013  assert( SCIPvarGetLbLocal(var2) <= 0.5 );
1014  }
1015  else if ( SCIPvarGetLbLocal(var2) > 0.5 )
1016  var2fix = FIXED1;
1017  else
1018  var2fix = UNFIXED;
1019 
1020  /* Encounter one of (_, _), (_, 0), (1, _), (1, 0). Check if (1, 1) or (0, 0) are possible, otherwise fix. */
1021  if ( var1fix != FIXED0 && var2fix != FIXED1 )
1022  {
1023  assert( SCIPvarGetUbLocal(var1) > 0.5 );
1024  assert( SCIPvarGetLbLocal(var2) < 0.5 );
1025 
1026  SCIPdebugMsg(scip, "Check variable pair (%d,%d).\n", i, invperm[i]);
1027  SCIPdebugMsg(scip, " -> node is feasible (could set pair to (1,0) and every earlier pair is constant).\n");
1028 
1029  if ( var1fix == UNFIXED || var2fix == UNFIXED )
1030  {
1031  /* Create arrays tempfixings and tempfixentries to store virtual fixings. */
1032  SCIP_CALL( SCIPallocCleanBufferArray(scip, &tempfixings, nvars) );
1033  SCIP_CALL( SCIPallocCleanBufferArray(scip, &tempfixentries, nvars) );
1034 
1035  if ( var1fix == UNFIXED )
1036  {
1037  assert( SCIPvarGetLbLocal(var1) < 0.5 );
1038 
1039  /* Peek whether a lexicographical larger-or-equal vector can be created with var1 fixed to 0 */
1040  SCIPdebugMsg(scip, " -> First entry is not fixed. Check if 0 is feasible.\n");
1041  tempfixings[i] = FIXED0;
1042  tempfixentries[0] = i;
1043  SCIP_CALL( checkFeasible(scip, vars, invperm, nvars, i, tempfixings, tempfixentries, 1,
1044  &peekinfeasible, &peekinfeasibleentry) );
1045 
1046  if ( peekinfeasible )
1047  {
1048  /* No feasible vector exists with var1 set to 0, so it must be a 1-fixing. */
1049  SCIPdebugMsg(scip, " -> First entry is not fixed. 0 is not feasible. Fixing to 1.\n");
1050  SCIP_CALL( SCIPinferVarLbCons(scip, var1, 1.0, cons, i + nvars * peekinfeasibleentry,
1051  FALSE, infeasible, &tightened) ); /*lint !e713*/
1052  assert( ! *infeasible );
1053 
1054  if ( tightened )
1055  ++(*ngen);
1056  }
1057 
1058  tempfixings[i] = NOINIT;
1059  tempfixentries[0] = 0;
1060  }
1061 
1062  if ( var2fix == UNFIXED )
1063  {
1064  assert( SCIPvarGetUbLocal(var2) > 0.5 );
1065 
1066  /* Peek whether a lexicographical larger-or-equal vector can be created with var2 fixed to 1 */
1067  SCIPdebugMsg(scip, " -> Second entry is not fixed. Check if 1 is feasible.\n");
1068  tempfixings[invperm[i]] = FIXED1;
1069  tempfixentries[0] = invperm[i];
1070  SCIP_CALL( checkFeasible(scip, vars, invperm, nvars, i, tempfixings, tempfixentries, 1,
1071  &peekinfeasible, &peekinfeasibleentry) );
1072 
1073  if ( peekinfeasible )
1074  {
1075  /* No feasible vector exists with var2 set to 1, so it must be a 1-fixing. */
1076  SCIPdebugMsg(scip, " -> Second entry is not fixed. 1 is not feasible. Fixing to 0.\n");
1077  SCIP_CALL( SCIPinferVarUbCons(scip, var2, 0.0, cons, i + nvars * peekinfeasibleentry,
1078  FALSE, infeasible, &tightened) ); /*lint !e713*/
1079  assert( ! *infeasible );
1080 
1081  if ( tightened )
1082  ++(*ngen);
1083  }
1084 
1085  tempfixings[invperm[i]] = NOINIT;
1086  tempfixentries[0] = 0;
1087  }
1088 
1089  SCIPfreeCleanBufferArray(scip, &tempfixentries);
1090  SCIPfreeCleanBufferArray(scip, &tempfixings);
1091  }
1092 
1093  /* Can stop here, because this row can become (1, 0). Therefore all next rows can take arbitrary values. */
1094  break;
1095  }
1096  /* Encounter (0, 1): If first part of variable pair fixed to 0 and second part is fixed to 1 */
1097  else if ( var1fix == FIXED0 && var2fix == FIXED1 )
1098  {
1099  SCIPdebugMsg(scip, "Check variable pair (%d,%d).\n", i, invperm[i]);
1100 
1101  SCIPdebugMsg(scip, " -> node infeasible (pair was fixed to (0,1) but there was no pair of type (1,0) before) ---> lexicographical order violated, infeasible.\n");
1102 
1103  /* perform conflict analysis */
1105  {
1107 
1108  for (r = 0; r <= i; ++r)
1109  {
1110  /* there are no fixed points */
1111  assert( invperm[r] != r );
1112 
1113  SCIP_CALL( SCIPaddConflictBinvar(scip, vars[r]) );
1114  SCIP_CALL( SCIPaddConflictBinvar(scip, vars[invperm[r]]) );
1115  }
1116 
1117  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
1118  }
1119 
1120  *infeasible = TRUE;
1121  break;
1122  }
1123  /* Encounter (0, _): Fix second part to 0 */
1124  else if ( var1fix == FIXED0 && var2fix != FIXED0 )
1125  {
1126  assert( SCIPvarGetUbLocal(var1) < 0.5 );
1127  assert( SCIPvarGetLbLocal(var2) < 0.5 );
1128  assert( SCIPvarGetUbLocal(var2) > 0.5 );
1129 
1130  SCIPdebugMsg(scip, "Check variable pair (%d,%d).\n", i, invperm[i]);
1131 
1132  assert( SCIPvarGetLbLocal(var2) < 0.5 );
1133  SCIP_CALL( SCIPinferVarUbCons(scip, var2, 0.0, cons, i, FALSE, infeasible, &tightened) ); /*lint !e713*/
1134  assert( ! *infeasible );
1135 
1136  if ( tightened )
1137  ++(*ngen);
1138  }
1139  /* Encounter (_, 1): fix first part to 1 */
1140  else if ( var1fix != FIXED1 && var2fix == FIXED1 )
1141  {
1142  assert( SCIPvarGetLbLocal(var1) < 0.5 );
1143  assert( SCIPvarGetUbLocal(var1) > 0.5 );
1144  assert( SCIPvarGetLbLocal(var2) > 0.5 );
1145 
1146  SCIPdebugMsg(scip, "Check variable pair (%d,%d).\n", i, invperm[i]);
1147 
1148  assert( SCIPvarGetUbLocal(var1) > 0.5 );
1149  SCIP_CALL( SCIPinferVarLbCons(scip, var1, 1.0, cons, i, FALSE, infeasible, &tightened) ); /*lint !e713*/
1150  assert( ! *infeasible );
1151 
1152  if ( tightened )
1153  ++(*ngen);
1154  }
1155  /* Remaining cases are (0, 0) and (1, 1). In these cases we can continue! */
1156  }
1157 
1158  return SCIP_OKAY;
1159 }
1160 
1161 
1162 /** add symresack cover inequality */
1163 static
1165  SCIP* scip, /**< SCIP pointer */
1166  SCIP_CONS* cons, /**< constraint */
1167  int nvars, /**< number of variables */
1168  SCIP_VAR** vars, /**< variables */
1169  int* coeffs, /**< coefficient vector of inequality to be added */
1170  SCIP_Real rhs, /**< right-hand side of inequality to be added */
1171  SCIP_Bool* infeasible /**< pointer to store whether we detected infeasibility */
1172  )
1173 {
1174  SCIP_ROW* row;
1175  int i;
1176 #ifdef SCIP_DEBUG
1177  SCIP_CONSDATA* consdata;
1178  char name[SCIP_MAXSTRLEN];
1179 #endif
1180 
1181  assert( scip != NULL );
1182  assert( cons != NULL );
1183  assert( nvars > 0 );
1184  assert( vars != NULL );
1185  assert( coeffs != NULL );
1186  assert( infeasible != NULL );
1187 
1188  *infeasible = FALSE;
1189 
1190 #ifdef SCIP_DEBUG
1191  consdata = SCIPconsGetData(cons);
1192  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "symresack_cover_%s_%d", SCIPconsGetName(cons), consdata->debugcnt);
1193  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, name, -SCIPinfinity(scip), rhs, FALSE, FALSE, TRUE) );
1194  ++consdata->debugcnt;
1195 #else
1196  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, "", -SCIPinfinity(scip), rhs, FALSE, FALSE, TRUE) );
1197 #endif
1198  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
1199 
1200  for (i = 0; i < nvars; ++i)
1201  {
1202  if ( coeffs[i] == 1 || coeffs[i] == -1 )
1203  {
1204  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[i], (SCIP_Real) coeffs[i]) );
1205  }
1206  }
1207  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
1208  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
1209  SCIP_CALL( SCIPreleaseRow(scip, &row) );
1210 
1211  return SCIP_OKAY;
1212 }
1213 
1214 
1215 /** Maximize a linear function on a "strict" symresack,
1216  * that is a symresack where we do not allow the solution x = gamma(x).
1217  */
1218 static
1220  SCIP* scip, /**< SCIP pointer */
1221  int nvars, /**< number of variables in symresack */
1222  SCIP_Real* objective, /**< the objective vector */
1223  int* perm, /**< the permutation (without fixed points) as an array */
1224  int* invperm, /**< the inverse permutation as an array */
1225  int* maxcrit, /**< pointer to the critical entry where optimality is found at */
1226  SCIP_Real* maxsoluval /**< pointer to store the optimal objective value */
1227  )
1228 {
1229  /* The maximal objective in every iteration. */
1230  SCIP_Real tmpobj;
1231  /* The new value of componentobj when combining two components. */
1232  SCIP_Real tmpnewcompobj;
1233  /* helperobj is the sum of all positive objective-sums for all components. */
1234  SCIP_Real helperobj = 0.0;
1235 
1236  int crit;
1237  int critinv;
1238  int i;
1239 
1240  /* For every vertex of degree < 2 we maintain componentends and componentobj. */
1241  int* componentends;
1242  SCIP_Real* componentobj;
1243 
1244  assert( scip != NULL );
1245  assert( nvars > 0 );
1246  assert( objective != NULL );
1247  assert( perm != NULL );
1248  assert( invperm != NULL );
1249  assert( maxcrit != NULL );
1250  assert( maxsoluval != NULL );
1251 
1252  /* The current best known critical entry and objective */
1253  *maxcrit = -1;
1254  *maxsoluval = -SCIP_DEFAULT_INFINITY;
1255 
1256  SCIP_CALL( SCIPallocBufferArray(scip, &componentends, nvars) );
1257  SCIP_CALL( SCIPallocBufferArray(scip, &componentobj, nvars) );
1258 
1259  /* Initialization: Every entry is a component in the graph,
1260  * having the corresponding objective
1261  */
1262  for (i = 0; i < nvars; ++i)
1263  {
1264  componentends[i] = i;
1265  componentobj[i] = objective[i];
1266  if ( SCIPisGT(scip, objective[i], 0.0) )
1267  helperobj += objective[i];
1268  }
1269 
1270  /* Iterate over all critical rows, and of the graph maintain the components on the vertices of degree < 2. */
1271  for (crit = 0; crit < nvars; ++crit)
1272  {
1273  critinv = invperm[crit];
1274 
1275  /* Do not allow fixed points. */
1276  assert( crit != critinv );
1277 
1278  /* If the other end of the component of crit is critinv, then crit cannot be a critical entry. */
1279  if ( componentends[crit] == critinv )
1280  continue;
1281 
1282  /* Compute objective for crit as critical entry. Update if it is better than the best found objective */
1283  tmpobj = helperobj;
1284  if ( SCIPisLT(scip, componentobj[crit], 0.0) )
1285  tmpobj += componentobj[crit];
1286  if ( SCIPisGT(scip, componentobj[critinv], 0.0) )
1287  tmpobj -= componentobj[critinv];
1288  if ( SCIPisGT(scip, tmpobj, *maxsoluval) )
1289  {
1290  *maxsoluval = tmpobj;
1291  *maxcrit = crit;
1292  }
1293 
1294  /* Update helperobj */
1295  tmpnewcompobj = componentobj[crit] + componentobj[critinv];
1296  if ( SCIPisGT(scip, componentobj[crit], 0.0) )
1297  helperobj -= componentobj[crit];
1298  if ( SCIPisGT(scip, componentobj[critinv], 0.0) )
1299  helperobj -= componentobj[critinv];
1300  if ( SCIPisGT(scip, tmpnewcompobj, 0.0) )
1301  helperobj += tmpnewcompobj;
1302 
1303  /* Update the objective of a component */
1304  componentobj[componentends[crit]] = tmpnewcompobj;
1305  componentobj[componentends[critinv]] = tmpnewcompobj;
1306 
1307  /* Connect the endpoints of the newly created path */
1308  if ( componentends[crit] == crit )
1309  {
1310  componentends[crit] = componentends[critinv];
1311  componentends[componentends[critinv]] = crit;
1312  }
1313  else
1314  {
1315  componentends[componentends[crit]] = componentends[critinv];
1316  componentends[componentends[critinv]] = componentends[crit];
1317  }
1318 
1319  /* Early termination criterion. helperobj is upper bound to tmpobj for every next iteration,
1320  * so if helperobj <= maxsoluval then we can terminate earlier.
1321  */
1322  if ( SCIPisGE(scip, *maxsoluval, helperobj) )
1323  break;
1324  }
1325 
1326  /* It is always possible to make the first entry critical. */
1327  assert( *maxcrit >= 0 );
1328 
1329  SCIPfreeBufferArray(scip, &componentobj);
1330  SCIPfreeBufferArray(scip, &componentends);
1331 
1332  return SCIP_OKAY;
1333 }
1334 
1335 
1336 /** For a symresack, determine a maximizer for optimizing linear function
1337  * over a symresack, where the critical entry is fixed.
1338  */
1339 static
1341  SCIP* scip, /**< SCIP pointer */
1342  int nvars, /**< number of variables in symresack */
1343  SCIP_Real* objective, /**< the objective vector */
1344  int* perm, /**< the permutation (without fixed points) as an array */
1345  int* invperm, /**< the inverse permutation as an array */
1346  int crit, /**< critical entry where optimality is found at */
1347  int* maxsolu /**< pointer to the optimal objective array */
1348  )
1349 {
1350  /* Compute to which components all entries belong. */
1351  int* entrycomponent;
1352  SCIP_Real* componentobjective;
1353 
1354  int i;
1355  int c;
1356 
1357  assert( scip != NULL );
1358  assert( nvars > 0 );
1359  assert( objective != NULL );
1360  assert( perm != NULL );
1361  assert( invperm != NULL );
1362  assert( maxsolu != NULL );
1363  assert( crit >= 0 );
1364  assert( crit <= nvars );
1365 
1366  SCIP_CALL( SCIPallocBufferArray(scip, &entrycomponent, nvars) );
1367  SCIP_CALL( SCIPallocBufferArray(scip, &componentobjective, nvars) );
1368 
1369  /* Initially: Everything forms its own component */
1370  for (i = 0; i < nvars; ++i)
1371  {
1372  entrycomponent[i] = i;
1373  componentobjective[i] = objective[i];
1374  }
1375  for (i = 0; i < crit; ++i)
1376  {
1377  /* The graph with arcs {i, invperm[i]} if i < c is a collection of paths, cycles and singletons.
1378  * Label the vertices to the lowest entry in the component, and store the value of that in this component.
1379  * Every inner while-loop labels one new vertex per iteration, and a vertex is relabeled exactly once.
1380  */
1381  if ( entrycomponent[i] < i )
1382  {
1383  /* This entry is already included in a component. */
1384  continue;
1385  }
1386 
1387  /* Follow the path forward: Take edges {c, invperm[c]} until c >= crit, or a cycle is found. */
1388  c = i;
1389  while( c < crit )
1390  {
1391  /* c < crit, so edge {c, invperm[c]} exists. Label invperm[c] as part of component of i */
1392  c = invperm[c];
1393 
1394  /* Stop if we find a cycle. */
1395  if ( entrycomponent[c] != c )
1396  break;
1397 
1398  entrycomponent[c] = i;
1399  componentobjective[i] += objective[c];
1400  }
1401 
1402  /* Follow the path backward: Take edges {c, perm[c]} until perm[c] >= crit, or a cycle is found. */
1403  c = perm[i];
1404  while( c < crit )
1405  {
1406  /* c < crit, so edge {c, invperm[c]} exists. Label c as part of component of i */
1407 
1408  /* Stop if we find a cycle. */
1409  if ( entrycomponent[c] != c )
1410  break;
1411 
1412  entrycomponent[c] = i;
1413  componentobjective[i] += objective[c];
1414  /* For next iteration: We do another step back */
1415  c = perm[c];
1416  }
1417  }
1418 
1419  /* Now fill the objective vector.
1420  * For the component containing crit, set the value to 1.
1421  * For the component contraining invperm[crit], set the value to 0.
1422  * For the other components, set the value to 1 if the objective sum is positive.
1423  * Otherwise to 0.
1424  */
1425  for (i = 0; i < nvars; ++i)
1426  {
1427  if ( entrycomponent[i] == entrycomponent[crit] )
1428  maxsolu[i] = 1;
1429  else if ( entrycomponent[i] == entrycomponent[invperm[crit]] )
1430  maxsolu[i] = 0;
1431  else if ( SCIPisGT(scip, componentobjective[entrycomponent[i]], 0.0) )
1432  maxsolu[i] = 1;
1433  else
1434  maxsolu[i] = 0;
1435  }
1436 
1437  SCIPfreeBufferArray(scip, &componentobjective);
1438  SCIPfreeBufferArray(scip, &entrycomponent);
1439 
1440  return SCIP_OKAY;
1441 }
1442 
1443 
1444 /** separate symresack cover inequalities
1445  *
1446  * We currently do NOT enter cuts into the pool.
1447  */
1448 static
1450  SCIP* scip, /**< SCIP pointer */
1451  SCIP_CONS* cons, /**< constraint */
1452  const SCIP_CONSDATA* consdata, /**< constraint data */
1453  SCIP_Real* vals, /**< solution values of variables */
1454  int* ngen, /**< pointer to store the number of separated covers */
1455  SCIP_Bool* infeasible /**< pointer to store whether we detected infeasibility */
1456  )
1457 {
1458  SCIP_Real constobjective;
1459  SCIP_Real* sepaobjective;
1460  SCIP_Real maxsoluobj = 0.0;
1461  int* maxsolu;
1462  int* invperm;
1463  int* perm;
1464  int nvars;
1465  int maxcrit;
1466  int i;
1467 
1468  *infeasible = FALSE;
1469  *ngen = 0;
1470 
1471  assert( scip != NULL );
1472  assert( consdata != NULL );
1473 
1474  /* we do not have to take care of trivial constraints */
1475  if ( consdata->nvars < 2 )
1476  return SCIP_OKAY;
1477 
1478  assert( consdata->vars != NULL );
1479  assert( consdata->perm != NULL );
1480  assert( consdata->invperm != NULL );
1481  assert( infeasible != NULL );
1482  assert( ngen != NULL );
1483 
1484  nvars = consdata->nvars;
1485  perm = consdata->perm;
1486  invperm = consdata->invperm;
1487 
1488  /* initialize objective */
1489  SCIP_CALL( SCIPallocBufferArray(scip, &sepaobjective, nvars) );
1490 
1491  constobjective = 1.0; /* constant part of separation objective */
1492  for (i = 0; i < nvars; ++i)
1493  {
1494  if ( i < perm[i] )
1495  sepaobjective[i] = - vals[i];
1496  else
1497  {
1498  sepaobjective[i] = 1.0 - vals[i];
1499  constobjective += vals[i] - 1.0;
1500  }
1501  }
1502 
1503  /* allocate memory for temporary and global solution */
1504  SCIP_CALL( SCIPallocBufferArray(scip, &maxsolu, nvars) );
1505 
1506  /* Find critical row of a maximally violated cover */
1507  SCIP_CALL( maximizeObjectiveSymresackStrict(scip, nvars, sepaobjective, perm, invperm, &maxcrit, &maxsoluobj) );
1508  assert( maxcrit >= 0 );
1509  SCIPdebugMsg(scip, "Critical row %d found; Computing maximally violated cover.\n", maxcrit);
1510  SCIP_CALL( maximizeObjectiveSymresackCriticalEntry(scip, nvars, sepaobjective, perm, invperm, maxcrit, maxsolu) );
1511 
1512  /* Add constant to maxsoluobj to get the real objective */
1513  maxsoluobj += constobjective;
1514 
1515  /* Check whether the separation objective is positive, i.e., a violated cover was found. */
1516  if ( SCIPisEfficacious(scip, maxsoluobj) )
1517  {
1518  /* Now add the cut. Reuse array maxsolu as coefficient vector for the constraint. */
1519  SCIP_Real rhs = -1.0;
1520  for (i = 0; i < nvars; ++i)
1521  {
1522  if ( i < perm[i] )
1523  maxsolu[i] = -maxsolu[i];
1524  else
1525  {
1526  if ( maxsolu[i] == 0 )
1527  rhs += 1.0;
1528  maxsolu[i] = 1 - maxsolu[i];
1529  }
1530  }
1531 
1532  /* add cover inequality */
1533  SCIP_CALL( addSymresackInequality(scip, cons, nvars, consdata->vars, maxsolu, rhs, infeasible) );
1534 
1535  if ( ! *infeasible )
1536  ++(*ngen);
1537  }
1538 
1539  SCIPfreeBufferArrayNull(scip, &maxsolu);
1540  SCIPfreeBufferArrayNull(scip, &sepaobjective);
1541 
1542  return SCIP_OKAY;
1543 }
1544 
1545 
1546 /** check whether solution is feasible for symresacks */
1547 static
1549  SCIP* scip, /**< SCIP pointer */
1550  SCIP_CONS* cons, /**< constrained for which we check the solution */
1551  SCIP_SOL* sol, /**< solution to be checked */
1552  SCIP_RESULT* result, /**< pointer to store whether we detected infeasibility */
1553  SCIP_Bool printreason /**< whether reason for infeasibility should be printed */
1554  )
1555 {
1556  SCIP_CONSDATA* consdata;
1557  SCIP_VAR** vars;
1558  int* invperm;
1559  int nvars;
1560  int i;
1561 
1562  assert( cons != NULL );
1563  consdata = SCIPconsGetData(cons);
1564  assert( consdata != NULL);
1565 
1566  /* we do not have to take care of trivial constraints */
1567  if ( consdata->nvars < 2 )
1568  return SCIP_OKAY;
1569 
1570  assert( consdata->vars != NULL );
1571  assert( consdata->invperm != NULL );
1572 
1573  SCIPdebugMsg(scip, "Check method for symresack constraint <%s> (%d rows) ...\n", SCIPconsGetName(cons), consdata->nvars);
1574 
1575  nvars = consdata->nvars;
1576  vars = consdata->vars;
1577  invperm = consdata->invperm;
1578 
1579  /* detect first non-constant pair of variables */
1580  for (i = 0; i < nvars; ++i)
1581  {
1582  SCIP_Real solval;
1583  int val1;
1584  int val2;
1585 
1586  /* there are no fixed points */
1587  assert( invperm[i] != i );
1588 
1589  /* get value of variable i and its inverse */
1590  solval = SCIPgetSolVal(scip, sol, vars[i]);
1591  assert( SCIPisFeasIntegral(scip, solval) );
1592  if ( solval > 0.5 )
1593  val1 = 1;
1594  else
1595  val1 = 0;
1596 
1597  solval = SCIPgetSolVal(scip, sol, vars[invperm[i]]);
1598  assert( SCIPisFeasIntegral(scip, solval) );
1599  if ( solval > 0.5 )
1600  val2 = 1;
1601  else
1602  val2 = 0;
1603 
1604  /* if we detected a constant pair */
1605  if ( val1 == val2 )
1606  continue;
1607  /* pair is (1,0) --> lexicographically maximal */
1608  else if ( val1 > val2 )
1609  break;
1610 
1611  /* pair is (0,1) --> solution is infeasible */
1612  assert( val2 > val1 );
1613  SCIPdebugMsg(scip, "Solution is infeasible.\n");
1614  *result = SCIP_INFEASIBLE;
1615 
1616  if ( printreason )
1617  SCIPinfoMessage(scip, NULL, "First non-constant pair (%d, %d) of variables has pattern (0,1).\n", i, invperm[i]);
1618 
1619  break;
1620  }
1621 
1622  return SCIP_OKAY;
1623 }
1624 
1625 
1626 /** Upgrade symresack constraints to orbisacks */
1627 static
1629  SCIP* scip, /**< SCIP pointer */
1630  SCIP_CONS** cons, /**< pointer to hold the created constraint */
1631  const char* name, /**< name of constraint */
1632  int* perm, /**< permutation */
1633  SCIP_VAR** inputvars, /**< permuted variables array */
1634  int nvars, /**< size of perm array */
1635  SCIP_Bool* upgrade, /**< whether constraint was upgraded */
1636  SCIP_Bool ismodelcons, /**< whether the symresack is a model constraint */
1637  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
1638  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1639  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
1640  * Usually set to TRUE. */
1641  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
1642  * TRUE for model constraints, FALSE for additional, redundant constraints. */
1643  SCIP_Bool check, /**< should the constraint be checked for feasibility?
1644  * TRUE for model constraints, FALSE for additional, redundant constraints. */
1645  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
1646  * Usually set to TRUE. */
1647  SCIP_Bool local, /**< is constraint only valid locally?
1648  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1649  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
1650  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
1651  * adds coefficients to this constraint. */
1652  SCIP_Bool dynamic, /**< is constraint subject to aging?
1653  * Usually set to FALSE. Set to TRUE for own cuts which
1654  * are separated as constraints. */
1655  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
1656  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
1657  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
1658  * if it may be moved to a more global node?
1659  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
1660  )
1661 {
1662  SCIP_CONSHDLR* conshdlr;
1663  SCIP_VAR** vars1;
1664  SCIP_VAR** vars2;
1665  int nrows = 0;
1666  int i;
1667 
1668  assert( scip != NULL );
1669  assert( perm != NULL );
1670  assert( nvars > 0 );
1671  assert( inputvars != NULL );
1672  assert( upgrade != NULL );
1673 
1674  *upgrade = TRUE;
1675 
1676  /* check whether orbisack conshdlr is available */
1677  conshdlr = SCIPfindConshdlr(scip, "orbisack");
1678  if ( conshdlr == NULL )
1679  {
1680  *upgrade = FALSE;
1681  SCIPdebugMsg(scip, "Cannot check whether symresack constraint can be upgraded to orbisack constraint. ");
1682  SCIPdebugMsg(scip, "---> Orbisack constraint handler not found.\n");
1683 
1684  return SCIP_OKAY;
1685  }
1686 
1687  SCIP_CALL( SCIPallocBufferArray(scip, &vars1, nvars) );
1688  SCIP_CALL( SCIPallocBufferArray(scip, &vars2, nvars) );
1689 
1690  /* check whether permutation is a composition of 2-cycles */
1691  for (i = 0; i < nvars; ++i)
1692  {
1693  /* ignore non-binary variables */
1694  if ( ! SCIPvarIsBinary(inputvars[i]) )
1695  continue;
1696 
1697  if ( perm[perm[i]] != i )
1698  {
1699  *upgrade = FALSE;
1700  break;
1701  }
1702 
1703  if ( perm[i] > i )
1704  {
1705  vars1[nrows] = inputvars[i];
1706  vars2[nrows++] = inputvars[perm[i]];
1707 
1708  assert( nrows <= nvars );
1709  }
1710  }
1711 
1712  /* if permutation can be upgraded to an orbisack */
1713  if ( nrows == 0 )
1714  *upgrade = FALSE;
1715  else if ( *upgrade )
1716  {
1717  SCIP_CALL( SCIPcreateConsOrbisack(scip, cons, name, vars1, vars2, nrows, FALSE, FALSE, ismodelcons,
1718  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
1719  }
1720 
1721  SCIPfreeBufferArray(scip, &vars2);
1722  SCIPfreeBufferArray(scip, &vars1);
1723 
1724  return SCIP_OKAY;
1725 }
1726 
1727 
1728 /** creates a symmetry breaking constraint
1729  *
1730  * Depending on the given permutation, either an orbisack or symresack constraint
1731  * is created.
1732  */
1734  SCIP* scip, /**< SCIP data structure */
1735  SCIP_CONS** cons, /**< pointer to hold the created constraint */
1736  const char* name, /**< name of constraint */
1737  int* perm, /**< permutation */
1738  SCIP_VAR** vars, /**< variables */
1739  int nvars, /**< number of variables in vars array */
1740  SCIP_Bool ismodelcons, /**< whether the added constraint is a model constraint */
1741  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
1742  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
1743  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
1744  * Usually set to TRUE. */
1745  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
1746  * TRUE for model constraints, FALSE for additional, redundant constraints. */
1747  SCIP_Bool check, /**< should the constraint be checked for feasibility?
1748  * TRUE for model constraints, FALSE for additional, redundant constraints. */
1749  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
1750  * Usually set to TRUE. */
1751  SCIP_Bool local, /**< is constraint only valid locally?
1752  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
1753  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
1754  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
1755  * adds coefficients to this constraint. */
1756  SCIP_Bool dynamic, /**< is constraint subject to aging?
1757  * Usually set to FALSE. Set to TRUE for own cuts which
1758  * are separated as constraints. */
1759  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
1760  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
1761  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
1762  * if it may be moved to a more global node?
1763  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
1764  )
1765 {
1766  SCIP_Bool upgrade = FALSE;
1767 
1768  assert( scip != NULL );
1769  assert( cons != NULL );
1770  assert( perm != NULL );
1771  assert( vars != NULL );
1772  assert( nvars > 0 );
1773 
1774  SCIP_CALL( orbisackUpgrade(scip, cons, name, perm, vars, nvars, &upgrade, ismodelcons,
1775  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
1776 
1777  if ( ! upgrade )
1778  {
1779  SCIP_CALL( SCIPcreateConsSymresack(scip, cons, name, perm, vars, nvars, ismodelcons,
1780  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
1781  }
1782 
1783  return SCIP_OKAY;
1784 }
1785 
1786 
1787 /*--------------------------------------------------------------------------------------------
1788  *--------------------------------- SCIP functions -------------------------------------------
1789  *--------------------------------------------------------------------------------------------*/
1790 
1791 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
1792 static
1793 SCIP_DECL_CONSHDLRCOPY(conshdlrCopySymresack)
1794 { /*lint --e{715}*/
1795  assert(scip != NULL);
1796  assert(conshdlr != NULL);
1797  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
1798 
1799  /* call inclusion method of constraint handler */
1801 
1802  *valid = TRUE;
1803 
1804  return SCIP_OKAY;
1805 }
1806 
1807 
1808 /** frees specific constraint data */
1809 static
1810 SCIP_DECL_CONSDELETE(consDeleteSymresack)
1811 { /*lint --e{715}*/
1812  assert( scip != NULL );
1813  assert( conshdlr != NULL );
1814  assert( consdata != NULL );
1815  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
1816 
1817  SCIP_CALL( consdataFree(scip, consdata) );
1818 
1819  return SCIP_OKAY;
1820 }
1821 
1822 
1823 /** frees constraint handler */
1824 static
1825 SCIP_DECL_CONSFREE(consFreeSymresack)
1826 { /*lint --e{715}*/
1827  SCIP_CONSHDLRDATA* conshdlrdata;
1828 
1829  assert( scip != NULL );
1830  assert( conshdlr != NULL );
1831  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
1832 
1833  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1834  assert( conshdlrdata != NULL );
1835 
1836  SCIPfreeBlockMemory(scip, &conshdlrdata);
1837 
1838  return SCIP_OKAY;
1839 }
1840 
1841 
1842 /** transforms constraint data into data belonging to the transformed problem */
1843 static
1844 SCIP_DECL_CONSTRANS(consTransSymresack)
1846  SCIP_CONSDATA* sourcedata;
1847  SCIP_CONSDATA* consdata = NULL;
1848  int nvars;
1849  int i;
1850 
1851  assert( scip != NULL );
1852  assert( conshdlr != NULL );
1853  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
1854  assert( sourcecons != NULL );
1855  assert( targetcons != NULL );
1856 
1857  SCIPdebugMsg(scip, "Transforming constraint.\n");
1858 
1859  /* get data of original constraint */
1860  sourcedata = SCIPconsGetData(sourcecons);
1861  assert( sourcedata != NULL);
1862 
1863  /* constraint might be empty and not deleted if no presolving took place */
1864  assert( sourcedata->nvars == 0 || sourcedata->vars != NULL );
1865  assert( sourcedata->nvars == 0 || sourcedata->perm != NULL );
1866  assert( sourcedata->nvars == 0 || sourcedata->invperm != NULL );
1867 #ifndef NDEBUG
1868  if ( sourcedata->ppupgrade )
1869  {
1870  assert( sourcedata->nvars > 0 );
1871  assert( sourcedata->ncycles != 0 );
1872  assert( sourcedata->cycledecomposition != NULL );
1873  for (i = 0; i < sourcedata->ncycles; ++i)
1874  {
1875  assert( sourcedata->cycledecomposition[i] != NULL );
1876  assert( sourcedata->cycledecomposition[i][0] != 0 );
1877  }
1878  }
1879 #endif
1880 
1881  /* create transformed constraint data
1882  *
1883  * do NOT call consdataCreate() again to avoid doing the packing-upgrade check twice
1884  */
1885  nvars = sourcedata->nvars;
1886 
1887  SCIP_CALL( SCIPallocBlockMemory(scip, &consdata) );
1888 
1889  consdata->vars = NULL;
1890  consdata->nvars = nvars;
1891  consdata->perm = NULL;
1892  consdata->invperm = NULL;
1893  consdata->ppupgrade = sourcedata->ppupgrade;
1894  consdata->ismodelcons = sourcedata->ismodelcons;
1895 #ifdef SCIP_DEBUG
1896  consdata->debugcnt = 0;
1897 #endif
1898  consdata->ncycles = 0;
1899  consdata->cycledecomposition = NULL;
1900  consdata->ndescentpoints = 0;
1901  consdata->descentpoints = NULL;
1902 
1903  if ( nvars > 0 )
1904  {
1905  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &consdata->vars, nvars) );
1906  SCIP_CALL( SCIPgetTransformedVars(scip, nvars, sourcedata->vars, consdata->vars) );
1907  for (i = 0; i < nvars; ++i)
1908  {
1909  SCIP_CALL( SCIPcaptureVar(scip, consdata->vars[i]) );
1910  }
1911 
1912  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->perm, sourcedata->perm, nvars) );
1913  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->invperm, sourcedata->invperm, nvars) );
1914 
1915  if ( sourcedata->ppupgrade )
1916  {
1917  consdata->ncycles = sourcedata->ncycles;
1918  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->cycledecomposition, sourcedata->cycledecomposition, sourcedata->ncycles) );
1919  for (i = 0; i < sourcedata->ncycles; ++i)
1920  {
1921  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->cycledecomposition[i], sourcedata->cycledecomposition[i], nvars + 1) ); /*lint !e866*/
1922  }
1923 
1924  consdata->ndescentpoints = sourcedata->ndescentpoints;
1925  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &consdata->descentpoints, sourcedata->descentpoints, sourcedata->ndescentpoints) );
1926  }
1927 
1928  /* Make sure that all variables cannot be multiaggregated (this cannot be handled by cons_symresack, since one cannot
1929  * easily eliminate single variables from a symresack constraint).
1930  *
1931  * We need to call this again to ensure that multiaggregation is forbidden also if the constraint was part
1932  * of the original problem.
1933  */
1934  for (i = 0; i < sourcedata->nvars; ++i)
1935  {
1936  SCIP_CALL( SCIPgetTransformedVar(scip, consdata->vars[i], &consdata->vars[i]) );
1937  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, consdata->vars[i]) );
1938  }
1939  }
1940 
1941  /* create transformed constraint */
1942  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, consdata,
1943  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons),
1944  SCIPconsIsEnforced(sourcecons), SCIPconsIsChecked(sourcecons),
1945  SCIPconsIsPropagated(sourcecons), SCIPconsIsLocal(sourcecons),
1946  SCIPconsIsModifiable(sourcecons), SCIPconsIsDynamic(sourcecons),
1947  SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
1948 
1949  return SCIP_OKAY;
1950 }
1951 
1952 
1953 /** LP initialization method of constraint handler (called before the initial LP relaxation at a node is solved) */
1954 static
1955 SCIP_DECL_CONSINITLP(consInitlpSymresack)
1957  int c;
1958  SCIP_CONSHDLRDATA* conshdlrdata;
1959 
1960  assert( infeasible != NULL );
1961  *infeasible = FALSE;
1962 
1963  assert( scip != NULL );
1964  assert( conshdlr != NULL );
1965  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
1966 
1967  conshdlrdata = SCIPconshdlrGetData(conshdlr);
1968  assert( conshdlrdata != NULL );
1969 
1970  /* loop through constraints */
1971  for (c = 0; c < nconss; ++c)
1972  {
1973  assert( conss[c] != NULL );
1974 
1975  SCIPdebugMsg(scip, "Generating initial symresack cut for constraint <%s> ...\n", SCIPconsGetName(conss[c]));
1976 
1977  SCIP_CALL( initLP(scip, conss[c], conshdlrdata->checkmonotonicity, infeasible) );
1978  if ( *infeasible )
1979  break;
1980  }
1981  SCIPdebugMsg(scip, "Generated initial symresack cuts.\n");
1982 
1983  return SCIP_OKAY;
1984 }
1985 
1986 
1987 /** solving process initialization method of constraint handler (called when branch and bound process is about to begin) */
1988 static
1989 SCIP_DECL_CONSINITSOL(consInitsolSymresack)
1991  SCIP_CONSHDLRDATA* conshdlrdata;
1992  int c;
1993 
1994  assert( scip != NULL );
1995  assert( conshdlr != NULL );
1996  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
1997 
1998  /* determine maximum number of vars in a symresack constraint */
1999  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2000  assert( conshdlrdata != NULL );
2001 
2002  conshdlrdata->maxnvars = 0;
2003 
2004  /* loop through constraints */
2005  for (c = 0; c < nconss; ++c)
2006  {
2007  SCIP_CONSDATA* consdata;
2008 
2009  assert( conss[c] != NULL );
2010 
2011  consdata = SCIPconsGetData(conss[c]);
2012  assert( consdata != NULL );
2013 
2014  /* update conshdlrdata if necessary */
2015  if ( consdata->nvars > conshdlrdata->maxnvars )
2016  conshdlrdata->maxnvars = consdata->nvars;
2017  }
2018 
2019  return SCIP_OKAY;
2020 }
2021 
2022 
2023 /** separation method of constraint handler for LP solution */
2024 static
2025 SCIP_DECL_CONSSEPALP(consSepalpSymresack)
2026 { /*lint --e{715}*/
2027  SCIP_CONSHDLRDATA* conshdlrdata;
2028  SCIP_CONSDATA* consdata;
2029  SCIP_Real* vals;
2030  int maxnvars;
2031  int c;
2032 
2033  assert( scip != NULL );
2034  assert( conshdlr != NULL );
2035  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2036  assert( result != NULL );
2037 
2038  SCIPdebugMsg(scip, "Separation method for symresack constraints\n");
2039 
2040  *result = SCIP_DIDNOTRUN;
2041 
2042  /* if solution is not integer */
2043  if ( SCIPgetNLPBranchCands(scip) == 0 )
2044  return SCIP_OKAY;
2045 
2046  if ( nconss == 0 )
2047  return SCIP_OKAY;
2048 
2049  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2050  assert( conshdlrdata != NULL );
2051 
2052  maxnvars = conshdlrdata->maxnvars;
2053  assert( maxnvars > 0 );
2054 
2055  SCIP_CALL( SCIPallocBufferArray(scip, &vals, maxnvars) );
2056 
2057  /* loop through constraints */
2058  for (c = 0; c < nconss; ++c)
2059  {
2060  SCIP_Bool infeasible = FALSE;
2061  int ngen = 0;
2062 
2063  SCIPdebugMsg(scip, "Separating symresack constraint <%s> ...\n", SCIPconsGetName(conss[c]));
2064 
2065  /* get data of constraint */
2066  assert( conss[c] != NULL );
2067  consdata = SCIPconsGetData(conss[c]);
2068 
2069  if ( consdata->nvars == 0 )
2070  continue;
2071 
2072  /* get solution */
2073  assert( consdata->nvars <= maxnvars );
2074  SCIP_CALL( SCIPgetSolVals(scip, NULL, consdata->nvars, consdata->vars, vals) );
2075  SCIP_CALL( separateSymresackCovers(scip, conss[c], consdata, vals, &ngen, &infeasible) );
2076 
2077  if ( infeasible )
2078  {
2079  *result = SCIP_CUTOFF;
2080  SCIPfreeBufferArray(scip, &vals);
2081 
2082  return SCIP_OKAY;
2083  }
2084 
2085  if ( ngen > 0 )
2086  *result = SCIP_SEPARATED;
2087 
2088  if ( *result == SCIP_DIDNOTRUN )
2089  *result = SCIP_DIDNOTFIND;
2090  }
2091  SCIPfreeBufferArray(scip, &vals);
2092 
2093  return SCIP_OKAY;
2094 }
2095 
2096 
2097 /** separation method of constraint handler for arbitrary primal solution */
2098 static
2099 SCIP_DECL_CONSSEPASOL(consSepasolSymresack)
2100 { /*lint --e{715}*/
2101  SCIP_CONSHDLRDATA* conshdlrdata;
2102  SCIP_CONSDATA* consdata;
2103  SCIP_Real* vals;
2104  int maxnvars;
2105  int c;
2106 
2107  assert( scip != NULL );
2108  assert( conshdlr != NULL );
2109  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2110  assert( result != NULL );
2111 
2112  SCIPdebugMsg(scip, "Separation method for symresack constraints\n");
2113 
2114  *result = SCIP_DIDNOTRUN;
2115 
2116  if ( nconss == 0 )
2117  return SCIP_OKAY;
2118 
2119  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2120  assert( conshdlrdata != NULL );
2121 
2122  maxnvars = conshdlrdata->maxnvars;
2123  assert( maxnvars > 0 );
2124 
2125  SCIP_CALL( SCIPallocBufferArray(scip, &vals, maxnvars) );
2126 
2127  /* loop through constraints */
2128  for (c = 0; c < nconss; ++c)
2129  {
2130  SCIP_Bool infeasible = FALSE;
2131  int ngen = 0;
2132 
2133  SCIPdebugMsg(scip, "Separating symresack constraint <%s> ...\n", SCIPconsGetName(conss[c]));
2134 
2135  /* get data of constraint */
2136  assert( conss[c] != NULL );
2137  consdata = SCIPconsGetData(conss[c]);
2138 
2139  if ( consdata->nvars == 0 )
2140  continue;
2141 
2142  /* get solution */
2143  assert( consdata->nvars <= maxnvars );
2144  SCIP_CALL( SCIPgetSolVals(scip, sol, consdata->nvars, consdata->vars, vals) );
2145  SCIP_CALL( separateSymresackCovers(scip, conss[c], consdata, vals, &ngen, &infeasible) );
2146 
2147  if ( infeasible )
2148  {
2149  *result = SCIP_CUTOFF;
2150  SCIPfreeBufferArray(scip, &vals);
2151 
2152  return SCIP_OKAY;
2153  }
2154 
2155  if ( ngen > 0 )
2156  *result = SCIP_SEPARATED;
2157 
2158  if ( *result == SCIP_DIDNOTRUN )
2159  *result = SCIP_DIDNOTFIND;
2160  }
2161  SCIPfreeBufferArray(scip, &vals);
2162 
2163  return SCIP_OKAY;
2164 }
2165 
2166 
2167 /** constraint enforcing method of constraint handler for LP solutions.
2168  *
2169  * To check feasibility, we separate cover inequalities.
2170  *
2171  * @pre It is assumed that the solution is integral (this can be ensured by appropriate priorities).
2172  */
2173 static
2174 SCIP_DECL_CONSENFOLP(consEnfolpSymresack)
2175 { /*lint --e{715}*/
2176  SCIP_CONSDATA* consdata;
2177  int c;
2178 
2179  assert( scip != NULL );
2180  assert( conshdlr != NULL );
2181  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2182  assert( result != NULL );
2183 
2184  SCIPdebugMsg(scip, "Enforcing method for symresack constraints (lp solutions) ...\n");
2185 
2186  /* we have a negative priority, so we should come after the integrality conshdlr. */
2187  assert( SCIPgetNLPBranchCands(scip) == 0 );
2188 
2189  *result = SCIP_FEASIBLE;
2190 
2191  if ( nconss > 0 )
2192  {
2193  SCIP_CONSHDLRDATA* conshdlrdata;
2194  SCIP_Real* vals;
2195  int maxnvars;
2196 
2197  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2198  assert( conshdlrdata != NULL );
2199 
2200  maxnvars = conshdlrdata->maxnvars;
2201  assert( maxnvars > 0 );
2202 
2203  SCIP_CALL( SCIPallocBufferArray(scip, &vals, maxnvars) );
2204 
2205  /* loop through constraints */
2206  for (c = 0; c < nconss; ++c)
2207  {
2208  SCIP_Bool infeasible = FALSE;
2209  int ngen = 0;
2210 
2211  SCIPdebugMsg(scip, "Enforcing symresack constraint <%s> ...\n", SCIPconsGetName(conss[c]));
2212 
2213  /* get data of constraint */
2214  assert( conss[c] != NULL );
2215  consdata = SCIPconsGetData(conss[c]);
2216  assert( consdata != NULL );
2217 
2218  /* do not enforce non-model constraints */
2219  if ( !consdata->ismodelcons )
2220  continue;
2221 
2222  if ( consdata->nvars == 0 )
2223  continue;
2224 
2225  /* get solution */
2226  assert( consdata->nvars <= maxnvars );
2227  SCIP_CALL( SCIPgetSolVals(scip, NULL, consdata->nvars, consdata->vars, vals) );
2228  SCIP_CALL( separateSymresackCovers(scip, conss[c], consdata, vals, &ngen, &infeasible) );
2229 
2230  if ( infeasible )
2231  {
2232  *result = SCIP_CUTOFF;
2233  SCIPfreeBufferArray(scip, &vals);
2234 
2235  return SCIP_OKAY;
2236  }
2237 
2238  /* SCIPdebugMsg(scip, "Generated symresack inequalities for <%s>: %d\n", SCIPconsGetName(conss[c]), ngen); */
2239 
2240  if ( ngen > 0 )
2241  *result = SCIP_SEPARATED;
2242  }
2243  SCIPfreeBufferArray(scip, &vals);
2244  }
2245 
2246  return SCIP_OKAY;
2247 }
2248 
2249 
2250 /** constraint enforcing method of constraint handler for pseudo solutions */
2251 static
2252 SCIP_DECL_CONSENFOPS(consEnfopsSymresack)
2253 { /*lint --e{715}*/
2254  SCIP_CONSDATA* consdata;
2255  int c;
2256 
2257  assert( scip != NULL );
2258  assert( conshdlr != NULL );
2259  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2260  assert( result != NULL );
2261 
2262  SCIPdebugMsg(scip, "Enforcing method for symresack constraints (pseudo solutions) ...\n");
2263 
2264  *result = SCIP_FEASIBLE;
2265 
2266  if ( objinfeasible || solinfeasible )
2267  return SCIP_OKAY;
2268 
2269  /* loop through constraints */
2270  for (c = 0; c < nconss; ++c)
2271  {
2272  consdata = SCIPconsGetData(conss[c]);
2273  assert( consdata != NULL );
2274 
2275  /* do not enforce non-model constraints */
2276  if ( !consdata->ismodelcons )
2277  continue;
2278 
2279  SCIP_CALL( checkSymresackSolution(scip, conss[c], NULL, result, FALSE) );
2280 
2281  if ( *result == SCIP_INFEASIBLE )
2282  break;
2283  }
2284 
2285  return SCIP_OKAY;
2286 }
2287 
2288 
2289 /** constraint enforcing method of constraint handler for relaxation solutions
2290  *
2291  * To check feasibility, we separate cover inequalities.
2292  *
2293  */
2294 static
2295 SCIP_DECL_CONSENFORELAX(consEnforelaxSymresack)
2296 { /*lint --e{715}*/
2297  SCIP_CONSDATA* consdata;
2298  int c;
2299 
2300  assert( scip != NULL );
2301  assert( conshdlr != NULL );
2302  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2303  assert( result != NULL );
2304 
2305  SCIPdebugMsg(scip, "Enforcing method for symresack constraints (relaxation solutions) ...\n");
2306 
2307  /* we have a negative priority, so we should come after the integrality conshdlr. */
2308  assert( SCIPgetNLPBranchCands(scip) == 0 );
2309 
2310  *result = SCIP_FEASIBLE;
2311 
2312  if ( nconss > 0 )
2313  {
2314  SCIP_CONSHDLRDATA* conshdlrdata;
2315  SCIP_Real* vals;
2316  int maxnvars;
2317 
2318  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2319  assert( conshdlrdata != NULL );
2320 
2321  maxnvars = conshdlrdata->maxnvars;
2322  assert( maxnvars > 0 );
2323 
2324  SCIP_CALL( SCIPallocBufferArray(scip, &vals, maxnvars) );
2325 
2326  /* loop through constraints */
2327  for (c = 0; c < nconss; ++c)
2328  {
2329  SCIP_Bool infeasible = FALSE;
2330  int ngen = 0;
2331 
2332  SCIPdebugMsg(scip, "Enforcing symresack constraint <%s> ...\n", SCIPconsGetName(conss[c]));
2333 
2334  /* get data of constraint */
2335  assert( conss[c] != NULL );
2336  consdata = SCIPconsGetData(conss[c]);
2337  assert( consdata != NULL );
2338 
2339  /* do not enforce non-model constraints */
2340  if ( !consdata->ismodelcons )
2341  continue;
2342 
2343  if ( consdata->nvars == 0 )
2344  continue;
2345 
2346  /* get solution */
2347  assert( consdata->nvars <= maxnvars );
2348  SCIP_CALL( SCIPgetSolVals(scip, sol, consdata->nvars, consdata->vars, vals) );
2349  SCIP_CALL( separateSymresackCovers(scip, conss[c], consdata, vals, &ngen, &infeasible) );
2350 
2351  if ( infeasible )
2352  {
2353  *result = SCIP_CUTOFF;
2354  SCIPfreeBufferArray(scip, &vals);
2355 
2356  return SCIP_OKAY;
2357  }
2358 
2359  if ( ngen > 0 )
2360  *result = SCIP_SEPARATED;
2361  }
2362  SCIPfreeBufferArray(scip, &vals);
2363  }
2364 
2365  return SCIP_OKAY;
2366 }
2367 
2368 
2369 /** feasibility check method of constraint handler for integral solutions */
2370 static
2371 SCIP_DECL_CONSCHECK(consCheckSymresack)
2372 { /*lint --e{715}*/
2373  SCIP_CONSDATA* consdata;
2374  int c;
2375 
2376  assert( scip != NULL );
2377  assert( conshdlr != NULL );
2378  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2379  assert( result != NULL );
2380 
2381  *result = SCIP_FEASIBLE;
2382 
2383  /* loop through constraints */
2384  for (c = 0; c < nconss; ++c)
2385  {
2386  consdata = SCIPconsGetData(conss[c]);
2387  assert( consdata != NULL );
2388 
2389  /* do not check non-model constraints */
2390  if ( !consdata->ismodelcons )
2391  continue;
2392 
2393  SCIP_CALL( checkSymresackSolution(scip, conss[c], sol, result, printreason) );
2394 
2395  if ( *result == SCIP_INFEASIBLE )
2396  break;
2397  }
2398 
2399  if ( *result == SCIP_FEASIBLE )
2400  SCIPdebugMsg(scip, "Solution is feasible.\n");
2401 
2402  return SCIP_OKAY;
2403 }
2404 
2405 
2406 /** domain propagation method of constraint handler */
2407 static
2408 SCIP_DECL_CONSPROP(consPropSymresack)
2409 { /*lint --e{715}*/
2410  int c;
2411  SCIP_Bool success = FALSE;
2412 
2413  assert( scip != NULL );
2414  assert( conshdlr != NULL );
2415  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2416  assert( result != NULL );
2417 
2418  *result = SCIP_DIDNOTRUN;
2419 
2420  SCIPdebugMsg(scip, "Propagation method of symresack constraint handler.\n");
2421 
2422  /* loop through constraints */
2423  for (c = 0; c < nconss; ++c)
2424  {
2425  SCIP_Bool infeasible = FALSE;
2426  int ngen = 0;
2427 
2428  assert( conss[c] != NULL );
2429 
2430  SCIP_CALL( propVariables(scip, conss[c], &infeasible, &ngen) );
2431 
2432  if ( infeasible )
2433  {
2434  *result = SCIP_CUTOFF;
2435  return SCIP_OKAY;
2436  }
2437 
2438  success = success || ( ngen > 0 );
2439 
2440  *result = SCIP_DIDNOTFIND;
2441  }
2442 
2443  if ( success )
2444  {
2445  *result = SCIP_REDUCEDDOM;
2446  return SCIP_OKAY;
2447  }
2448 
2449  return SCIP_OKAY;
2450 }
2451 
2452 
2453 /** presolving method of constraint handler */
2454 static
2455 SCIP_DECL_CONSPRESOL(consPresolSymresack)
2456 { /*lint --e{715}*/
2457  int c;
2458  SCIP_Bool success = FALSE;
2459  int oldndelconss;
2460 
2461  assert( scip != NULL );
2462  assert( conshdlr != NULL );
2463  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2464  assert( result != NULL );
2465 
2466  oldndelconss = *ndelconss;
2467 
2468  SCIPdebugMsg(scip, "Presolving method of symresack constraint handler. Propagating symresack inequalities.\n");
2469  *result = SCIP_DIDNOTRUN;
2470 
2471  /* loop through constraints */
2472  for (c = 0; c < nconss; ++c)
2473  {
2474  SCIP_Bool infeasible = FALSE;
2475  SCIP_CONSDATA* consdata;
2476  int ngen = 0;
2477 
2478  assert( conss[c] != NULL );
2479 
2480  consdata = SCIPconsGetData(conss[c]);
2481  assert( consdata != NULL );
2482 
2483  /* avoid trivial problems */
2484  if ( consdata->nvars == 0 )
2485  {
2486  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
2487  (*ndelconss)++;
2488  }
2489  else
2490  {
2491  SCIP_CALL( propVariables(scip, conss[c], &infeasible, &ngen) );
2492  }
2493 
2494  if ( infeasible )
2495  {
2496  *result = SCIP_CUTOFF;
2497  break;
2498  }
2499 
2500  if ( ngen > 0 )
2501  {
2502  *nfixedvars += ngen;
2503  success = TRUE;
2504  }
2505 
2506  *result = SCIP_DIDNOTFIND;
2507  }
2508 
2509  if ( *ndelconss > oldndelconss || success )
2510  *result = SCIP_SUCCESS;
2511 
2512  return SCIP_OKAY;
2513 }
2514 
2515 
2516 /** Propagation resolution for conflict analysis */
2517 static
2518 SCIP_DECL_CONSRESPROP(consRespropSymresack)
2519 { /*lint --e{715}*/
2520  SCIP_CONSDATA* consdata;
2521  SCIP_VAR** vars;
2522  int* perm;
2523  int* invperm;
2524  int nvars;
2525  int i;
2526  int varrow;
2527  int infrow;
2528 
2529  assert( scip != NULL );
2530  assert( conshdlr != NULL );
2531  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2532  assert( cons != NULL );
2533  assert( infervar != NULL );
2534  assert( bdchgidx != NULL );
2535  assert( result != NULL );
2536 
2537  SCIPdebugMsg(scip, "Propagation resolution method of symresack constraint handler.\n");
2538 
2539  *result = SCIP_DIDNOTFIND;
2540 
2541  consdata = SCIPconsGetData(cons);
2542  assert( consdata != NULL );
2543 
2544  /* we do not have to take care of trivial constraints */
2545  if ( consdata->nvars < 2 )
2546  return SCIP_OKAY;
2547 
2548  assert( consdata->vars != NULL );
2549  assert( consdata->invperm != NULL );
2550 
2551  vars = consdata->vars;
2552  nvars = consdata->nvars;
2553  perm = consdata->perm;
2554  invperm = consdata->invperm;
2555 
2556  /* inferinfo == varrow + infrow * nvars.
2557  * infrow is 0 if the fixing is not caused by a lookahead.
2558  */
2559  varrow = inferinfo % nvars;
2560  infrow = inferinfo / nvars;
2561 
2562  assert( varrow >= 0 );
2563  assert( varrow < nvars );
2564  assert( infrow >= 0 );
2565  assert( infrow < nvars );
2566  assert( vars[varrow] == infervar || vars[invperm[varrow]] == infervar );
2567 
2568  /* Up to entry varrow the vectors x and perm[x] are equal. */
2569  for (i = 0; i < varrow; ++i)
2570  {
2571  /* Conflict caused by bounds of x[i] and perm(x)[i] = x[invperm[i]]. */
2572 
2573  /* No fixed points in the permutation. */
2574  assert( i != invperm[i] );
2575 
2576  /* Up to entry varrow the vectors x and perm[x] are fixed to the same value. */
2577  assert( ISFIXED(vars[i], bdchgidx) );
2578  assert( ISFIXED(vars[invperm[i]], bdchgidx) );
2579  assert( REALABS(SCIPvarGetUbAtIndex(vars[i], bdchgidx, FALSE) -
2580  SCIPvarGetUbAtIndex(vars[invperm[i]], bdchgidx, FALSE)) < 0.5 );
2581  assert( REALABS(SCIPvarGetLbAtIndex(vars[i], bdchgidx, FALSE) -
2582  SCIPvarGetLbAtIndex(vars[invperm[i]], bdchgidx, FALSE)) < 0.5 );
2583 
2584  /* At iteration i the vars x[i] and x[invperm[i]] are fixed.
2585  * So only new information is received if i < perm[i] (i.e. there is no j < i with j = invperm[i])
2586  * Or if invperm[i] > i.
2587  */
2588  if ( i < perm[i] )
2589  {
2590  assert( vars[i] != infervar );
2591  SCIP_CALL( SCIPaddConflictUb(scip, vars[i], bdchgidx) );
2592  SCIP_CALL( SCIPaddConflictLb(scip, vars[i], bdchgidx) );
2593  }
2594  if ( invperm[i] > i )
2595  {
2596  assert( vars[invperm[i]] != infervar );
2597  SCIP_CALL( SCIPaddConflictUb(scip, vars[invperm[i]], bdchgidx) );
2598  SCIP_CALL( SCIPaddConflictLb(scip, vars[invperm[i]], bdchgidx) );
2599  }
2600  }
2601 
2602  /* Case distinction: Fixing due to propagation or due to lookahead */
2603  if ( infrow > 0 )
2604  {
2605  /* The fixing of infervar is caused by a lookahead (checkFeasible)
2606  * Up to row "varrow" the entries x[i] and perm(x)[i] are forced to be equal
2607  * If x[varrow] = perm(x)[varrow] is assumed, then until infrow we find x[i] = perm(x)[i] ( = x[invperm[i]] )
2608  * and (x[infrow], perm(x)[infrow]) = (0, 1).
2609  */
2610 
2611  /* Everything after varrow to infrow is forced to a constant, and row infrow is (0, 1) */
2612  for (i = varrow + 1; i <= infrow; ++i)
2613  {
2614  /* Conflict caused by bounds of x[i] and perm(x)[i] = x[invperm[i]]. */
2615 
2616  /* No fixed points in the permutation. */
2617  assert( i != invperm[i] );
2618 
2619  /* The fixing are applied 'virtually', i.e. if varrow is considered constant, then fixings will follow.
2620  * Thus, between entries varrow and infrow of vectorx x and gamma(x) the entries do not have to be fixed.
2621  * For conflict analysis, only the fixed entries matter.
2622  */
2623  if ( ( i < perm[i] || i == invperm[varrow] ) && ISFIXED(vars[i], bdchgidx) )
2624  {
2625  assert( vars[i] != infervar );
2626  SCIP_CALL( SCIPaddConflictUb(scip, vars[i], bdchgidx) );
2627  SCIP_CALL( SCIPaddConflictLb(scip, vars[i], bdchgidx) );
2628  }
2629  if ( ( invperm[i] > i || invperm[i] == varrow ) && ISFIXED(vars[invperm[i]], bdchgidx) )
2630  {
2631  assert( vars[invperm[i]] != infervar );
2632  SCIP_CALL( SCIPaddConflictUb(scip, vars[invperm[i]], bdchgidx) );
2633  SCIP_CALL( SCIPaddConflictLb(scip, vars[invperm[i]], bdchgidx) );
2634  }
2635  }
2636  }
2637  else
2638  {
2639  /* This is not a fixing caused by lookahead (checkFeasible),
2640  * so row "varrow" was (0, _) or (_, 1) and for i < varrow x[i] = perm(x)[i].
2641  */
2642  if ( boundtype == SCIP_BOUNDTYPE_LOWER )
2643  {
2644  /* Changed the lower bound of infervar to 1. That means that this fixing is due to (_, 1) */
2645  assert( infervar == vars[varrow] );
2646  assert( ISFIXED(vars[invperm[varrow]], bdchgidx) );
2647 
2648  if ( invperm[varrow] > varrow )
2649  {
2650  SCIP_CALL( SCIPaddConflictUb(scip, vars[invperm[varrow]], bdchgidx) );
2651  SCIP_CALL( SCIPaddConflictLb(scip, vars[invperm[varrow]], bdchgidx) );
2652  }
2653  }
2654  else
2655  {
2656  /* Changed the lower bound of infervar to 0. That means that this fixing is due to (0, _) */
2657  assert( infervar == vars[invperm[varrow]] );
2658  assert( ISFIXED(vars[varrow], bdchgidx) );
2659 
2660  if ( varrow < perm[varrow] )
2661  {
2662  SCIP_CALL( SCIPaddConflictUb(scip, vars[varrow], bdchgidx) );
2663  SCIP_CALL( SCIPaddConflictLb(scip, vars[varrow], bdchgidx) );
2664  }
2665  }
2666  }
2667 
2668  *result = SCIP_SUCCESS;
2669 
2670  return SCIP_OKAY;
2671 }
2672 
2673 
2674 /** lock variables
2675  *
2676  * We assume we have only one global (void) constraint and lock all binary variables
2677  * which do not correspond to fixed points of the permutation.
2678  *
2679  * - Symresack constraints may get violated if the variables with a negative coefficient
2680  * in the FD inequality are rounded down, we therefor call
2681  * SCIPaddVarLocksType(..., nlockspos, nlocksneg).
2682  * - Symresack constraints may get violated if the variables with a positive coefficient
2683  * in the FD inequality are rounded up, we therefor call
2684  * SCIPaddVarLocksType(..., nlocksneg, nlockspo ).
2685  */
2686 static
2687 SCIP_DECL_CONSLOCK(consLockSymresack)
2688 { /*lint --e{715}*/
2689  SCIP_CONSDATA* consdata;
2690  SCIP_VAR** vars;
2691  int* perm;
2692  int nvars;
2693  int i;
2694 
2695  assert( scip != NULL );
2696  assert( conshdlr != NULL );
2697  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2698  assert( cons != NULL );
2699 
2700  SCIPdebugMsg(scip, "Locking method for symresack constraint handler.\n");
2701 
2702  /* get data of original constraint */
2703  consdata = SCIPconsGetData(cons);
2704  assert( consdata != NULL );
2705 
2706  /* we do not have to take care of trivial constraints */
2707  if ( consdata->nvars < 2 )
2708  return SCIP_OKAY;
2709 
2710  assert( consdata->vars != NULL );
2711  assert( consdata->perm != NULL );
2712 
2713  nvars = consdata->nvars;
2714  vars = consdata->vars;
2715  perm = consdata->perm;
2716 
2717  for (i = 0; i < nvars; ++i)
2718  {
2719  /* due to clean-up in consdataCreate, there are no fixed points */
2720  assert( perm[i] != i );
2721 
2722  if ( perm[i] > i )
2723  {
2724  SCIP_CALL( SCIPaddVarLocksType(scip, vars[i], locktype, nlockspos, nlocksneg) );
2725  }
2726  else
2727  {
2728  SCIP_CALL( SCIPaddVarLocksType(scip, vars[i], locktype, nlocksneg, nlockspos) );
2729  }
2730  }
2731 
2732  return SCIP_OKAY;
2733 }
2734 
2735 
2736 /** constraint copying method of constraint handler */
2737 static
2738 SCIP_DECL_CONSCOPY(consCopySymresack)
2740  SCIP_CONSHDLRDATA* conshdlrdata;
2741  SCIP_CONSDATA* sourcedata;
2742  SCIP_VAR** sourcevars;
2743  SCIP_VAR** vars;
2744  int nvars;
2745  int i;
2746 
2747  assert( scip != NULL );
2748  assert( cons != NULL );
2749  assert( sourcescip != NULL );
2750  assert( sourceconshdlr != NULL );
2751  assert( strcmp(SCIPconshdlrGetName(sourceconshdlr), CONSHDLR_NAME) == 0 );
2752  assert( sourcecons != NULL );
2753  assert( varmap != NULL );
2754  assert( valid != NULL );
2755 
2756  *valid = TRUE;
2757 
2758  SCIPdebugMsg(scip, "Copying method for symresack constraint handler.\n");
2759 
2760  sourcedata = SCIPconsGetData(sourcecons);
2761  assert( sourcedata != NULL );
2762  assert( sourcedata->vars != NULL );
2763  assert( sourcedata->perm != NULL );
2764  assert( sourcedata->nvars > 0 );
2765 
2766  conshdlrdata = SCIPconshdlrGetData(sourceconshdlr);
2767  assert( conshdlrdata != NULL );
2768 
2769  /* do not copy non-model constraints */
2770  if ( !sourcedata->ismodelcons && !conshdlrdata->forceconscopy )
2771  {
2772  *valid = FALSE;
2773 
2774  return SCIP_OKAY;
2775  }
2776 
2777  sourcevars = sourcedata->vars;
2778  nvars = sourcedata->nvars;
2779 
2780  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nvars) );
2781 
2782  for (i = 0; i < nvars && *valid; ++i)
2783  {
2784  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[i], &(vars[i]), varmap, consmap, global, valid) );
2785  assert( !(*valid) || vars[i] != NULL );
2786  }
2787 
2788  /* only create the target constraint, if all variables could be copied */
2789  if ( *valid )
2790  {
2791  /* create copied constraint */
2792  if ( name == NULL )
2793  name = SCIPconsGetName(sourcecons);
2794 
2795  SCIP_CALL( SCIPcreateConsSymresack(scip, cons, name, sourcedata->perm, vars, nvars, sourcedata->ismodelcons,
2796  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
2797  }
2798 
2799  SCIPfreeBufferArray(scip, &vars);
2800 
2801  return SCIP_OKAY;
2802 }
2803 
2804 
2805 /** constraint parsing method of constraint handler */
2806 static
2807 SCIP_DECL_CONSPARSE(consParseSymresack)
2808 { /*lint --e{715}*/
2809  const char* s;
2810  char* endptr;
2811  SCIP_VAR** vars;
2812  SCIP_VAR* var;
2813  int* perm;
2814  int val;
2815  int nvars = 0;
2816  int cnt = 0;
2817  int nfoundpermidx = 0;
2818  int maxnvars = 128;
2819 
2820  assert( success != NULL );
2821 
2822  *success = TRUE;
2823  s = str;
2824 
2825  /* skip white space */
2826  while ( *s != '\0' && isspace((unsigned char)*s) )
2827  ++s;
2828 
2829  if ( strncmp(s, "symresack(", 10) != 0 )
2830  {
2831  SCIPerrorMessage("Syntax error - expected \"symresack(\", but got '%s'", s);
2832  *success = FALSE;
2833  return SCIP_OKAY;
2834  }
2835  s += 10;
2836 
2837  /* loop through string */
2838  SCIP_CALL( SCIPallocBufferArray(scip, &vars, maxnvars) );
2839  SCIP_CALL( SCIPallocBufferArray(scip, &perm, maxnvars) );
2840 
2841  do
2842  {
2843  if ( cnt > 1 )
2844  {
2845  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected two arrays, but got more\n");
2846  *success = FALSE;
2847 
2848  SCIPfreeBufferArray(scip, &perm);
2849  SCIPfreeBufferArray(scip, &vars);
2850  }
2851 
2852  /* skip whitespace and ',' */
2853  while ( *s != '\0' && ( isspace((unsigned char)*s) || *s == ',' ) )
2854  ++s;
2855 
2856  /* if we could not find starting indicator of array */
2857  if ( *s != '[' )
2858  {
2859  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "expected '[' to start new array\n");
2860  *success = FALSE;
2861 
2862  SCIPfreeBufferArray(scip, &perm);
2863  SCIPfreeBufferArray(scip, &vars);
2864  }
2865  ++s;
2866 
2867  /* read array, cnt = 0: variables; cnt = 1: permutation*/
2868  if ( cnt == 0 )
2869  {
2870  do
2871  {
2872  /* skip whitespace and ',' */
2873  while ( *s != '\0' && ( isspace((unsigned char)*s) || *s == ',' ) )
2874  ++s;
2875 
2876  /* parse variable name */
2877  SCIP_CALL( SCIPparseVarName(scip, s, &var, &endptr) );
2878  if ( var == NULL )
2879  {
2880  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable name at '%s'\n", str);
2881  *success = FALSE;
2882  SCIPfreeBufferArray(scip, &vars);
2883  return SCIP_OKAY;
2884  }
2885  s = endptr;
2886  assert( s != NULL );
2887 
2888  vars[nvars++] = var;
2889 
2890  if ( nvars >= maxnvars )
2891  {
2892  int newsize;
2893 
2894  newsize = SCIPcalcMemGrowSize(scip, nvars + 1);
2895  SCIP_CALL( SCIPreallocBufferArray(scip, &vars, newsize) );
2896  SCIP_CALL( SCIPreallocBufferArray(scip, &perm, newsize) );
2897  maxnvars = newsize;
2898  }
2899  }
2900  while ( *s != ']' );
2901  }
2902  else
2903  {
2904  do
2905  {
2906  /* skip whitespace and ',' */
2907  while ( *s != '\0' && ( isspace((unsigned char)*s) || *s == ',' ) )
2908  ++s;
2909 
2910  /* parse integer value */
2911  if ( ! SCIPstrToIntValue(s, &val, &endptr) )
2912  {
2913  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "could not extract int from string '%s'\n", str);
2914  *success = FALSE;
2915  SCIPfreeBufferArray(scip, &perm);
2916  SCIPfreeBufferArray(scip, &vars);
2917  return SCIP_OKAY;
2918  }
2919  s = endptr;
2920  assert( s != NULL );
2921 
2922  perm[nfoundpermidx++] = val;
2923 
2924  if ( nfoundpermidx > nvars )
2925  {
2926  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "permutation is longer than vars array\n");
2927  *success = FALSE;
2928  SCIPfreeBufferArray(scip, &perm);
2929  SCIPfreeBufferArray(scip, &vars);
2930  return SCIP_OKAY;
2931  }
2932  }
2933  while ( *s != ']' );
2934  }
2935  ++s;
2936  ++cnt;
2937  }
2938  while ( *s != ')' );
2939 
2940  if ( nfoundpermidx == nvars )
2941  {
2942  SCIP_CALL( SCIPcreateConsBasicSymresack(scip, cons, name, perm, vars, nvars, TRUE) );
2943  }
2944  else
2945  {
2947  "Length of permutation is not equal to number of given variables.\n");
2948  *success = FALSE;
2949  }
2950 
2951  SCIPfreeBufferArray(scip, &perm);
2952  SCIPfreeBufferArray(scip, &vars);
2953 
2954  return SCIP_OKAY;
2955 }
2956 
2957 
2958 /** constraint display method of constraint handler
2959  *
2960  * The constraint handler should output a representation of the constraint into the given text file.
2961  */
2962 static
2963 SCIP_DECL_CONSPRINT(consPrintSymresack)
2964 { /*lint --e{715}*/
2965  SCIP_CONSDATA* consdata;
2966  SCIP_VAR** vars;
2967  int* perm;
2968  int nvars;
2969  int i;
2970 
2971  assert( scip != NULL );
2972  assert( conshdlr != NULL );
2973  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2974  assert( cons != NULL );
2975 
2976  consdata = SCIPconsGetData(cons);
2977  assert( consdata != NULL );
2978 
2979  SCIPdebugMsg(scip, "Printing method for symresack constraint handler\n");
2980 
2981  /* we do not have to take care of trivial constraints */
2982  if ( consdata->nvars < 2 )
2983  return SCIP_OKAY;
2984 
2985  assert( consdata->vars != NULL );
2986  assert( consdata->perm != NULL );
2987 
2988  vars = consdata->vars;
2989  nvars = consdata->nvars;
2990  perm = consdata->perm;
2991 
2992  SCIPinfoMessage(scip, file, "symresack([");
2993  SCIP_CALL( SCIPwriteVarName(scip, file, vars[0], TRUE) );
2994 
2995  for (i = 1; i < nvars; ++i)
2996  {
2997  SCIPinfoMessage(scip, file, ",");
2998  SCIP_CALL( SCIPwriteVarName(scip, file, vars[i], TRUE) );
2999  }
3000  SCIPinfoMessage(scip, file, "],[%d", perm[0]);
3001  for (i = 1; i < nvars; ++i)
3002  SCIPinfoMessage(scip, file, ",%d", perm[i]);
3003  SCIPinfoMessage(scip, file, "])");
3004 
3005  return SCIP_OKAY;
3006 }
3007 
3008 
3009 /** constraint method of constraint handler which returns the variables (if possible) */
3010 static
3011 SCIP_DECL_CONSGETVARS(consGetVarsSymresack)
3012 { /*lint --e{715}*/
3013  SCIP_CONSDATA* consdata;
3014 
3015  assert( cons != NULL );
3016  assert( success != NULL );
3017  assert( vars != NULL );
3018 
3019  consdata = SCIPconsGetData(cons);
3020  assert( consdata != NULL );
3021 
3022  if ( varssize < consdata->nvars )
3023  (*success) = FALSE;
3024  else
3025  {
3026  int cnt = 0;
3027  int i;
3028 
3029  for (i = 0; i < consdata->nvars; ++i)
3030  vars[cnt++] = consdata->vars[i];
3031  (*success) = TRUE;
3032  }
3033 
3034  return SCIP_OKAY;
3035 }
3036 
3037 
3038 /** constraint method of constraint handler which returns the number of variables (if possible) */
3039 static
3040 SCIP_DECL_CONSGETNVARS(consGetNVarsSymresack)
3041 { /*lint --e{715}*/
3042  SCIP_CONSDATA* consdata;
3043 
3044  assert( cons != NULL );
3045  assert( success != NULL );
3046  assert( nvars != NULL );
3047 
3048  consdata = SCIPconsGetData(cons);
3049  assert( consdata != NULL );
3050 
3051  (*nvars) = consdata->nvars;
3052  (*success) = TRUE;
3053 
3054  return SCIP_OKAY;
3055 }
3056 
3057 
3058 /** creates the handler for symresack constraints and includes it in SCIP */
3060  SCIP* scip /**< SCIP data structure */
3061  )
3062 {
3063  SCIP_CONSHDLRDATA* conshdlrdata = NULL;
3064  SCIP_CONSHDLR* conshdlr;
3065 
3066  SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
3067 
3068  /* include constraint handler */
3071  consEnfolpSymresack, consEnfopsSymresack, consCheckSymresack, consLockSymresack,
3072  conshdlrdata) );
3073  assert( conshdlr != NULL );
3074 
3075  /* set non-fundamental callbacks via specific setter functions */
3076  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopySymresack, consCopySymresack) );
3077  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxSymresack) );
3078  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeSymresack) );
3079  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteSymresack) );
3080  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsSymresack) );
3081  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsSymresack) );
3082  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseSymresack) );
3083  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolSymresack, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
3084  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintSymresack) );
3086  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropSymresack) );
3087  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpSymresack, consSepasolSymresack, CONSHDLR_SEPAFREQ, CONSHDLR_SEPAPRIORITY, CONSHDLR_DELAYSEPA) );
3088  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransSymresack) );
3089  SCIP_CALL( SCIPsetConshdlrInitlp(scip, conshdlr, consInitlpSymresack) );
3090  SCIP_CALL( SCIPsetConshdlrInitsol(scip, conshdlr, consInitsolSymresack) );
3091 
3092  /* whether we allow upgrading to packing/partioning symresack constraints*/
3093  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/ppsymresack",
3094  "Upgrade symresack constraints to packing/partioning symresacks?",
3095  &conshdlrdata->checkppsymresack, TRUE, DEFAULT_PPSYMRESACK, NULL, NULL) );
3096 
3097  /* whether we check for monotonicity of perm when upgrading to packing/partioning symresacks */
3098  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/checkmonotonicity",
3099  "Check whether permutation is monotone when upgrading to packing/partioning symresacks?",
3100  &conshdlrdata->checkmonotonicity, TRUE, DEFAULT_CHECKMONOTONICITY, NULL, NULL) );
3101 
3102  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forceconscopy",
3103  "Whether symresack constraints should be forced to be copied to sub SCIPs.",
3104  &conshdlrdata->forceconscopy, TRUE, DEFAULT_FORCECONSCOPY, NULL, NULL) );
3105 
3106  return SCIP_OKAY;
3107 }
3108 
3109 
3110 /*
3111  * constraint specific interface methods
3112  */
3113 
3114 /** creates and captures a symresack constraint
3115  *
3116  * In a presolving step, we check whether the permutation acts only on binary points. Otherwise, we eliminate
3117  * the non-binary variables from the permutation.
3118  *
3119  * @note The constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons().
3120  */
3122  SCIP* scip, /**< SCIP data structure */
3123  SCIP_CONS** cons, /**< pointer to hold the created constraint */
3124  const char* name, /**< name of constraint */
3125  int* perm, /**< permutation */
3126  SCIP_VAR** vars, /**< variables */
3127  int nvars, /**< number of variables in vars array */
3128  SCIP_Bool ismodelcons, /**< whether the symresack is a model constraint */
3129  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
3130  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
3131  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
3132  * Usually set to TRUE. */
3133  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
3134  * TRUE for model constraints, FALSE for additional, redundant constraints. */
3135  SCIP_Bool check, /**< should the constraint be checked for feasibility?
3136  * TRUE for model constraints, FALSE for additional, redundant constraints. */
3137  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
3138  * Usually set to TRUE. */
3139  SCIP_Bool local, /**< is constraint only valid locally?
3140  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
3141  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
3142  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
3143  * adds coefficients to this constraint. */
3144  SCIP_Bool dynamic, /**< is constraint subject to aging?
3145  * Usually set to FALSE. Set to TRUE for own cuts which
3146  * are separated as constraints. */
3147  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
3148  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
3149  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
3150  * if it may be moved to a more global node?
3151  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
3152  )
3153 {
3154  SCIP_CONSHDLR* conshdlr;
3155  SCIP_CONSDATA* consdata;
3156 
3157  assert( cons != NULL );
3158  assert( nvars > 0 );
3159 
3160  /* find the symresack constraint handler */
3161  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
3162  if ( conshdlr == NULL )
3163  {
3164  SCIPerrorMessage("Symresack constraint handler not found.\n");
3165  return SCIP_PLUGINNOTFOUND;
3166  }
3167 
3168  /* create constraint data */
3169  SCIP_CALL( consdataCreate(scip, conshdlr, &consdata, vars, nvars, perm, ismodelcons) );
3170 
3171  /* create constraint */
3172  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate && (! consdata->ppupgrade), enforce, check, propagate,
3173  local, modifiable, dynamic, removable, stickingatnode) );
3174 
3175  return SCIP_OKAY;
3176 }
3177 
3178 
3179 /** creates and captures a symresack constraint
3180  * in its most basic variant, i.e., with all constraint flags set to their default values
3181  *
3182  * In a presolving step, we remove all fixed points and cycles that act on non-binary variables of the permutation
3183  *
3184  * @note The constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons().
3185  */
3187  SCIP* scip, /**< SCIP data structure */
3188  SCIP_CONS** cons, /**< pointer to hold the created constraint */
3189  const char* name, /**< name of constraint */
3190  int* perm, /**< permutation */
3191  SCIP_VAR** vars, /**< variables */
3192  int nvars, /**< number of variables in vars array */
3193  SCIP_Bool ismodelcons /**< whether the symresack is a model constraint */
3194  )
3195 {
3196  SCIP_CALL( SCIPcreateConsSymresack(scip, cons, name, perm, vars, nvars, ismodelcons,
3198 
3199  return SCIP_OKAY;
3200 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:61
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
SCIP_RETCODE SCIPcreateEmptyRowCons(SCIP *scip, SCIP_ROW **row, SCIP_CONS *cons, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1422
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:572
#define CONSHDLR_ENFOPRIORITY
#define CONSHDLR_PRESOLTIMING
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
SCIP_RETCODE SCIPcreateConsOrbisack(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR *const *vars1, SCIP_VAR *const *vars2, int nrows, SCIP_Bool ispporbisack, SCIP_Bool isparttype, SCIP_Bool ismodelcons, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
static SCIP_DECL_CONSPROP(consPropSymresack)
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1635
public methods for SCIP parameter handling
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8353
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:595
public methods for memory management
static SCIP_DECL_CONSFREE(consFreeSymresack)
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:886
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1658
int SCIPgetNVarsSetppc(SCIP *scip, SCIP_CONS *cons)
Definition: cons_setppc.c:9408
#define SCIPallocClearBufferArray(scip, ptr, num)
Definition: scip_mem.h:126
#define CONSHDLR_NAME
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata)
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:825
#define SCIP_MAXSTRLEN
Definition: def.h:302
SCIP_RETCODE SCIPcreateSymbreakCons(SCIP *scip, SCIP_CONS **cons, const char *name, int *perm, SCIP_VAR **vars, int nvars, SCIP_Bool ismodelcons, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
public methods for conflict handler plugins and conflict analysis
SCIP_RETCODE SCIPsetConshdlrEnforelax(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSENFORELAX((*consenforelax)))
Definition: scip_cons.c:317
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2851
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:139
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1695
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17975
static SCIP_DECL_CONSENFORELAX(consEnforelaxSymresack)
SCIP_RETCODE SCIPaddConflictBinvar(SCIP *scip, SCIP_VAR *var)
SCIP_Bool SCIPisGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPcreateConsBasicSymresack(SCIP *scip, SCIP_CONS **cons, const char *name, int *perm, SCIP_VAR **vars, int nvars, SCIP_Bool ismodelcons)
#define ISFIXED(x, bdchgidx)
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip_var.c:1445
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip_var.c:533
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1254
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:17440
static SCIP_DECL_CONSCOPY(consCopySymresack)
static SCIP_DECL_CONSPARSE(consParseSymresack)
static SCIP_RETCODE initLP(SCIP *scip, SCIP_CONS *cons, SCIP_Bool checkmonotonicity, SCIP_Bool *infeasible)
SCIP_CONS ** SCIPconshdlrGetConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4556
#define FALSE
Definition: def.h:96
#define CONSHDLR_PROPFREQ
SCIP_RETCODE SCIPincludeConshdlrBasic(SCIP *scip, SCIP_CONSHDLR **conshdlrptr, const char *name, const char *desc, int enfopriority, int chckpriority, int eagerfreq, SCIP_Bool needscons, SCIP_DECL_CONSENFOLP((*consenfolp)), SCIP_DECL_CONSENFOPS((*consenfops)), SCIP_DECL_CONSCHECK((*conscheck)), SCIP_DECL_CONSLOCK((*conslock)), SCIP_CONSHDLRDATA *conshdlrdata)
Definition: scip_cons.c:175
constraint handler for orbisack constraints
SCIP_Real SCIPinfinity(SCIP *scip)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10764
#define TRUE
Definition: def.h:95
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
SCIP_RETCODE SCIPaddConflictUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8373
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA **consdata, SCIP_VAR *const *inputvars, int inputnvars, int *inputperm, SCIP_Bool ismodelcons)
static SCIP_RETCODE checkSymresackSolution(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_RESULT *result, SCIP_Bool printreason)
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:17609
#define CONSHDLR_MAXPREROUNDS
public methods for problem variables
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
SCIP_Bool SCIPstrToIntValue(const char *str, int *value, char **endptr)
Definition: misc.c:10834
SCIP_RETCODE SCIPsetConshdlrSepa(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSSEPALP((*conssepalp)), SCIP_DECL_CONSSEPASOL((*conssepasol)), int sepafreq, int sepapriority, SCIP_Bool delaysepa)
Definition: scip_cons.c:229
#define FIXED0
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
static SCIP_DECL_CONSPRESOL(consPresolSymresack)
Constraint handler for the set partitioning / packing / covering constraints .
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip_general.c:575
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip_branch.c:428
public methods for SCIP variables
static SCIP_DECL_CONSGETNVARS(consGetNVarsSymresack)
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8363
SCIP_RETCODE SCIPsetConshdlrInitlp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITLP((*consinitlp)))
Definition: scip_cons.c:618
#define SCIPdebugMsg
Definition: scip_message.h:78
SCIP_RETCODE SCIPgetTransformedVars(SCIP *scip, int nvars, SCIP_VAR **vars, SCIP_VAR **transvars)
Definition: scip_var.c:1486
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip_cons.c:802
static SCIP_RETCODE separateSymresackCovers(SCIP *scip, SCIP_CONS *cons, const SCIP_CONSDATA *consdata, SCIP_Real *vals, int *ngen, SCIP_Bool *infeasible)
static SCIP_DECL_CONSINITLP(consInitlpSymresack)
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:208
SCIP_RETCODE SCIPcreateCons(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_CONSHDLR *conshdlr, SCIP_CONSDATA *consdata, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
Definition: scip_cons.c:943
SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
static SCIP_RETCODE maximizeObjectiveSymresackStrict(SCIP *scip, int nvars, SCIP_Real *objective, int *perm, int *invperm, int *maxcrit, SCIP_Real *maxsoluval)
public methods for numerical tolerances
static SCIP_DECL_CONSPRINT(consPrintSymresack)
#define CONSHDLR_NEEDSCONS
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4265
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
constraint handler for symresack constraints
#define SCIPallocCleanBufferArray(scip, ptr, num)
Definition: scip_mem.h:142
SCIP_RETCODE SCIPsetConshdlrInitsol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSINITSOL((*consinitsol)))
Definition: scip_cons.c:438
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:105
public methods for managing constraints
static SCIP_RETCODE addSymresackInequality(SCIP *scip, SCIP_CONS *cons, int nvars, SCIP_VAR **vars, int *coeffs, SCIP_Real rhs, SCIP_Bool *infeasible)
static SCIP_RETCODE orbisackUpgrade(SCIP *scip, SCIP_CONS **cons, const char *name, int *perm, SCIP_VAR **inputvars, int nvars, SCIP_Bool *upgrade, SCIP_Bool ismodelcons, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:341
static SCIP_DECL_CONSSEPALP(consSepalpSymresack)
#define CONSHDLR_EAGERFREQ
SCIP_RETCODE SCIPincludeConshdlrSymresack(SCIP *scip)
#define SCIPerrorMessage
Definition: pub_message.h:64
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4184
void SCIPsortIntInt(int *intarray1, int *intarray2, int len)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPcreateConsSymresack(SCIP *scip, SCIP_CONS **cons, const char *name, int *perm, SCIP_VAR **vars, int nvars, SCIP_Bool ismodelcons, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip_sol.c:1398
static SCIP_DECL_CONSENFOLP(consEnfolpSymresack)
#define SCIPfreeBufferArrayNull(scip, ptr)
Definition: scip_mem.h:137
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip_cut.c:135
SCIP_Real SCIPvarGetUbAtIndex(SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: var.c:16670
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8094
static SCIP_DECL_CONSLOCK(consLockSymresack)
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:8721
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8313
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:366
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4204
static SCIP_DECL_CONSDELETE(consDeleteSymresack)
#define NULL
Definition: lpi_spx1.cpp:164
#define REALABS(x)
Definition: def.h:210
#define CONSHDLR_SEPAFREQ
static SCIP_RETCODE maximizeObjectiveSymresackCriticalEntry(SCIP *scip, int nvars, SCIP_Real *objective, int *perm, int *invperm, int crit, int *maxsolu)
#define SCIP_CALL(x)
Definition: def.h:393
#define FIXED1
SCIP_RETCODE SCIPanalyzeConflictCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *success)
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:225
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8333
static SCIP_DECL_CONSSEPASOL(consSepasolSymresack)
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:250
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip_cons.c:641
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:65
#define UNFIXED
static SCIP_RETCODE packingUpgrade(SCIP *scip, SCIP_CONSDATA **consdata, int *perm, SCIP_VAR **vars, int nvars, SCIP_Bool checkmonotonicity, SCIP_Bool *upgrade)
int SCIPconshdlrGetNConss(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4599
public methods for constraint handler plugins and constraints
#define DEFAULT_CHECKMONOTONICITY
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
public data structures and miscellaneous methods
#define SCIP_Bool
Definition: def.h:93
SCIP_SETPPCTYPE SCIPgetTypeSetppc(SCIP *scip, SCIP_CONS *cons)
Definition: cons_setppc.c:9454
SCIP_Real SCIPvarGetLbAtIndex(SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: var.c:16551
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopySymresack)
static SCIP_DECL_CONSRESPROP(consRespropSymresack)
public methods for cuts and aggregation rows
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8293
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8263
static SCIP_DECL_CONSCHECK(consCheckSymresack)
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip_cons.c:779
SCIP_RETCODE SCIPinferVarLbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5507
public methods for the LP relaxation, rows and columns
SCIP_VAR ** SCIPgetVarsSetppc(SCIP *scip, SCIP_CONS *cons)
Definition: cons_setppc.c:9431
#define CONSHDLR_DELAYSEPA
SCIP_Real * r
Definition: circlepacking.c:59
public methods for branching rule plugins and branching
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1562
general public methods
#define SCIP_DEFAULT_INFINITY
Definition: def.h:191
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define CONSHDLR_PROP_TIMING
public methods for solutions
SCIP_RETCODE SCIPgetVarCopy(SCIP *sourcescip, SCIP *targetscip, SCIP_VAR *sourcevar, SCIP_VAR **targetvar, SCIP_HASHMAP *varmap, SCIP_HASHMAP *consmap, SCIP_Bool global, SCIP_Bool *success)
Definition: scip_copy.c:711
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8124
SCIP_RETCODE SCIPinferVarUbCons(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_CONS *infercons, int inferinfo, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5621
static SCIP_DECL_CONSGETVARS(consGetVarsSymresack)
#define DEFAULT_PPSYMRESACK
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:534
static SCIP_RETCODE checkFeasible(SCIP *scip, SCIP_VAR **vars, int *invperm, int nvars, int start, int *tempfixings, int *tempfixentries, int numfixentriesinit, SCIP_Bool *infeasible, int *infeasibleentry)
#define DEFAULT_FORCECONSCOPY
public methods for message output
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1220
#define SCIP_Real
Definition: def.h:186
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8343
SCIP_RETCODE SCIPaddVarsToRow(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip_lp.c:1721
#define SCIPfreeCleanBufferArray(scip, ptr)
Definition: scip_mem.h:146
#define CONSHDLR_CHECKPRIORITY
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:848
public methods for message handling
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8283
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8273
#define NOINIT
#define CONSHDLR_DESC
static SCIP_DECL_CONSENFOPS(consEnfopsSymresack)
#define CONSHDLR_SEPAPRIORITY
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:64
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17985
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:111
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
#define CONSHDLR_DELAYPROP
static SCIP_RETCODE propVariables(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *infeasible, int *ngen)
SCIP_RETCODE SCIPwriteVarName(SCIP *scip, FILE *file, SCIP_VAR *var, SCIP_Bool type)
Definition: scip_var.c:230
public methods for global and local (sub)problems
static SCIP_DECL_CONSINITSOL(consInitsolSymresack)
static SCIP_DECL_CONSTRANS(consTransSymresack)
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1361
SCIP callable library.
SCIP_RETCODE SCIPaddBoolParam(SCIP *scip, const char *name, const char *desc, SCIP_Bool *valueptr, SCIP_Bool isadvanced, SCIP_Bool defaultvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:57
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition: var.c:17415
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:128
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip_cons.c:275
memory allocation routines