Scippy

SCIP

Solving Constraint Integer Programs

cons_orbitope.c
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program and library */
4 /* SCIP --- Solving Constraint Integer Programs */
5 /* */
6 /* Copyright (C) 2002-2022 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SCIP is distributed under the terms of the ZIB Academic License. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SCIP; see the file COPYING. If not visit scipopt.org. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15 
16 /**@file cons_orbitope.c
17  * @ingroup DEFPLUGINS_CONS
18  * @brief constraint handler for (partitioning/packing/full) orbitope constraints w.r.t. the full symmetric group
19  * @author Timo Berthold
20  * @author Marc Pfetsch
21  * @author Christopher Hojny
22  *
23  * The type of constraints of this constraint handler is described in cons_orbitope.h.
24  *
25  * The details of the method implemented here are described in the following papers.
26  *
27  * Packing and Partitioning Orbitopes@n
28  * Volker Kaibel and Marc E. Pfetsch,@n
29  * Math. Program. 114, No. 1, 1-36 (2008)
30  *
31  * Among other things, this paper describes so-called shifted column inequalities of the following
32  * form \f$x(S) \leq x(B)\f$, where \f$S\f$ is a so-called shifted column and \f$B\f$ is a so-called
33  * bar. These inequalities can be used to handle symmetry and they are separated in this constraint
34  * handler. We use the linear time separation algorithm of the paper.@par
35  *
36  * Orbitopal Fixing@n
37  * Volker Kaibel, Matthias Peinhardt, and Marc E. Pfetsch,@n
38  * Discrete Optimization 8, No. 4, 595-610 (2011)
39  * (A preliminary version appears in Proc. IPCO 2007.)
40  *
41  * In this paper a linear time propagation algorithm is described, a variant of which is implemented
42  * here. The implemented variant does not run in linear time, but is very fast in practice.
43  *
44  * <table>
45  * <caption>translation table</caption>
46  * <tr><td>here</td><td>paper</td></tr>
47  * <tr><td></td><td></td></tr>
48  * <tr><td>nspcons </td><td>p </td></tr>
49  * <tr><td>nblocks </td><td>q </td></tr>
50  * <tr><td>vars </td><td>x </td></tr>
51  * <tr><td>vals </td><td>A^\\star</td></tr>
52  * <tr><td>weights </td><td>\\omega </td></tr>
53  * <tr><td>cases </td><td>\\tau </td></tr>
54  * <tr><td>fixtriangle </td><td>-- </td></tr>
55  * <tr><td>resolveprop </td><td>-- </td></tr>
56  * <tr><td>firstnonzeros</td><td>\\mu </td></tr>
57  * <tr><td>lastones </td><td>\\alpha </td></tr>
58  * <tr><td>frontiersteps</td><td>\\Gamma </td></tr>
59  * </table>
60  *
61  * Orbitopal fixing for the full (sub-)orbitope and application to the Unit Commitment Problem@n
62  * Pascale Bendotti, Pierre Fouilhoux, and Cecile Rottner,@n
63  * Optimization Online: http://www.optimization-online.org/DB_HTML/2017/10/6301.html
64  *
65  * Two linear time propagation algorithms for full orbitopes are described in this paper, a static
66  * version and a dynamic one. While the static version uses a fixed variable order, the dynamic
67  * version determines the variable order during the solving process via branching descisions.
68  * We implemented the static version as well as a modified version of the dynamic one. The reason
69  * for the latter is to simplify the compatibility with full orbitope cutting planes.
70  *
71  * Note, however, that the dynamic version may lead to conflicts if orbitopes are copied to subSCIPs.
72  * Since the dynamic version is based on branching decisions, which may be different in main SCIP
73  * and subSCIPs, orbitopes using the dynamic algorithm are not allowed to be copied. However, as a
74  * user might use orbitopes to enforce a certain variable ordering in a solution, we distinguish
75  * whether an orbitope is a model constraint or not. If it is a model constraint, we assume that
76  * a variable order has already been fixed and disable the dynamic algorithm. In this case, orbitope
77  * constraints are copied to subSCIPs. If it is not a model constraint, the orbitope was added to
78  * handle symmetries but not to enforce a solution to have a certain structure. In this case, the
79  * dynamic algorithm can be used and we do not copy orbitope constraints to subSCIPs.
80  *
81  * Polytopes associated with symmetry handling@n
82  * Christopher Hojny and Marc E. Pfetsch,@n
83  * Math. Program. (2018)
84  *
85  * In this paper, a linear time separation algorithm for orbisacks (full orbitopes with two columnes)
86  * is described. We use this algorithm for every pair of adjacent columns within the orbitope as well
87  * as a version that is adapted to the reordering based on the dynamic full orbitope propagation
88  * algorithm to ensure validity of binary points via cutting planes.
89  */
90 
91 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
92 
93 #include "blockmemshell/memory.h"
94 #include "scip/cons_orbisack.h"
95 #include "scip/cons_orbitope.h"
96 #include "scip/cons_setppc.h"
97 #include "scip/pub_cons.h"
98 #include "scip/pub_message.h"
99 #include "scip/pub_var.h"
100 #include "scip/scip.h"
101 #include "scip/scip_branch.h"
102 #include "scip/scip_conflict.h"
103 #include "scip/scip_cons.h"
104 #include "scip/scip_copy.h"
105 #include "scip/scip_cut.h"
106 #include "scip/scip_general.h"
107 #include "scip/scip_lp.h"
108 #include "scip/scip_mem.h"
109 #include "scip/scip_message.h"
110 #include "scip/scip_numerics.h"
111 #include "scip/scip_param.h"
112 #include "scip/scip_prob.h"
113 #include "scip/scip_probing.h"
114 #include "scip/scip_sol.h"
115 #include "scip/scip_var.h"
116 #include "scip/symmetry.h"
117 #include <ctype.h>
118 #include <string.h>
119 #include <symmetry/type_symmetry.h>
120 
121 /* constraint handler properties */
122 #define CONSHDLR_NAME "orbitope"
123 #define CONSHDLR_DESC "symmetry breaking constraint handler relying on (partitioning/packing) orbitopes"
124 #define CONSHDLR_SEPAPRIORITY +40100 /**< priority of the constraint handler for separation */
125 #define CONSHDLR_ENFOPRIORITY -1005200 /**< priority of the constraint handler for constraint enforcing */
126 #define CONSHDLR_CHECKPRIORITY -1005200 /**< priority of the constraint handler for checking feasibility */
127 #define CONSHDLR_SEPAFREQ -1 /**< frequency for separating cuts; zero means to separate only in the root node */
128 #define CONSHDLR_PROPFREQ 1 /**< frequency for propagating domains; zero means only preprocessing propagation */
129 #define CONSHDLR_EAGERFREQ -1 /**< frequency for using all instead of only the useful constraints in separation,
130  * propagation and enforcement, -1 for no eager evaluations, 0 for first only */
131 #define CONSHDLR_MAXPREROUNDS -1 /**< maximal number of presolving rounds the constraint handler participates in (-1: no limit) */
132 #define CONSHDLR_DELAYSEPA FALSE /**< should separation method be delayed, if other separators found cuts? */
133 #define CONSHDLR_DELAYPROP FALSE /**< should propagation method be delayed, if other propagators found reductions? */
134 #define CONSHDLR_NEEDSCONS TRUE /**< should the constraint handler be skipped, if no constraints are available? */
136 #define CONSHDLR_PROP_TIMING SCIP_PROPTIMING_BEFORELP /**< propagation timing mask of the constraint handler */
137 #define CONSHDLR_PRESOLTIMING SCIP_PRESOLTIMING_MEDIUM /**< presolving timing of the constraint handler (fast, medium, or exhaustive) */
139 #define DEFAULT_PPORBITOPE TRUE /**< whether we check if full orbitopes can be strengthened to packing/partitioning orbitopes */
140 #define DEFAULT_SEPAFULLORBITOPE FALSE /**< whether we separate inequalities for full orbitopes */
141 #define DEFAULT_FORCECONSCOPY FALSE /**< whether orbitope constraints should be forced to be copied to sub SCIPs */
143 /*
144  * Data structures
145  */
146 
147 /** constraint handler data */
148 struct SCIP_ConshdlrData
149 {
150  SCIP_Bool checkpporbitope; /**< whether we allow upgrading to packing/partitioning orbitopes */
151  SCIP_Bool sepafullorbitope; /**< whether we separate inequalities for full orbitopes orbitopes */
152  SCIP_Bool forceconscopy; /**< whether orbitope constraints should be forced to be copied to sub SCIPs */
153 };
154 
155 /** constraint data for orbitope constraints */
156 struct SCIP_ConsData
157 {
158  SCIP_VAR*** vars; /**< matrix of variables on which the symmetry acts */
159  SCIP_VAR** tmpvars; /**< temporary storage for variables */
160  SCIP_HASHMAP* rowindexmap; /**< map of variables to row index in orbitope matrix */
161  SCIP_Real** vals; /**< LP-solution for those variables */
162  SCIP_Real* tmpvals; /**< temporary storage for values */
163  SCIP_Real** weights; /**< SC weight table */
164  int** cases; /**< indicator of the SC cases */
165  int nspcons; /**< number of set partitioning/packing constraints <=> p */
166  int nblocks; /**< number of symmetric variable blocks <=> q */
167  SCIP_ORBITOPETYPE orbitopetype; /**< type of orbitope constraint */
168  SCIP_Bool resolveprop; /**< should propagation be resolved? */
169  SCIP_Bool istrianglefixed; /**< has the upper right triangle already globally been fixed to zero? */
170  int* roworder; /**< order of orbitope rows if dynamic propagation for full orbitopes
171  * is used. */
172  SCIP_Bool* rowused; /**< whether a row has been considered in roworder */
173  int nrowsused; /**< number of rows that have already been considered in roworder */
174  SCIP_Bool ismodelcons; /**< whether the orbitope is a model constraint */
175  SCIP_Bool mayinteract; /**< whether symmetries corresponding to orbitope might interact
176  * with symmetries handled by other routines */
177  SCIP_Bool usedynamicprop; /**< whether we use a dynamic version of the propagation routine */
178 };
179 
180 
181 /*
182  * Local methods
183  */
184 
185 /** frees an orbitope constraint data */
186 static
188  SCIP* scip, /**< SCIP data structure */
189  SCIP_CONSDATA** consdata /**< pointer to orbitope constraint data */
190  )
191 {
192  int p;
193  int q;
194 
195  assert( consdata != NULL );
196  assert( *consdata != NULL );
197 
198  if ( (*consdata)->usedynamicprop && (*consdata)->rowindexmap != NULL )
199  {
200  SCIPhashmapFree(&((*consdata)->rowindexmap));
201  }
202 
203  p = (*consdata)->nspcons;
204  q = (*consdata)->nblocks;
205  for (int i = 0; i < p; ++i)
206  {
207  SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->cases[i]), q); /*lint !e866*/
208  SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->vars[i]), q); /*lint !e866*/
209  SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->weights[i]), q); /*lint !e866*/
210  SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->vals[i]), q); /*lint !e866*/
211  }
212 
213  if ( (*consdata)->usedynamicprop )
214  {
215  SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->rowused), p);
216  }
217  SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->roworder), p);
218  SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->cases), p);
219  SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->vars), p);
220  SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->weights), p);
221  SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->vals), p);
222 
223  SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->tmpvals), p + q);
224  SCIPfreeBlockMemoryArrayNull(scip, &((*consdata)->tmpvars), p + q);
225 
226  SCIPfreeBlockMemory(scip, consdata);
227 
228  return SCIP_OKAY;
229 }
230 
231 
232 /** creates orbitope constraint data */
233 static
235  SCIP* scip, /**< SCIP data structure */
236  SCIP_CONSDATA** consdata, /**< pointer to store constraint data */
237  SCIP_VAR*** vars, /**< variables array, must have size nspcons x nblocks */
238  int nspcons, /**< number of set partitioning (packing) constraints <=> p */
239  int nblocks, /**< number of symmetric variable blocks <=> q */
240  SCIP_ORBITOPETYPE orbitopetype, /**< type of orbitope constraint */
241  SCIP_Bool resolveprop, /**< should propagation be resolved? */
242  SCIP_Bool usedynamicprop, /**< whether we use a dynamic version of the propagation routine */
243  SCIP_Bool ismodelcons, /**< whether the orbitope is a model constraint */
244  SCIP_Bool mayinteract /**< whether symmetries corresponding to orbitope might interact
245  * with symmetries handled by other routines */
246  )
247 {
248  int i;
249  int j;
250 
251  assert(consdata != NULL);
252 #ifndef NDEBUG
253  if ( usedynamicprop )
254  {
255  assert( ! mayinteract );
256  }
257 #endif
258 
259  SCIP_CALL( SCIPallocBlockMemory(scip, consdata) );
260 
261  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->vals, nspcons) );
262  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->weights, nspcons) );
263  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->vars, nspcons) );
264  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->cases, nspcons) );
265  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->roworder, nspcons) );
266 
267  /* if orbitope might interact with other symmetries, we cannot adapt the row order of orbitopes dynamically */
268  if ( usedynamicprop )
269  {
270  SCIP_CALL( SCIPhashmapCreate(&(*consdata)->rowindexmap, SCIPblkmem(scip), nspcons) );
271  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->rowused, nspcons) );
272  }
273 
274  for (i = 0; i < nspcons; ++i)
275  {
276  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->vals[i], nblocks) ); /*lint !e866*/
277  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->weights[i], nblocks) ); /*lint !e866*/
278  SCIP_CALL( SCIPduplicateBlockMemoryArray(scip, &(*consdata)->vars[i], vars[i], nblocks) ); /*lint !e866*/
279  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->cases[i], nblocks) ); /*lint !e866*/
280  (*consdata)->roworder[i] = i;
281 
282  if ( usedynamicprop )
283  {
284  (*consdata)->rowused[i] = FALSE;
285  }
286  }
287  (*consdata)->nrowsused = 0;
288 
289  (*consdata)->tmpvals = NULL;
290  (*consdata)->tmpvars = NULL;
291  (*consdata)->nspcons = nspcons;
292  (*consdata)->nblocks = nblocks;
293  (*consdata)->orbitopetype = orbitopetype;
294  (*consdata)->resolveprop = resolveprop;
295  (*consdata)->istrianglefixed = FALSE;
296  (*consdata)->ismodelcons = ismodelcons;
297  (*consdata)->mayinteract = mayinteract;
298  (*consdata)->usedynamicprop = usedynamicprop;
299 
300  /* get transformed variables, if we are in the transformed problem */
301  if ( SCIPisTransformed(scip) )
302  {
303  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->tmpvals, nspcons + nblocks) );
304  SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*consdata)->tmpvars, nspcons + nblocks) );
305 
306  for (i = 0; i < nspcons; ++i)
307  {
308  /* make sure that no variable gets multiaggregated (cannot be handled by cons_orbitope, since one cannot easily
309  * eliminate single variables from an orbitope constraint).
310  */
311  for (j = 0; j < nblocks; ++j)
312  {
313  SCIP_CALL( SCIPgetTransformedVar(scip, (*consdata)->vars[i][j], &(*consdata)->vars[i][j]) );
314  SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*consdata)->vars[i][j]) );
315  if ( usedynamicprop )
316  {
317  SCIP_CALL( SCIPhashmapInsert((*consdata)->rowindexmap, (*consdata)->vars[i][j], (void*) (size_t) i) );
318  }
319  }
320  }
321  }
322 
323  return SCIP_OKAY;
324 }
325 
326 
327 /** strengthen full orbitopes to packing/partitioning orbitopes if possible */
328 static
330  SCIP* scip, /**< SCIP data structure */
331  SCIP_VAR*** vars, /**< variable matrix of orbitope constraint */
332  int* nrows, /**< pointer to number of rows of variable matrix */
333  int ncols, /**< number of columns of variable matrix */
334  SCIP_ORBITOPETYPE* type, /**< pointer to store type of orbitope constraint after strengthening */
335  SCIP_Bool mayinteract /**< whether symmetries corresponding to orbitope might interact
336  * with symmetries handled by other routines */
337  )
338 {
339  SCIP_Bool* pprows = NULL;
340  int npprows;
341  int nrowsorig;
342 
343  assert( scip != NULL );
344  assert( vars != NULL );
345  assert( vars != NULL );
346  assert( *nrows > 0 );
347  assert( ncols > 0 );
348  assert( type != NULL );
349 
350  nrowsorig = *nrows;
351  SCIP_CALL( SCIPisPackingPartitioningOrbitope(scip, vars, *nrows, ncols, &pprows, &npprows, type) );
352 
353  /* If only some rows are contained in set packing/partitioning constraints, it may still be worth it
354  * to exploit the packing/partitioning structure on these rows, because packing/partitioning orbitopes
355  * or more restrictive than full orbitopes. If at least three rows have this property, we discard
356  * all rows not contained in set packing/partitioning constraints and add the smaller sub packing orbitope.
357  * This is only possible if the orbitope's symmetries do not interact with other symmetry handling
358  * methods (otherwise, dropping rows might change the variable order).
359  */
360  if ( npprows >= 3 && ! mayinteract )
361  {
362  int r = *nrows - 1;
363  int i;
364 
365  assert( pprows != NULL );
366 
367  while ( r >= 0 )
368  {
369  if ( ! pprows[r] )
370  {
371  for (i = r; i < *nrows - 1; ++i)
372  {
373  SCIP_VAR** row;
374  row = vars[i];
375  vars[i] = vars[i+1];
376  vars[i+1] = row;
377  }
378  *nrows -= 1;
379  }
380  --r;
381  }
383  }
384 
385  /* pprows might not have been initialized if there are no setppc conss */
386  if ( pprows != NULL )
387  {
388  SCIPfreeBlockMemoryArray(scip, &pprows, nrowsorig);
389  }
390 
391  return SCIP_OKAY;
392 }
393 
394 #ifdef PRINT_MATRIX
395 /** debug method, prints variable matrix */
396 static
397 void printMatrix(
398  SCIP* scip, /**< SCIP data structure */
399  SCIP_CONSDATA* consdata /**< the constraint data */
400  )
401 {
402  int i;
403  int j;
404 
405  assert( consdata != NULL );
406  assert( consdata->nspcons > 0 );
407  assert( consdata->nblocks > 0 );
408  assert( consdata->vars != NULL );
409 
410  for (j = 0; j < consdata->nblocks; ++j)
411  SCIPinfoMessage(scip, NULL, "-");
412 
413  SCIPinfoMessage(scip, NULL, "\n");
414  for (i = 0; i < consdata->nspcons; ++i)
415  {
416  for (j = 0; j < consdata->nblocks; ++j)
417  {
418  if ( SCIPvarGetUbLocal(consdata->vars[i][j]) - SCIPvarGetLbLocal(consdata->vars[i][j]) < 0.5 )
419  SCIPinfoMessage(scip, NULL, "%1.0f", REALABS(SCIPvarGetUbLocal(consdata->vars[i][j])));
420  else
421  SCIPinfoMessage(scip, NULL, " ");
422  }
423  SCIPinfoMessage(scip, NULL, "|\n");
424  }
425  for (j = 0; j < consdata->nblocks; ++j)
426  SCIPinfoMessage(scip, NULL, "-");
427  SCIPinfoMessage(scip, NULL, "\n");
428 }
429 #endif
430 
431 
432 #ifdef SHOW_SCI
433 /** Print SCI in nice form for debugging */
434 static
435 SCIP_RETCODE printSCI(
436  SCIP* scip, /**< SCIP pointer */
437  int p, /**< number of rows */
438  int q, /**< number of columns */
439  int** cases, /**< SCI dynamic programming table */
440  int i, /**< row position of bar */
441  int j /**< column position of bar */
442  )
443 {
444  int k;
445  int l;
446  int** M;
447  int p1;
448  int p2;
449 
450  SCIP_CALL( SCIPallocBufferArray(scip, &M, p) );
451  for (k = 0; k < p; ++k)
452  {
453  SCIP_CALL( SCIPallocBufferArray(scip, &M[k], q) ); /*lint !e866*/
454  for (l = 0; l < q; ++l)
455  M[k][l] = 0;
456  }
457 
458  /* first add bar */
459  for (l = j; l < q; ++l)
460  {
461  assert( M[i][l] == 0 );
462  M[i][l] = 1;
463  }
464 
465  /* then add shifted column */
466  p1 = i-1;
467  p2 = j-1;
468  do
469  {
470  assert( cases[p1][p2] != -1 );
471  assert( p1 >= 0 && p1 < i );
472  assert( p2 >= 0 && p2 < j );
473 
474  /* if case 1 */
475  if ( cases[p1][p2] == 1 )
476  --p2; /* decrease column */
477  else
478  {
479  /* case 2 or 3: */
480  assert( cases[p1][p2] == 2 || cases[p1][p2] == 3 );
481  assert( M[p1][p2] == 0 );
482  M[p1][p2] = -1;
483  if ( cases[p1][p2] == 3 )
484  break;
485  }
486  --p1; /* decrease row */
487  }
488  while ( p1 >= 0 ); /* should always be true, i.e. the break should end the loop */
489  assert( cases[p1][p2] == 3 );
490 
491  /* now output matrix M */
492  for (l = 0; l < q; ++l)
493  SCIPinfoMessage(scip, NULL, "-");
494  SCIPinfoMessage(scip, NULL, "\n");
495 
496  for (k = 0; k < p; ++k)
497  {
498  for (l = 0; l < q; ++l)
499  {
500  if ( l > k )
501  SCIPinfoMessage(scip, NULL, "*");
502  else
503  {
504  switch (M[k][l])
505  {
506  case 1:
507  SCIPinfoMessage(scip, NULL, "+");
508  break;
509  case -1:
510  SCIPinfoMessage(scip, NULL, "-");
511  break;
512  case 0:
513  SCIPinfoMessage(scip, NULL, "#");
514  break;
515  default:
516  SCIPerrorMessage("unexpected matrix entry <%d>: should be -1, 0 or +1\n", M[k][l]);
517  SCIPABORT();
518  }
519  }
520  }
521  SCIPinfoMessage(scip, NULL, "\n");
522  }
523 
524  for (l = 0; l < q; ++l)
525  SCIPinfoMessage(scip, NULL, "-");
526  SCIPinfoMessage(scip, NULL, "\n");
527 
528  for (k = 0; k < p; ++k)
529  SCIPfreeBufferArray(scip, &M[k]);
530  SCIPfreeBufferArray(scip, &M);
531 
532  return SCIP_OKAY;
533 }
534 #endif
535 
536 
537 /** copies the variables values from the solution to the constraint data structure */
538 static
539 void copyValues(
540  SCIP* scip, /**< the SCIP data structure */
541  SCIP_CONSDATA* consdata, /**< the constraint data */
542  SCIP_SOL* sol /**< a primal solution or NULL for the current LP optimum */
543  )
544 {
545  int i;
546  int j;
547 
548  assert( scip != NULL );
549  assert( consdata != NULL );
550  assert( consdata->nspcons > 0 );
551  assert( consdata->nblocks > 0 );
552  assert( consdata->vars != NULL );
553  assert( consdata->vals != NULL );
554 
555  for (i = 0; i < consdata->nspcons; ++i)
556  {
557  for (j = 0; j < consdata->nblocks; ++j)
558  consdata->vals[i][j] = SCIPgetSolVal(scip, sol, consdata->vars[i][j]);
559  }
560 }
561 
562 
563 /** compute the dynamic programming table for SC
564  *
565  * Build up dynamic programming table in order to find SCs with minimum weight.
566  *
567  * The values of the minimal SCIs are stored in @a weights.
568  * The array @a cases[i][j] stores which of the cases were applied to get @a weights[i][j].
569  * Here, 3 means that we have reached the upper limit.
570  *
571  * We assume that the upper right triangle is fixed to 0. Hence we can perform the computation a
572  * bit more efficient.
573  */
574 static
575 void computeSCTable(
576  SCIP* scip, /**< SCIP pointer */
577  int nspcons, /**< number of set partitioning (packing) constraints <=> p */
578  int nblocks, /**< number of symmetric variable blocks <=> q */
579  SCIP_Real** weights, /**< SC weight table */
580  int** cases, /**< indicator of the SC cases */
581  SCIP_Real** vals /**< current solution */
582  )
583 {
584  SCIP_Real minvalue;
585  int diagsize;
586  int i;
587  int j;
588 
589  assert( weights != NULL );
590  assert( cases != NULL );
591  assert( vals != NULL );
592 
593 #ifndef NDEBUG
594  /* for debugging */
595  for (i = 0; i < nspcons; ++i)
596  {
597  for (j = 0; j < nblocks; ++j)
598  {
599  if ( i >= j )
600  {
601  weights[i][j] = -1.0;
602  cases[i][j] = -1;
603  }
604  }
605  }
606 #endif
607 
608  /* initialize diagonal */
609  minvalue = vals[0][0];
610  weights[0][0] = minvalue;
611  cases[0][0] = 3;
612 
613  /* get last row of triangle */
614  diagsize = nblocks;
615  if ( nspcons < nblocks )
616  diagsize = nspcons;
617 
618  for (j = 1; j < diagsize; ++j)
619  {
620  /* use LT to move entry as far to the left as possible */
621  if ( SCIPisLT(scip, vals[j][j], minvalue) )
622  {
623  minvalue = vals[j][j];
624  cases[j][j] = 3;
625  }
626  else
627  cases[j][j] = 1;
628  weights[j][j] = minvalue;
629  }
630 
631  /* initialize first column */
632  for (i = 1; i < nspcons; ++i)
633  {
634  weights[i][0] = weights[i-1][0] + vals[i][0];
635  cases[i][0] = 2; /* second case */
636  }
637 
638  /* build the table */
639  for (i = 2; i < nspcons; ++i)
640  {
641  for (j = 1; j < nblocks && j < i; ++j)
642  {
643  SCIP_Real weightleft;
644  SCIP_Real weightright;
645 
646  assert( cases[i-1][j] != -1 );
647  assert( cases[i-1][j-1] != -1 );
648 
649  weightleft = weights[i-1][j-1];
650  weightright = vals[i][j] + weights[i-1][j];
651 
652  /* For first column: cannot take left possibility */
653  if ( SCIPisLT(scip, weightleft, weightright) )
654  {
655  weights[i][j] = weightleft;
656  cases[i][j] = 1;
657  }
658  else
659  {
660  weights[i][j] = weightright;
661  cases[i][j] = 2;
662  }
663  }
664  }
665 }
666 
667 
668 /** fix upper right triangle if necessary */
669 static
671  SCIP* scip, /**< SCIP data structure */
672  SCIP_CONS* cons, /**< constraint to be processed */
673  SCIP_Bool* infeasible, /**< pointer to store TRUE, if the node can be cut off */
674  int* nfixedvars /**< pointer to add up the number of found domain reductions */
675  )
676 {
677  SCIP_CONSDATA* consdata;
678  SCIP_VAR*** vars;
679  SCIP_Bool fixedglobal;
680  SCIP_Bool fixed;
681  int diagsize;
682  int nspcons;
683  int nblocks;
684  int i;
685  int j;
686 
687  assert( scip != NULL );
688  assert( cons != NULL );
689  assert( infeasible != NULL );
690  assert( nfixedvars != NULL );
691 
692  consdata = SCIPconsGetData(cons);
693  assert( consdata != NULL );
694  assert( consdata->nspcons > 0 );
695  assert( consdata->nblocks > 0 );
696  assert( consdata->vars != NULL );
697 
698  *infeasible = FALSE;
699  *nfixedvars = 0;
700 
701  if ( consdata->istrianglefixed )
702  return SCIP_OKAY;
703 
704  nspcons = consdata->nspcons;
705  nblocks = consdata->nblocks;
706  vars = consdata->vars;
707  fixedglobal = TRUE;
708 
709  /* get last row of triangle */
710  diagsize = nblocks;
711  if ( nspcons < nblocks )
712  diagsize = nspcons;
713 
714  /* fix variables to 0 */
715  for (i = 0; i < diagsize; ++i)
716  {
717  for (j = i+1; j < nblocks; ++j)
718  {
719  /* fix variable, if not in the root the fixation is local */
720  SCIP_CALL( SCIPfixVar(scip, vars[i][j], 0.0, infeasible, &fixed) );
721 
722  if ( *infeasible )
723  {
724  SCIPdebugMsg(scip, "The problem is infeasible: some variable in the upper right triangle is fixed to 1.\n");
725  return SCIP_OKAY;
726  }
727 
728  if ( fixed )
729  ++(*nfixedvars);
730 
731  if ( SCIPvarGetUbGlobal(vars[i][j]) > 0.5 )
732  fixedglobal = FALSE;
733  }
734  }
735  if ( *nfixedvars > 0 )
736  {
737  SCIPdebugMsg(scip, "<%s>: %s fixed upper right triangle to 0 (fixed vars: %d).\n", SCIPconsGetName(cons), fixedglobal ? "globally" : "locally", *nfixedvars);
738  }
739  else
740  {
741  SCIPdebugMsg(scip, "<%s>: Upper right triangle already fixed to 0.\n", SCIPconsGetName(cons));
742  }
743 
744  if ( fixedglobal )
745  consdata->istrianglefixed = TRUE;
746 
747  return SCIP_OKAY;
748 }
749 
750 
751 /** separates shifted column inequalities according to the solution stored in consdata->vals */
752 static
754  SCIP* scip, /**< the SCIP data structure */
755  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
756  SCIP_CONS* cons, /**< constraint */
757  SCIP_CONSDATA* consdata, /**< the constraint data */
758  SCIP_Bool* infeasible, /**< whether we detected infeasibility */
759  int* nfixedvars, /**< pointer to store the number of variables fixed */
760  int* ncuts /**< pointer to store number of separated SCIs */
761  )
762 {
763  SCIP_Real** vals;
764  SCIP_Real** weights;
765  SCIP_Real* tmpvals;
766  SCIP_VAR*** vars;
767  SCIP_VAR** tmpvars;
768  int** cases;
769  int nspcons;
770  int nblocks;
771  int i;
772  int j;
773  int l;
774 
775  assert( scip != NULL );
776  assert( conshdlr != NULL );
777  assert( cons != NULL );
778  assert( infeasible != NULL);
779  assert( nfixedvars != NULL );
780  assert( ncuts != NULL );
781 
782  assert( consdata != NULL );
783  assert( consdata->nspcons > 0 );
784  assert( consdata->nblocks > 0 );
785  assert( consdata->vars != NULL );
786  assert( consdata->vals != NULL );
787  assert( consdata->tmpvars != NULL );
788  assert( consdata->tmpvals != NULL );
789  assert( consdata->weights != NULL );
790  assert( consdata->cases != NULL );
791 
792  *infeasible = FALSE;
793  *nfixedvars = 0;
794  *ncuts = 0;
795 
796  nspcons = consdata->nspcons;
797  nblocks = consdata->nblocks;
798  vars = consdata->vars;
799  vals = consdata->vals;
800  tmpvars = consdata->tmpvars;
801  tmpvals = consdata->tmpvals;
802  weights = consdata->weights;
803  cases = consdata->cases;
804 
805  /* check for upper right triangle */
806  if ( ! consdata->istrianglefixed )
807  {
808  SCIP_CALL( fixTriangle(scip, cons, infeasible, nfixedvars) );
809  if ( *infeasible )
810  return SCIP_OKAY;
811  if ( *nfixedvars > 0 )
812  return SCIP_OKAY;
813  }
814 
815  /* compute table if necessary (i.e., not computed before) */
816  computeSCTable(scip, nspcons, nblocks, weights, cases, vals);
817 
818  /* loop through rows */
819  for (i = 1; i < nspcons && ! (*infeasible); ++i)
820  {
821  SCIP_Real bar; /* value of bar: */
822  int lastcolumn; /* last column considered as part of the bar */
823 
824  bar = 0.0;
825  lastcolumn = nblocks - 1;
826  if ( lastcolumn > i )
827  lastcolumn = i;
828 
829  /* traverse row from right to left: */
830  /* j >= 1, since for j = 0, i.e., the bar is a complete row, there does not exist an SCI */
831  for (j = lastcolumn; j > 0; --j)
832  {
833  bar += vals[i][j];
834 
835  /* check whether weights[i-1][j-1] < bar (<=> bar - weights[i-1][j-1] > 0), i.e. cut is violated) */
836  if ( SCIPisEfficacious(scip, bar - weights[i-1][j-1]) )
837  {
838  SCIP_Real weight;
839  SCIP_ROW* row;
840 #ifdef SCIP_DEBUG
841  char name[SCIP_MAXSTRLEN];
842 #endif
843  int nvars;
844  int p1;
845  int p2;
846 
847  nvars = 0;
848  p1 = i-1;
849  p2 = j-1;
850  weight = 0.0;
851 
852  /* first add bar */
853  for (l = j; l <= lastcolumn; ++l)
854  {
855  tmpvars[nvars] = vars[i][l];
856  tmpvals[nvars] = 1.0;
857  nvars++;
858  }
859 
860  /* then add shifted column */
861  do
862  {
863  assert( cases[p1][p2] != -1 );
864  assert( p1 >= 0 && p1 < i );
865  assert( p2 >= 0 && p2 < j );
866 
867  /* if case 1 */
868  if (cases[p1][p2] == 1)
869  p2--; /* decrease column */
870  else
871  {
872  /* case 2 or 3: */
873  assert( cases[p1][p2] == 2 || cases[p1][p2] == 3 );
874  tmpvars[nvars] = vars[p1][p2];
875  tmpvals[nvars] = -1.0;
876  nvars++;
877  weight += vals[p1][p2];
878  if ( cases[p1][p2] == 3 )
879  break;
880  }
881  p1--; /* decrease row */
882  }
883  while ( p1 >= 0 ); /* should always be true, i.e. the break should end the loop */
884  assert( cases[p1][p2] == 3 );
885 
886  /* generate cut */
887 #ifdef SCIP_DEBUG
888  (void) SCIPsnprintf(name, SCIP_MAXSTRLEN, "sci_%d_%d", i, j);
889  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, conshdlr, name, -SCIPinfinity(scip), 0.0, FALSE, FALSE, TRUE) );
890 #else
891  SCIP_CALL( SCIPcreateEmptyRowConshdlr(scip, &row, conshdlr, "", -SCIPinfinity(scip), 0.0, FALSE, FALSE, TRUE) );
892 #endif
893  SCIP_CALL( SCIPaddVarsToRow(scip, row, nvars, tmpvars, tmpvals) );
894  /*SCIP_CALL( SCIPprintRow(scip, row, NULL) ); */
895  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
896  SCIP_CALL( SCIPreleaseRow(scip, &row) );
897  ++(*ncuts);
898 
899 #ifdef SHOW_SCI
900  SCIP_CALL( printSCI(scip, nspcons, nblocks, cases, i, j) );
901 #endif
902 
903  assert( SCIPisSumEQ(scip, weights[i-1][j-1], weight) );
904  }
905  }
906  }
907  return SCIP_OKAY;
908 }
909 
910 
911 /** propagation method for a single packing or partitioning orbitope constraint */
912 static
914  SCIP* scip, /**< SCIP data structure */
915  SCIP_CONS* cons, /**< constraint to be processed */
916  SCIP_Bool* infeasible, /**< pointer to store TRUE, if the node can be cut off */
917  int* nfixedvars /**< pointer to add up the number of found domain reductions */
918  )
919 {
920  SCIP_CONSDATA* consdata;
921  SCIP_VAR*** vars;
922  SCIP_ORBITOPETYPE orbitopetype;
923  int* firstnonzeros;
924  int* lastones;
925  int* frontiersteps;
926  int lastoneprevrow;
927  int nspcons;
928  int nblocks;
929  int nsteps;
930  int i;
931  int j;
932 
933  assert( scip != NULL );
934  assert( cons != NULL );
935  assert( infeasible != NULL );
936  assert( nfixedvars != NULL );
937 
938  *nfixedvars = 0;
939 
940  if( !SCIPallowStrongDualReds(scip) )
941  return SCIP_OKAY;
942 
943  consdata = SCIPconsGetData(cons);
944  assert( consdata != NULL );
945  assert( consdata->nspcons > 0 );
946  assert( consdata->nblocks > 0 );
947  assert( consdata->vars != NULL );
948 
949  nspcons = consdata->nspcons;
950  nblocks = consdata->nblocks;
951  vars = consdata->vars;
952  orbitopetype = consdata->orbitopetype;
953 
954  assert( orbitopetype == SCIP_ORBITOPETYPE_PACKING || orbitopetype == SCIP_ORBITOPETYPE_PARTITIONING );
955 
956  /* fix upper right triangle if still necessary */
957  if ( ! consdata->istrianglefixed )
958  {
959  int nfixed = 0;
960  SCIP_CALL( fixTriangle(scip, cons, infeasible, &nfixed) );
961  *nfixedvars += nfixed;
962  }
963 
964  /* prepare further propagation */
965  SCIP_CALL( SCIPallocBufferArray(scip, &firstnonzeros, nspcons) );
966  SCIP_CALL( SCIPallocBufferArray(scip, &lastones, nspcons) );
967  SCIP_CALL( SCIPallocBufferArray(scip, &frontiersteps, nblocks) );
968 
969 #ifdef PRINT_MATRIX
970  SCIPdebugMsg(scip, "Matrix:\n");
971  printMatrix(scip, consdata);
972 #endif
973 
974  /* propagate */
975  lastoneprevrow = 0;
976  lastones[0] = 0;
977 
978  if ( orbitopetype == SCIP_ORBITOPETYPE_PACKING )
979  {
980  /* packing case: if entry (0,0) is fixed to 0 */
981  if ( SCIPvarGetUbLocal(vars[0][0]) < 0.5 )
982  {
983  lastoneprevrow = -1;
984  lastones[0] = -1;
985  }
986  }
987  nsteps = 0;
988 
989  for (i = 1; i < nspcons; ++i)
990  {
991  int lastcolumn;
992  int firstnonzeroinrow;
993  int lastoneinrow;
994  SCIP_Bool infrontier;
995 
996  /* last column considered as part of the bar: */
997  lastcolumn = nblocks - 1;
998  if ( lastcolumn > i )
999  lastcolumn = i;
1000 
1001  /* find first position not fixed to 0 (partitioning) or fixed to 1 (packing) */
1002  firstnonzeroinrow = -1;
1003  for (j = 0; j <= lastcolumn; ++j)
1004  {
1005  if ( orbitopetype == SCIP_ORBITOPETYPE_PARTITIONING )
1006  {
1007  /* partitioning case: if variable is not fixed to 0 */
1008  if ( SCIPvarGetUbLocal(vars[i][j]) > 0.5 )
1009  {
1010  firstnonzeroinrow = j;
1011  break;
1012  }
1013  }
1014  else
1015  {
1016  /* packing case: if variable is fixed to 1 */
1017  if ( SCIPvarGetLbLocal(vars[i][j]) > 0.5 )
1018  {
1019  firstnonzeroinrow = j;
1020  break;
1021  }
1022  }
1023  }
1024  /* if all variables are fixed to 0 in the partitioning case - should not happen */
1025  if ( firstnonzeroinrow == -1 && orbitopetype == SCIP_ORBITOPETYPE_PARTITIONING )
1026  {
1027  SCIPdebugMsg(scip, " -> Infeasible node: all variables in row %d are fixed to 0.\n", i);
1028  *infeasible = TRUE;
1029  /* conflict should be analyzed by setppc constraint handler */
1030  goto TERMINATE;
1031  }
1032  firstnonzeros[i] = firstnonzeroinrow;
1033  assert( orbitopetype == SCIP_ORBITOPETYPE_PACKING || firstnonzeroinrow >= 0 );
1034  assert( -1 <= firstnonzeroinrow && firstnonzeroinrow <= lastcolumn );
1035 
1036  /* compute rightmost possible position for a 1 */
1037  assert( orbitopetype == SCIP_ORBITOPETYPE_PACKING || 0 <= lastoneprevrow );
1038  assert( lastoneprevrow <= lastcolumn );
1039 
1040  /* if we are at right border or if entry in column lastoneprevrow+1 is fixed to 0 */
1041  infrontier = FALSE;
1042  assert( lastoneprevrow + 1 >= 0 );
1043  if ( lastoneprevrow == nblocks-1 || SCIPvarGetUbLocal(vars[i][lastoneprevrow+1]) < 0.5 ) /*lint !e679*/
1044  lastoneinrow = lastoneprevrow;
1045  else
1046  {
1047  lastoneinrow = lastoneprevrow + 1;
1048  frontiersteps[nsteps++] = i;
1049  infrontier = TRUE;
1050  }
1051 
1052  /* store lastoneinrow */
1053  assert( orbitopetype == SCIP_ORBITOPETYPE_PACKING || 0 <= lastoneinrow );
1054  assert( lastoneinrow <= lastcolumn );
1055  lastones[i] = lastoneinrow;
1056 
1057  /* check whether we are infeasible */
1058  if ( firstnonzeroinrow > lastoneinrow )
1059  {
1060  int k;
1061 
1062 #ifdef SCIP_DEBUG
1063  if ( orbitopetype == SCIP_ORBITOPETYPE_PARTITIONING )
1064  {
1065  SCIPdebugMsg(scip, " -> Infeasible node: row %d, leftmost nonzero at %d, rightmost 1 at %d\n",
1066  i, firstnonzeroinrow, lastoneinrow);
1067  }
1068  else
1069  {
1070  SCIPdebugMsg(scip, " -> Infeasible node: row %d, 1 at %d, rightmost position for 1 at %d\n",
1071  i, firstnonzeroinrow, lastoneinrow);
1072  }
1073 #endif
1074  /* check if conflict analysis is applicable */
1076  {
1077  /* conflict analysis only applicable in SOLVING stage */
1078  assert( SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip) );
1079 
1080  /* perform conflict analysis */
1082 
1083  if ( orbitopetype == SCIP_ORBITOPETYPE_PARTITIONING )
1084  {
1085  /* add bounds (variables fixed to 0) that result in the first nonzero entry */
1086  for (j = 0; j <= lastcolumn; ++j)
1087  {
1088  /* add varaibles in row up to the first variable fixed to 0 */
1089  if ( SCIPvarGetUbLocal(vars[i][j]) > 0.5 )
1090  break;
1091 
1092  assert( SCIPvarGetUbLocal(vars[i][j]) < 0.5 );
1093  SCIP_CALL( SCIPaddConflictBinvar(scip, vars[i][j]) );
1094  }
1095  }
1096  else
1097  {
1098  /* add bounds that result in the last one - check top left entry for packing case */
1099  if ( lastones[0] == -1 )
1100  {
1101  assert( SCIPvarGetUbLocal(vars[0][0]) < 0.5 );
1102  SCIP_CALL( SCIPaddConflictBinvar(scip, vars[0][0]) );
1103  }
1104 
1105  /* mark variable fixed to 1 */
1106  assert( SCIPvarGetLbLocal(vars[i][firstnonzeroinrow]) > 0.5 );
1107  SCIP_CALL( SCIPaddConflictBinvar(scip, vars[i][firstnonzeroinrow]) );
1108  }
1109 
1110  /* add bounds that result in the last one - pass through rows */
1111  for (k = 1; k < i; ++k)
1112  {
1113  int l;
1114  l = lastones[k] + 1;
1115 
1116  /* if the frontier has not moved and we are not beyond the matrix boundaries */
1117  if ( l <= nblocks-1 && l <= k && lastones[k-1] == lastones[k] )
1118  {
1119  assert( SCIPvarGetUbLocal(vars[k][l]) < 0.5 );
1120  SCIP_CALL( SCIPaddConflictBinvar(scip, vars[k][l]) );
1121  }
1122  }
1123  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
1124  }
1125 
1126  *infeasible = TRUE;
1127  goto TERMINATE;
1128  }
1129 
1130  /* fix entries beyond the last possible position for a 1 in the row to 0 (see Lemma 1 in the paper) */
1131  for (j = lastoneinrow+1; j <= lastcolumn; ++j)
1132  {
1133  /* if the entry is not yet fixed to 0 */
1134  if ( SCIPvarGetUbLocal(vars[i][j]) > 0.5 )
1135  {
1136  SCIP_Bool tightened;
1137  int inferInfo;
1138 
1139  SCIPdebugMsg(scip, " -> Fixing entry (%d,%d) to 0.\n", i, j);
1140 
1141  tightened = FALSE;
1142 
1143  /* fix variable to 0 and store position of (i,lastoneinrow+1) for conflict resolution */
1144  inferInfo = i * nblocks + lastoneinrow + 1;
1145  /* correction according to Lemma 1 in the paper (second part): store (i,lastoneinrow+2) */
1146  if ( !infrontier )
1147  ++inferInfo;
1148  SCIP_CALL( SCIPinferBinvarCons(scip, vars[i][j], FALSE, cons, inferInfo, infeasible, &tightened) );
1149 
1150  /* if entry is fixed to one -> infeasible node */
1151  if ( *infeasible )
1152  {
1153  SCIPdebugMsg(scip, " -> Infeasible node: row %d, 1 in column %d beyond rightmost position %d\n", i, j, lastoneinrow);
1154  /* check if conflict analysis is applicable */
1156  {
1157  int k;
1158 
1159  /* conflict analysis only applicable in SOLVING stage */
1160  assert(SCIPgetStage(scip) == SCIP_STAGE_SOLVING || SCIPinProbing(scip));
1161 
1162  /* perform conflict analysis */
1164 
1165  /* add current bound */
1166  SCIP_CALL( SCIPaddConflictBinvar(scip, vars[i][j]) );
1167 
1168  /* add bounds that result in the last one - check top left entry for packing case */
1169  if ( orbitopetype == SCIP_ORBITOPETYPE_PACKING && lastones[0] == -1 )
1170  {
1171  assert( SCIPvarGetUbLocal(vars[0][0]) < 0.5 );
1172  SCIP_CALL( SCIPaddConflictBinvar(scip, vars[0][0]) );
1173  }
1174 
1175  /* add bounds that result in the last one - pass through rows */
1176  for (k = 1; k < i; ++k)
1177  {
1178  int l;
1179  l = lastones[k] + 1;
1180 
1181  /* if the frontier has not moved and we are not beyond the matrix boundaries */
1182  if ( l <= nblocks-1 && l <= k && lastones[k-1] == lastones[k] )
1183  {
1184  assert( SCIPvarGetUbLocal(vars[k][l]) < 0.5 );
1185  SCIP_CALL( SCIPaddConflictBinvar(scip, vars[k][l]) );
1186  }
1187  }
1188  SCIP_CALL( SCIPanalyzeConflictCons(scip, cons, NULL) );
1189  }
1190 
1191  goto TERMINATE;
1192  }
1193  if ( tightened )
1194  ++(*nfixedvars);
1195  }
1196  }
1197 
1198  lastoneprevrow = lastoneinrow;
1199  }
1200 
1201  /* check whether fixing any entry to 0 results in a contradiction -> loop through rows in frontiersteps (a.k.a. gamma) */
1202  for (j = 0; j < nsteps; ++j)
1203  {
1204  int s;
1205  int lastoneinrow;
1206 
1207  s = frontiersteps[j];
1208  lastoneinrow = lastones[s];
1209  /* note for packing case: if we are in a frontier step then lastoneinrow >= 0 */
1210  assert( 0 <= lastoneinrow && lastoneinrow < nblocks );
1211 
1212  /* if entry is not fixed */
1213  if ( SCIPvarGetLbLocal(vars[s][lastoneinrow]) < 0.5 && SCIPvarGetUbLocal(vars[s][lastoneinrow]) > 0.5 )
1214  {
1215  int betaprev;
1216  betaprev = lastoneinrow - 1;
1217 
1218  /* loop through rows below s */
1219  for (i = s+1; i < nspcons; ++i)
1220  {
1221  int beta;
1222 
1223  assert( betaprev + 1 >= 0 );
1224  if ( betaprev == nblocks-1 || SCIPvarGetUbLocal(vars[i][betaprev+1]) < 0.5 ) /*lint !e679*/
1225  beta = betaprev;
1226  else
1227  beta = betaprev + 1;
1228  assert( -1 <= beta && beta < nblocks );
1229 
1230  if ( firstnonzeros[i] > beta )
1231  {
1232  SCIP_Bool tightened;
1233  int inferInfo;
1234 
1235  /* can fix (s,lastoneinrow) (a.k.a (s,alpha)) to 1
1236  * (do not need to fix other entries to 0, since they will be
1237  * automatically fixed by SCIPtightenVarLb.)
1238  */
1239  assert( SCIPvarGetLbLocal(vars[s][lastoneinrow]) < 0.5 );
1240  SCIPdebugMsg(scip, " -> Fixing entry (%d,%d) to 1.\n", s, lastoneinrow);
1241 
1242  tightened = FALSE;
1243 
1244  /* store position (i,firstnonzeros[i]) */
1245  inferInfo = nblocks * nspcons + i * nblocks + firstnonzeros[i];
1246  SCIP_CALL( SCIPinferBinvarCons(scip, vars[s][lastoneinrow], TRUE, cons, inferInfo, infeasible, &tightened) );
1247 
1248  assert( !(*infeasible) );
1249  if ( tightened )
1250  ++(*nfixedvars);
1251  break;
1252  }
1253  betaprev = beta;
1254  }
1255  }
1256  }
1257 
1258  TERMINATE:
1259  SCIPfreeBufferArray(scip, &frontiersteps);
1260  SCIPfreeBufferArray(scip, &lastones);
1261  SCIPfreeBufferArray(scip, &firstnonzeros);
1262 
1263  return SCIP_OKAY;
1264 }
1265 
1266 
1267 /* Compute dynamic order of rows based on the branching decisions, i.e., the row of the first branching variable
1268  * determines the first row in the new ordering, the row of the second branching variable determines the second
1269  * row in the new ordering if it differs from the row of the first branching variable, and so on.
1270  *
1271  * The roworder array stores this reordering, where acutally only the first maxrowlabel entries encode the
1272  * reordering.
1273  */
1274 static
1276  SCIP* scip, /**< SCIP pointer */
1277  SCIP_HASHMAP* rowindexmap, /**< map of variables to indices in orbitope vars matrix */
1278  SCIP_Bool* rowused, /**< bitset marking whether a row has been considered in the new order */
1279  int* roworder, /**< reordering of the rows w.r.t. branching decisions */
1280  int nrows, /**< number of rows in orbitope */
1281  int ncols, /**< number of columns in orbitope */
1282  int* maxrowlabel /**< maximum row label in ordering */
1283  )
1284 {
1285  int i;
1286  SCIP_NODE* node;
1287  int* branchdecisions;
1288  int nbranchdecision;
1289 
1290  assert( scip != NULL );
1291  assert( rowindexmap != NULL );
1292  assert( roworder != NULL );
1293  assert( nrows > 0 );
1294  assert( maxrowlabel != NULL );
1295 
1296  SCIP_CALL( SCIPallocBufferArray(scip, &branchdecisions, nrows * ncols) );
1297  nbranchdecision = 0;
1298 
1299  /* get current node */
1300  node = SCIPgetCurrentNode(scip);
1301 
1302  /* follow path to the root (in the root no domains were changed due to branching) */
1303  while ( SCIPnodeGetDepth(node) != 0 )
1304  {
1305  SCIP_BOUNDCHG* boundchg;
1306  SCIP_DOMCHG* domchg;
1307  SCIP_VAR* branchvar;
1308  int nboundchgs;
1309 
1310  /* get domain changes of current node */
1311  domchg = SCIPnodeGetDomchg(node);
1312  assert( domchg != NULL );
1313 
1314  /* loop through all bound changes */
1315  nboundchgs = SCIPdomchgGetNBoundchgs(domchg);
1316  for (i = 0; i < nboundchgs; ++i)
1317  {
1318  /* get bound change info */
1319  boundchg = SCIPdomchgGetBoundchg(domchg, i);
1320  assert( boundchg != NULL );
1321 
1322  /* branching decisions have to be in the beginning of the bound change array */
1324  break;
1325 
1326  /* get corresponding branching variable */
1327  branchvar = SCIPboundchgGetVar(boundchg);
1328 
1329  /* we only consider binary variables */
1330  if ( SCIPvarGetType(branchvar) == SCIP_VARTYPE_BINARY )
1331  {
1332  int rowidx;
1333 
1334  /* make sure that branching variable is present in the orbitope */
1335  if ( ! SCIPhashmapExists(rowindexmap, (void*) branchvar) )
1336  continue;
1337 
1338  rowidx = (int) (size_t) SCIPhashmapGetImage(rowindexmap, (void*) branchvar);
1339  branchdecisions[nbranchdecision++] = rowidx;
1340  }
1341  }
1342 
1343  node = SCIPnodeGetParent(node);
1344  }
1345 
1346  /* Insert branching decisions of current path into global row order.
1347  * Iterate in reverse order over branching decisions to get the path
1348  * from the root to the current node.
1349  */
1350  for (i = nbranchdecision - 1; i >= 0; --i)
1351  {
1352  if ( ! rowused[branchdecisions[i]] )
1353  {
1354  roworder[*maxrowlabel] = branchdecisions[i];
1355  rowused[branchdecisions[i]] = TRUE;
1356  *maxrowlabel += 1;
1357  }
1358  }
1359 
1360  SCIPfreeBufferArray(scip, &branchdecisions);
1361 
1362  return SCIP_OKAY;
1363 }
1364 
1365 
1366 /* Compute lexicographically minimal face of the hypercube w.r.t. some coordinate fixing */
1367 static
1369  SCIP_VAR*** vars, /**< variable matrix */
1370  int** lexminfixes, /**< fixings characterzing lex-min face */
1371  int* minfixedrowlexmin, /**< index of minimum fixed row for each column or
1372  * NULL (if in prop) */
1373  SCIP_Bool* infeasible, /**< pointer to store whether infeasibility has been
1374  * detected or NULL (if in resprop) */
1375  int m, /**< number of rows in vars */
1376  int n, /**< number of columns in vars */
1377  int nrowsused, /**< number of rows considered in propagation */
1378  SCIP_Bool resprop /**< whether we are in resprop (TRUE) or prop (FALSE) */
1379  )
1380 {
1381  int i;
1382  int j;
1383  *infeasible = FALSE;
1384 
1385  assert( vars != NULL );
1386  assert( lexminfixes != NULL );
1387  assert( !resprop || minfixedrowlexmin != NULL );
1388  assert( m > 0 );
1389  assert( n > 0 );
1390  assert( nrowsused > 0 );
1391  assert( nrowsused <= m );
1392  assert( infeasible != NULL );
1393 
1394  /* iterate over columns in reverse order and find the lexicographically minimal face
1395  * of the hypercube containing lexminfixes
1396  */
1397  for (j = n - 2; j >= 0; --j)
1398  {
1399  int maxdiscriminating = m;
1400  int minfixed = -1;
1401 
1402  /* fix free entries in column j to the corresponding value in column j + 1 and collect some information */
1403  for (i = 0; i < nrowsused; ++i)
1404  {
1405  /* is row i j-discriminating? */
1406  if ( minfixed == -1 && lexminfixes[i][j] != 0 && lexminfixes[i][j + 1] != 1 )
1407  {
1408  assert( lexminfixes[i][j + 1] == 0 );
1409 
1410  maxdiscriminating = i;
1411  }
1412 
1413  /* is row i j-fixed? */
1414  if ( minfixed == -1 && lexminfixes[i][j] != lexminfixes[i][j + 1] && lexminfixes[i][j] != 2 )
1415  {
1416  assert( lexminfixes[i][j + 1] != 2 );
1417 
1418  minfixed = i;
1419 
1420  /* detect infeasibility */
1421  if ( maxdiscriminating > minfixed )
1422  {
1423  *infeasible = TRUE;
1424 
1425  return SCIP_OKAY;
1426  }
1427  }
1428  }
1429 
1430  /* ensure that column j is lexicographically not smaller than column j + 1 */
1431  for (i = 0; i < nrowsused; ++i)
1432  {
1433  if ( lexminfixes[i][j] == 2 )
1434  {
1435  if ( i < maxdiscriminating || minfixed == -1 )
1436  lexminfixes[i][j] = lexminfixes[i][j + 1];
1437  else if ( i == maxdiscriminating )
1438  lexminfixes[i][j] = 1;
1439  else
1440  lexminfixes[i][j] = 0;
1441  }
1442  }
1443 
1444  if ( resprop )
1445  {
1446  assert( minfixedrowlexmin != NULL );
1447 
1448  /* store minimum fixed row */
1449  if ( minfixed == -1 )
1450  minfixedrowlexmin[j] = nrowsused - 1;
1451  else
1452  minfixedrowlexmin[j] = minfixed;
1453 
1454  /* columns 1, ..., n-2 are contained in two columns (take the minimum) and
1455  * the minimum fixed row of column n-1 is determined by column n-2 */
1456  if ( minfixedrowlexmin[j + 1] < minfixedrowlexmin[j] )
1457  minfixedrowlexmin[j + 1] = minfixedrowlexmin[j];
1458  }
1459  }
1460 
1461  return SCIP_OKAY;
1462 }
1463 
1464 
1465 /* Compute lexicographically maximal face of the hypercube w.r.t. some coordinate fixing */
1466 static
1468  SCIP_VAR*** vars, /**< variable matrix */
1469  int** lexmaxfixes, /**< fixings characterzing lex-max face */
1470  int* minfixedrowlexmax, /**< index of minimum fixed row for each column or
1471  * NULL (if in prop) */
1472  SCIP_Bool* infeasible, /**< pointer to store whether infeasibility has been
1473  * detected or NULL (if in resprop) */
1474  int m, /**< number of rows in vars */
1475  int n, /**< number of columns in vars */
1476  int nrowsused, /**< number of rows considered in propagation */
1477  SCIP_Bool resprop /**< whether we are in resprop (TRUE) or prop (FALSE) */
1478  )
1479 {
1480  int i;
1481  int j;
1482  *infeasible = FALSE;
1483 
1484  assert( vars != NULL );
1485  assert( lexmaxfixes != NULL );
1486  assert( !resprop || minfixedrowlexmax != NULL );
1487  assert( m > 0 );
1488  assert( n > 0 );
1489  assert( nrowsused > 0 );
1490  assert( nrowsused <= m );
1491  assert( infeasible != NULL );
1492 
1493  for (j = 1; j < n; ++j)
1494  {
1495  int maxdiscriminating = m;
1496  int minfixed = -1;
1497 
1498  /* fix free entries in column j to the corresponding value in column j - 1 and collect some information */
1499  for (i = 0; i < nrowsused; ++i)
1500  {
1501  /* is row i j-discriminating? */
1502  if ( minfixed == -1 && lexmaxfixes[i][j - 1] != 0 && lexmaxfixes[i][j] != 1 )
1503  {
1504  assert( lexmaxfixes[i][j - 1] == 1 );
1505 
1506  maxdiscriminating = i;
1507  }
1508 
1509  /* is row i j-fixed? */
1510  if ( minfixed == -1 && lexmaxfixes[i][j - 1] != lexmaxfixes[i][j] && lexmaxfixes[i][j] != 2 )
1511  {
1512  assert( lexmaxfixes[i][j - 1] != 2 );
1513 
1514  minfixed = i;
1515 
1516  /* detect infeasibility */
1517  if ( maxdiscriminating > minfixed )
1518  {
1519  *infeasible = TRUE;
1520 
1521  return SCIP_OKAY;
1522  }
1523  }
1524  }
1525 
1526  /* ensure that column j is lexicographically not greater than column j - 1 */
1527  for (i = 0; i < nrowsused; ++i)
1528  {
1529  if ( lexmaxfixes[i][j] == 2 )
1530  {
1531  if ( i < maxdiscriminating || minfixed == -1 )
1532  lexmaxfixes[i][j] = lexmaxfixes[i][j - 1];
1533  else if ( i == maxdiscriminating )
1534  lexmaxfixes[i][j] = 0;
1535  else
1536  lexmaxfixes[i][j] = 1;
1537  }
1538  }
1539 
1540  if ( resprop )
1541  {
1542  assert( minfixedrowlexmax != NULL );
1543 
1544  /* store minimum fixed row */
1545  if ( minfixed == -1 )
1546  minfixedrowlexmax[j] = nrowsused - 1;
1547  else
1548  minfixedrowlexmax[j] = minfixed;
1549 
1550  /* columns 1, ..., n-2 are contained in two columns (take the minimum) and
1551  * the minimum fixed row of column 0 is determined by column 1 */
1552  if ( minfixedrowlexmax[j - 1] < minfixedrowlexmax[j] )
1553  minfixedrowlexmax[j - 1] = minfixedrowlexmax[j];
1554  }
1555  }
1556 
1557  return SCIP_OKAY;
1558 }
1559 
1560 
1561 /** propagation method for a single packing or partitioning orbitope constraint */
1562 static
1564  SCIP* scip, /**< SCIP data structure */
1565  SCIP_CONS* cons, /**< constraint to be processed */
1566  SCIP_Bool* infeasible, /**< pointer to store TRUE, if the node can be cut off */
1567  int* nfixedvars, /**< pointer to add up the number of found domain reductions */
1568  SCIP_Bool dynamic /**< whether we use a dynamic propagation routine */
1569  )
1570 {
1571  SCIP_CONSDATA* consdata;
1572  SCIP_VAR*** vars;
1573  int** lexminfixes;
1574  int** lexmaxfixes;
1575  int* roworder;
1576  int nrowsused;
1577  int i;
1578  int j;
1579  int m;
1580  int n;
1581 
1582  assert( scip != NULL );
1583  assert( cons != NULL );
1584  assert( infeasible != NULL );
1585  assert( nfixedvars != NULL );
1586 
1587  *nfixedvars = 0;
1588  *infeasible = FALSE;
1589 
1590  /* @todo Can the following be removed? */
1591  if ( ! SCIPallowStrongDualReds(scip) )
1592  return SCIP_OKAY;
1593 
1594  /* do nothing if we use dynamic propagation and if we are in a probing node */
1595  if ( dynamic && SCIPinProbing(scip) )
1596  return SCIP_OKAY;
1597 
1598  consdata = SCIPconsGetData(cons);
1599  assert( consdata != NULL );
1600  assert( consdata->nspcons > 0 );
1601  assert( consdata->nblocks > 0 );
1602  assert( consdata->vars != NULL );
1603  assert( consdata->orbitopetype == SCIP_ORBITOPETYPE_FULL );
1604 
1605  m = consdata->nspcons;
1606  n = consdata->nblocks;
1607  vars = consdata->vars;
1608 
1609  /* determine order of orbitope rows dynamically by branching decisions */
1610  if ( dynamic )
1611  {
1612  SCIP_CALL( computeDynamicRowOrder(scip, consdata->rowindexmap, consdata->rowused,
1613  consdata->roworder, m, n, &(consdata->nrowsused)) );
1614 
1615  /* if no branching variable is contained in the full orbitope */
1616  if ( consdata->nrowsused == 0 )
1617  return SCIP_OKAY;
1618 
1619  nrowsused = consdata->nrowsused;
1620  }
1621  else
1622  nrowsused = m;
1623  roworder = consdata->roworder;
1624 
1625  /* Initialize lexicographically minimal matrix by fixed entries at the current node.
1626  * Free entries in the last column are set to 0.
1627  */
1628  SCIP_CALL( SCIPallocBufferArray(scip, &lexminfixes, nrowsused) );
1629  for (i = 0; i < nrowsused; ++i)
1630  {
1631  SCIP_CALL( SCIPallocBufferArray(scip, &lexminfixes[i], n) ); /*lint !e866*/
1632  }
1633 
1634  for (i = 0; i < nrowsused; ++i)
1635  {
1636  int origrow;
1637 
1638  origrow = roworder[i];
1639 
1640  for (j = 0; j < n; ++j)
1641  {
1642  if ( SCIPvarGetLbLocal(vars[origrow][j]) > 0.5 )
1643  lexminfixes[i][j] = 1;
1644  else if ( SCIPvarGetUbLocal(vars[origrow][j]) < 0.5 || j == n - 1 )
1645  lexminfixes[i][j] = 0;
1646  else
1647  lexminfixes[i][j] = 2;
1648  }
1649  }
1650 
1651  /* find lexicographically minimal face of hypercube containing lexmin fixes */
1652  SCIP_CALL( findLexMinFace(vars, lexminfixes, NULL, infeasible, m, n, nrowsused, FALSE) );
1653 
1654  if ( *infeasible == TRUE )
1655  goto FREELEXMIN;
1656 
1657  /* Initialize lexicographically maximal matrix by fixed entries at the current node.
1658  * Free entries in the first column are set to 1.
1659  */
1660  SCIP_CALL( SCIPallocBufferArray(scip, &lexmaxfixes, nrowsused) );
1661  for (i = 0; i < nrowsused; ++i)
1662  {
1663  SCIP_CALL( SCIPallocBufferArray(scip, &lexmaxfixes[i], n) ); /*lint !e866*/
1664  }
1665 
1666  for (i = 0; i < nrowsused; ++i)
1667  {
1668  int origrow;
1669 
1670  origrow = roworder[i];
1671 
1672  for (j = 0; j < n; ++j)
1673  {
1674  if ( SCIPvarGetUbLocal(vars[origrow][j]) < 0.5 )
1675  lexmaxfixes[i][j] = 0;
1676  else if ( SCIPvarGetLbLocal(vars[origrow][j]) > 0.5 || j == 0 )
1677  lexmaxfixes[i][j] = 1;
1678  else
1679  lexmaxfixes[i][j] = 2;
1680  }
1681  }
1682 
1683  /* find lexicographically maximal face of hypercube containing lexmax fixes */
1684  SCIP_CALL( findLexMaxFace(vars, lexmaxfixes, NULL, infeasible, m, n, nrowsused, FALSE) );
1685 
1686  if ( *infeasible )
1687  goto FREELEXMAX;
1688 
1689  /* Find for each column j the minimal row in which lexminfixes and lexmaxfixes differ. Fix all entries above this
1690  * row to the corresponding value in lexminfixes (or lexmaxfixes).
1691  */
1692  for (j = 0; j < n; ++j)
1693  {
1694  for (i = 0; i < nrowsused; ++i)
1695  {
1696  int origrow;
1697 
1698  origrow = roworder[i];
1699 
1700  if ( lexminfixes[i][j] != lexmaxfixes[i][j] )
1701  break;
1702 
1703  if ( SCIPvarGetLbLocal(vars[origrow][j]) < 0.5 && SCIPvarGetUbLocal(vars[origrow][j]) > 0.5 )
1704  {
1705  SCIP_Bool success;
1706 
1707  SCIP_CALL( SCIPinferBinvarCons(scip, vars[origrow][j], (SCIP_Bool) lexminfixes[i][j],
1708  cons, 0, infeasible, &success) );
1709 
1710  if ( success )
1711  *nfixedvars += 1;
1712  }
1713  }
1714  }
1715 
1716  FREELEXMAX:
1717  for (i = 0; i < nrowsused; ++i)
1718  SCIPfreeBufferArray(scip, &lexmaxfixes[i]);
1719  SCIPfreeBufferArray(scip, &lexmaxfixes);
1720 
1721  FREELEXMIN:
1722  for (i = 0; i < nrowsused; ++i)
1723  SCIPfreeBufferArray(scip, &lexminfixes[i]);
1724  SCIPfreeBufferArray(scip, &lexminfixes);
1725 
1726  return SCIP_OKAY;
1727 }
1728 
1729 
1730 /** propagation method for a single orbitope constraint */
1731 static
1733  SCIP* scip, /**< SCIP data structure */
1734  SCIP_CONS* cons, /**< constraint to be processed */
1735  SCIP_Bool* infeasible, /**< pointer to store TRUE, if the node can be cut off */
1736  int* nfixedvars /**< pointer to add up the number of found domain reductions */
1737  )
1738 {
1739  SCIP_CONSDATA* consdata;
1740  SCIP_ORBITOPETYPE orbitopetype;
1741 
1742  assert( scip != NULL );
1743  assert( cons != NULL );
1744  assert( infeasible != NULL );
1745  assert( nfixedvars != NULL );
1746 
1747  consdata = SCIPconsGetData(cons);
1748  assert( consdata != NULL );
1749 
1750  orbitopetype = consdata->orbitopetype;
1751 
1752  if ( orbitopetype == SCIP_ORBITOPETYPE_FULL )
1753  {
1754  SCIP_CALL( propagateFullOrbitopeCons(scip, cons, infeasible, nfixedvars,
1755  consdata->usedynamicprop && !consdata->ismodelcons) );
1756  }
1757  else
1758  {
1759  assert( orbitopetype == SCIP_ORBITOPETYPE_PACKING || orbitopetype == SCIP_ORBITOPETYPE_PARTITIONING );
1760  SCIP_CALL( propagatePackingPartitioningCons(scip, cons, infeasible, nfixedvars) );
1761  }
1762 
1763  return SCIP_OKAY;
1764 }
1765 
1766 
1767 /** Propagation conflict resolving method of propagator
1768  *
1769  * In this function we use that all variable reductions that can be found by the propagation algorithm
1770  * are only due to the fixed variables that are in or above the minimum fixed row of each pair of adjacent
1771  * columns of the lexmin and lexmax matrices.
1772  *
1773  * Since the storage of an integer is not enough to store the complete information about the fixing,
1774  * we have to use the linear time algorithm for finding the lexmin and lexmax
1775  * matrices and determine from this the minimum fixed rows.
1776  */
1777 static
1779  SCIP* scip, /**< SCIP data structure */
1780  SCIP_CONSHDLR* conshdlr, /**< constraint handler of the corresponding constraint */
1781  SCIP_CONS* cons, /**< constraint that inferred the bound change */
1782  int inferinfo, /**< inference information */
1783  SCIP_BDCHGIDX* bdchgidx, /**< bound change index (time stamp of bound change), or NULL for current time */
1784  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
1785  )
1786 { /*lint --e{715}*/
1787  SCIP_CONSDATA* consdata;
1788  SCIP_VAR*** vars;
1789  int** lexminfixes;
1790  int** lexmaxfixes;
1791  int* roworder;
1792  int* minfixedrowlexmin;
1793  int* minfixedrowlexmax;
1794  int i;
1795  int j;
1796  int m;
1797  int n;
1798  int nrowsused;
1799  SCIP_Bool dynamic;
1800  SCIP_Bool terminate;
1801 
1802  *result = SCIP_DIDNOTFIND;
1803 
1804  assert( scip != NULL );
1805  assert( conshdlr != NULL );
1806  assert( cons != NULL );
1807  assert( result != NULL );
1808 
1809  consdata = SCIPconsGetData(cons);
1810  assert( consdata != NULL );
1811  assert( consdata->nspcons > 0 );
1812  assert( consdata->nblocks > 0 );
1813  assert( consdata->vars != NULL );
1814  assert( consdata->orbitopetype == SCIP_ORBITOPETYPE_FULL );
1815 
1816  dynamic = consdata->usedynamicprop && !consdata->ismodelcons;
1817  m = consdata->nspcons;
1818  n = consdata->nblocks;
1819  vars = consdata->vars;
1820 
1821  if ( dynamic )
1822  {
1823  assert( consdata->roworder != NULL );
1824  assert( consdata->nrowsused > 0 );
1825 
1826  nrowsused = consdata->nrowsused;
1827  }
1828  else
1829  nrowsused = m;
1830  roworder = consdata->roworder;
1831 
1832  assert( inferinfo <= consdata->nspcons );
1833 
1834  /* Initialize lexicographically minimal matrix by fixed entries at the current node.
1835  * Free entries in the last column are set to 0.
1836  */
1837  SCIP_CALL( SCIPallocBufferArray(scip, &lexminfixes, nrowsused) );
1838  for (i = 0; i < nrowsused; ++i)
1839  {
1840  SCIP_CALL( SCIPallocBufferArray(scip, &lexminfixes[i], n) ); /*lint !e866*/
1841  }
1842 
1843  /* store minimum fixed row for each column */
1844  SCIP_CALL( SCIPallocBufferArray(scip, &minfixedrowlexmin, n) );
1845  minfixedrowlexmin[n - 1] = -1;
1846 
1847  for (i = 0; i < nrowsused; ++i)
1848  {
1849  int origrow;
1850 
1851  origrow = roworder[i];
1852 
1853  for (j = 0; j < n; ++j)
1854  {
1855  if ( SCIPvarGetLbAtIndex(vars[origrow][j], bdchgidx, FALSE) > 0.5 )
1856  lexminfixes[i][j] = 1;
1857  else if ( SCIPvarGetUbAtIndex(vars[origrow][j], bdchgidx, FALSE) < 0.5 || j == n - 1 )
1858  lexminfixes[i][j] = 0;
1859  else
1860  lexminfixes[i][j] = 2;
1861  }
1862  }
1863 
1864  /* find lexicographically minimal face of hypercube containing lexmin fixes */
1865  SCIP_CALL( findLexMinFace(vars, lexminfixes, minfixedrowlexmin, &terminate, m, n, nrowsused, TRUE) );
1866 
1867  if ( terminate )
1868  goto FREELEXMIN;
1869 
1870  /* Initialize lexicographically maximal matrix by fixed entries at the current node.
1871  * Free entries in the first column are set to 1.
1872  */
1873  SCIP_CALL( SCIPallocBufferArray(scip, &lexmaxfixes, nrowsused) );
1874  for (i = 0; i < nrowsused; ++i)
1875  {
1876  SCIP_CALL( SCIPallocBufferArray(scip, &lexmaxfixes[i], n) ); /*lint !e866*/
1877  }
1878 
1879  /* store minimum fixed row for each column */
1880  SCIP_CALL( SCIPallocBufferArray(scip, &minfixedrowlexmax, n) );
1881  minfixedrowlexmax[0] = -1;
1882 
1883  for (i = 0; i < nrowsused; ++i)
1884  {
1885  int origrow;
1886 
1887  origrow = roworder[i];
1888 
1889  for (j = 0; j < n; ++j)
1890  {
1891  if ( SCIPvarGetUbAtIndex(vars[origrow][j], bdchgidx, FALSE) < 0.5 )
1892  lexmaxfixes[i][j] = 0;
1893  else if ( SCIPvarGetLbAtIndex(vars[origrow][j], bdchgidx, FALSE) > 0.5 || j == 0 )
1894  lexmaxfixes[i][j] = 1;
1895  else
1896  lexmaxfixes[i][j] = 2;
1897  }
1898  }
1899 
1900  /* find lexicographically maximal face of hypercube containing lexmax fixes */
1901  SCIP_CALL( findLexMaxFace(vars, lexmaxfixes, minfixedrowlexmax, &terminate, m, n, nrowsused, TRUE) );
1902 
1903  if ( terminate )
1904  goto FREELEXMAX;
1905 
1906  /* Find for each column j the minimal row in which lexminfixes and lexmaxfixes differ. Fix all entries above this
1907  * row to the corresponding value in lexminfixes (or lexmaxfixes).
1908  */
1909  for (j = 0; j < n; ++j)
1910  {
1911  int ub = MAX(minfixedrowlexmin[j], minfixedrowlexmax[j]);
1912 
1913  for (i = 0; i <= ub; ++i)
1914  {
1915  int origrow;
1916 
1917  origrow = roworder[i];
1918 
1919  if ( SCIPvarGetLbAtIndex(vars[origrow][j], bdchgidx, FALSE) > 0.5 ||
1920  SCIPvarGetUbAtIndex(vars[origrow][j], bdchgidx, FALSE) < 0.5 )
1921  {
1922  SCIP_CALL( SCIPaddConflictBinvar(scip, vars[origrow][j]) );
1923  *result = SCIP_SUCCESS;
1924  }
1925  }
1926  }
1927 
1928  FREELEXMAX:
1929  SCIPfreeBufferArray(scip, &minfixedrowlexmax);
1930  for (i = 0; i < nrowsused; ++i)
1931  SCIPfreeBufferArray(scip, &lexmaxfixes[i]);
1932  SCIPfreeBufferArray(scip, &lexmaxfixes);
1933 
1934  FREELEXMIN:
1935  SCIPfreeBufferArray(scip, &minfixedrowlexmin);
1936  for (i = 0; i < nrowsused; ++i)
1937  SCIPfreeBufferArray(scip, &lexminfixes[i]);
1938  SCIPfreeBufferArray(scip, &lexminfixes);
1939 
1940  return SCIP_OKAY;
1941 }
1942 
1943 
1944 /** Propagation conflict resolving method of propagator
1945  *
1946  * In this function we use that the propagation method above implicitly propagates SCIs, i.e., every
1947  * fixing can also be gotten via an SCI-fixing.
1948  *
1949  * Since the storage of an integer is not enough to store the complete information about the fixing
1950  * nor a complete shifted column, we have to use the linear time algorithm for SCIs.
1951  *
1952  * The inferinfo integer is set as follows:
1953  *
1954  * - If a shifted column is fixed to 0 and the corresponding bar does not necessarily has value 1
1955  * then we fix these entries to 0 and inferinfo is i * nblocks + j, where (i,j) is the leader of the
1956  * bar. The SCI depends on whether i is in Gamma or not (see Lemma 1 in the paper and the comments
1957  * above).
1958  *
1959  * - If a bar has value 1 and the shifted column has one entry that is not fixed, it can be fixed to
1960  * 1 and inferinfo is (nspcons*nblocks) + i * nblocks + j, where (i,j) is the leader of the bar; see
1961  * Proposition 1 (2c).
1962  */
1963 static
1965  SCIP* scip, /**< SCIP data structure */
1966  SCIP_CONS* cons, /**< constraint that inferred the bound change */
1967  int inferinfo, /**< inference information */
1968  SCIP_BDCHGIDX* bdchgidx, /**< bound change index (time stamp of bound change), or NULL for current time */
1969  SCIP_RESULT* result /**< pointer to store the result of the propagation conflict resolving call */
1970  )
1971 { /*lint --e{715}*/
1972  SCIP_CONSDATA* consdata;
1973  SCIP_Real** vals;
1974  SCIP_Real** weights;
1975  SCIP_VAR*** vars;
1976  SCIP_ORBITOPETYPE orbitopetype;
1977  int** cases;
1978 
1979  int i;
1980  int j;
1981  int nspcons;
1982  int nblocks;
1983 
1984  assert( scip != NULL );
1985  assert( cons != NULL );
1986  assert( result != NULL );
1987 
1988  consdata = SCIPconsGetData(cons);
1989  assert( consdata != NULL );
1990  assert( consdata->nspcons > 0 );
1991  assert( consdata->nblocks > 0 );
1992  assert( consdata->vars != NULL );
1993  assert( consdata->vals != NULL );
1994  assert( consdata->weights != NULL );
1995  assert( consdata->cases != NULL );
1996  assert( consdata->istrianglefixed );
1997 
1998  *result = SCIP_DIDNOTFIND;
1999  if ( ! consdata->resolveprop )
2000  return SCIP_OKAY;
2001 
2002  nspcons = consdata->nspcons;
2003  nblocks = consdata->nblocks;
2004  vars = consdata->vars;
2005  vals = consdata->vals;
2006  weights = consdata->weights;
2007  orbitopetype = consdata->orbitopetype;
2008  cases = consdata->cases;
2009 
2010  SCIPdebugMsg(scip, "Propagation resolution method of orbitope constraint using orbitopal fixing\n");
2011 
2012  /* fill table */
2013  for (i = 0; i < nspcons; ++i)
2014  {
2015  int lastcolumn;
2016 
2017  /* last column considered as part of the bar: */
2018  lastcolumn = nblocks - 1;
2019  if ( lastcolumn > i )
2020  lastcolumn = i;
2021  for (j = 0; j <= lastcolumn; ++j)
2022  {
2023  /* if the variable was fixed to zero at conflict time */
2024  if ( SCIPgetVarUbAtIndex(scip, vars[i][j], bdchgidx, FALSE) < 0.5 )
2025  vals[i][j] = 0.0;
2026  else
2027  {
2028  /* if the variable was fixed to one at conflict time */
2029  if ( SCIPgetVarLbAtIndex(scip, vars[i][j], bdchgidx, FALSE) > 0.5 )
2030  vals[i][j] = 2.0;
2031  else
2032  vals[i][j] = 1.0;
2033  }
2034  }
2035  }
2036 
2037 #ifdef PRINT_MATRIX
2038  SCIPdebugMsg(scip, "Matrix:\n");
2039  printMatrix(scip, consdata);
2040 #endif
2041 
2042  /* computation of table: this now minimizes the value of the shifted column */
2043  assert( consdata->istrianglefixed );
2044  computeSCTable(scip, nspcons, nblocks, weights, cases, vals);
2045 
2046  /* if we fixed variables in the bar to zero */
2047  assert( inferinfo >= 0 && inferinfo < 2 * nspcons * nblocks );
2048  if ( inferinfo < nspcons * nblocks )
2049  {
2050  int p1;
2051  int p2;
2052 #ifdef SCIP_DEBUG
2053  char str[SCIP_MAXSTRLEN];
2054  char tmpstr[SCIP_MAXSTRLEN];
2055 #endif
2056 
2057  i = (int) (inferinfo / nblocks);
2058  j = inferinfo % nblocks;
2059  assert( 0 <= i && i < nspcons );
2060  assert( 0 <= j && j < nblocks );
2061 
2062  /* find SCI with value 0 */
2063  assert( weights[i-1][j-1] < 0.5 );
2064 
2065  SCIPdebugMsg(scip, " -> reason for x[%d][%d] = ... = x[%d][%d] = 0 was the following SC:\n", i, j, i, MIN(i,nblocks));
2066 #ifdef SCIP_DEBUG
2067  str[0] = '\0';
2068 #endif
2069 
2070  p1 = i-1;
2071  p2 = j-1;
2072  do
2073  {
2074  assert( cases[p1][p2] != -1 );
2075  assert( p1 >= 0 && p1 < i );
2076  assert( p2 >= 0 && p2 < j );
2077 
2078  /* if case 1 */
2079  if ( cases[p1][p2] == 1 )
2080  --p2; /* decrease column */
2081  else
2082  {
2083  /* case 2 or 3: */
2084  assert( cases[p1][p2] == 2 || cases[p1][p2] == 3 );
2085  assert( SCIPgetVarUbAtIndex(scip, vars[p1][p2], bdchgidx, FALSE) < 0.5 );
2086  SCIP_CALL( SCIPaddConflictUb(scip, vars[p1][p2], bdchgidx) );
2087  *result = SCIP_SUCCESS;
2088 
2089 #ifdef SCIP_DEBUG
2090  (void) SCIPsnprintf(tmpstr, SCIP_MAXSTRLEN, " (%d,%d)", p1, p2);
2091  (void) strncat(str, tmpstr, SCIP_MAXSTRLEN);
2092 #endif
2093 
2094  if ( cases[p1][p2] == 3 )
2095  break;
2096  }
2097  --p1; /* decrease row */
2098  }
2099  while ( p1 >= 0 ); /* should always be true, i.e. the break should end the loop */
2100  assert( cases[p1][p2] == 3 );
2101 
2102 #ifdef SCIP_DEBUG
2103  SCIPdebugMsg(scip, "%s\n", str);
2104 #endif
2105  }
2106  else
2107  {
2108  int k;
2109  int p1;
2110  int p2;
2111 #ifndef NDEBUG
2112  int pos1;
2113  int pos2;
2114 #endif
2115 #ifdef SCIP_DEBUG
2116  char str[SCIP_MAXSTRLEN];
2117  char tmpstr[SCIP_MAXSTRLEN];
2118 #endif
2119 
2120  /* if we fixed a variable in the SC to 1 */
2121  inferinfo -= nspcons * nblocks;
2122  i = (int) inferinfo / nblocks;
2123  j = inferinfo % nblocks;
2124  assert( 0 <= i && i < nspcons );
2125  assert( 0 <= j && j < nblocks );
2126 
2127  /* In rare cases it might happen that we fixed a variable to 1, but the node later becomes infeasible by globally
2128  * fixing variables to 0. In this case, it might happen that we find a SC with value 0 instead of 1. We then
2129  * cannot use this SC to repropagate (and do not know how to reconstruct the original reasoning). */
2130  if ( weights[i-1][j-1] > 0.5 && weights[i-1][j-1] < 1.5 )
2131  {
2132  SCIPdebugMsg(scip, " -> reason for x[%d][%d] = 1 was the following SC:\n", i, j);
2133 #ifdef SCIP_DEBUG
2134  (void) SCIPsnprintf(str, SCIP_MAXSTRLEN, "SC:");
2135 #endif
2136 
2137  p1 = i-1;
2138  p2 = j-1;
2139 #ifndef NDEBUG
2140  pos1 = -1;
2141  pos2 = -1;
2142 #endif
2143  do
2144  {
2145  assert( cases[p1][p2] != -1 );
2146  assert( p1 >= 0 && p1 < i );
2147  assert( p2 >= 0 && p2 < j );
2148 
2149  /* if case 1 */
2150  if ( cases[p1][p2] == 1 )
2151  --p2; /* decrease column */
2152  else
2153  {
2154  /* case 2 or 3: reason are formed by variables in SC fixed to 0 */
2155  assert( cases[p1][p2] == 2 || cases[p1][p2] == 3 );
2156  if ( SCIPgetVarUbAtIndex(scip, vars[p1][p2], bdchgidx, FALSE) < 0.5 )
2157  {
2158  SCIP_CALL( SCIPaddConflictUb(scip, vars[p1][p2], bdchgidx) );
2159  *result = SCIP_SUCCESS;
2160 
2161 #ifdef SCIP_DEBUG
2162  (void) SCIPsnprintf(tmpstr, SCIP_MAXSTRLEN, " (%d,%d)", p1, p2);
2163  (void) strncat(str, tmpstr, SCIP_MAXSTRLEN);
2164 #endif
2165  }
2166 #ifndef NDEBUG
2167  else
2168  {
2169  assert( SCIPgetVarLbAtIndex(scip, vars[p1][p2], bdchgidx, FALSE) < 0.5 );
2170  assert( pos1 == -1 && pos2 == -1 );
2171  pos1 = p1;
2172  pos2 = p2;
2173  }
2174 #endif
2175  if ( cases[p1][p2] == 3 )
2176  break;
2177  }
2178  --p1; /* decrease row */
2179  }
2180  while ( p1 >= 0 ); /* should always be true, i.e., the break should end the loop */
2181  assert( cases[p1][p2] == 3 );
2182  assert( pos1 >= 0 && pos2 >= 0 );
2183 
2184  /* distinguish partitioning/packing */
2185  if ( orbitopetype == SCIP_ORBITOPETYPE_PARTITIONING )
2186  {
2187  /* partitioning case */
2188 #ifdef SCIP_DEBUG
2189  (void) SCIPsnprintf(tmpstr, SCIP_MAXSTRLEN, " before bar: ");
2190  (void) strncat(str, tmpstr, SCIP_MAXSTRLEN);
2191 #endif
2192  /* add variables before the bar in the partitioning case */
2193  for (k = 0; k < j; ++k)
2194  {
2195  assert( SCIPgetVarUbAtIndex(scip, vars[i][k], bdchgidx, FALSE) < 0.5 );
2196  SCIP_CALL( SCIPaddConflictUb(scip, vars[i][k], bdchgidx) );
2197  *result = SCIP_SUCCESS;
2198 #ifdef SCIP_DEBUG
2199  (void) SCIPsnprintf(tmpstr, SCIP_MAXSTRLEN, " (%d,%d)", i, k);
2200  (void) strncat(str, tmpstr, SCIP_MAXSTRLEN);
2201 #endif
2202  }
2203 
2204 #ifdef SCIP_DEBUG
2205  SCIPdebugMsg(scip, "%s\n", str);
2206 #endif
2207  }
2208  else
2209  {
2210  /* packing case */
2211  int lastcolumn;
2212 
2213  /* last column considered as part of the bar: */
2214  lastcolumn = nblocks - 1;
2215  if ( lastcolumn > i )
2216  lastcolumn = i;
2217 
2218  /* search for variable in the bar that is fixed to 1 in the packing case */
2219  for (k = j; k <= lastcolumn; ++k)
2220  {
2221  if ( SCIPgetVarLbAtIndex(scip, vars[i][k], bdchgidx, FALSE) > 0.5 )
2222  {
2223  SCIP_CALL( SCIPaddConflictLb(scip, vars[i][k], bdchgidx) );
2224  *result = SCIP_SUCCESS;
2225  SCIPdebugMsg(scip, " and variable x[%d][%d] fixed to 1.\n", i, k);
2226  break;
2227  }
2228  }
2229  }
2230  }
2231  }
2232 
2233  return SCIP_OKAY;
2234 }
2235 
2236 
2237 /** check packing/partitioning orbitope solution for feasibility */
2238 static
2240  SCIP* scip, /**< SCIP data structure */
2241  SCIP_CONS* cons, /**< pointer to orbitope constraint */
2242  SCIP_RESULT* result /**< pointer to store the result of the enforcing call */
2243  )
2244 {
2245  SCIP_CONSDATA* consdata;
2246  SCIP_Real** weights;
2247  SCIP_Real** vals;
2248  int** cases;
2249  int nspcons;
2250  int nblocks;
2251  int i;
2252  int j;
2253 
2254  assert( cons != NULL );
2255 
2256  consdata = SCIPconsGetData(cons);
2257 
2258  assert( scip != NULL );
2259  assert( consdata != NULL );
2260  assert( consdata->nspcons > 0 );
2261  assert( consdata->nblocks > 0 );
2262  assert( consdata->vals != NULL );
2263  assert( consdata->weights != NULL );
2264  assert( consdata->cases != NULL );
2265 
2266  /* check for upper right triangle */
2267  if ( ! consdata->istrianglefixed )
2268  {
2269  SCIP_Bool infeasible = FALSE;
2270  int nfixedvars = 0;
2271 
2272  SCIP_CALL( fixTriangle(scip, cons, &infeasible, &nfixedvars) );
2273  if ( infeasible )
2274  {
2275  *result = SCIP_CUTOFF;
2276  return SCIP_OKAY;
2277  }
2278  if ( nfixedvars > 0 )
2279  {
2280  *result = SCIP_REDUCEDDOM;
2281  return SCIP_OKAY;
2282  }
2283  }
2284 
2285  nspcons = consdata->nspcons;
2286  nblocks = consdata->nblocks;
2287  vals = consdata->vals;
2288  weights = consdata->weights;
2289  cases = consdata->cases;
2290 
2291  /* get solution */
2292  copyValues(scip, consdata, NULL);
2293  SCIPdebugMsg(scip, "Enforcing (pseudo solutions) for orbitope constraint <%s>\n", SCIPconsGetName(cons));
2294 
2295  /* compute table */
2296  assert( consdata->istrianglefixed );
2297  computeSCTable(scip, nspcons, nblocks, weights, cases, vals);
2298 
2299  /* loop through rows */
2300  for (i = 1; i < nspcons; ++i)
2301  {
2302  SCIP_Real bar = 0.0;
2303  int lastcolumn;
2304 
2305  lastcolumn = nblocks - 1;
2306 
2307  /* last column considered as part of the bar: */
2308  if ( lastcolumn > i )
2309  lastcolumn = i;
2310 
2311  /* traverse row from right to left */
2312  for (j = lastcolumn; j > 0; --j)
2313  {
2314  bar += vals[i][j];
2315  assert( SCIPisIntegral(scip, vals[i][j]) );
2316 
2317  /* check whether weights[i-1][j-1] < bar (<=> bar - weights[i-1][j-1] > 0), i.e. cut is violated) */
2318  if ( SCIPisGT(scip, bar - weights[i-1][j-1], 0.0) )
2319  {
2320  SCIPdebugMsg(scip, "Solution is infeasible.\n");
2321  *result = SCIP_INFEASIBLE;
2322  return SCIP_OKAY;
2323  }
2324  }
2325  }
2326 
2327  return SCIP_OKAY;
2328 }
2329 
2330 
2331 /** check packing/partitioning orbitope solution for feasibility */
2332 static
2334  SCIP* scip, /**< SCIP data structure */
2335  SCIP_CONS* cons, /**< pointer to orbitope constraint */
2336  SCIP_SOL* sol, /**< solution to be checked */
2337  SCIP_RESULT* result, /**< pointer to store the result of the enforcing call */
2338  SCIP_Bool printreason /**< whether reason for infeasibility should be printed */
2339  )
2340 {
2341  SCIP_CONSDATA* consdata;
2342  SCIP_VAR*** vars;
2343  SCIP_Real** vals;
2344  SCIP_Real** weights;
2345  int** cases;
2346  int nspcons;
2347  int nblocks;
2348  int i;
2349  int j;
2350 
2351  /* get data of constraint */
2352  assert( cons != 0 );
2353  consdata = SCIPconsGetData(cons);
2354 
2355  assert( consdata != NULL );
2356  assert( consdata->nspcons > 0 );
2357  assert( consdata->nblocks > 0 );
2358  assert( consdata->vars != NULL );
2359  assert( consdata->vals != NULL );
2360  assert( consdata->weights != NULL );
2361  assert( consdata->cases != NULL );
2362 
2363  nspcons = consdata->nspcons;
2364  nblocks = consdata->nblocks;
2365  vars = consdata->vars;
2366  vals = consdata->vals;
2367  weights = consdata->weights;
2368  cases = consdata->cases;
2369 
2370  /* get solution */
2371  copyValues(scip, consdata, sol);
2372  SCIPdebugMsg(scip, "Checking orbitope constraint <%s> ...\n", SCIPconsGetName(cons));
2373 
2374  /* check upper right triangle (if not yet fixed to zero or in debug mode */
2375 #ifdef NDEBUG
2376  if ( ! consdata->istrianglefixed )
2377 #endif
2378  {
2379  int diagsize;
2380 
2381  /* get last row of triangle */
2382  diagsize = nblocks;
2383  if ( nspcons < nblocks )
2384  diagsize = nspcons;
2385 
2386  /* check variables */
2387  for (i = 0; i < diagsize; ++i)
2388  {
2389  for (j = i+1; j < nblocks; ++j)
2390  {
2391  if ( ! SCIPisFeasZero(scip, vals[i][j]) )
2392  {
2393  if ( printreason )
2394  SCIPinfoMessage(scip, NULL, "variable x[%d][%d] = %f on upper right nonzero.\n", i, j, vals[i][j]);
2395  *result = SCIP_INFEASIBLE;
2396  }
2397  }
2398  }
2399  }
2400 
2401  /* compute table */
2402  computeSCTable(scip, nspcons, nblocks, weights, cases, vals);
2403 
2404  /* loop through rows */
2405  for (i = 1; i < nspcons; ++i)
2406  {
2407  SCIP_Real bar;
2408  int lastcolumn;
2409 
2410  lastcolumn = nblocks - 1;
2411  bar = 0.0;
2412  /* last column considered as part of the bar: */
2413  if ( lastcolumn > i )
2414  lastcolumn = i;
2415 
2416  /* traverse row from right to left */
2417  for (j = lastcolumn; j > 0; --j)
2418  {
2419  bar += vals[i][j];
2420  assert( SCIPisFeasIntegral(scip, vals[i][j]) );
2421 
2422  /* check whether weights[i-1][j-1] < bar (<=> bar - weights[i-1][j-1] > 0), i.e. cut is violated) */
2423  if ( SCIPisGT(scip, bar - weights[i-1][j-1], 0.0) )
2424  {
2425  SCIPdebugMsg(scip, "Solution is infeasible.\n");
2426  *result = SCIP_INFEASIBLE;
2427 
2428  if ( printreason )
2429  {
2430  int l;
2431  int p1;
2432  int p2;
2433 
2434  SCIPinfoMessage(scip, NULL, "violated SCI: bar(");
2435 
2436  /* first output bar */
2437  for (l = j; l < nblocks; ++l)
2438  SCIPinfoMessage(scip, NULL, "<%s> (%f)", SCIPvarGetName(vars[i][l]), consdata->vals[i][l]);
2439 
2440  SCIPinfoMessage(scip, NULL, ") SC(");
2441 
2442  /* output shifted column */
2443  p1 = i-1;
2444  p2 = j-1;
2445  do
2446  {
2447  assert( cases[p1][p2] != -1 );
2448  assert( p1 >= 0 && p1 < i );
2449  assert( p2 >= 0 && p2 < j );
2450 
2451  /* if case 1 */
2452  if (cases[p1][p2] == 1)
2453  --p2; /* decrease column */
2454  else
2455  {
2456  /* case 2 or 3: */
2457  assert( cases[p1][p2] == 2 || cases[p1][p2] == 3 );
2458  SCIPinfoMessage(scip, NULL, "<%s> (%f)", SCIPvarGetName(vars[p1][p2]), consdata->vals[p1][p2]);
2459  if ( cases[p1][p2] == 3 )
2460  break;
2461  }
2462  --p1; /* decrease row */
2463  }
2464  while ( p1 >= 0 ); /* should always be true, i.e. the break should end the loop */
2465  assert( cases[p1][p2] == 3 );
2466 
2467  SCIPinfoMessage(scip, NULL, ")");
2468  }
2469  }
2470  }
2471  }
2472 
2473  return SCIP_OKAY;
2474 }
2475 
2476 
2477 /** check full orbitope solution for feasibility */
2478 static
2480  SCIP* scip, /**< SCIP data structure */
2481  SCIP_CONS* cons, /**< constraint to process */
2482  SCIP_SOL* sol, /**< solution to be checked */
2483  SCIP_Bool printreason, /**< whether reason for infeasibility should be printed */
2484  SCIP_Bool* feasible /**< memory address to store whether solution is feasible */
2485  )
2486 {
2487  SCIP_CONSDATA* consdata;
2488  SCIP_VAR*** vars;
2489  SCIP_VAR** vars1;
2490  SCIP_VAR** vars2;
2491  int nrows;
2492  int ncols;
2493  int j;
2494  int i;
2495 
2496  assert( scip != NULL );
2497  assert( cons != NULL );
2498  assert( feasible != NULL );
2499 
2500  consdata = SCIPconsGetData(cons);
2501 
2502  assert( consdata != NULL );
2503  assert( consdata->vars != NULL );
2504  assert( consdata->nspcons > 0 );
2505  assert( consdata->nblocks > 0 );
2506  assert( ! consdata->ismodelcons ); /* non-model constraints are never checked */
2507 
2508  vars = consdata->vars;
2509  nrows = consdata->nspcons;
2510  ncols = consdata->nblocks;
2511 
2512  SCIP_CALL( SCIPallocBufferArray(scip, &vars1, nrows) );
2513  SCIP_CALL( SCIPallocBufferArray(scip, &vars2, nrows) );
2514 
2515  /* iterate over adjacent columns of orbitope and check whether the first column in this
2516  * column pair is lexicographically not smaller than the second column in the pair */
2517  *feasible = TRUE;
2518  for (j = 1; j < ncols && *feasible; ++j)
2519  {
2520  for (i = 0; i < nrows; ++i)
2521  {
2522  vars1[i] = vars[i][j - 1];
2523  vars2[i] = vars[i][j];
2524  }
2525 
2526  SCIP_CALL( SCIPcheckSolutionOrbisack(scip, sol, vars1, vars2, nrows, printreason, feasible) );
2527  }
2528 
2529  SCIPfreeBufferArray(scip, &vars2);
2530  SCIPfreeBufferArray(scip, &vars1);
2531 
2532  return SCIP_OKAY;
2533 }
2534 
2535 
2536 /** separate orbisack cover inequalities */
2537 static
2539  SCIP* scip, /**< SCIP data structure */
2540  SCIP_CONS* cons, /**< constraint to process */
2541  SCIP_SOL* sol, /**< solution to separate (NULL for the LP solution) */
2542  SCIP_Bool dynamic, /**< whether we use a dynamic row order */
2543  int* ngen, /**< pointer to store number of generated cuts */
2544  SCIP_Bool* infeasible /**< pointer to store whether infeasibility has been detected */
2545  )
2546 {
2547  SCIP_CONSDATA* consdata;
2548  SCIP_VAR*** vars;
2549  int* roworder;
2550  int nrowsused;
2551  int nrows;
2552  int ncols;
2553  int i;
2554  int j;
2555  int origrow;
2556  SCIP_Real rhs;
2557  SCIP_Real lhs;
2558  SCIP_Real* coeffs1;
2559  SCIP_Real* coeffs2;
2560 
2561  assert( scip != NULL );
2562  assert( cons != NULL );
2563  assert( ngen != NULL );
2564  assert( infeasible != NULL );
2565 
2566  *ngen = 0;
2567  *infeasible = FALSE;
2568 
2569  /* get basic data */
2570  consdata = SCIPconsGetData(cons);
2571  assert( consdata != NULL );
2572 
2573  vars = consdata->vars;
2574  nrows = consdata->nspcons;
2575  ncols = consdata->nblocks;
2576  nrowsused = dynamic ? consdata->nrowsused : nrows;
2577  roworder = consdata->roworder;
2578 
2579  /* allocate memory for cover inequalities */
2580  SCIP_CALL( SCIPallocBufferArray(scip, &coeffs1, nrowsused) );
2581  SCIP_CALL( SCIPallocBufferArray(scip, &coeffs2, nrowsused) );
2582 
2583  lhs = 0.0;
2584  rhs = 0.0;
2585 
2586  /* separate orbisack cover inequalities for adjacent columns */
2587  for (j = 0; j < ncols - 1 && ! *infeasible; ++j)
2588  {
2589  SCIP_Real rowval;
2590 
2591  for (i = 0; i < nrowsused; ++i)
2592  {
2593  origrow = roworder[i];
2594 
2595  assert( origrow >= 0 );
2596  assert( origrow < nrows );
2597 
2598  rowval = SCIPgetSolVal(scip, sol, vars[origrow][j + 1]) - SCIPgetSolVal(scip, sol, vars[origrow][j]);
2599 
2600  /* check whether cover inequality is violated */
2601  if ( SCIPisEfficacious(scip, rowval + lhs - rhs) )
2602  {
2603  SCIP_ROW* row;
2604  int k;
2605 
2606  /* set coefficients for current inequality */
2607  coeffs1[i] = -1.0;
2608  coeffs2[i] = 1.0;
2609 
2610  /* add violated orbisack cover inequality */
2611  SCIP_CALL( SCIPcreateEmptyRowCons(scip, &row, cons, "orbisackcover", -SCIPinfinity(scip), rhs, FALSE, FALSE, TRUE) );
2612  SCIP_CALL( SCIPcacheRowExtensions(scip, row) );
2613 
2614  for (k = 0; k <= i; ++k)
2615  {
2616  int origrow2;
2617 
2618  origrow2 = roworder[k];
2619 
2620  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[origrow2][j], coeffs1[k]) );
2621  SCIP_CALL( SCIPaddVarToRow(scip, row, vars[origrow2][j + 1], coeffs2[k]) );
2622  }
2623  SCIP_CALL( SCIPflushRowExtensions(scip, row) );
2624 
2625  SCIP_CALL( SCIPaddRow(scip, row, FALSE, infeasible) );
2626 #ifdef SCIP_DEBUG
2627  SCIP_CALL( SCIPprintRow(scip, row, NULL) );
2628 #endif
2629  SCIP_CALL( SCIPreleaseRow(scip, &row) );
2630 
2631  *ngen += 1;
2632  if ( *infeasible )
2633  break;
2634 
2635  /* reset coefficients for next inequality */
2636  coeffs1[i] = 0.0;
2637  coeffs2[i] = 0.0;
2638  }
2639 
2640  /* add argmax( 1 - vals[i][0], vals[i][1] ) as coefficient and ensure that both vars1[0] and vars2[0] are
2641  * contained in the LIFTED cover inequality */
2642  rowval = SCIPgetSolVal(scip, sol, vars[origrow][j]) + SCIPgetSolVal(scip, sol, vars[origrow][j + 1]);
2643  if ( SCIPisEfficacious(scip, 1.0 - rowval) )
2644  {
2645  coeffs1[i] = -1.0;
2646  coeffs2[i] = 0.0;
2647  lhs -= SCIPgetSolVal(scip, sol, vars[origrow][j]);
2648 
2649  /* apply lifting? */
2650  if ( i == 0 )
2651  {
2652  coeffs2[i] = 1.0;
2653  lhs += SCIPgetSolVal(scip, sol, vars[origrow][j + 1]);
2654  }
2655  }
2656  else
2657  {
2658  coeffs1[i] = 0.0;
2659  coeffs2[i] = 1.0;
2660  lhs += SCIPgetSolVal(scip, sol, vars[origrow][j]);
2661  rhs += 1.0;
2662 
2663  /* apply lifting? */
2664  if ( i == 0 )
2665  {
2666  coeffs1[i] = -1.0;
2667  lhs -= SCIPgetSolVal(scip, sol, vars[origrow][j]);
2668  rhs -= 1.0;
2669  }
2670  }
2671  }
2672  }
2673 
2674  SCIPfreeBufferArray(scip, &coeffs1);
2675  SCIPfreeBufferArray(scip, &coeffs2);
2676 
2677  return SCIP_OKAY;
2678 }
2679 
2680 
2681 /** separate or enforce constraints */
2682 static
2684  SCIP* scip, /**< SCIP data structure */
2685  SCIP_CONSHDLR* conshdlr, /**< constraint handler */
2686  SCIP_CONS** conss, /**< constraints to process */
2687  int nconss, /**< number of constraints */
2688  int nusefulconss, /**< number of useful (non-obsolete) constraints to process */
2689  SCIP_SOL* sol, /**< solution to separate (NULL for the LP solution) */
2690  SCIP_RESULT* result, /**< pointer to store the result (should be initialized) */
2691  SCIP_Bool enforce /**< whether we enforce orbitope constraints */
2692  )
2693 {
2694  SCIP_Bool infeasible = FALSE;
2695  int nfixedvars = 0;
2696  int ncuts = 0;
2697  int c;
2698 
2699  assert( scip != NULL );
2700  assert( conshdlr != NULL );
2701  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2702  assert( result != NULL );
2703 
2704  /* loop through constraints */
2705  for (c = 0; c < nconss && ! infeasible; c++)
2706  {
2707  SCIP_CONSHDLRDATA* conshdlrdata;
2708  SCIP_CONSDATA* consdata;
2709  int nconsfixedvars = 0;
2710  int nconscuts = 0;
2711  SCIP_ORBITOPETYPE orbitopetype;
2712 
2713  assert( conss[c] != NULL );
2714 
2715  /* get data of constraint */
2716  consdata = SCIPconsGetData(conss[c]);
2717  assert( consdata != NULL );
2718 
2719  /* do not enforce non-model constraints */
2720  if ( enforce && !consdata->ismodelcons )
2721  continue;
2722 
2723  /* get solution */
2724  copyValues(scip, consdata, sol);
2725 
2726  /* separate */
2727  orbitopetype = consdata->orbitopetype;
2728 
2729  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2730  if ( orbitopetype == SCIP_ORBITOPETYPE_PACKING || orbitopetype == SCIP_ORBITOPETYPE_PARTITIONING )
2731  {
2732  SCIP_CALL( separateSCIs(scip, conshdlr, conss[c], consdata, &infeasible, &nconsfixedvars, &nconscuts) );
2733  nfixedvars += nconsfixedvars;
2734  }
2735  else if ( conshdlrdata->sepafullorbitope )
2736  {
2737  SCIP_CALL( separateCoversOrbisack(scip, conss[c], sol, consdata->usedynamicprop && !consdata->ismodelcons, &nconscuts, &infeasible) );
2738  }
2739  ncuts += nconscuts;
2740 
2741  /* stop after the useful constraints if we found cuts of fixed variables */
2742  if ( c >= nusefulconss && (ncuts > 0 || nfixedvars > 0) )
2743  break;
2744  }
2745 
2746  if ( infeasible )
2747  {
2748  SCIPdebugMsg(scip, "Infeasible node.\n");
2749  *result = SCIP_CUTOFF;
2750  }
2751  else if ( nfixedvars > 0 )
2752  {
2753  SCIPdebugMsg(scip, "Fixed %d variables.\n", nfixedvars);
2754  *result = SCIP_REDUCEDDOM;
2755  }
2756  else if ( ncuts > 0 )
2757  {
2758  SCIPdebugMsg(scip, "Separated %dinequalities.\n", ncuts);
2759  *result = SCIP_SEPARATED;
2760  }
2761  else
2762  {
2763  SCIPdebugMsg(scip, "No violated inequality found during separation.\n");
2764  }
2765 
2766  return SCIP_OKAY;
2767 }
2768 
2769 
2770 /** check whether all variables in an orbitope constraint are fixed */
2771 static
2773  SCIP* scip, /**< SCIP data structure */
2774  SCIP_CONS* cons, /**< constraint to be processed */
2775  SCIP_Bool* redundant /**< pointer to store whether constraint is redundant (contains no active vars) */
2776  )
2777 {
2778  SCIP_CONSDATA* consdata;
2779  SCIP_VAR*** vars;
2780  int i;
2781  int j;
2782  int nrows;
2783  int ncols;
2784 
2785  assert( scip != NULL );
2786  assert( cons != NULL );
2787  assert( redundant != NULL );
2788 
2789  *redundant = FALSE;
2790 
2791  consdata = SCIPconsGetData(cons);
2792  assert( consdata != NULL );
2793  assert( consdata->vars != NULL );
2794  assert( consdata->nspcons > 0 );
2795  assert( consdata->nblocks > 0 );
2796 
2797  vars = consdata->vars;
2798  nrows = consdata->nspcons;
2799  ncols = consdata->nblocks;
2800 
2801  /* check whether there exists an active variable in the orbitope */
2802  for (i = 0; i < nrows; ++i)
2803  {
2804  for (j = 0; j < ncols; ++j)
2805  {
2806  if ( SCIPvarIsActive(vars[i][j]) )
2807  return SCIP_OKAY;
2808  }
2809  }
2810 
2811  *redundant = TRUE;
2812 
2813  return SCIP_OKAY;
2814 }
2815 
2816 
2817 /*
2818  * Callback methods of constraint handler
2819  */
2820 
2821 /** copy method for constraint handler plugins (called when SCIP copies plugins) */
2822 static
2823 SCIP_DECL_CONSHDLRCOPY(conshdlrCopyOrbitope)
2824 { /*lint --e{715}*/
2825  assert(scip != NULL);
2826  assert(conshdlr != NULL);
2827  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2828 
2829  /* call inclusion method of constraint handler */
2831 
2832  *valid = TRUE;
2833 
2834  return SCIP_OKAY;
2835 }
2836 
2837 /** frees constraint handler */
2838 static
2839 SCIP_DECL_CONSFREE(consFreeOrbitope)
2840 { /*lint --e{715}*/
2841  SCIP_CONSHDLRDATA* conshdlrdata;
2842 
2843  assert( scip != 0 );
2844  assert( conshdlr != 0 );
2845  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2846 
2847  conshdlrdata = SCIPconshdlrGetData(conshdlr);
2848  assert( conshdlrdata != NULL );
2849 
2850  SCIPfreeBlockMemory(scip, &conshdlrdata);
2851 
2852  return SCIP_OKAY;
2853 }
2854 
2855 /** frees specific constraint data */
2856 static
2857 SCIP_DECL_CONSDELETE(consDeleteOrbitope)
2858 { /*lint --e{715}*/
2859  assert(conshdlr != NULL);
2860  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2861 
2862  SCIP_CALL( consdataFree(scip, consdata) );
2863 
2864  return SCIP_OKAY;
2865 }
2866 
2867 /** transforms constraint data into data belonging to the transformed problem */
2868 static
2869 SCIP_DECL_CONSTRANS(consTransOrbitope)
2870 { /*lint --e{715}*/
2871  SCIP_CONSDATA* sourcedata;
2872  SCIP_CONSDATA* targetdata;
2873 
2874  assert(conshdlr != NULL);
2875  assert(strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0);
2876  assert(SCIPgetStage(scip) == SCIP_STAGE_TRANSFORMING);
2877  assert(sourcecons != NULL);
2878  assert(targetcons != NULL);
2879 
2880  sourcedata = SCIPconsGetData(sourcecons);
2881  assert(sourcedata != NULL);
2882 
2883  /* create linear constraint data for target constraint */
2884  SCIP_CALL( consdataCreate(scip, &targetdata, sourcedata->vars, sourcedata->nspcons, sourcedata->nblocks,
2885  sourcedata->orbitopetype, sourcedata->resolveprop, sourcedata->usedynamicprop, sourcedata->ismodelcons,
2886  sourcedata->mayinteract) );
2887 
2888  /* create target constraint */
2889  SCIP_CALL( SCIPcreateCons(scip, targetcons, SCIPconsGetName(sourcecons), conshdlr, targetdata,
2890  SCIPconsIsInitial(sourcecons), SCIPconsIsSeparated(sourcecons), SCIPconsIsEnforced(sourcecons),
2891  SCIPconsIsChecked(sourcecons), SCIPconsIsPropagated(sourcecons),
2892  SCIPconsIsLocal(sourcecons), SCIPconsIsModifiable(sourcecons),
2893  SCIPconsIsDynamic(sourcecons), SCIPconsIsRemovable(sourcecons), SCIPconsIsStickingAtNode(sourcecons)) );
2894 
2895  return SCIP_OKAY;
2896 }
2897 
2898 /** separation method of constraint handler for LP solutions */
2899 static
2900 SCIP_DECL_CONSSEPALP(consSepalpOrbitope)
2901 { /*lint --e{715}*/
2902  assert( scip != NULL );
2903  assert( result != NULL );
2904 
2905  SCIPdebugMsg(scip, "Separation of orbitope constraint handler <%s> for LP solution.\n", SCIPconshdlrGetName(conshdlr));
2906 
2907  *result = SCIP_DIDNOTRUN;
2908 
2909  /* if solution is integer, skip separation */
2910  if ( SCIPgetNLPBranchCands(scip) <= 0 )
2911  return SCIP_OKAY;
2912 
2913  *result = SCIP_DIDNOTFIND;
2914 
2915  /* separate constraints */
2916  SCIP_CALL( separateConstraints(scip, conshdlr, conss, nconss, nusefulconss, NULL, result, FALSE) );
2917 
2918  return SCIP_OKAY;
2919 }
2920 
2921 /** separation method of constraint handler for arbitrary primal solutions */
2922 static
2923 SCIP_DECL_CONSSEPASOL(consSepasolOrbitope)
2924 { /*lint --e{715}*/
2925  assert( scip != NULL );
2926  assert( result != NULL );
2927 
2928  SCIPdebugMsg(scip, "Separation of orbitope constraint handler <%s> for primal solution.\n", SCIPconshdlrGetName(conshdlr));
2929 
2930  *result = SCIP_DIDNOTFIND;
2931 
2932  /* separate constraints */
2933  SCIP_CALL( separateConstraints(scip, conshdlr, conss, nconss, nusefulconss, sol, result, FALSE) );
2934 
2935  return SCIP_OKAY;
2936 }
2937 
2938 
2939 /** constraint enforcing method of constraint handler for LP solutions */
2940 static
2941 SCIP_DECL_CONSENFOLP(consEnfolpOrbitope)
2942 { /*lint --e{715}*/
2943  assert( scip != NULL );
2944  assert( result != NULL );
2945 
2946  /* we have a negative priority, so we should come after the integrality conshdlr */
2947  assert( SCIPgetNLPBranchCands(scip) == 0 );
2948 
2949  SCIPdebugMsg(scip, "Enforcement for orbitope constraint handler <%s> for LP solution.\n", SCIPconshdlrGetName(conshdlr));
2950 
2951  *result = SCIP_FEASIBLE;
2952 
2953  /* separate constraints */
2954  SCIP_CALL( separateConstraints(scip, conshdlr, conss, nconss, nusefulconss, NULL, result, TRUE) );
2955 
2956  return SCIP_OKAY;
2957 }
2958 
2959 
2960 /** constraint enforcing method of constraint handler for relaxation solutions */
2961 static
2962 SCIP_DECL_CONSENFORELAX(consEnforelaxOrbitope)
2963 { /*lint --e{715}*/
2964  assert( result != NULL );
2965  assert( scip != NULL );
2966 
2967  SCIPdebugMsg(scip, "Enforcement for orbitope constraint handler <%s> for relaxation solution.\n", SCIPconshdlrGetName(conshdlr));
2968 
2969  *result = SCIP_FEASIBLE;
2970 
2971  /* separate constraints */
2972  SCIP_CALL( separateConstraints(scip, conshdlr, conss, nconss, nusefulconss, sol, result, TRUE) );
2973 
2974  return SCIP_OKAY;
2975 }
2976 
2977 
2978 /** constraint enforcing method of constraint handler for pseudo solutions */
2979 static
2980 SCIP_DECL_CONSENFOPS(consEnfopsOrbitope)
2981 { /*lint --e{715}*/
2982  int c;
2983 
2984  assert( scip != NULL );
2985  assert( conshdlr != NULL );
2986  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
2987  assert( result != NULL );
2988 
2989  *result = SCIP_FEASIBLE;
2990  if ( objinfeasible || solinfeasible )
2991  return SCIP_OKAY;
2992 
2993  /* loop through constraints */
2994  for (c = 0; c < nconss; ++c)
2995  {
2996  SCIP_CONS* cons;
2997  SCIP_CONSDATA* consdata;
2998  SCIP_ORBITOPETYPE orbitopetype;
2999  SCIP_Bool feasible;
3000 
3001  /* get data of constraint */
3002  cons = conss[c];
3003  assert( cons != 0 );
3004  consdata = SCIPconsGetData(cons);
3005 
3006  assert( consdata != NULL );
3007 
3008  /* do not enforce non-model constraints */
3009  if ( !consdata->ismodelcons )
3010  continue;
3011 
3012  orbitopetype = consdata->orbitopetype;
3013 
3014  if ( orbitopetype == SCIP_ORBITOPETYPE_PACKING || orbitopetype == SCIP_ORBITOPETYPE_PARTITIONING )
3015  {
3017  }
3018  else
3019  {
3020  SCIP_CALL( checkFullOrbitopeSolution(scip, cons, NULL, FALSE, &feasible) );
3021 
3022  if ( ! feasible )
3023  *result = SCIP_INFEASIBLE;
3024  }
3025 
3026  if ( *result == SCIP_INFEASIBLE )
3027  break;
3028  }
3029 
3030  return SCIP_OKAY;
3031 }
3032 
3033 
3034 /** feasibility check method of constraint handler for integral solutions */
3035 static
3036 SCIP_DECL_CONSCHECK(consCheckOrbitope)
3037 { /*lint --e{715}*/
3038  int c;
3039  SCIP_CONSDATA* consdata;
3040  SCIP_ORBITOPETYPE orbitopetype;
3041  SCIP_Bool feasible;
3042 
3043  assert( scip != NULL );
3044  assert( conshdlr != NULL );
3045  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
3046  assert( result != NULL );
3047 
3048  *result = SCIP_FEASIBLE;
3049 
3050  /* loop through constraints */
3051  for( c = 0; c < nconss && (*result == SCIP_FEASIBLE || completely); ++c )
3052  {
3053  assert( conss[c] != 0 );
3054  consdata = SCIPconsGetData(conss[c]);
3055 
3056  assert( consdata != NULL );
3057 
3058  /* do not check non-model constraints */
3059  if ( !consdata->ismodelcons )
3060  continue;
3061 
3062  orbitopetype = consdata->orbitopetype;
3063 
3064  if ( orbitopetype == SCIP_ORBITOPETYPE_PACKING || orbitopetype == SCIP_ORBITOPETYPE_PARTITIONING )
3065  {
3066  SCIP_CALL( checkPackingPartitioningOrbitopeSolution(scip, conss[c], sol, result, printreason) );
3067  }
3068  else
3069  {
3070  SCIP_CALL( checkFullOrbitopeSolution(scip, conss[c], sol, printreason, &feasible) );
3071 
3072  if ( ! feasible )
3073  *result = SCIP_INFEASIBLE;
3074  }
3075  }
3076  SCIPdebugMsg(scip, "Solution is feasible.\n");
3077 
3078  return SCIP_OKAY;
3079 }
3080 
3081 
3082 /** domain propagation method of constraint handler */
3083 static
3084 SCIP_DECL_CONSPROP(consPropOrbitope)
3085 { /*lint --e{715}*/
3086  SCIP_Bool infeasible = FALSE;
3087  int nfixedvars = 0;
3088  int c;
3089 
3090  assert( scip != NULL );
3091  assert( conshdlr != NULL );
3092  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
3093  assert( result != NULL );
3094 
3095  *result = SCIP_DIDNOTRUN;
3096 
3097  /* propagate all useful constraints */
3098  for (c = 0; c < nusefulconss && !infeasible; ++c)
3099  {
3100  assert( conss[c] != 0 );
3101 
3102  SCIPdebugMsg(scip, "Propagation of orbitope constraint <%s> ...\n", SCIPconsGetName(conss[c]));
3103 
3104  SCIP_CALL( propagateCons(scip, conss[c], &infeasible, &nfixedvars) );
3105  }
3106 
3107  /* return the correct result */
3108  if ( infeasible )
3109  {
3110  *result = SCIP_CUTOFF;
3111  SCIPdebugMsg(scip, "Propagation via orbitopal fixing proved node to be infeasible.\n");
3112  }
3113  else if ( nfixedvars > 0 )
3114  {
3115  *result = SCIP_REDUCEDDOM;
3116  SCIPdebugMsg(scip, "Propagated %d variables via orbitopal fixing.\n", nfixedvars);
3117  }
3118  else if ( nusefulconss > 0 )
3119  {
3120  *result = SCIP_DIDNOTFIND;
3121  SCIPdebugMsg(scip, "Propagation via orbitopal fixing did not find anything.\n");
3122  }
3123 
3124  return SCIP_OKAY;
3125 }
3126 
3127 
3128 /** presolving method of constraint handler */
3129 static
3130 SCIP_DECL_CONSPRESOL(consPresolOrbitope)
3131 { /*lint --e{715}*/
3132  SCIP_Bool infeasible = FALSE;
3133  int noldfixedvars;
3134  int c;
3135  SCIP_Bool redundant;
3136 
3137  assert( scip != NULL );
3138  assert( conshdlr != NULL );
3139  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
3140  assert( result != NULL );
3141 
3142  *result = SCIP_DIDNOTRUN;
3143  noldfixedvars = *nfixedvars;
3144 
3145  /* propagate all useful constraints
3146  *
3147  * @todo use an event handler to only propagate if a variable in the orbitope has been fixed
3148  */
3149  for (c = 0; c < nconss && !infeasible; ++c)
3150  {
3151  int nfixed = 0;
3152 
3153  assert( conss[c] != 0 );
3154 
3155  SCIPdebugMsg(scip, "Presolving of orbitope constraint <%s> ...\n", SCIPconsGetName(conss[c]));
3156 
3157  /* first propagate */
3158  SCIP_CALL( propagateCons(scip, conss[c], &infeasible, &nfixed) );
3159  *nfixedvars += nfixed;
3160 
3161  if ( ! infeasible )
3162  {
3163  SCIP_CALL( checkRedundantCons(scip, conss[c], &redundant) );
3164 
3165  if ( redundant )
3166  {
3167  SCIPdebugMsg(scip, "Orbitope constraint <%s> is redundant: it does not contain active variables\n",
3168  SCIPconsGetName(conss[c]));
3169  SCIP_CALL( SCIPdelCons(scip, conss[c]) );
3170  assert( ! SCIPconsIsActive(conss[c]) );
3171  (*ndelconss)++;
3172  continue;
3173  }
3174  }
3175  }
3176 
3177  if ( infeasible )
3178  {
3179  *result = SCIP_CUTOFF;
3180  SCIPdebugMsg(scip, "Presolving detected infeasibility.\n");
3181  }
3182  else if ( *nfixedvars > noldfixedvars )
3183  {
3184  *result = SCIP_SUCCESS;
3185  }
3186  else if ( nconss > 0 )
3187  {
3188  *result = SCIP_DIDNOTFIND;
3189  SCIPdebugMsg(scip, "Presolving via orbitopal fixing did not find anything.\n");
3190  }
3191 
3192  return SCIP_OKAY;
3193 }
3194 
3195 
3196 /** propagation conflict resolving method of constraint handler */
3197 static
3198 SCIP_DECL_CONSRESPROP(consRespropOrbitope)
3199 { /*lint --e{715}*/
3200  SCIP_CONSDATA* consdata;
3201  SCIP_ORBITOPETYPE orbitopetype;
3202 
3203  assert( scip != NULL );
3204  assert( cons != NULL );
3205  assert( infervar != NULL );
3206  assert( bdchgidx != NULL );
3207  assert( result != NULL );
3208 
3209  consdata = SCIPconsGetData(cons);
3210  assert( consdata != NULL );
3211 
3212  orbitopetype = consdata->orbitopetype;
3213 
3214  /* resolution for full orbitopes not availabe yet */
3215  if ( orbitopetype == SCIP_ORBITOPETYPE_PACKING || orbitopetype == SCIP_ORBITOPETYPE_PARTITIONING )
3216  {
3217  SCIP_CALL( resolvePropagation(scip, cons, inferinfo, bdchgidx, result) );
3218  }
3219  else
3220  {
3221  SCIP_CALL( resolvePropagationFullOrbitope(scip, conshdlr, cons, inferinfo, bdchgidx, result) );
3222  }
3223 
3224  return SCIP_OKAY;
3225 }
3226 
3227 
3228 /** variable rounding lock method of constraint handler */
3229 static
3230 SCIP_DECL_CONSLOCK(consLockOrbitope)
3231 { /*lint --e{715}*/
3232  SCIP_CONSDATA* consdata;
3233  SCIP_VAR*** vars;
3234  int i;
3235  int j;
3236  int nspcons;
3237  int nblocks;
3238 
3239  assert( scip != NULL );
3240  assert( conshdlr != NULL );
3241  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
3242  assert( cons != NULL );
3243  assert( locktype == SCIP_LOCKTYPE_MODEL );
3244 
3245  consdata = SCIPconsGetData(cons);
3246  assert( consdata != NULL );
3247  assert( consdata->nspcons > 0 );
3248  assert( consdata->nblocks > 0 );
3249  assert( consdata->vars != NULL );
3250 
3251  SCIPdebugMsg(scip, "Locking method for orbitope constraint handler\n");
3252 
3253  nspcons = consdata->nspcons;
3254  nblocks = consdata->nblocks;
3255  vars = consdata->vars;
3256 
3257  /* add up locks and down locks on each variable */
3258  for (i = 0; i < nspcons; ++i)
3259  {
3260  for (j = 0; j < nblocks; ++j)
3261  SCIP_CALL( SCIPaddVarLocksType(scip, vars[i][j], locktype, nlockspos + nlocksneg, nlockspos + nlocksneg) );
3262  }
3263 
3264  return SCIP_OKAY;
3265 }
3266 
3267 
3268 /** constraint display method of constraint handler */
3269 static
3270 SCIP_DECL_CONSPRINT(consPrintOrbitope)
3272  SCIP_CONSDATA* consdata;
3273  SCIP_VAR*** vars;
3274  int i;
3275  int j;
3276  int nspcons;
3277  int nblocks;
3278  SCIP_ORBITOPETYPE orbitopetype;
3279 
3280  assert( scip != NULL );
3281  assert( conshdlr != NULL );
3282  assert( strcmp(SCIPconshdlrGetName(conshdlr), CONSHDLR_NAME) == 0 );
3283  assert( cons != NULL );
3284 
3285  consdata = SCIPconsGetData(cons);
3286  assert( consdata != NULL );
3287  assert( consdata->nspcons > 0 );
3288  assert( consdata->nblocks > 0 );
3289  assert( consdata->vars != NULL );
3290 
3291  nspcons = consdata->nspcons;
3292  nblocks = consdata->nblocks;
3293  vars = consdata->vars;
3294  orbitopetype = consdata->orbitopetype;
3295 
3296  SCIPdebugMsg(scip, "Printing method for orbitope constraint handler\n");
3297 
3298  switch ( orbitopetype )
3299  {
3301  SCIPinfoMessage(scip, file, "partOrbitope(");
3302  break;
3304  SCIPinfoMessage(scip, file, "packOrbitope(");
3305  break;
3307  SCIPinfoMessage(scip, file, "fullOrbitope(");
3308  break;
3309  default:
3310  SCIPABORT();
3311  }
3312 
3313  for (i = 0; i < nspcons; ++i)
3314  {
3315  for (j = 0; j < nblocks; ++j)
3316  {
3317  if ( j > 0 )
3318  SCIPinfoMessage(scip, file, ",");
3319  SCIP_CALL( SCIPwriteVarName(scip, file, vars[i][j], TRUE) );
3320  }
3321  if ( i < nspcons-1 )
3322  SCIPinfoMessage(scip, file, ".");
3323  }
3324  SCIPinfoMessage(scip, file, ")");
3325 
3326  return SCIP_OKAY;
3327 }
3328 
3329 
3330 /** constraint copying method of constraint handler */
3331 static
3332 SCIP_DECL_CONSCOPY(consCopyOrbitope)
3334  SCIP_CONSHDLRDATA* conshdlrdata;
3335  SCIP_CONSDATA* sourcedata;
3336  SCIP_VAR*** sourcevars;
3337  SCIP_VAR*** vars;
3338  int nspcons;
3339  int nblocks;
3340  int i;
3341  int k;
3342  int j;
3343 
3344  assert( scip != NULL );
3345  assert( cons != NULL );
3346  assert( sourcescip != NULL );
3347  assert( sourceconshdlr != NULL );
3348  assert( strcmp(SCIPconshdlrGetName(sourceconshdlr), CONSHDLR_NAME) == 0 );
3349  assert( sourcecons != NULL );
3350  assert( varmap != NULL );
3351  assert( valid != NULL );
3352 
3353  *valid = TRUE;
3354 
3355  SCIPdebugMsg(scip, "Copying method for orbitope constraint handler.\n");
3356 
3357  sourcedata = SCIPconsGetData(sourcecons);
3358  assert( sourcedata != NULL );
3359  assert( sourcedata->nspcons > 0 );
3360  assert( sourcedata->nblocks > 0 );
3361  assert( sourcedata->vars != NULL );
3362 
3363  conshdlrdata = SCIPconshdlrGetData(sourceconshdlr);
3364  assert( conshdlrdata != NULL );
3365 
3366  /* do not copy non-model constraints */
3367  if ( !sourcedata->ismodelcons && !conshdlrdata->forceconscopy )
3368  {
3369  *valid = FALSE;
3370 
3371  return SCIP_OKAY;
3372  }
3373 
3374  nspcons = sourcedata->nspcons;
3375  nblocks = sourcedata->nblocks;
3376  sourcevars = sourcedata->vars;
3377 
3378  SCIP_CALL( SCIPallocBufferArray(scip, &vars, nspcons) );
3379  for (i = 0; i < nspcons && *valid; ++i)
3380  {
3381  SCIP_CALL( SCIPallocBufferArray(scip, &(vars[i]), nblocks) ); /*lint !e866*/
3382 
3383  for (j = 0; j < nblocks && *valid; ++j)
3384  {
3385  SCIP_CALL( SCIPgetVarCopy(sourcescip, scip, sourcevars[i][j], &(vars[i][j]), varmap, consmap, global, valid) );
3386  assert( !(*valid) || vars[i][j] != NULL );
3387  }
3388  }
3389 
3390  /* only create the target constraint, if all variables could be copied */
3391  if ( *valid )
3392  {
3393  /* create copied constraint */
3394  if ( name == NULL )
3395  name = SCIPconsGetName(sourcecons);
3396 
3397  SCIP_CALL( SCIPcreateConsOrbitope(scip, cons, name,
3398  vars, sourcedata->orbitopetype, nspcons, nblocks, sourcedata->usedynamicprop,
3399  sourcedata->resolveprop, sourcedata->ismodelcons, sourcedata->mayinteract,
3400  initial, separate, enforce, check, propagate,
3401  local, modifiable, dynamic, removable, stickingatnode) );
3402  }
3403 
3404  /* free space; only up to row i if copying failed */
3405  assert( 0 <= i && i <= nspcons );
3406  for (k = i - 1; k >= 0; --k)
3407  SCIPfreeBufferArray(scip, &vars[k]);
3408  SCIPfreeBufferArray(scip, &vars);
3409 
3410  return SCIP_OKAY;
3411 }
3412 
3413 
3414 /** constraint parsing method of constraint handler */
3415 static
3416 SCIP_DECL_CONSPARSE(consParseOrbitope)
3417 { /*lint --e{715}*/
3418  const char* s;
3419  char* endptr;
3420  SCIP_ORBITOPETYPE orbitopetype;
3421  SCIP_VAR*** vars;
3422  SCIP_VAR* var;
3423  int nspcons;
3424  int maxnspcons;
3425  int nblocks;
3426  int maxnblocks;
3427  int k;
3428  int j;
3429 
3430  assert( success != NULL );
3431 
3432  *success = TRUE;
3433  s = str;
3434 
3435  /* skip white space */
3436  while ( *s != '\0' && isspace((unsigned char)*s) )
3437  ++s;
3438 
3439  if ( strncmp(s, "partOrbitope(", 13) == 0 )
3440  orbitopetype = SCIP_ORBITOPETYPE_PARTITIONING;
3441  else if ( strncmp(s, "packOrbitope(", 13) == 0 )
3442  orbitopetype = SCIP_ORBITOPETYPE_PACKING;
3443  else
3444  {
3445  if ( strncmp(s, "fullOrbitope(", 13) != 0 )
3446  {
3447  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "Syntax error - expected \"fullOrbitope(\", \"partOrbitope\" or \"packOrbitope\": %s\n", s);
3448  *success = FALSE;
3449  return SCIP_OKAY;
3450  }
3451  orbitopetype = SCIP_ORBITOPETYPE_FULL;
3452  }
3453  s += 13;
3454 
3455  /* loop through string */
3456  nspcons = 0;
3457  nblocks = 0;
3458  maxnspcons = 10;
3459  maxnblocks = 10;
3460 
3461  SCIP_CALL( SCIPallocBufferArray(scip, &vars, maxnspcons) );
3462  SCIP_CALL( SCIPallocBufferArray(scip, &(vars[0]), maxnblocks) );
3463 
3464  j = 0;
3465  do
3466  {
3467  /* skip whitespace */
3468  while ( isspace((int)*s) )
3469  ++s;
3470 
3471  /* parse variable name */
3472  SCIP_CALL( SCIPparseVarName(scip, s, &var, &endptr) );
3473  if ( var == NULL )
3474  {
3475  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "unknown variable name at '%s'\n", str);
3476  *success = FALSE;
3477  return SCIP_OKAY;
3478  }
3479  vars[nspcons][j++] = var;
3480  s = endptr;
3481 
3482  if ( j > nblocks )
3483  {
3484  if ( nspcons > 0 )
3485  {
3486  SCIPverbMessage(scip, SCIP_VERBLEVEL_MINIMAL, NULL, "variables per row do not match.\n");
3487  *success = FALSE;
3488  return SCIP_OKAY;
3489  }
3490  nblocks = j;
3491 
3492  if ( nblocks > maxnblocks )
3493  {
3494  int newsize;
3495 
3496  newsize = SCIPcalcMemGrowSize(scip, nblocks);
3497  SCIP_CALL( SCIPreallocBufferArray(scip, &(vars[nspcons]), newsize) ); /*lint !e866*/
3498  maxnblocks = newsize;
3499  }
3500  }
3501  assert( nblocks <= maxnblocks );
3502 
3503  /* skip white space and ',' */
3504  while ( *s != '\0' && ( isspace((unsigned char)*s) || *s == ',' ) )
3505  ++s;
3506 
3507  /* begin new row if required */
3508  if ( *s == '.' )
3509  {
3510  ++nspcons;
3511  ++s;
3512 
3513  if ( nspcons >= maxnspcons )
3514  {
3515  int newsize;
3516 
3517  newsize = SCIPcalcMemGrowSize(scip, nspcons+1);
3518  SCIP_CALL( SCIPreallocBufferArray(scip, &vars, newsize) );
3519  maxnspcons = newsize;
3520  }
3521  assert(nspcons < maxnspcons);
3522 
3523  SCIP_CALL( SCIPallocBufferArray(scip, &(vars[nspcons]), nblocks) ); /*lint !e866*/
3524  j = 0;
3525  }
3526  }
3527  while ( *s != ')' );
3528  ++nspcons;
3529 
3530  /* to ensure consistency, we disable dynamic propagation and tell SCIP that the orbitope could potentially
3531  * interact with other symmetry handling constraints
3532  */
3533  SCIP_CALL( SCIPcreateConsOrbitope(scip, cons, name, vars, orbitopetype, nspcons, nblocks, FALSE, TRUE, TRUE, TRUE,
3534  initial, separate, enforce, check, propagate, local, modifiable, dynamic, removable, stickingatnode) );
3535 
3536  for (k = nspcons - 1; k >= 0; --k)
3537  SCIPfreeBufferArray(scip, &vars[k]);
3538  SCIPfreeBufferArray(scip, &vars);
3539 
3540  return SCIP_OKAY;
3541 }
3542 
3543 
3544 /** constraint method of constraint handler which returns the variables (if possible) */
3545 static
3546 SCIP_DECL_CONSGETVARS(consGetVarsOrbitope)
3547 { /*lint --e{715}*/
3548  SCIP_CONSDATA* consdata;
3549 
3550  assert( cons != NULL );
3551  assert( success != NULL );
3552  assert( vars != NULL );
3553 
3554  consdata = SCIPconsGetData(cons);
3555  assert( consdata != NULL );
3556 
3557  if ( varssize < consdata->nblocks * consdata->nspcons )
3558  (*success) = FALSE;
3559  else
3560  {
3561  int cnt = 0;
3562  int i;
3563  int j;
3564 
3565  for (i = 0; i < consdata->nspcons; ++i)
3566  {
3567  for (j = 0; j < consdata->nblocks; ++j)
3568  vars[cnt++] = consdata->vars[i][j];
3569  }
3570  (*success) = TRUE;
3571  }
3572 
3573  return SCIP_OKAY;
3574 }
3575 
3576 
3577 /** constraint method of constraint handler which returns the number of variables (if possible) */
3578 static
3579 SCIP_DECL_CONSGETNVARS(consGetNVarsOrbitope)
3580 { /*lint --e{715}*/
3581  SCIP_CONSDATA* consdata;
3582 
3583  assert( cons != NULL );
3584 
3585  consdata = SCIPconsGetData(cons);
3586  assert( consdata != NULL );
3587 
3588  (*nvars) = consdata->nblocks * consdata->nspcons;
3589  (*success) = TRUE;
3590 
3591  return SCIP_OKAY;
3592 }
3593 
3594 
3595 /*
3596  * constraint specific interface methods
3597  */
3598 
3599 /** creates the handler for orbitope constraints and includes it in SCIP */
3601  SCIP* scip /**< SCIP data structure */
3602  )
3603 {
3604  SCIP_CONSHDLRDATA* conshdlrdata;
3605  SCIP_CONSHDLR* conshdlr;
3606 
3607  /* create orbitope constraint handler data */
3608  SCIP_CALL( SCIPallocBlockMemory(scip, &conshdlrdata) );
3609 
3610  /* include constraint handler */
3614  consEnfolpOrbitope, consEnfopsOrbitope, consCheckOrbitope, consLockOrbitope,
3615  conshdlrdata) );
3616  assert(conshdlr != NULL);
3617 
3618  /* set non-fundamental callbacks via specific setter functions */
3619  SCIP_CALL( SCIPsetConshdlrCopy(scip, conshdlr, conshdlrCopyOrbitope, consCopyOrbitope) );
3620  SCIP_CALL( SCIPsetConshdlrFree(scip, conshdlr, consFreeOrbitope) );
3621  SCIP_CALL( SCIPsetConshdlrDelete(scip, conshdlr, consDeleteOrbitope) );
3622  SCIP_CALL( SCIPsetConshdlrGetVars(scip, conshdlr, consGetVarsOrbitope) );
3623  SCIP_CALL( SCIPsetConshdlrGetNVars(scip, conshdlr, consGetNVarsOrbitope) );
3624  SCIP_CALL( SCIPsetConshdlrParse(scip, conshdlr, consParseOrbitope) );
3625  SCIP_CALL( SCIPsetConshdlrPresol(scip, conshdlr, consPresolOrbitope, CONSHDLR_MAXPREROUNDS, CONSHDLR_PRESOLTIMING) );
3626  SCIP_CALL( SCIPsetConshdlrPrint(scip, conshdlr, consPrintOrbitope) );
3627  SCIP_CALL( SCIPsetConshdlrProp(scip, conshdlr, consPropOrbitope, CONSHDLR_PROPFREQ, CONSHDLR_DELAYPROP,
3629  SCIP_CALL( SCIPsetConshdlrResprop(scip, conshdlr, consRespropOrbitope) );
3630  SCIP_CALL( SCIPsetConshdlrSepa(scip, conshdlr, consSepalpOrbitope, consSepasolOrbitope, CONSHDLR_SEPAFREQ,
3632  SCIP_CALL( SCIPsetConshdlrTrans(scip, conshdlr, consTransOrbitope) );
3633  SCIP_CALL( SCIPsetConshdlrEnforelax(scip, conshdlr, consEnforelaxOrbitope) );
3634 
3635  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/checkpporbitope",
3636  "Strengthen orbitope constraints to packing/partioning orbitopes?",
3637  &conshdlrdata->checkpporbitope, TRUE, DEFAULT_PPORBITOPE, NULL, NULL) );
3638 
3639  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/sepafullorbitope",
3640  "Whether we separate inequalities for full orbitopes?",
3641  &conshdlrdata->sepafullorbitope, TRUE, DEFAULT_SEPAFULLORBITOPE, NULL, NULL) );
3642 
3643  SCIP_CALL( SCIPaddBoolParam(scip, "constraints/" CONSHDLR_NAME "/forceconscopy",
3644  "Whether orbitope constraints should be forced to be copied to sub SCIPs.",
3645  &conshdlrdata->forceconscopy, TRUE, DEFAULT_FORCECONSCOPY, NULL, NULL) );
3646 
3647  return SCIP_OKAY;
3648 }
3649 
3650 
3651 /** creates and captures a orbitope constraint
3652  *
3653  * @pre If packing/partitioning orbitopes are used, this constraint handler assumes that constraints which enforce
3654  * the packing/partitioning constraints are contained in the problem. It does not implement, e.g., separation and
3655  * propagation of set packing/partitioning constraints, since this would just copy large parts of the code of the
3656  * setppc constraint handler.
3657  *
3658  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
3659  */
3661  SCIP* scip, /**< SCIP data structure */
3662  SCIP_CONS** cons, /**< pointer to hold the created constraint */
3663  const char* name, /**< name of constraint */
3664  SCIP_VAR*** vars, /**< matrix of variables on which the symmetry acts */
3665  SCIP_ORBITOPETYPE orbitopetype, /**< type of orbitope constraint */
3666  int nspcons, /**< number of set partitioning/packing constraints <=> p */
3667  int nblocks, /**< number of symmetric variable blocks <=> q */
3668  SCIP_Bool usedynamicprop, /**< whether dynamic propagation should be used */
3669  SCIP_Bool mayinteract, /**< whether symmetries corresponding to orbitope might interact
3670  * with symmetries handled by other routines */
3671  SCIP_Bool resolveprop, /**< should propagation be resolved? */
3672  SCIP_Bool ismodelcons, /**< whether the orbitope is a model constraint */
3673  SCIP_Bool initial, /**< should the LP relaxation of constraint be in the initial LP?
3674  * Usually set to TRUE. Set to FALSE for 'lazy constraints'. */
3675  SCIP_Bool separate, /**< should the constraint be separated during LP processing?
3676  * Usually set to TRUE. */
3677  SCIP_Bool enforce, /**< should the constraint be enforced during node processing?
3678  * TRUE for model constraints, FALSE for additional, redundant constraints. */
3679  SCIP_Bool check, /**< should the constraint be checked for feasibility?
3680  * TRUE for model constraints, FALSE for additional, redundant constraints. */
3681  SCIP_Bool propagate, /**< should the constraint be propagated during node processing?
3682  * Usually set to TRUE. */
3683  SCIP_Bool local, /**< is constraint only valid locally?
3684  * Usually set to FALSE. Has to be set to TRUE, e.g., for branching constraints. */
3685  SCIP_Bool modifiable, /**< is constraint modifiable (subject to column generation)?
3686  * Usually set to FALSE. In column generation applications, set to TRUE if pricing
3687  * adds coefficients to this constraint. */
3688  SCIP_Bool dynamic, /**< is constraint subject to aging?
3689  * Usually set to FALSE. Set to TRUE for own cuts which
3690  * are separated as constraints. */
3691  SCIP_Bool removable, /**< should the relaxation be removed from the LP due to aging or cleanup?
3692  * Usually set to FALSE. Set to TRUE for 'lazy constraints' and 'user cuts'. */
3693  SCIP_Bool stickingatnode /**< should the constraint always be kept at the node where it was added, even
3694  * if it may be moved to a more global node?
3695  * Usually set to FALSE. Set to TRUE to for constraints that represent node data. */
3696  )
3697 {
3698  SCIP_CONSHDLRDATA* conshdlrdata;
3699  SCIP_CONSHDLR* conshdlr;
3700  SCIP_CONSDATA* consdata;
3701 
3702  /* find the orbitope constraint handler */
3703  conshdlr = SCIPfindConshdlr(scip, CONSHDLR_NAME);
3704  if ( conshdlr == NULL )
3705  {
3706  SCIPerrorMessage("orbitope constraint handler not found\n");
3707  return SCIP_PLUGINNOTFOUND;
3708  }
3709 
3710  /* check for consistency */
3711  if ( usedynamicprop && mayinteract )
3712  {
3713  SCIPwarningMessage(scip, "Dynamic propagation is only possible if orbitope does not interact with \
3714  other symmetry handling constraints. Ignore value of <usedynamicprop>.\n");
3715  }
3716 
3717  assert( nspcons > 0 );
3718  assert( nblocks > 0 );
3719 
3720  /* run some checks */
3721 #ifndef NDEBUG
3722  {
3723  SCIP_Real obj;
3724  int i;
3725  int j;
3726  for (i = 0; i < nspcons; ++i)
3727  {
3728  /* initialize obj to infinity */
3729  obj = SCIPinfinity(scip);
3730  for (j = 0; j < nblocks; ++j)
3731  {
3732  SCIP_Bool fixedZero;
3733  SCIP_VAR* var;
3734 
3735  var = vars[i][j];
3736  assert(var != NULL);
3737 
3738  if ( SCIPvarIsNegated(var) )
3739  var = SCIPvarGetNegatedVar(var);
3740 
3741  /* all variables need to be binary */
3742  assert( SCIPvarIsBinary(var) );
3743 
3744  /* fixed variables have obj = 0; for variables fixed to 0, we assume that there is no
3745  problem (but we cannot always check it, e.g., when in the original problem
3746  variables were fixed and this problem was copied.) */
3747  fixedZero = ( SCIPisZero(scip, SCIPvarGetLbGlobal(var)) && SCIPisZero(scip, SCIPvarGetUbGlobal(var)) );
3748 
3749  /* @todo adapt correctness of the following check for sub-scips */
3750  if ( SCIPgetSubscipDepth(scip) == 0 )
3751  {
3752  /* check whether all variables in a row have the same objective */
3753  if ( ! fixedZero && SCIPisInfinity(scip, obj) )
3754  obj = SCIPvarGetObj(var);
3755  else
3756  {
3757  assert( fixedZero || ! SCIPvarIsActive(var) || SCIPisEQ(scip, obj, SCIPvarGetObj(var)) );
3758  }
3759  }
3760  }
3761  }
3762  }
3763 #endif
3764 
3765  conshdlrdata = SCIPconshdlrGetData(conshdlr);
3766  if ( conshdlrdata->checkpporbitope && orbitopetype != SCIP_ORBITOPETYPE_PARTITIONING
3767  && orbitopetype != SCIP_ORBITOPETYPE_PACKING )
3768  {
3769  SCIP_CALL( strengthenOrbitopeConstraint(scip, vars, &nspcons, nblocks, &orbitopetype, mayinteract) );
3770  }
3771 
3772  /* create constraint data */
3773  SCIP_CALL( consdataCreate(scip, &consdata, vars, nspcons, nblocks, orbitopetype,
3774  resolveprop, usedynamicprop && ! mayinteract, ismodelcons, mayinteract) );
3775 
3776  /* create constraint */
3777  SCIP_CALL( SCIPcreateCons(scip, cons, name, conshdlr, consdata, initial, separate, enforce, check, propagate,
3778  local, modifiable, dynamic, removable, stickingatnode) );
3779 
3780  return SCIP_OKAY;
3781 }
3782 
3783 /** creates and captures an orbitope constraint
3784  * in its most basic variant, i. e., with all constraint flags set to their default values
3785  *
3786  * @note the constraint gets captured, hence at one point you have to release it using the method SCIPreleaseCons()
3787  */
3789  SCIP* scip, /**< SCIP data structure */
3790  SCIP_CONS** cons, /**< pointer to hold the created constraint */
3791  const char* name, /**< name of constraint */
3792  SCIP_VAR*** vars, /**< matrix of variables on which the symmetry acts */
3793  SCIP_ORBITOPETYPE orbitopetype, /**< type of orbitope constraint */
3794  int nspcons, /**< number of set partitioning/packing constraints <=> p */
3795  int nblocks, /**< number of symmetric variable blocks <=> q */
3796  SCIP_Bool usedynamicprop, /**< whether dynamic propagation should be used */
3797  SCIP_Bool resolveprop, /**< should propagation be resolved? */
3798  SCIP_Bool ismodelcons, /**< whether the orbitope is a model constraint */
3799  SCIP_Bool mayinteract /**< whether symmetries corresponding to orbitope might interact
3800  * with symmetries handled by other routines */
3801  )
3802 {
3803  SCIP_CALL( SCIPcreateConsOrbitope(scip, cons, name, vars, orbitopetype, nspcons, nblocks, usedynamicprop,
3804  resolveprop, ismodelcons, mayinteract, TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
3805 
3806  return SCIP_OKAY;
3807 }
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:52
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:101
SCIP_Bool SCIPisFeasZero(SCIP *scip, SCIP_Real val)
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:1413
SCIP_RETCODE SCIPsetConshdlrDelete(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSDELETE((*consdelete)))
Definition: scip_cons.c:563
static SCIP_DECL_CONSPARSE(consParseOrbitope)
static SCIP_RETCODE strengthenOrbitopeConstraint(SCIP *scip, SCIP_VAR ***vars, int *nrows, int ncols, SCIP_ORBITOPETYPE *type, SCIP_Bool mayinteract)
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:84
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1626
enum SCIP_OrbitopeType SCIP_ORBITOPETYPE
SCIP_Real SCIPgetVarUbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:2125
public methods for SCIP parameter handling
SCIP_NODE * SCIPgetCurrentNode(SCIP *scip)
Definition: scip_tree.c:82
SCIP_STAGE SCIPgetStage(SCIP *scip)
Definition: scip_general.c:356
static SCIP_RETCODE computeDynamicRowOrder(SCIP *scip, SCIP_HASHMAP *rowindexmap, SCIP_Bool *rowused, int *roworder, int nrows, int ncols, int *maxrowlabel)
static SCIP_RETCODE fixTriangle(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *infeasible, int *nfixedvars)
#define CONSHDLR_SEPAFREQ
SCIP_Bool SCIPconsIsDynamic(SCIP_CONS *cons)
Definition: cons.c:8344
SCIP_RETCODE SCIPsetConshdlrTrans(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSTRANS((*constrans)))
Definition: scip_cons.c:586
#define CONSHDLR_DELAYPROP
static SCIP_RETCODE checkPackingPartitioningOrbitopeSolution(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_RESULT *result, SCIP_Bool printreason)
SCIP_RETCODE SCIPcreateConsBasicOrbitope(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR ***vars, SCIP_ORBITOPETYPE orbitopetype, int nspcons, int nblocks, SCIP_Bool usedynamicprop, SCIP_Bool resolveprop, SCIP_Bool ismodelcons, SCIP_Bool mayinteract)
SCIP_Real SCIPgetVarLbAtIndex(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: scip_var.c:1989
public methods for memory management
static SCIP_DECL_CONSENFORELAX(consEnforelaxOrbitope)
SCIP_CONSHDLR * SCIPfindConshdlr(SCIP *scip, const char *name)
Definition: scip_cons.c:877
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1649
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:17910
SCIP_RETCODE SCIPsetConshdlrGetVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETVARS((*consgetvars)))
Definition: scip_cons.c:816
#define SCIP_MAXSTRLEN
Definition: def.h:293
static void copyValues(SCIP *scip, SCIP_CONSDATA *consdata, SCIP_SOL *sol)
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:308
SCIP_RETCODE SCIPdelCons(SCIP *scip, SCIP_CONS *cons)
Definition: scip_prob.c:2842
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:130
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1686
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:17966
SCIP_RETCODE SCIPaddConflictBinvar(SCIP *scip, SCIP_VAR *var)
SCIP_NODE * SCIPnodeGetParent(SCIP_NODE *node)
Definition: tree.c:7714
SCIP_RETCODE SCIPgetTransformedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **transvar)
Definition: scip_var.c:1436
SCIP_RETCODE SCIPparseVarName(SCIP *scip, const char *str, SCIP_VAR **var, char **endptr)
Definition: scip_var.c:524
SCIP_Bool SCIPvarIsBinary(SCIP_VAR *var)
Definition: var.c:17431
static SCIP_RETCODE findLexMinFace(SCIP_VAR ***vars, int **lexminfixes, int *minfixedrowlexmin, SCIP_Bool *infeasible, int m, int n, int nrowsused, SCIP_Bool resprop)
#define CONSHDLR_SEPAPRIORITY
#define FALSE
Definition: def.h:87
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3014
static SCIP_DECL_CONSPRESOL(consPresolOrbitope)
int SCIPgetSubscipDepth(SCIP *scip)
Definition: scip_copy.c:2591
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:166
constraint handler for orbisack constraints
SCIP_Real SCIPinfinity(SCIP *scip)
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10755
#define TRUE
Definition: def.h:86
static SCIP_DECL_CONSENFOPS(consEnfopsOrbitope)
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:54
static SCIP_DECL_CONSGETVARS(consGetVarsOrbitope)
SCIP_RETCODE SCIPaddConflictUb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
SCIP_Bool SCIPconsIsStickingAtNode(SCIP_CONS *cons)
Definition: cons.c:8364
#define CONSHDLR_DESC
public methods for problem variables
SCIP_RETCODE SCIPinitConflictAnalysis(SCIP *scip, SCIP_CONFTYPE conftype, SCIP_Bool iscutoffinvolved)
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:99
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:220
#define CONSHDLR_NAME
static SCIP_DECL_CONSFREE(consFreeOrbitope)
void * SCIPhashmapGetImage(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3201
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
int SCIPnodeGetDepth(SCIP_NODE *node)
Definition: tree.c:7444
#define CONSHDLR_PROPFREQ
#define CONSHDLR_PROP_TIMING
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:127
Constraint handler for the set partitioning / packing / covering constraints .
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip_general.c:566
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip_branch.c:419
public methods for SCIP variables
SCIP_Bool SCIPconsIsRemovable(SCIP_CONS *cons)
Definition: cons.c:8354
static SCIP_DECL_CONSPRINT(consPrintOrbitope)
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:111
#define SCIPdebugMsg
Definition: scip_message.h:69
SCIP_RETCODE SCIPsetConshdlrParse(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPARSE((*consparse)))
Definition: scip_cons.c:793
SCIP_RETCODE SCIPincludeConshdlrOrbitope(SCIP *scip)
#define CONSHDLR_ENFOPRIORITY
SCIP_Bool SCIPconsIsActive(SCIP_CONS *cons)
Definition: cons.c:8146
void SCIPinfoMessage(SCIP *scip, FILE *file, const char *formatstr,...)
Definition: scip_message.c:199
static SCIP_DECL_CONSENFOLP(consEnfolpOrbitope)
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:934
SCIP_RETCODE SCIPaddConflictLb(SCIP *scip, SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx)
static void computeSCTable(SCIP *scip, int nspcons, int nblocks, SCIP_Real **weights, int **cases, SCIP_Real **vals)
public methods for numerical tolerances
#define CONSHDLR_CHECKPRIORITY
static SCIP_RETCODE enfopsPackingPartitioningOrbitopeSolution(SCIP *scip, SCIP_CONS *cons, SCIP_RESULT *result)
SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
Definition: var.c:17726
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3363
SCIP_RETCODE SCIPaddVarLocksType(SCIP *scip, SCIP_VAR *var, SCIP_LOCKTYPE locktype, int nlocksdown, int nlocksup)
Definition: scip_var.c:4256
SCIP_Bool SCIPisConflictAnalysisApplicable(SCIP *scip)
constraint handler for (partitioning/packing/full) orbitope constraints w.r.t. the full symmetric gro...
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:17920
#define SCIPduplicateBlockMemoryArray(scip, ptr, source, num)
Definition: scip_mem.h:96
public methods for managing constraints
#define DEFAULT_PPORBITOPE
SCIP_RETCODE SCIPsetConshdlrCopy(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSHDLRCOPY((*conshdlrcopy)), SCIP_DECL_CONSCOPY((*conscopy)))
Definition: scip_cons.c:332
static SCIP_RETCODE separateConstraints(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS **conss, int nconss, int nusefulconss, SCIP_SOL *sol, SCIP_RESULT *result, SCIP_Bool enforce)
#define SCIPerrorMessage
Definition: pub_message.h:55
const char * SCIPconshdlrGetName(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4175
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define CONSHDLR_NEEDSCONS
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip_cut.c:126
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:48
SCIP_Real SCIPvarGetUbAtIndex(SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: var.c:16661
SCIP_RETCODE SCIPisPackingPartitioningOrbitope(SCIP *scip, SCIP_VAR ***vars, int nrows, int ncols, SCIP_Bool **pprows, int *npprows, SCIP_ORBITOPETYPE *type)
Definition: symmetry.c:1152
const char * SCIPconsGetName(SCIP_CONS *cons)
Definition: cons.c:8085
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:8712
SCIP_Bool SCIPconsIsPropagated(SCIP_CONS *cons)
Definition: cons.c:8304
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:17251
static SCIP_RETCODE resolvePropagationFullOrbitope(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, int inferinfo, SCIP_BDCHGIDX *bdchgidx, SCIP_RESULT *result)
SCIP_RETCODE SCIPsetConshdlrFree(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSFREE((*consfree)))
Definition: scip_cons.c:357
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3048
SCIP_CONSHDLRDATA * SCIPconshdlrGetData(SCIP_CONSHDLR *conshdlr)
Definition: cons.c:4195
static SCIP_RETCODE checkRedundantCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *redundant)
SCIP_DOMCHG * SCIPnodeGetDomchg(SCIP_NODE *node)
Definition: tree.c:7529
#define NULL
Definition: lpi_spx1.cpp:155
static SCIP_RETCODE separateSCIs(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_CONS *cons, SCIP_CONSDATA *consdata, SCIP_Bool *infeasible, int *nfixedvars, int *ncuts)
static SCIP_RETCODE propagateFullOrbitopeCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *infeasible, int *nfixedvars, SCIP_Bool dynamic)
static SCIP_DECL_CONSCOPY(consCopyOrbitope)
#define REALABS(x)
Definition: def.h:201
public methods for problem copies
SCIP_Bool SCIPisSumEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
#define SCIP_CALL(x)
Definition: def.h:384
static SCIP_DECL_CONSPROP(consPropOrbitope)
static SCIP_RETCODE separateCoversOrbisack(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool dynamic, int *ngen, SCIP_Bool *infeasible)
static SCIP_RETCODE findLexMaxFace(SCIP_VAR ***vars, int **lexmaxfixes, int *minfixedrowlexmax, SCIP_Bool *infeasible, int m, int n, int nrowsused, SCIP_Bool resprop)
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:216
SCIP_Bool SCIPconsIsLocal(SCIP_CONS *cons)
Definition: cons.c:8324
static SCIP_DECL_CONSSEPASOL(consSepasolOrbitope)
SCIP_RETCODE SCIPaddRow(SCIP *scip, SCIP_ROW *row, SCIP_Bool forcecut, SCIP_Bool *infeasible)
Definition: scip_cut.c:241
SCIP_RETCODE SCIPsetConshdlrResprop(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSRESPROP((*consresprop)))
Definition: scip_cons.c:632
struct SCIP_ConsData SCIP_CONSDATA
Definition: type_cons.h:56
static SCIP_RETCODE propagatePackingPartitioningCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *infeasible, int *nfixedvars)
public methods for constraint handler plugins and constraints
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:115
#define SCIP_Bool
Definition: def.h:84
static SCIP_DECL_CONSHDLRCOPY(conshdlrCopyOrbitope)
SCIP_BOUNDCHGTYPE SCIPboundchgGetBoundchgtype(SCIP_BOUNDCHG *boundchg)
Definition: var.c:17168
SCIP_Real SCIPvarGetLbAtIndex(SCIP_VAR *var, SCIP_BDCHGIDX *bdchgidx, SCIP_Bool after)
Definition: var.c:16542
static SCIP_RETCODE resolvePropagation(SCIP *scip, SCIP_CONS *cons, int inferinfo, SCIP_BDCHGIDX *bdchgidx, SCIP_RESULT *result)
static SCIP_DECL_CONSDELETE(consDeleteOrbitope)
#define MAX(x, y)
Definition: tclique_def.h:83
SCIP_VAR * SCIPboundchgGetVar(SCIP_BOUNDCHG *boundchg)
Definition: var.c:17158
SCIP_BOUNDCHG * SCIPdomchgGetBoundchg(SCIP_DOMCHG *domchg, int pos)
Definition: var.c:17206
public methods for cuts and aggregation rows
SCIP_Bool SCIPconsIsChecked(SCIP_CONS *cons)
Definition: cons.c:8284
#define CONSHDLR_PRESOLTIMING
SCIP_Bool SCIPconsIsInitial(SCIP_CONS *cons)
Definition: cons.c:8254
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:17758
SCIP_RETCODE SCIPfixVar(SCIP *scip, SCIP_VAR *var, SCIP_Real fixedval, SCIP_Bool *infeasible, SCIP_Bool *fixed)
Definition: scip_var.c:8273
SCIP_RETCODE SCIPsetConshdlrPrint(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRINT((*consprint)))
Definition: scip_cons.c:770
static SCIP_DECL_CONSLOCK(consLockOrbitope)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
#define DEFAULT_SEPAFULLORBITOPE
SCIP_Bool SCIPinProbing(SCIP *scip)
Definition: scip_probing.c:88
public methods for the LP relaxation, rows and columns
static SCIP_RETCODE propagateCons(SCIP *scip, SCIP_CONS *cons, SCIP_Bool *infeasible, int *nfixedvars)
static SCIP_DECL_CONSTRANS(consTransOrbitope)
SCIP_Real * r
Definition: circlepacking.c:50
static SCIP_DECL_CONSCHECK(consCheckOrbitope)
public methods for branching rule plugins and branching
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1553
general public methods
type definitions for symmetry computations
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
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:702
SCIP_CONSDATA * SCIPconsGetData(SCIP_CONS *cons)
Definition: cons.c:8115
methods for handling symmetries
int SCIPdomchgGetNBoundchgs(SCIP_DOMCHG *domchg)
Definition: var.c:17198
public methods for the probing mode
static SCIP_RETCODE consdataCreate(SCIP *scip, SCIP_CONSDATA **consdata, SCIP_VAR ***vars, int nspcons, int nblocks, SCIP_ORBITOPETYPE orbitopetype, SCIP_Bool resolveprop, SCIP_Bool usedynamicprop, SCIP_Bool ismodelcons, SCIP_Bool mayinteract)
#define CONSHDLR_MAXPREROUNDS
SCIP_RETCODE SCIPsetConshdlrPresol(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPRESOL((*conspresol)), int maxprerounds, SCIP_PRESOLTIMING presoltiming)
Definition: scip_cons.c:525
public methods for message output
static SCIP_RETCODE checkFullOrbitopeSolution(SCIP *scip, SCIP_CONS *cons, SCIP_SOL *sol, SCIP_Bool printreason, SCIP_Bool *feasible)
#define SCIP_Real
Definition: def.h:177
SCIP_Bool SCIPconsIsModifiable(SCIP_CONS *cons)
Definition: cons.c:8334
SCIP_RETCODE SCIPaddVarsToRow(SCIP *scip, SCIP_ROW *row, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip_lp.c:1712
SCIP_RETCODE SCIPsetConshdlrGetNVars(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSGETNVARS((*consgetnvars)))
Definition: scip_cons.c:839
public methods for message handling
SCIP_Bool SCIPconsIsEnforced(SCIP_CONS *cons)
Definition: cons.c:8274
static SCIP_RETCODE consdataFree(SCIP *scip, SCIP_CONSDATA **consdata)
SCIP_Bool SCIPconsIsSeparated(SCIP_CONS *cons)
Definition: cons.c:8264
SCIP_RETCODE SCIPprintRow(SCIP *scip, SCIP_ROW *row, FILE *file)
Definition: scip_lp.c:2197
#define DEFAULT_FORCECONSCOPY
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:17416
SCIP_RETCODE SCIPcreateConsOrbitope(SCIP *scip, SCIP_CONS **cons, const char *name, SCIP_VAR ***vars, SCIP_ORBITOPETYPE orbitopetype, int nspcons, int nblocks, SCIP_Bool usedynamicprop, SCIP_Bool mayinteract, SCIP_Bool resolveprop, SCIP_Bool ismodelcons, SCIP_Bool initial, SCIP_Bool separate, SCIP_Bool enforce, SCIP_Bool check, SCIP_Bool propagate, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool dynamic, SCIP_Bool removable, SCIP_Bool stickingatnode)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
struct SCIP_ConshdlrData SCIP_CONSHDLRDATA
Definition: type_cons.h:55
static SCIP_DECL_CONSRESPROP(consRespropOrbitope)
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:17976
static SCIP_DECL_CONSGETNVARS(consGetNVarsOrbitope)
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:102
SCIP_Bool SCIPisFeasIntegral(SCIP *scip, SCIP_Real val)
SCIP_RETCODE SCIPhashmapInsert(SCIP_HASHMAP *hashmap, void *origin, void *image)
Definition: misc.c:3096
SCIPallocBlockMemory(scip, subsol))
SCIP_RETCODE SCIPcreateEmptyRowConshdlr(SCIP *scip, SCIP_ROW **row, SCIP_CONSHDLR *conshdlr, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1382
#define SCIPABORT()
Definition: def.h:356
SCIP_RETCODE SCIPwriteVarName(SCIP *scip, FILE *file, SCIP_VAR *var, SCIP_Bool type)
Definition: scip_var.c:221
public methods for global and local (sub)problems
SCIP_Real SCIPgetSolVal(SCIP *scip, SCIP_SOL *sol, SCIP_VAR *var)
Definition: scip_sol.c:1352
#define CONSHDLR_EAGERFREQ
SCIP_Bool SCIPallowStrongDualReds(SCIP *scip)
Definition: scip_var.c:8626
SCIP_RETCODE SCIPinferBinvarCons(SCIP *scip, SCIP_VAR *var, SCIP_Bool fixedval, SCIP_CONS *infercons, int inferinfo, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:5720
SCIP_RETCODE SCIPcheckSolutionOrbisack(SCIP *scip, SCIP_SOL *sol, SCIP_VAR **vars1, SCIP_VAR **vars2, int nrows, SCIP_Bool printreason, SCIP_Bool *feasible)
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:48
#define CONSHDLR_DELAYSEPA
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:17580
static SCIP_DECL_CONSSEPALP(consSepalpOrbitope)
SCIP_Bool SCIPvarIsNegated(SCIP_VAR *var)
Definition: var.c:17406
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:119
SCIP_RETCODE SCIPsetConshdlrProp(SCIP *scip, SCIP_CONSHDLR *conshdlr, SCIP_DECL_CONSPROP((*consprop)), int propfreq, SCIP_Bool delayprop, SCIP_PROPTIMING proptiming)
Definition: scip_cons.c:266
memory allocation routines