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