Scippy

SCIP

Solving Constraint Integer Programs

symmetry_lexred.c
Go to the documentation of this file.
1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2/* */
3/* This file is part of the program and library */
4/* SCIP --- Solving Constraint Integer Programs */
5/* */
6/* Copyright (c) 2002-2025 Zuse Institute Berlin (ZIB) */
7/* */
8/* Licensed under the Apache License, Version 2.0 (the "License"); */
9/* you may not use this file except in compliance with the License. */
10/* You may obtain a copy of the License at */
11/* */
12/* http://www.apache.org/licenses/LICENSE-2.0 */
13/* */
14/* Unless required by applicable law or agreed to in writing, software */
15/* distributed under the License is distributed on an "AS IS" BASIS, */
16/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17/* See the License for the specific language governing permissions and */
18/* limitations under the License. */
19/* */
20/* You should have received a copy of the Apache-2.0 license */
21/* along with SCIP; see the file LICENSE. If not visit scipopt.org. */
22/* */
23/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24
25/**@file symmetry_lexred.c
26 * @ingroup OTHER_CFILES
27 * @brief methods for handling symmetries by dynamic lexicographic ordering reduction
28 * @author Jasper van Doornmalen
29 *
30 * This implements lexicographic reduction, which generalizes symresack propagation to work for non-binary variable
31 * domains, and is dynamified. Whereas static lexicographic reduction propagates that a vector \f$x\f$ is
32 * lexicographically larger than its permuted counterpart (i.e., \f$x \succeq \gamma(x)\f$ with \f$\succeq\f$ being
33 * standard elementwise lexicographic comparison), the dynamic variant determines the variable vector ordering
34 * dynamically. Just as in orbital reduction (cf. symmetry_orbital.c), the variable order is chosen as the variables
35 * branched on from the root node to the focus node.
36 * Thus, in node \f$\beta\f$, we propagate \f$\sigma_\beta(x) \succeq \sigma_\beta(\gamma(x))\f$,
37 * where \f$\sigma_\beta(\cdot)\f$ permutes and restricts the variable vector such that it corresponds to the branched
38 * variables in the order from the rooted path to \f$\beta\f$.
39 *
40 * See Section 4.1 and Example 11 in [vD,H]:@n
41 * J. van Doornmalen, C. Hojny, "A Unified Framework for Symmetry Handling", preprint, 2023,
42 * https://doi.org/10.48550/arXiv.2211.01295.
43 *
44 * For dynamic lexicographic reduction, it is crucial that the vectors \f$\sigma_\beta(x)\f$ are the branching
45 * variables up to node \f$\beta\f$ in the given order. Since SCIP can change the tree structure during solving
46 * (re-writing history), we store the original branching decisions at the moment they are made. See event_shadowtree.c .
47 */
48
49/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
50
53#include "scip/pub_cons.h"
54#include "scip/pub_message.h"
55#include "scip/pub_var.h"
56#include "scip/struct_var.h"
57#include "scip/type_var.h"
58#include "scip/scip.h"
59#include "scip/scip_branch.h"
60#include "scip/scip_conflict.h"
61#include "scip/scip_cons.h"
62#include "scip/scip_copy.h"
63#include "scip/scip_cut.h"
64#include "scip/scip_general.h"
65#include "scip/scip_lp.h"
66#include "scip/scip_mem.h"
67#include "scip/scip_message.h"
68#include "scip/scip_numerics.h"
69#include "scip/scip_param.h"
70#include "scip/scip_prob.h"
71#include "scip/scip_probing.h"
72#include "scip/scip_sol.h"
73#include "scip/scip_var.h"
74#include "scip/debug.h"
75#include "scip/struct_scip.h"
76#include "scip/struct_mem.h"
77#include "scip/struct_tree.h"
78#include "scip/symmetry.h"
80#include <string.h>
81
82
83/*
84 * Data structures
85 */
86
87
88/** data per permutation for lexicographic reduction propagator */
90{
91 SCIP_Bool isdynamic; /**< whether permutation shall be propagated with dynamic variable order */
92 SCIP_VAR** vars; /**< variables affected by permutation */
93 int nvars; /**< number of variables */
94 int* perm; /**< permutation for lexicographic reduction */
95 int* invperm; /**< inverse permutation */
96 SCIP_HASHMAP* varmap; /**< map of variables to indices in vars array */
97 SYM_SYMTYPE symtype; /**< type of symmetries in perm */
98 SCIP_Real* vardomaincenter; /**< array of centers of variable domains */
99};
100typedef struct LexRedPermData LEXDATA;
101
102
103/** data for dynamic lexicographic reduction propagator */
104struct SCIP_LexRedData
105{
106 SCIP_EVENTHDLR* shadowtreeeventhdlr;/**< eventhandler for the shadow tree data structure */
107 SCIP_HASHMAP* symvarmap; /**< map of variables affected by some permutation handled by a LEXDATA */
108 int nsymvars; /**< number of variables in symvarmap */
109 LEXDATA** lexdatas; /**< array of pointers to individual LEXDATA's */
110 int nlexdatas; /**< number of datas in array */
111 int maxnlexdatas; /**< allocated datas array size */
112 int nred; /**< total number of reductions */
113 int ncutoff; /**< total number of cutoffs */
114 SCIP_Bool hasdynamicperm; /**< whether there exists a permutation that is treated dynamically */
115 SCIP_Bool treewarninggiven; /**< whether a warning is given for missing nodes in shadowtree */
116};
117
118
119/** to store branch-and-bound tree paths, (depth, index)-information per variable in rooted path */
121{
122 int nodedepth; /**< depth of var domain change */
123 int index; /**< index of var domain change on node at depth */
124};
126
127
128/** auxiliary struct to pass branch-and-bound tree information to sort function */
130{
131 NODEDEPTHBRANCHINDEX* nodedepthbranchindices; /**< pointer to branch-and-bound tree information */
132 SCIP_LEXREDDATA* masterdata; /**< pointer to global data for lexicographic reduction propagator */
133 SCIP_VAR** vars; /**< pointer to variable array */
134};
136
137
138/*
139 * Local methods
140 */
141
142/** frees dynamic lexicographic reduction propagator data */
143static
145 SCIP* scip, /**< SCIP data structure */
146 LEXDATA** lexdata /**< pointer to individual lexicographic reduction propagator datas */
147 )
148{
149 SCIP_Bool issigned;
150 int permlen;
151 int i;
152
153 assert( scip != NULL );
154 assert( lexdata != NULL );
155 assert( (*lexdata) != NULL );
156
157 if ( (*lexdata)->symtype == SYM_SYMTYPE_SIGNPERM )
158 {
159 issigned = TRUE;
160 permlen = 2 * (*lexdata)->nvars;
161 }
162 else
163 {
164 issigned = FALSE;
165 permlen = (*lexdata)->nvars;
166 }
167
168 if ( (*lexdata)->nvars > 0 )
169 {
170 assert( (*lexdata)->invperm != NULL );
171 assert( (*lexdata)->perm != NULL );
172 assert( (*lexdata)->vars != NULL );
173
174 /* free hashmap */
175 if ( (*lexdata)->isdynamic )
176 {
177 assert( (*lexdata)->varmap != NULL );
178 SCIPhashmapFree(&((*lexdata)->varmap));
179 }
180
181 /* release variables */
182 for (i = 0; i < (*lexdata)->nvars; ++i)
183 {
184 SCIP_CALL( SCIPreleaseVar(scip, &(*lexdata)->vars[i]) );
185 }
186
187 SCIPfreeBlockMemoryArray(scip, &(*lexdata)->invperm, permlen);
188 SCIPfreeBlockMemoryArray(scip, &(*lexdata)->perm, permlen);
189 SCIPfreeBlockMemoryArray(scip, &(*lexdata)->vars, (*lexdata)->nvars);
190
191 if ( issigned )
192 {
193 SCIPfreeBlockMemoryArray(scip, &(*lexdata)->vardomaincenter, (*lexdata)->nvars);
194 }
195 else
196 {
197 assert( (*lexdata)->vardomaincenter == NULL );
198 }
199 }
200#ifndef NDEBUG
201 else
202 {
203 assert( (*lexdata)->nvars == 0 );
204 assert( (*lexdata)->invperm == NULL );
205 assert( (*lexdata)->vardomaincenter == NULL );
206 assert( (*lexdata)->perm == NULL );
207 assert( (*lexdata)->vars == NULL );
208 assert( (*lexdata)->varmap == NULL );
209 }
210#endif
211 SCIPfreeBlockMemory(scip, lexdata);
212
213 return SCIP_OKAY;
214}
215
216
217/** creates dynamic lexicographic reduction propagator data
218 *
219 * Fixed points are removed.
220 */
221static
223 SCIP* scip, /**< SCIP data structure */
224 SCIP_LEXREDDATA* masterdata, /**< pointer to global data for lexicographic reduction propagator */
225 LEXDATA** lexdata, /**< pointer to store data for permutation to be added */
226 SCIP_VAR*const* vars, /**< input variables of the lexicographic reduction propagator */
227 int nvars, /**< input number of variables of the lexicographic reduction propagator */
228 int* perm, /**< input permutation of the lexicographic reduction propagator */
229 SYM_SYMTYPE symtype, /**< type of symmetries in perm */
230 SCIP_Real* permvardomaincenter, /**< array containing center point for each variable domain */
231 SCIP_Bool usedynamicorder, /**< whether a dynamic variable order shall be used */
232 SCIP_Bool* success /**< to store whether the component is successfully added */
233 )
234{
235 SCIP_VAR* var;
236 SCIP_Bool issignedperm;
237 int* indexcorrection;
238 int naffectedvariables;
239 int permlen;
240 int i;
241 int j;
242
243 assert( scip != NULL );
244 assert( masterdata != NULL );
245 assert( lexdata != NULL );
246 assert( vars != NULL );
247 assert( nvars >= 0 );
248 assert( perm != NULL );
249 assert( symtype == SYM_SYMTYPE_PERM || permvardomaincenter != NULL );
250 assert( success != NULL );
251 assert( SCIPisTransformed(scip) );
252 assert( masterdata->shadowtreeeventhdlr != NULL );
253
254 *success = TRUE;
255 issignedperm = symtype == SYM_SYMTYPE_PERM ? FALSE : TRUE;
256
257 /* initialize the data structures */
259 (*lexdata)->symtype = symtype;
260
261 (*lexdata)->isdynamic = usedynamicorder;
262
263 /* remove fixed points */
264 naffectedvariables = 0;
265 SCIP_CALL( SCIPallocBufferArray(scip, &indexcorrection, nvars) );
266 for (i = 0; i < nvars; ++i)
267 {
268 if ( perm[i] == i )
269 indexcorrection[i] = -1; /* fixed points get an entry < 0 in the indexcorrection array */
270 else
271 indexcorrection[i] = naffectedvariables++;
272 }
273
274 /* do nothing if reductions would be trivial */
275 if ( naffectedvariables <= 0 )
276 {
277 assert( naffectedvariables == 0 );
278 SCIPfreeBufferArray(scip, &indexcorrection);
279
280 *success = FALSE;
281 SCIPfreeBlockMemory(scip, lexdata);
282 return SCIP_OKAY;
283 }
284
285 /* require that the shadowtree is active if dynamic propagation is used */
286 if ( usedynamicorder )
287 {
288 masterdata->hasdynamicperm = TRUE;
289
290 SCIP_CALL( SCIPactivateShadowTree(scip, masterdata->shadowtreeeventhdlr) );
291 }
292
293 /* initialize variable arrays */
294 (*lexdata)->nvars = naffectedvariables;
295 permlen = issignedperm ? 2 * (*lexdata)->nvars : (*lexdata)->nvars;
296
297 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*lexdata)->vars, (*lexdata)->nvars) );
298 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*lexdata)->perm, permlen) );
299 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*lexdata)->invperm, permlen) );
300 if ( issignedperm )
301 {
302 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*lexdata)->vardomaincenter, (*lexdata)->nvars) );
303 }
304 else
305 (*lexdata)->vardomaincenter = NULL;
306
307 /* determine the vars, perm, and centers */
308 for (j = 0; j < nvars; ++j)
309 {
310 i = indexcorrection[j];
311 if ( i < 0 )
312 continue;
313
314 /* j is the original index, i is the relabeled index */
315 (*lexdata)->vars[i] = vars[j];
316
317 if ( issignedperm )
318 {
319 if ( perm[j] >= nvars )
320 {
321 (*lexdata)->perm[i] = indexcorrection[perm[j] - nvars] + (*lexdata)->nvars;
322 (*lexdata)->perm[i + (*lexdata)->nvars] = indexcorrection[perm[j] - nvars];
323 assert( (*lexdata)->nvars <= (*lexdata)->perm[i] && (*lexdata)->perm[i] < 2 * (*lexdata)->nvars );
324 }
325 else
326 {
327 (*lexdata)->perm[i] = indexcorrection[perm[j]];
328 (*lexdata)->perm[i + (*lexdata)->nvars] = indexcorrection[perm[j]] + (*lexdata)->nvars;
329 }
330 }
331 else
332 (*lexdata)->perm[i] = indexcorrection[perm[j]];
333
334 if ( issignedperm )
335 (*lexdata)->vardomaincenter[i] = permvardomaincenter[j];
336
337 assert( perm[j] != j );
338 assert( (*lexdata)->perm[i] != i );
339 assert( (*lexdata)->perm[i] >= 0 );
340 assert( (*lexdata)->perm[i] < permlen );
341 }
342
343 /* determine invperm */
344 for (i = 0; i < (*lexdata)->nvars; ++i)
345 {
346 if ( (*lexdata)->perm[i] >= (*lexdata)->nvars )
347 {
348 assert( issignedperm );
349
350 (*lexdata)->invperm[(*lexdata)->perm[i]] = i;
351 (*lexdata)->invperm[(*lexdata)->perm[i] - (*lexdata)->nvars] = i + (*lexdata)->nvars;
352 }
353 else
354 {
355 (*lexdata)->invperm[(*lexdata)->perm[i]] = i;
356
357 if ( issignedperm )
358 (*lexdata)->invperm[(*lexdata)->perm[i] + (*lexdata)->nvars] = i + (*lexdata)->nvars;
359 }
360 }
361 SCIPfreeBufferArray(scip, &indexcorrection);
362
363 /* make sure that we deal with transformed variables and that variables cannot be multi-aggregated, and capture */
364 for (i = 0; i < (*lexdata)->nvars; ++i)
365 {
366 assert( SCIPvarIsTransformed((*lexdata)->vars[i]) );
367 SCIP_CALL( SCIPmarkDoNotMultaggrVar(scip, (*lexdata)->vars[i]) );
368 SCIP_CALL( SCIPcaptureVar(scip, (*lexdata)->vars[i]) );
369 }
370
371 /* create hashmap for all variables, both globally and just for this lexdata */
372 assert( (masterdata->symvarmap == NULL) == (masterdata->nsymvars == 0) );
373 if ( usedynamicorder )
374 {
375 if ( masterdata->symvarmap == NULL )
376 {
377 SCIP_CALL( SCIPhashmapCreate(&masterdata->symvarmap, SCIPblkmem(scip), (*lexdata)->nvars) );
378 }
379 assert( masterdata->symvarmap != NULL );
380
381 SCIP_CALL( SCIPhashmapCreate(&(*lexdata)->varmap, SCIPblkmem(scip), (*lexdata)->nvars) );
382 assert( (*lexdata)->varmap != NULL );
383
384 for (i = 0; i < (*lexdata)->nvars; ++i)
385 {
386 var = (*lexdata)->vars[i];
387 assert( var != NULL );
388 assert( SCIPvarIsTransformed(var) );
389
390 /* the hashmap in lexdata maps to the index in the vars array */
391 SCIP_CALL( SCIPhashmapInsertInt((*lexdata)->varmap, (void*) var, i) );
392
393 /* var already added to hashmap */
394 if ( SCIPhashmapExists(masterdata->symvarmap, (void*) var) )
395 continue;
396
397 /* the hashmap in symvarmap maps to a unique index */
398 SCIP_CALL( SCIPhashmapInsertInt(masterdata->symvarmap, (void*) var, masterdata->nsymvars++) );
399 }
400 }
401 else
402 (*lexdata)->varmap = NULL;
403
404 return SCIP_OKAY;
405}
406
407
408/** comparator used in the getVarOrder() function, for sorting an array of NODEDEPTHBRANCHINDEX by depth, then by index
409 *
410 * @warning this function is only meant to be used in the getVarOrder() function
411 *
412 * @pre datapointer is populated with a VARARRAYNODEDEPTHBRANCHINDEX pointer
413 * @pre the comparator is only called on entries with set (depth, index)-information
414 * @pre the (depth, index)-informations are all different
415 *
416 * result:
417 * 0: the same index is compared, so the (depth, index)-informations are the same
418 * -1: the depth of ind1 is smaller than the depth of ind2, or it's equal and the index is smaller
419 * 1: the depth of ind2 is smaller than the depth of ind1, or it's equal and the index is smaller
420 */
421static
422SCIP_DECL_SORTINDCOMP(sortbynodedepthbranchindices)
423{
424 /* unpack the dataptr */
425 VARARRAYNODEDEPTHBRANCHINDEX* vararraynodedepthbranchindices;
428 SCIP_VAR** vars;
429 NODEDEPTHBRANCHINDEX* index1;
430 NODEDEPTHBRANCHINDEX* index2;
431
432 vararraynodedepthbranchindices = (VARARRAYNODEDEPTHBRANCHINDEX*) dataptr;
433 nodedepthbranchindices = vararraynodedepthbranchindices->nodedepthbranchindices;
434 masterdata = vararraynodedepthbranchindices->masterdata;
435 vars = vararraynodedepthbranchindices->vars;
436
437 /* comparing the same element is an identity operation */
438 if ( ind1 == ind2 )
439 return 0;
440
441 /* sort by depth, then by index, in increasing order */
442 index1 = &(nodedepthbranchindices[SCIPhashmapGetImageInt(masterdata->symvarmap, vars[ind1])]);
443 index2 = &(nodedepthbranchindices[SCIPhashmapGetImageInt(masterdata->symvarmap, vars[ind2])]);
444
445 if ( index1->nodedepth < index2->nodedepth )
446 return -1;
447 if ( index1->nodedepth > index2->nodedepth )
448 return 1;
449 assert( index1->index != index2->index );
450
451 /* depth is the same, sort by index */
452 if ( index1->index < index2->index )
453 return -1;
454 if ( index1->index > index2->index )
455 return 1;
456
457 /* this may not happen, since all elements must be different */
458 assert( index1->index == index2->index );
459
460 return 0;
461}
462
463
464/** return the index of a variable at a specific position of a variable order */
465static
467 int* varorder, /**< variable order (or NULL) */
468 int pos /**< position for which index is returned */
469 )
470{
471 assert( pos >= 0 );
472
473 if ( varorder == NULL )
474 return pos;
475 return varorder[pos];
476}
477
478
479/** gets the variable ordering based on the branching decisions at the node */
480static
482 SCIP* scip, /**< SCIP data structure */
483 SCIP_LEXREDDATA* masterdata, /**< pointer to global data for lexicographic reduction propagator */
484 LEXDATA* lexdata, /**< pointer to data for this permutation */
485 NODEDEPTHBRANCHINDEX* nodedepthbranchindices, /**< array with (depth, index)-information per variable in rooted path to focus node */
486 int nvarstotal, /**< length of that array */
487 SCIP_VAR** branchvars, /**< array populated with variables branched on in the symvarmap hashset */
488 int nbranchvars, /**< number of elements in branchvars array */
489 int* varorder, /**< array to populate with variable order */
490 int* nselvars, /**< pointer to number of variables in the ordering */
491 int maxnselvars /**< maximal size of the number of selected variables */
492 )
493{
494 SCIP_VAR** vars;
495 int nvars;
496 SCIP_VAR* var;
497 int varindex;
498 int i;
499
500 assert( scip != NULL );
501 assert( masterdata != NULL );
502 assert( lexdata != NULL );
503 assert( nodedepthbranchindices != NULL );
504 assert( nvarstotal >= 0 );
505 assert( branchvars != NULL );
506 assert( nbranchvars >= 0 );
507 assert( varorder != NULL );
508 assert( nselvars != NULL );
509
510 vars = lexdata->vars;
511 assert( vars != NULL );
512 nvars = lexdata->nvars;
513 assert( nvars >= 0 );
514
515 /* first collect every variable that was branched on */
516 *nselvars = 0;
517
518 if ( nvars < nbranchvars )
519 {
520 /* for permutations with small support, just check all support entries */
521 for (i = 0; i < nvars; ++i)
522 {
523 var = vars[i];
524 assert( var != NULL );
525
526 assert( SCIPhashmapExists(masterdata->symvarmap, (void*) var) );
527 varindex = SCIPhashmapGetImageInt(masterdata->symvarmap, var);
528 assert( varindex >= 0 );
529 assert( varindex < masterdata->nsymvars );
530
531 assert( nodedepthbranchindices[varindex].nodedepth >= 0 );
532
533 /* skip variables that have not been used for branching */
534 if ( nodedepthbranchindices[varindex].nodedepth <= 0 )
535 continue;
536
537 /* add index i of branching variable */
538 assert( i >= 0 );
539 assert( i < nvars );
540 assert( (*nselvars) < maxnselvars );
541 varorder[(*nselvars)++] = i;
542 }
543 }
544 else
545 {
546 /* for permutations where the support is larger than the number of branched vars, check for the branched vars */
547 for (i = 0; i < nbranchvars; ++i)
548 {
549 var = branchvars[i];
550 assert( var != NULL );
551
552#ifndef NDEBUG
553 /* debugging: test if it is indeed a branched variable! */
554 varindex = SCIPhashmapGetImageInt(masterdata->symvarmap, var);
555 assert( varindex >= 0 );
556 assert( varindex < masterdata->nsymvars );
557 assert( nodedepthbranchindices[varindex].nodedepth > 0 );
558#endif
559
560 /* get the variable index in the lexdata->vars array */
561 varindex = SCIPhashmapGetImageInt(lexdata->varmap, (void*) var);
562 assert( varindex == INT_MAX || (varindex >= 0 && varindex < lexdata->nvars) );
563
564 /* skip variables that are not permuted by the permutation */
565 if ( varindex == INT_MAX )
566 continue;
567 assert( lexdata->vars[varindex] == var );
568
569 /* add index varindex of the branching variable */
570 varorder[(*nselvars)++] = varindex;
571 }
572 }
573
574 if ( *nselvars > 1 )
575 {
576 /* sort the first n elements of varorder by depth, then by index, as indicated by nodedepthbranchindices. */
577 VARARRAYNODEDEPTHBRANCHINDEX vararraynodedepthbranchindices;
578 vararraynodedepthbranchindices.nodedepthbranchindices = nodedepthbranchindices;
579 vararraynodedepthbranchindices.masterdata = masterdata;
580 vararraynodedepthbranchindices.vars = vars;
581 SCIPsortInd(varorder, sortbynodedepthbranchindices, (void*) &vararraynodedepthbranchindices, *nselvars);
582 }
583
584 return SCIP_OKAY;
585}
586
587
588/** gerts local variable bounds or reads bound from peek data */
589static
591 SCIP_VAR* var1, /**< first variable in comparison */
592 SCIP_VAR* var2, /**< second variable in comparison */
593 SCIP_Bool peekmode, /**< whether function is called in peek mode */
594 int varidx1, /**< index of var1 (or NULL) */
595 int varidx2, /**< index of var2 (or NULL) */
596 SCIP_Real* peeklbs, /**< lower bounds of variables in peek mode (or NULL) */
597 SCIP_Real* peekubs, /**< upper bounds of variables in peek mode (or NULL) */
598 SCIP_Bool* peekbdset, /**< whether peek bounds have been set (or NULL) */
599 SCIP_Real* lb1, /**< pointer to store lower bound of var1 */
600 SCIP_Real* ub1, /**< pointer to store upper bound of var1 */
601 SCIP_Real* lb2, /**< pointer to store lower bound of var2 */
602 SCIP_Real* ub2 /**< pointer to store upper bound of var2 */
603 )
604{
605 assert( var1 != NULL );
606 assert( var2 != NULL );
607 assert( (!peekmode) || peeklbs != NULL );
608 assert( (!peekmode) || peekubs != NULL );
609 assert( (!peekmode) || peekbdset != NULL );
610 assert( lb1 != NULL );
611 assert( ub1 != NULL );
612 assert( lb2 != NULL );
613 assert( ub2 != NULL );
614
615 if ( peekmode && peekbdset[varidx1] )
616 {
617 *ub1 = peekubs[varidx1];
618 *lb1 = peeklbs[varidx1];
619 }
620 else
621 {
622 *ub1 = SCIPvarGetUbLocal(var1);
623 *lb1 = SCIPvarGetLbLocal(var1);
624 }
625 if ( peekmode && peekbdset[varidx2] )
626 {
627 *ub2 = peekubs[varidx2];
628 *lb2 = peeklbs[varidx2];
629 }
630 else
631 {
632 *ub2 = SCIPvarGetUbLocal(var2);
633 *lb2 = SCIPvarGetLbLocal(var2);
634 }
635
636 return SCIP_OKAY;
637}
638
639/** returns whether a shifted variable is always smaller than another shifted variable
640 *
641 * Shifts are always (var - shift).
642 */
643static
645 SCIP* scip, /**< SCIP data structure */
646 SCIP_VAR* var1, /**< first variable in comparison */
647 SCIP_VAR* var2, /**< second variable in comparison */
648 SCIP_Real shift1, /**< shift of var1 */
649 SCIP_Real shift2, /**< shift of var2 */
650 SCIP_Bool isnegated, /**< whether shift of var2 is negated */
651 SCIP_Bool peekmode, /**< whether function is called in peek mode */
652 int varidx1, /**< index of var1 (or NULL) */
653 int varidx2, /**< index of var2 (or NULL) */
654 SCIP_Real* peeklbs, /**< lower bounds of variables in peek mode (or NULL) */
655 SCIP_Real* peekubs, /**< upper bounds of variables in peek mode (or NULL) */
656 SCIP_Bool* peekbdset /**< whether peek bounds have been set (or NULL) */
657 )
658{
659 SCIP_Real ub1;
660 SCIP_Real ub2;
661 SCIP_Real lb1;
662 SCIP_Real lb2;
663
664 assert( scip != NULL );
665 assert( var1 != NULL );
666 assert( var2 != NULL );
667 assert( (!peekmode) || peeklbs != NULL );
668 assert( (!peekmode) || peekubs != NULL );
669 assert( (!peekmode) || peekbdset != NULL );
670
671 SCIP_CALL_ABORT( getVarBounds(var1, var2, peekmode, varidx1, varidx2, peeklbs, peekubs, peekbdset,
672 &lb1, &ub1, &lb2, &ub2) );
673
674 /* for negated variables, check: var1 - shift1 < shift2 - var2 */
675 if ( isnegated && SCIPisLT(scip, ub1, shift1 + shift2 - ub2) )
676 return TRUE;
677
678 /* for non-negated variables, check: var1 - center1 < var2 - center2 */
679 if ( (!isnegated) && SCIPisLT(scip, ub1, shift1 - shift2 + lb2) )
680 return TRUE;
681
682 return FALSE;
683}
684
685
686/** returns whether a shifted variable can be greater than another shifted variable
687 *
688 * Shifts are always (var - shift).
689 */
690static
692 SCIP* scip, /**< SCIP data structure */
693 SCIP_VAR* var1, /**< first variable in comparison */
694 SCIP_VAR* var2, /**< second variable in comparison */
695 SCIP_Real shift1, /**< shift of var1 */
696 SCIP_Real shift2, /**< shift of var2 */
697 SCIP_Bool isnegated, /**< whether shift of var2 is negated */
698 SCIP_Bool peekmode, /**< whether function is called in peek mode */
699 int varidx1, /**< index of var1 (or NULL) */
700 int varidx2, /**< index of var2 (or NULL) */
701 SCIP_Real* peeklbs, /**< lower bounds of variables in peek mode (or NULL) */
702 SCIP_Real* peekubs, /**< upper bounds of variables in peek mode (or NULL) */
703 SCIP_Bool* peekbdset /**< whether peek bounds have been set (or NULL) */
704 )
705{
706 SCIP_Real ub1;
707 SCIP_Real ub2;
708 SCIP_Real lb1;
709 SCIP_Real lb2;
710
711 assert( scip != NULL );
712 assert( var1 != NULL );
713 assert( var2 != NULL );
714 assert( (!peekmode) || peeklbs != NULL );
715 assert( (!peekmode) || peekubs != NULL );
716 assert( (!peekmode) || peekbdset != NULL );
717
718 SCIP_CALL_ABORT( getVarBounds(var1, var2, peekmode, varidx1, varidx2, peeklbs, peekubs, peekbdset,
719 &lb1, &ub1, &lb2, &ub2) );
720
721 /* for negated variables, check: var1 - shift1 > shift2 - var2 */
722 if ( isnegated && SCIPisGT(scip, ub1, shift1 + shift2 - ub2) )
723 return TRUE;
724
725 /* for non-negated variables, check: var1 - center1 > var2 - center2 */
726 if ( (!isnegated) && SCIPisGT(scip, ub1, shift1 - shift2 + lb2) )
727 return TRUE;
728
729 return FALSE;
730}
731
732
733/** propagates lower bound of first variable in relation x >= y for shifted variables */
734static
736 SCIP* scip, /**< SCIP data structure */
737 SCIP_VAR* var1, /**< first variable in pair */
738 SCIP_VAR* var2, /**< second variable in pair */
739 SCIP_Real center1, /**< center of var1 (original var domain) */
740 SCIP_Real center2, /**< center of var2 (original var domain) */
741 SCIP_Bool isnegated, /**< whether var2 is negated by symmetry */
742 SCIP_Bool* infeasible, /**< pointer to store whether infeasibility is found */
743 int* nreductions, /**< pointer to store number of reductions */
744 SCIP_Bool peekmode, /**< whether function is called in peek mode */
745 int varidx1, /**< index of var1 (or NULL) */
746 int varidx2, /**< index of var2 (or NULL) */
747 SCIP_Real* peeklbs, /**< lower bounds of variables in peek mode (or NULL) */
748 SCIP_Real* peekubs, /**< upper bounds of variables in peek mode (or NULL) */
749 SCIP_Bool* peekbdset /**< whether peek bounds have been set (or NULL) */
750 )
751{
752 SCIP_Real ub1;
753 SCIP_Real ub2;
754 SCIP_Real lb1;
755 SCIP_Real lb2;
756
757 SCIP_Bool tighten = FALSE;
758 SCIP_Real newbd;
759
760 assert( (!peekmode) || peeklbs != NULL );
761 assert( (!peekmode) || peekubs != NULL );
762 assert( (!peekmode) || peekbdset != NULL );
763
764 SCIP_CALL( getVarBounds(var1, var2, peekmode, varidx1, varidx2, peeklbs, peekubs, peekbdset,
765 &lb1, &ub1, &lb2, &ub2) );
766
767 /* tighten domain of var1 to ensure that var1 - center1 >= isnegated * (var2 - center2 ) */
768 if ( isnegated )
769 {
770 if ( SCIPisLT(scip, lb1 - center1, center2 - ub2) )
771 {
772 tighten = TRUE;
773 newbd = center1 + center2 - ub2;
774 }
775 }
776 else
777 {
778 if ( SCIPisLT(scip, lb1 - center1, lb2 - center2) )
779 {
780 tighten = TRUE;
781 newbd = center1 + lb2 - center2;
782 }
783 }
784
785 if ( tighten )
786 {
787 /* in peek mode, only store updated bounds */
788 if ( peekmode )
789 {
790 peeklbs[varidx1] = newbd; /*lint !e644*/
791 peekubs[varidx1] = ub1;
792 peekbdset[varidx1] = TRUE;
793 }
794 else
795 {
796 SCIP_CALL( SCIPtightenVarLb(scip, var1, newbd, TRUE, infeasible, &tighten) );
797 if ( tighten )
798 {
799 SCIPdebugMessage("Restricting variable LB %12s to %5.2f\n", SCIPvarGetName(var1), newbd);
800 *nreductions += 1;
801 }
802 else
803 {
804 SCIPdebugMessage("Restricting variable LB %12s to %5.2f (no success)\n",
805 SCIPvarGetName(var1), newbd);
806 }
807 if ( *infeasible )
808 {
809 SCIPdebugMessage("Detected infeasibility restricting variable LB %12s to %5.2f\n",
810 SCIPvarGetName(var1), newbd);
811 return SCIP_OKAY;
812 }
813 }
814 }
815
816 return SCIP_OKAY;
817}
818
819
820/** propagates upper bound of second variable in relation x >= y for shifted variables */
821static
823 SCIP* scip, /**< SCIP data structure */
824 SCIP_VAR* var1, /**< first variable in pair */
825 SCIP_VAR* var2, /**< second variable in pair */
826 SCIP_Real center1, /**< center of var1 (original var domain) */
827 SCIP_Real center2, /**< center of var2 (original var domain) */
828 SCIP_Bool isnegated, /**< whether var2 is negated by symmetry */
829 SCIP_Bool* infeasible, /**< pointer to store whether infeasibility is found */
830 int* nreductions, /**< pointer to store number of reductions */
831 SCIP_Bool peekmode, /**< whether function is called in peek mode */
832 int varidx1, /**< index of var1 (or NULL) */
833 int varidx2, /**< index of var2 (or NULL) */
834 SCIP_Real* peeklbs, /**< lower bounds of variables in peek mode (or NULL) */
835 SCIP_Real* peekubs, /**< upper bounds of variables in peek mode (or NULL) */
836 SCIP_Bool* peekbdset /**< whether peek bounds have been set (or NULL) */
837 )
838{
839 SCIP_Real ub1;
840 SCIP_Real ub2;
841 SCIP_Real lb1;
842 SCIP_Real lb2;
843
844 SCIP_Bool tighten = FALSE;
845 SCIP_Real newbd;
846
847 assert( scip != NULL );
848 assert( var1 != NULL );
849 assert( var2 != NULL );
850 assert( infeasible != NULL );
851 assert( nreductions != NULL );
852 assert( (!peekmode) || peeklbs != NULL );
853 assert( (!peekmode) || peekubs != NULL );
854 assert( (!peekmode) || peekbdset != NULL );
855
856 SCIP_CALL( getVarBounds(var1, var2, peekmode, varidx1, varidx2, peeklbs, peekubs, peekbdset,
857 &lb1, &ub1, &lb2, &ub2) );
858
859 /* tighten domain of var2 to ensure that var1 - center1 >= isnegated * (var2 - center2 ) */
860 if ( isnegated )
861 {
862 if ( SCIPisLT(scip, ub1 - center1, center2 - lb2) )
863 {
864 tighten = TRUE;
865 newbd = center1 + center2 - ub1;
866 }
867 }
868 else
869 {
870 if ( SCIPisLT(scip, ub1 - center1, ub2 - center2) )
871 {
872 tighten = TRUE;
873 newbd = center2 - center1 + ub1;
874 }
875 }
876
877 if ( tighten )
878 {
879 /* in peek mode, only store updated bounds */
880 if ( peekmode )
881 {
882 if ( isnegated )
883 {
884 peeklbs[varidx2] = newbd; /*lint !e644*/
885 peekubs[varidx2] = ub2;
886 peekbdset[varidx2] = TRUE;
887 }
888 else
889 {
890 peeklbs[varidx2] = lb2;
891 peekubs[varidx2] = newbd;
892 peekbdset[varidx2] = TRUE;
893 }
894 }
895 else
896 {
897 if ( isnegated )
898 {
899 SCIP_CALL( SCIPtightenVarLb(scip, var2, newbd, TRUE, infeasible, &tighten) );
900 }
901 else
902 {
903 SCIP_CALL( SCIPtightenVarUb(scip, var2, newbd, TRUE, infeasible, &tighten) );
904 }
905
906 if ( tighten )
907 {
908 SCIPdebugMessage("Restricting variable %sB %12s to %5.2f\n",
909 isnegated ? "L" : "U", SCIPvarGetName(var2), newbd);
910 *nreductions += 1;
911 }
912 else
913 {
914 SCIPdebugMessage("Restricting variable %sB %12s to %5.2f (no success)\n",
915 isnegated ? "L" : "U", SCIPvarGetName(var2), newbd);
916 }
917 if ( *infeasible )
918 {
919 SCIPdebugMessage("Detected infeasibility restricting variable %sB %12s to %5.2f\n",
920 isnegated ? "L" : "U", SCIPvarGetName(var2), newbd);
921 return SCIP_OKAY;
922 }
923 }
924 }
925
926 return SCIP_OKAY;
927}
928
929
930/** propagates x - c >= c - x */
931static
933 SCIP* scip, /**< SCIP data structure */
934 SCIP_VAR* var, /**< variable */
935 SCIP_Real center, /**< center of var (original var domain) */
936 SCIP_Bool* infeasible, /**< pointer to store whether infeasibility is found */
937 int* nreductions, /**< pointer to store number of reductions */
938 SCIP_Bool peekmode, /**< whether function is called in peek mode */
939 int varidx, /**< index of var (or NULL) */
940 SCIP_Real* peeklbs, /**< lower bounds of variables in peek mode (or NULL) */
941 SCIP_Real* peekubs, /**< upper bounds of variables in peek mode (or NULL) */
942 SCIP_Bool* peekbdset /**< whether peek bounds have been set (or NULL) */
943 )
944{
945 SCIP_Real ub1;
946 SCIP_Real ub2;
947 SCIP_Real lb1;
948 SCIP_Real lb2;
949 SCIP_Bool tighten = FALSE;
950
951 assert( scip != NULL );
952 assert( var != NULL );
953 assert( infeasible != NULL );
954 assert( nreductions != NULL );
955 assert( (!peekmode) || peeklbs != NULL );
956 assert( (!peekmode) || peekubs != NULL );
957 assert( (!peekmode) || peekbdset != NULL );
958
959 SCIP_CALL( getVarBounds(var, var, peekmode, varidx, varidx, peeklbs, peekubs, peekbdset,
960 &lb1, &ub1, &lb2, &ub2) );
961
962 if ( SCIPisLT(scip, ub1, center) )
963 {
964 *infeasible = TRUE;
965 return SCIP_OKAY;
966 }
967 else if ( SCIPisLT(scip, lb1, center) )
968 {
969 if ( peekmode )
970 {
971 peeklbs[varidx] = center;
972 peekubs[varidx] = ub1;
973 peekbdset[varidx] = TRUE;
974 }
975 else
976 {
977 SCIP_CALL( SCIPtightenVarLb(scip, var, center, TRUE, infeasible, &tighten) );
978 if ( tighten )
979 {
980 SCIPdebugMessage("Restricting variable LB %12s to %5.2f\n", SCIPvarGetName(var), center);
981 *nreductions += 1;
982 }
983 else
984 {
985 SCIPdebugMessage("Restricting variable LB %12s to %5.2f (no success)\n",
986 SCIPvarGetName(var), center);
987 }
988 if ( *infeasible )
989 {
990 SCIPdebugMessage("Detected infeasibility restricting variable LB %12s to %5.2f\n",
991 SCIPvarGetName(var), center);
992 return SCIP_OKAY;
993 }
994 }
995 }
996
997 return SCIP_OKAY;
998}
999
1000
1001/** propagates lexicographic order for one pair of symmetric variables */
1002static
1004 SCIP* scip, /**< SCIP data structure */
1005 SCIP_VAR* var1, /**< first variable in pair */
1006 SCIP_VAR* var2, /**< second variable in pair */
1007 SCIP_Real center1, /**< center of var1 (original var domain) */
1008 SCIP_Real center2, /**< center of var2 (original var domain) */
1009 SCIP_Bool isnegated, /**< whether var2 is negated by symmetry */
1010 SCIP_Bool* infeasible, /**< pointer to store whether infeasibility is found */
1011 int* nreductions, /**< pointer to store number of reductions */
1012 SCIP_Bool peekmode, /**< whether function is called in peek mode */
1013 int varidx1, /**< index of var1 (or NULL) */
1014 int varidx2, /**< index of var2 (or NULL) */
1015 SCIP_Real* peeklbs, /**< lower bounds of variables in peek mode (or NULL) */
1016 SCIP_Real* peekubs, /**< upper bounds of variables in peek mode (or NULL) */
1017 SCIP_Bool* peekbdset /**< whether peek bounds have been set (or NULL) */
1018 )
1019{
1020 assert( scip != NULL );
1021 assert( var1 != NULL );
1022 assert( var2 != NULL );
1023 assert( infeasible != NULL );
1024 assert( nreductions != NULL );
1025
1026 /* perform lexicographic comparison: var1 - center1 >= +/- (var2 - center2) */
1027 if ( alwaysLTshiftedVars(scip, var1, var2, center1, center2, isnegated, peekmode,
1028 varidx1, varidx2, peeklbs, peekubs, peekbdset) )
1029 {
1030#ifdef SCIP_DEBUG
1031 SCIP_Real ub1;
1032 SCIP_Real ub2;
1033 SCIP_Real lb1;
1034 SCIP_Real lb2;
1035
1036 /* get bounds of shifted (and possibly negated) variables */
1037 ub1 = SCIPvarGetUbLocal(var1);
1038 lb1 = SCIPvarGetLbLocal(var1);
1039 ub2 = SCIPvarGetUbLocal(var2);
1040 lb2 = SCIPvarGetLbLocal(var2);
1041
1042 SCIPdebugMessage("Detected infeasibility: x < y for "
1043 "x: lb=%5.2f, ub=%5.2f, shift=%5.2f "
1044 "y: lb=%5.2f, ub=%5.2f, shift=%5.2f negated=%u\n",
1045 lb1, ub1, center1, lb2, ub2, center2, isnegated);
1046#endif
1047
1048 *infeasible = TRUE;
1049 return SCIP_OKAY;
1050 }
1051
1052 /* for signed permutations, a variable might be mapped to itself */
1053 if ( var1 == var2 )
1054 {
1055 SCIP_CALL( propagateSelfReflectionVar(scip, var1, center1, infeasible, nreductions, peekmode, varidx1,
1056 peeklbs, peekubs, peekbdset) );
1057 }
1058 else
1059 {
1060 SCIP_CALL( propagateLowerBoundVar(scip, var1, var2, center1, center2, isnegated, infeasible, nreductions, peekmode,
1061 varidx1, varidx2, peeklbs, peekubs, peekbdset) );
1062 if ( *infeasible )
1063 return SCIP_OKAY;
1064
1065 SCIP_CALL( propagateUpperBoundSymVar(scip, var1, var2, center1, center2, isnegated, infeasible, nreductions, peekmode,
1066 varidx1, varidx2, peeklbs, peekubs, peekbdset) );
1067 }
1068
1069 return SCIP_OKAY;
1070}
1071
1072/** checks if the static lexred with a certain variable ordering is feasible in the hypothetical scenario where
1073 * variables with indices i and j are fixed to fixvalue (i.e., peeking)
1074 */
1075static
1077 SCIP* scip, /**< SCIP data structure */
1078 LEXDATA* lexdata, /**< pointer to data for this permutation */
1079 int* varorder, /**< array populated with variable order (or NULL for static propagation) */
1080 int nselvars, /**< number of variables in the ordering */
1081 int fixi, /**< variable index of left fixed column */
1082 int fixj, /**< variable index of right fixed column */
1083 int fixrow, /**< row index in var ordering, from which to start peeking */
1084 SCIP_Real fixvaluei, /**< value on which variables i is fixed */
1085 SCIP_Real fixvaluej, /**< value on which variables j is fixed */
1086 SCIP_Bool* peekfeasible, /**< pointer to store whether this is feasible or not */
1087 SCIP_Real* peeklbs, /**< lower bounds of variables in peek mode (or NULL) */
1088 SCIP_Real* peekubs, /**< upper bounds of variables in peek mode (or NULL) */
1089 SCIP_Bool* peekbdset /**< whether peek bounds have been set (or NULL) */
1090 )
1091{
1092 int row;
1093 int i;
1094 int j;
1095 SCIP_VAR* vari;
1096 SCIP_VAR* varj;
1097 SCIP_Real centeri;
1098 SCIP_Real centerj;
1099 SCIP_Bool issigned;
1100 SCIP_Bool isnegated;
1101 SCIP_Bool infeasible = FALSE;
1102 int nreductions;
1103
1104 assert( scip != NULL );
1105 assert( lexdata != NULL );
1106 assert( lexdata->vars != NULL );
1107 assert( lexdata->nvars >= 0 );
1108 assert( nselvars <= lexdata->nvars );
1109 assert( nselvars > 0 );
1110 assert( fixi >= 0 );
1111 assert( fixi < lexdata->nvars );
1112 assert( fixj < lexdata->nvars );
1113 assert( fixi != fixj || lexdata->symtype == SYM_SYMTYPE_SIGNPERM );
1114 assert( fixi != fixj || fixvaluei == fixvaluej ); /*lint !e777*/
1115 assert( fixrow >= 0 );
1116 assert( fixrow < nselvars );
1117 assert( peekfeasible != NULL );
1118 assert( fixi == varOrderGetIndex(varorder, fixrow) );
1119 assert( fixj == (lexdata->invperm[varOrderGetIndex(varorder, fixrow)] % lexdata->nvars) );
1120 assert( fixi == (lexdata->perm[fixj] % lexdata->nvars) );
1121
1122 *peekfeasible = TRUE;
1123 issigned = lexdata->symtype == SYM_SYMTYPE_SIGNPERM ? TRUE : FALSE;
1124 assert( (!issigned) || lexdata->vardomaincenter != NULL );
1125
1126 /* intialize peekbdset */
1127 for (i = 0; i < lexdata->nvars; ++i)
1128 peekbdset[i] = FALSE;
1129
1130 peeklbs[fixi] = fixvaluei;
1131 peeklbs[fixj] = fixvaluej;
1132 peekubs[fixi] = fixvaluei;
1133 peekubs[fixj] = fixvaluej;
1134 peekbdset[fixi] = TRUE;
1135 peekbdset[fixj] = TRUE;
1136
1137 for (row = fixrow + 1; row < nselvars; ++row)
1138 {
1139 /* get left and right column indices */
1140 i = varOrderGetIndex(varorder, row);
1141 j = lexdata->invperm[i];
1142 assert( i == lexdata->perm[j] );
1143
1144 /* no fixed points */
1145 assert( i != j );
1146
1147 assert( 0 <= i && i < lexdata->nvars );
1148 assert( 0 <= j && j < 2 * lexdata->nvars );
1149 assert( issigned || j < lexdata->nvars );
1150
1151 vari = lexdata->vars[i];
1152 if ( j >= lexdata->nvars )
1153 {
1154 assert( lexdata->symtype == SYM_SYMTYPE_SIGNPERM );
1155 j = j - lexdata->nvars;
1156 varj = lexdata->vars[j];
1157 isnegated = TRUE;
1158 }
1159 else
1160 {
1161 varj = lexdata->vars[j];
1162 isnegated = FALSE;
1163 }
1164
1165 if ( issigned )
1166 {
1167 assert( lexdata->vardomaincenter != NULL );
1168 centeri = lexdata->vardomaincenter[i];
1169 centerj = lexdata->vardomaincenter[j];
1170 }
1171 else
1172 {
1173 centeri = 0.0;
1174 centerj = 0.0;
1175 }
1176
1177 /* propagate that vari >= varj */
1178
1179 /* vari >= varj can never hold if the maximal value of vari is smaller than the minimal value of varj */
1180 if ( alwaysLTshiftedVars(scip, vari, varj, centeri, centerj, isnegated, TRUE, i, j, peeklbs, peekubs, peekbdset) )
1181 {
1182 *peekfeasible = FALSE;
1183 SCIPdebugMessage("PEEK: Detected infeasibility at row %3d.\n", row);
1184 break;
1185 }
1186
1187 SCIP_CALL( propagateLowerBoundVar(scip, vari, varj, centeri, centerj, isnegated, &infeasible, &nreductions, TRUE,
1188 i, j, peeklbs, peekubs, peekbdset) );
1189
1190 SCIP_CALL( propagateUpperBoundSymVar(scip, vari, varj, centeri, centerj, isnegated, &infeasible, &nreductions, TRUE,
1191 i, j, peeklbs, peekubs, peekbdset) );
1192
1193 /* if there exists a solution with vari > varj, reductions are feasible w.r.t. lexred */
1194 if ( canGTshiftedVars(scip, vari, varj, centeri, centerj, isnegated, TRUE,
1195 i, j, peeklbs, peekubs, peekbdset) )
1196 break;
1197 }
1198
1199 return SCIP_OKAY;
1200}
1201
1202/** propagates static lexicographic reduction with specified variable ordering */
1203static
1205 SCIP* scip, /**< SCIP data structure */
1206 LEXDATA* lexdata, /**< pointer to data for this permutation */
1207 int* varorder, /**< array populated with variable order (or NULL if static propagation) */
1208 int nselvars, /**< number of variables in the ordering */
1209 SCIP_Bool* infeasible, /**< pointer to store whether the problem is infeasible */
1210 int* nreductions /**< pointer to store the number of found domain reductions */
1211 )
1212{ /*lint --e{771}*/
1213 int row;
1214 int i = -1;
1215 int j = -1;
1216 SCIP_VAR* vari = NULL;
1217 SCIP_VAR* varj = NULL;
1218 SCIP_Real centeri;
1219 SCIP_Real centerj;
1220 SCIP_Bool success;
1221 SCIP_Bool issigned;
1222 SCIP_Bool isnegated;
1223
1224 assert( scip != NULL );
1225 assert( lexdata != NULL );
1226 assert( nselvars >= 0 );
1227 assert( infeasible != NULL );
1228 assert( !*infeasible );
1229 assert( nreductions != NULL );
1230 assert( *nreductions >= 0 );
1231
1232 /* avoid trivial cases */
1233 if ( nselvars <= 0 )
1234 return SCIP_OKAY;
1235
1236 issigned = lexdata->symtype == SYM_SYMTYPE_SIGNPERM ? TRUE : FALSE;
1237 assert( (!issigned) || lexdata->vardomaincenter != NULL );
1238
1239 /* iterate over the variable array entrywise
1240 *
1241 * We see this as two columns, with the left vector being the variable ordering,
1242 * and the right column the permuted variables of this var ordering.
1243 */
1244 for (row = 0; row < nselvars; ++row)
1245 {
1246 /* left and right column indices */
1247 i = varOrderGetIndex(varorder, row);
1248 j = lexdata->invperm[i];
1249 assert( i == lexdata->perm[j] );
1250
1251 /* no fixed points */
1252 assert( i != j );
1253
1254 assert( 0 <= i && i < lexdata->nvars );
1255 assert( 0 <= j && j < 2 * lexdata->nvars );
1256 assert( issigned || j < lexdata->nvars );
1257
1258 vari = lexdata->vars[i];
1259 if ( j >= lexdata->nvars )
1260 {
1261 assert( issigned );
1262 j = j - lexdata->nvars;
1263 varj = lexdata->vars[j];
1264 isnegated = TRUE;
1265 }
1266 else
1267 {
1268 varj = lexdata->vars[j];
1269 isnegated = FALSE;
1270 }
1271
1272 if ( issigned )
1273 {
1274 assert( lexdata->vardomaincenter != NULL );
1275 centeri = lexdata->vardomaincenter[i];
1276 centerj = lexdata->vardomaincenter[j];
1277 }
1278 else
1279 {
1280 centeri = 0.0;
1281 centerj = 0.0;
1282 }
1283
1284 SCIP_CALL( propagateVariablePair(scip, vari, varj, centeri, centerj, isnegated, infeasible, nreductions, FALSE,
1285 0, 0, NULL, NULL, NULL) );
1286
1287 if ( *infeasible )
1288 return SCIP_OKAY;
1289
1290 /* terminate if there exists a solution being lexicographically strictly larger than its image */
1291 if ( canGTshiftedVars(scip, vari, varj, centeri, centerj, isnegated, FALSE,
1292 0, 0, NULL, NULL, NULL) )
1293 break;
1294 }
1295 assert( vari != NULL );
1296 assert( varj != NULL );
1297 assert( 0 <= i && i < lexdata->nvars );
1298 assert( 0 <= j && j < lexdata->nvars );
1299
1300 /* if the variables in "row" are fixed to the same value, we might find further propagations */
1301 if ( row < nselvars )
1302 {
1303 SCIP_Real* peeklbs;
1304 SCIP_Real* peekubs;
1305 SCIP_Bool* peekbdset;
1306 SCIP_Real ub1;
1307 SCIP_Real ub2;
1308 SCIP_Real lb1;
1309 SCIP_Real lb2;
1310 SCIP_Real lbi;
1311 SCIP_Real ubi;
1312 SCIP_Real lbj;
1313 SCIP_Real ubj;
1314 SCIP_Bool peekfeasible;
1315
1316 SCIP_CALL( getVarBounds(vari, varj, FALSE, 0, 0, NULL, NULL, NULL, &lb1, &ub1, &lb2, &ub2) );
1317
1318 /* special treatment if i-th and j-th variable are the same in a signed permutation */
1319 if ( vari == varj )
1320 {
1321 assert( lexdata->symtype == SYM_SYMTYPE_SIGNPERM );
1322 assert( SCIPsymGE(scip, lb1, lexdata->vardomaincenter[i]) ); /* propagation enforces xi - center >= center - xi */
1323
1324 /* both variables can only be the same if they are fixed to the domain center */
1325 if ( SCIPsymGT(scip, lb1, lexdata->vardomaincenter[i]) )
1326 return SCIP_OKAY;
1327
1328 SCIP_CALL( SCIPallocBufferArray(scip, &peeklbs, lexdata->nvars) );
1329 SCIP_CALL( SCIPallocBufferArray(scip, &peekubs, lexdata->nvars) );
1330 SCIP_CALL( SCIPallocBufferArray(scip, &peekbdset, lexdata->nvars) );
1331
1332 SCIP_CALL( peekStaticLexredIsFeasible(scip, lexdata, varorder, nselvars, i, j,
1333 row, lexdata->vardomaincenter[i], lexdata->vardomaincenter[i],
1334 &peekfeasible, peeklbs, peekubs, peekbdset) );
1335 if ( !peekfeasible )
1336 {
1337 /* both variables cannot be the same, so the non-negated variable must be greater than the domain center */
1338 if( SCIPvarIsIntegral(vari) )
1339 {
1340 assert( SCIPisIntegral(scip, lb1) );
1341 SCIP_CALL( SCIPtightenVarLb(scip, vari, lexdata->vardomaincenter[i] + 1.0, TRUE, infeasible, &success) );
1342 if ( success )
1343 *nreductions += 1;
1344 if ( *infeasible )
1345 goto FREEMEMORY;
1346 lb1 = lexdata->vardomaincenter[i] + 1.0;
1347 assert( SCIPsymLE(scip, lb1, ub1) );
1348 }
1349 else
1350 {
1351 /* continuous variable type: act as if we increase the variable by a very little bit.
1352 * This is only possible if we're able to increase the variable bound by a bit.
1353 */
1354 if ( SCIPsymEQ(scip, lb1, ub1) )
1355 {
1356 *infeasible = TRUE;
1357 goto FREEMEMORY;
1358 }
1359 }
1360 }
1361 }
1362 else
1363 {
1364 /* The previous loop is broken at row "row", which allows for choosing vari > varj.
1365 *
1366 * Now check if vari == varj is permitted, and if not, tighten the domain further.
1367 *
1368 * @todo We peek twice if vari and varj are unfixed
1369 * But, if the subcycle only contains var1 and var2, a single peek suffices.
1370 * This is similar to orbisack and symresack propagation.
1371 *
1372 * Case 1: vari is minimal (lbi).
1373 * Then, propagation of lbi = vari >= varj can yield two situations:
1374 * Option 1: varj can take a value < lbi. Then no further reductions can be detected.
1375 * Option 2: varj gets fixed to lbi. Then, we must check if feasibility is found, still.
1376 * If it turns out infeasible, then we know vari cannot take value lbi, so we can increase the lower bound.
1377 */
1378 centeri = 0.0;
1379 centerj = 0.0;
1380
1381 if ( lexdata->vardomaincenter != NULL )
1382 {
1383 centeri = lexdata->vardomaincenter[i];
1384 centerj = lexdata->vardomaincenter[j];
1385 }
1386
1387 /* translate variable bounds to shifted variable domain and take negation into account */
1388 lbi = lb1 - centeri;
1389 ubi = ub1 - centeri;
1390 if ( isnegated )
1391 {
1392 lbj = centerj - ub2;
1393 ubj = centerj - lb2;
1394 }
1395 else
1396 {
1397 lbj = lb2 - centerj;
1398 ubj = ub2 - centerj;
1399 }
1400
1401 /* check whether peek is called */
1402 if ( (!SCIPsymEQ(scip, lbi, lbj)) && (!SCIPsymEQ(scip, ubi, ubj)) )
1403 return SCIP_OKAY;
1404
1405 SCIP_CALL( SCIPallocBufferArray(scip, &peeklbs, lexdata->nvars) );
1406 SCIP_CALL( SCIPallocBufferArray(scip, &peekubs, lexdata->nvars) );
1407 SCIP_CALL( SCIPallocBufferArray(scip, &peekbdset, lexdata->nvars) );
1408
1409 if ( SCIPsymEQ(scip, lbj, lbi) )
1410 {
1411 SCIP_Real fixvalj;
1412
1413 /* translate lbj back to original variable domain of variable j */
1414 if ( isnegated )
1415 fixvalj = centerj - lbj;
1416 else
1417 fixvalj = lbj + centerj;
1418
1419 /* this is Option 2: varj gets fixed to lbi by propagation. */
1420 SCIP_CALL( peekStaticLexredIsFeasible(scip, lexdata, varorder, nselvars, i, j,
1421 row, lbi + centeri, fixvalj, &peekfeasible, peeklbs, peekubs, peekbdset) );
1422 if ( !peekfeasible )
1423 {
1424 /* vari cannot take value lb1, so we increase the lower bound (do not use lbi as this is a shifted domain bound) */
1425 if( SCIPvarIsIntegral(vari) )
1426 {
1427 /* discrete variable type: increase lower bound by 1. */
1428 assert( SCIPisIntegral(scip, lb1) );
1429 SCIP_CALL( SCIPtightenVarLb(scip, vari, lb1 + 1.0, TRUE, infeasible, &success) );
1430 if ( success )
1431 *nreductions += 1;
1432 if ( *infeasible )
1433 goto FREEMEMORY;
1434 lb1 = lb1 + 1.0;
1435 assert( SCIPsymLE(scip, lb1, ub1) );
1436 }
1437 else
1438 {
1439 /* continuous variable type: act as if we increase the variable by a very little bit.
1440 * That is only possible if we're able to increase the variable bound by a bit.
1441 */
1442 if ( SCIPsymEQ(scip, lbi, ubi) )
1443 {
1444 *infeasible = TRUE;
1445 goto FREEMEMORY;
1446 }
1447 }
1448 }
1449 }
1450
1451 /* Case 2: varj is maximal (ubj).
1452 * Then, propagation of vari >= varj = ubj can yield two situatiosn:
1453 * Option 1: vari can take a value > ubj. Then, no further reductions can be detected.
1454 * Option 2: vari gets fixed to ubj. Then, we must check if feasibility is found, still.
1455 * If it turns out infeasible, then we know varj cannot take value ubj, so we can decrease the upper bound.
1456 */
1457 assert( SCIPsymGE(scip, ubi, ubj) ); /* this must be the case after reductions in the for-loop */
1458 if ( SCIPsymEQ(scip, ubi, ubj) )
1459 {
1460 SCIP_Real fixvalj;
1461
1462 /* translate ubj back to original variable domain of variable j */
1463 if ( isnegated )
1464 fixvalj = centerj - ubj;
1465 else
1466 fixvalj = ubj + centerj;
1467
1468 /* this is Option 2: vari gets fixed to ubj by propagation. */
1469 SCIP_CALL( peekStaticLexredIsFeasible(scip, lexdata, varorder, nselvars, i, j,
1470 row, ubi + centeri, fixvalj, &peekfeasible, peeklbs, peekubs, peekbdset) );
1471 if ( !peekfeasible )
1472 {
1473 /* varj cannot take value ub2, so we decrease the upper or lower bound (do not use ubj as this is a shifted domain bound) */
1474 if( SCIPvarIsIntegral(varj) )
1475 {
1476 /* discrete variable type: decrease upper bound by 1. */
1477 if ( isnegated )
1478 {
1479 assert( SCIPisIntegral(scip, lb2) );
1480 SCIP_CALL( SCIPtightenVarUb(scip, varj, lb2 + 1.0, TRUE, infeasible, &success) );
1481 }
1482 else
1483 {
1484 assert( SCIPisIntegral(scip, ub2) );
1485 SCIP_CALL( SCIPtightenVarUb(scip, varj, ub2 - 1.0, TRUE, infeasible, &success) );
1486 }
1487 if ( success )
1488 *nreductions += 1;
1489 if ( *infeasible )
1490 goto FREEMEMORY;
1491 ubj = ubj - 1.0;
1492 assert( SCIPsymLE(scip, lbj, ubj) );
1493 }
1494 else
1495 {
1496 /* continuous variable type: act as if we decrease the variable by a very little bit.
1497 * that is only possible if we're able to decrease the variable bound by a bit. */
1498 if ( SCIPsymEQ(scip, lbj, ubj) )
1499 {
1500 *infeasible = TRUE;
1501 goto FREEMEMORY;
1502 }
1503 }
1504 }
1505 }
1506 }
1507 FREEMEMORY:
1508 SCIPfreeBufferArray(scip, &peekbdset);
1509 SCIPfreeBufferArray(scip, &peekubs);
1510 SCIPfreeBufferArray(scip, &peeklbs);
1511 }
1512
1513 return SCIP_OKAY;
1514}
1515
1516
1517/** propagation method for a dynamic lexicographic reduction */
1518static
1520 SCIP* scip, /**< SCIP data structure */
1521 SCIP_LEXREDDATA* masterdata, /**< pointer to global data for lexicographic reduction propagator */
1522 LEXDATA* lexdata, /**< pointer to data for this permutation */
1523 NODEDEPTHBRANCHINDEX* nodedepthbranchindices, /**< array with (depth, index)-information per variable in rooted path to focus node */
1524 int nvarstotal, /**< length of nodedepthbranchindices array */
1525 SCIP_VAR** branchvars, /**< array populated with variables branched on */
1526 int nbranchvars, /**< number of elements in branchvars array */
1527 SCIP_Bool* infeasible, /**< pointer to store whether the problem is infeasible */
1528 int* nreductions /**< pointer to store the number of found domain reductions */
1529 )
1530{
1531 int* varorder;
1532 int nvarorder;
1533 int nvars;
1534
1535 assert( scip != NULL );
1536 assert( masterdata != NULL );
1537 assert( lexdata != NULL );
1538 assert( lexdata->isdynamic );
1539 assert( nodedepthbranchindices != NULL );
1540 assert( nvarstotal >= 0 );
1541 assert( branchvars != NULL );
1542 assert( nbranchvars >= 0 );
1543 assert( infeasible != NULL );
1544 assert( nreductions != NULL );
1545
1546 nvars = lexdata->nvars;
1547
1548 /* get variable order */
1549 SCIP_CALL( SCIPallocBufferArray(scip, &varorder, nvars) );
1550
1551 SCIP_CALL( getVarOrder(scip, masterdata, lexdata, nodedepthbranchindices, nvarstotal, branchvars, nbranchvars,
1552 varorder, &nvarorder, nvars) );
1553 assert( nvarorder >= 0 );
1554 assert( nvarorder <= nvars );
1555
1556 /* possibly propagate the constraint with this variable order */
1557 if ( nvarorder > 0 )
1558 {
1559 SCIP_CALL( propagateStaticLexred(scip, lexdata, varorder, nvarorder, infeasible, nreductions) );
1560 }
1561 SCIPfreeBufferArray(scip, &varorder);
1562
1563 return SCIP_OKAY;
1564}
1565
1566
1567/** propagation method for a dynamic lexicographic reduction */
1568static
1570 SCIP* scip, /**< SCIP data structure */
1571 SCIP_LEXREDDATA* masterdata, /**< pointer to global data for lexicographic reduction propagator */
1572 LEXDATA* lexdata, /**< pointer to data for this permutation */
1573 SCIP_Bool* infeasible, /**< pointer to store whether the problem is infeasible */
1574 int* nreductions /**< pointer to store the number of found domain reductions */
1575 )
1576{
1577 assert( scip != NULL );
1578 assert( masterdata != NULL );
1579 assert( lexdata != NULL );
1580 assert( ! lexdata->isdynamic );
1581 assert( infeasible != NULL );
1582 assert( nreductions != NULL );
1583
1584 /* skip trivial cases */
1585 if ( lexdata->nvars == 0 )
1586 return SCIP_OKAY;
1587
1588 /* propagate the constraint with this variable order */
1589 SCIP_CALL( propagateStaticLexred(scip, lexdata, NULL, lexdata->nvars, infeasible, nreductions) );
1590
1591 return SCIP_OKAY;
1592}
1593
1594
1595/** propagation method for applying dynamic lexicographic reduction for a single permutation */
1596static
1598 SCIP* scip, /**< SCIP data structure */
1599 SCIP_LEXREDDATA* masterdata, /**< pointer to global data for lexicographic reduction propagator */
1600 LEXDATA* lexdata, /**< pointer to data for this permutation */
1601 NODEDEPTHBRANCHINDEX* nodedepthbranchindices, /**< array with (depth, index)-information per variable in rooted path to focus node */
1602 int nvarstotal, /**< length of that array */
1603 SCIP_VAR** branchvars, /**< array populated with variables branched on */
1604 int nbranchvars, /**< number of elements in branchvars array */
1605 SCIP_Bool* infeasible, /**< pointer to store whether the problem is infeasible */
1606 int* nreductions /**< pointer to store the number of found domain reductions */
1607 )
1608{
1609 assert( scip != NULL );
1610 assert( masterdata != NULL );
1611 assert( lexdata != NULL );
1612 assert( nodedepthbranchindices != NULL || ! lexdata->isdynamic );
1613 assert( nvarstotal >= 0 || ! lexdata->isdynamic );
1614 assert( branchvars != NULL || ! lexdata->isdynamic );
1615 assert( nbranchvars >= 0 || ! lexdata->isdynamic );
1616 assert( infeasible != NULL );
1617 assert( nreductions != NULL );
1618
1619 *nreductions = 0;
1620 *infeasible = FALSE;
1621
1622 if ( lexdata->isdynamic )
1623 {
1625 nodedepthbranchindices, nvarstotal, branchvars, nbranchvars, infeasible, nreductions) );
1626 }
1627 else
1628 {
1629 SCIP_CALL( propagateLexredStatic(scip, masterdata, lexdata, infeasible, nreductions) );
1630 }
1631
1632 return SCIP_OKAY;
1633}
1634
1635
1636/** populates array with information of first variable change
1637 * @pre assuming nodedepthbranchindices is initially clean
1638 */
1639static
1641 SCIP* scip, /**< SCIP data structure */
1642 SCIP_LEXREDDATA* masterdata, /**< pointer to global data for lexicographic reduction propagator */
1643 NODEDEPTHBRANCHINDEX* nodedepthbranchindices, /**< array to populate */
1644 SCIP_VAR** branchvars, /**< array to populate with variables branched on */
1645 int* nbranchvars, /**< number of elements in branchvars array */
1646 SCIP_SHADOWTREE* shadowtree, /**< pointer to shadow tree structure */
1647 SCIP_NODE* focusnode, /**< focusnode to which the rooted path is evaluated */
1648 SCIP_Bool* inforesolved /**< pointer to store whether information is successfully resolved */
1649 )
1650{
1651 SCIP_SHADOWNODE* shadownode;
1652 SCIP_SHADOWNODE* shadowchild;
1653 int shadowdepth;
1654 SCIP_VAR* var;
1655 int varindex;
1656 int nlevelvars;
1657 int c;
1658 int i;
1659
1660 assert( scip != NULL );
1661 assert( masterdata != NULL );
1662 assert( masterdata->symvarmap != NULL );
1663 assert( masterdata->nsymvars >= 0 );
1664 assert( nodedepthbranchindices != NULL );
1665 assert( branchvars != NULL );
1666 assert( nbranchvars != NULL );
1667 assert( shadowtree != NULL );
1668 assert( focusnode != NULL );
1669 assert( inforesolved != NULL );
1670
1671 shadownode = SCIPshadowTreeGetShadowNode(shadowtree, focusnode);
1672
1673 if ( shadownode == NULL )
1674 {
1675 /* the arrays to fill are unchanged, so they remain clean */
1676 *inforesolved = FALSE;
1677 if ( !masterdata->treewarninggiven )
1678 {
1679 SCIPwarningMessage(scip, "Attempting lexicographic reduction on nodes not existing in the symmetry shadowtree"
1680 " (and suppressing future warnings)\n");
1681 masterdata->treewarninggiven = TRUE;
1682 }
1683 return SCIP_OKAY;
1684 }
1685 shadowdepth = SCIPnodeGetDepth(focusnode);
1686
1687 /* branchvars array is initially empty */
1688 *nbranchvars = 0;
1689
1690 /* We start looking one level lower, because we consider the branching decisions each time. */
1691 shadownode = shadownode->parent;
1692
1693 /* Now, walk from the leaf to the root. Each time look at all the children of the node considered,
1694 * and save the variable depth and index in the branching array. It is important to consider all children each time,
1695 * because we need to comply with the instance where in different branches it is branched on different variables.
1696 * This has to be consistent.
1697 */
1698 while (shadownode != NULL)
1699 {
1700 assert( shadowdepth > 0 );
1701 nlevelvars = 0;
1702 for (c = 0; c < shadownode->nchildren; ++c)
1703 {
1704 shadowchild = shadownode->children[c];
1705
1706 /* get the variables branched on, for each of the children (that's likely 1 variable each time) */
1707 for (i = 0; i < shadowchild->nbranchingdecisions; ++i)
1708 {
1709 var = shadowchild->branchingdecisions[i].var;
1710 assert( SCIPvarIsTransformed(var) );
1711
1712 varindex = SCIPhashmapGetImageInt(masterdata->symvarmap, var);
1713
1714 /* ignore variables that are irrelevant for lexicographic reduction */
1715 if ( varindex == INT_MAX )
1716 continue;
1717
1718 assert( varindex >= 0 );
1719 assert( varindex < masterdata->nsymvars );
1720
1721 /* var already in other child at this level? Continue */
1722 if ( nodedepthbranchindices[varindex].nodedepth == shadowdepth )
1723 continue;
1724
1725 /* the variable is either not seen (nodedepth == 0), or it is at a higher level (nodedepth > shadowdepth) */
1726 assert( nodedepthbranchindices[varindex].nodedepth == 0 ||
1727 nodedepthbranchindices[varindex].nodedepth > shadowdepth);
1728
1729 if ( nodedepthbranchindices[varindex].nodedepth == 0 )
1730 {
1731 /* variable is not featured in branchvars, yet */
1732 assert( *nbranchvars < masterdata->nsymvars );
1733 branchvars[(*nbranchvars)++] = var;
1734 }
1735
1736 /* var is not seen on this level yet. Update */
1737 nodedepthbranchindices[varindex].nodedepth = shadowdepth;
1738 nodedepthbranchindices[varindex].index = nlevelvars++;
1739 }
1740 }
1741
1742 /* prepare for the next iteration */
1743 shadownode = shadownode->parent;
1744 --shadowdepth;
1745 }
1746 /* In the last iteration, we handled the branching decisions at the root node, so shadowdepth must have value 0. */
1747 assert( shadowdepth == 0 );
1748
1749 *inforesolved = TRUE;
1750 return SCIP_OKAY;
1751}
1752
1753
1754/** cleans nodedepthbranchindices array */
1755static
1757 SCIP* scip, /**< SCIP data structure */
1758 SCIP_LEXREDDATA* masterdata, /**< pointer to global data for lexicographic reduction propagator */
1759 NODEDEPTHBRANCHINDEX* nodedepthbranchindices, /**< array populated by nodedepthbranchindices to clean */
1760 SCIP_VAR** branchvars, /**< array populated with variables branched on */
1761 int* nbranchvars, /**< number of elements in branchvars array */
1762 SCIP_SHADOWTREE* shadowtree, /**< pointer to shadow tree structure */
1763 SCIP_NODE* focusnode /**< focusnode to which the rooted path is evaluated */
1764 )
1765{
1766 /* undo the operations from shadowtreeFillNodeDepthBranchIndices, which makes nodedepthbranchindices clean */
1767 SCIP_SHADOWNODE* shadownode;
1768 SCIP_SHADOWNODE* shadowchild;
1769#ifndef NDEBUG
1770 int shadowdepth;
1771#endif
1772 SCIP_VAR* var;
1773 int varindex;
1774 int c;
1775 int i;
1776
1777 assert( scip != NULL );
1778 assert( masterdata != NULL );
1779 assert( masterdata->symvarmap != NULL );
1780 assert( masterdata->nsymvars >= 0 );
1781 assert( nodedepthbranchindices != NULL );
1782 assert( branchvars != NULL );
1783 assert( nbranchvars != NULL );
1784 assert( *nbranchvars >= 0 );
1785 assert( *nbranchvars <= masterdata->nsymvars );
1786 assert( shadowtree != NULL );
1787 assert( focusnode != NULL );
1788
1789 shadownode = SCIPshadowTreeGetShadowNode(shadowtree, focusnode);
1790#ifndef NDEBUG
1791 shadowdepth = SCIPnodeGetDepth(focusnode);
1792#endif
1793
1794 /* clean nbranchvars array */
1795 while ( *nbranchvars > 0 )
1796 branchvars[--(*nbranchvars)] = NULL;
1797 assert( *nbranchvars == 0 );
1798
1799 /* we start looking one level lower, because we consider the branching decisions each time */
1800 /* coverity[dereference] */
1801 shadownode = shadownode->parent;
1802
1803 /* now, walk from the leaf to the root. Each time look at all the children of the node considered,
1804 * and save the variable depth and index in the branching array. It is important to consider all children each time,
1805 * because we need to comply with the instance where in different branches it is branched on different variables.
1806 * This has to be consistent.
1807 */
1808 while (shadownode != NULL)
1809 {
1810#ifndef NDEBUG
1811 assert( shadowdepth > 0 );
1812#endif
1813 for (c = 0; c < shadownode->nchildren; ++c)
1814 {
1815 shadowchild = shadownode->children[c];
1816 /* get the variables branched on, for each of the children (that's likely 1 variable each time) */
1817 for (i = 0; i < shadowchild->nbranchingdecisions; ++i)
1818 {
1819 var = shadowchild->branchingdecisions[i].var;
1820 /* ignore variables not relevant for lexicographic reduction */
1821 if ( !SCIPhashmapExists(masterdata->symvarmap, (void*) var) )
1822 continue;
1823 assert( SCIPhashmapExists(masterdata->symvarmap, (void*) var) );
1824
1825 varindex = SCIPhashmapGetImageInt(masterdata->symvarmap, var);
1826 assert( varindex >= 0 );
1827 assert( varindex < masterdata->nsymvars );
1828
1829 /* reset */
1830 nodedepthbranchindices[varindex].index = 0;
1831 nodedepthbranchindices[varindex].nodedepth = 0;
1832 }
1833 }
1834
1835 /* prepare for the next iteration */
1836 shadownode = shadownode->parent;
1837#ifndef NDEBUG
1838 --shadowdepth;
1839#endif
1840 }
1841 /* In the last iteration, we handled the branching decisions at the root node, so shadowdepth must have value 0. */
1842 assert( shadowdepth == 0 );
1843
1844 return SCIP_OKAY;
1845}
1846
1847
1848/*
1849 * Interface methods
1850 */
1851
1852
1853/** prints lexicographic reduction propagation data */
1855 SCIP* scip, /**< SCIP data structure */
1856 SCIP_LEXREDDATA* masterdata, /**< pointer to global data for lexicographic reduction propagator */
1857 int* nred, /**< total number of reductions applied */
1858 int* ncutoff /**< total number of cutoffs applied */
1859 )
1860{
1861 assert( scip != NULL );
1862 assert( masterdata != NULL );
1863 assert( nred != NULL );
1864
1865 *nred = masterdata->nred;
1866 *ncutoff = masterdata->ncutoff;
1867
1868 return SCIP_OKAY;
1869}
1870
1871/** prints lexicographic reduction propagation data */
1873 SCIP* scip, /**< SCIP data structure */
1874 SCIP_LEXREDDATA* masterdata /**< pointer to global data for lexicographic reduction propagator */
1875 )
1876{
1877 int i;
1878
1879 assert( scip != NULL );
1880 assert( masterdata != NULL );
1881
1882 if ( masterdata->nlexdatas == 0 )
1883 {
1884 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, " lexicographic reduction: no permutations\n");
1885 return SCIP_OKAY;
1886 }
1887
1888 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, " lexicographic reduction: %4d permutations with support sizes ",
1889 masterdata->nlexdatas);
1890
1891 for (i = 0; i < masterdata->nlexdatas; ++i)
1892 {
1893 if ( i > 0 )
1895 SCIPverbMessage(scip, SCIP_VERBLEVEL_HIGH, NULL, "%d", masterdata->lexdatas[i]->nvars);
1896 }
1897
1899
1900 return SCIP_OKAY;
1901}
1902
1903
1904/** applies lexicographic reduction propagation */
1906 SCIP* scip, /**< SCIP data structure */
1907 SCIP_LEXREDDATA* masterdata, /**< pointer to global data for lexicographic reduction propagator */
1908 SCIP_Bool* infeasible, /**< pointer to store whether infeasibility is found */
1909 int* nred, /**< pointer to store the number of domain reductions */
1910 SCIP_Bool* didrun /**< a global pointer maintaining if any symmetry propagator has run
1911 * only set this to TRUE when a reduction is found, never set to FALSE */
1912 )
1913{
1914 int nlocalred;
1915 int p;
1916 SCIP_SHADOWTREE* shadowtree = NULL;
1917 SCIP_NODE* focusnode = NULL;
1919 SCIP_VAR** branchvars = NULL;
1920 int nbranchvars = 0;
1921 SCIP_Bool inforesolved;
1922
1923 assert( scip != NULL );
1924 assert( masterdata != NULL );
1925 assert( (masterdata->lexdatas == NULL) == (masterdata->nlexdatas == 0) );
1926 assert( masterdata->nlexdatas >= 0 );
1927 assert( masterdata->nlexdatas <= masterdata->maxnlexdatas );
1928 assert( infeasible != NULL );
1929 assert( nred != NULL );
1930 assert( didrun != NULL );
1931
1932 *infeasible = FALSE;
1933 *nred = 0;
1934 *didrun = FALSE;
1935
1936 /* early termination */
1937 if ( masterdata->nlexdatas == 0 )
1938 return SCIP_OKAY;
1939
1940 /* compute the variable ordering based on the branching decisions
1941 * of the shadowtree if there exist dynamic permutations
1942 */
1943 if ( masterdata->hasdynamicperm )
1944 {
1945 assert( masterdata->shadowtreeeventhdlr != NULL );
1946 shadowtree = SCIPgetShadowTree(masterdata->shadowtreeeventhdlr);
1947 focusnode = SCIPgetFocusNode(scip);
1948
1949 /* fill the node-depth-branch-indices structure
1950 *
1951 * this is an array that maps every variable index to (depth, index) = (0, 0) if the variable is not branched on,
1952 * or (depth, index) is the depth (branching at root node: depth 1) and variable index when it was branched thereon.
1953 * For individual dynamic lexicographic reductions, we use this ordering the following way:
1954 * 1. Choose those variables that have (depth, index) with depth > 0 (these)
1955 * 2. Sort by depth, then by index, in increasing order.
1956 */
1958 SCIP_CALL( SCIPallocCleanBufferArray(scip, &branchvars, masterdata->nsymvars) );
1960 branchvars, &nbranchvars, shadowtree, focusnode, &inforesolved) );
1961
1962 /* if the information cannot be resolved because a node is missing from the shadowtree, do not propagate */
1963 if ( !inforesolved )
1964 {
1965 /* shadowtreeFillNodeDepthBranchIndices keeps the input arrays clean if it terminates early */
1966 SCIPfreeCleanBufferArray(scip, &branchvars);
1968 return SCIP_OKAY;
1969 }
1970 /* ... Do everything using this nodedepthbranchindices structure */
1971 }
1972
1973 if ( nbranchvars > 0 || ! masterdata->hasdynamicperm )
1974 {
1975 /* apply lexicographic reduction propagator to all lexdata objects */
1976 for (p = 0; p < masterdata->nlexdatas; ++p)
1977 {
1978 assert( masterdata->lexdatas[p] != NULL );
1979
1981 nodedepthbranchindices, masterdata->nsymvars, branchvars, nbranchvars, infeasible, &nlocalred) );
1982
1983 /* keep track of the total number of fixed vars */
1984 *nred += nlocalred;
1985
1986 /* a symmetry propagator has ran, so set didrun to TRUE */
1987 *didrun = TRUE;
1988
1989 /* stop if we find infeasibility */
1990 if ( *infeasible )
1991 break;
1992 }
1993
1994 /* maintain total number of reductions made */
1995 masterdata->nred += *nred;
1996 if ( *infeasible )
1997 ++masterdata->ncutoff;
1998 }
1999
2000 /* possibly clean the node-depth-branch-indices structure */
2001 if ( masterdata->hasdynamicperm )
2002 {
2003 assert( shadowtree != NULL );
2004 assert( focusnode != NULL );
2006 branchvars, &nbranchvars, shadowtree, focusnode) );
2007 assert( nbranchvars == 0 );
2008 SCIPfreeCleanBufferArray(scip, &branchvars);
2010 }
2011
2012 return SCIP_OKAY;
2013}
2014
2015
2016/** adds permutation for lexicographic reduction propagation */
2018 SCIP* scip, /**< SCIP data structure */
2019 SCIP_LEXREDDATA* masterdata, /**< pointer to global data for lexicographic reduction propagator */
2020 SCIP_VAR** permvars, /**< variable array of the permutation */
2021 int npermvars, /**< number of variables in that array */
2022 int* perm, /**< permutation */
2023 SYM_SYMTYPE symtype, /**< type of symmetries in perm */
2024 SCIP_Real* permvardomaincenter, /**< array containing center point for each variable domain */
2025 SCIP_Bool usedynamicorder, /**< whether a dynamic variable order shall be used */
2026 SCIP_Bool* success /**< to store whether the component is successfully added */
2027 )
2028{
2029 assert( scip != NULL );
2030 assert( masterdata != NULL );
2031 assert( (masterdata->lexdatas == NULL) == (masterdata->nlexdatas == 0) );
2032 assert( masterdata->nlexdatas >= 0 );
2033 assert( masterdata->nlexdatas <= masterdata->maxnlexdatas );
2034 assert( masterdata->shadowtreeeventhdlr != NULL );
2035 assert( permvars != NULL );
2036 assert( npermvars > 0 );
2037 assert( perm != NULL );
2038
2039 if ( symtype != SYM_SYMTYPE_PERM && symtype != SYM_SYMTYPE_SIGNPERM )
2040 {
2041 *success = FALSE;
2042 return SCIP_OKAY;
2043 }
2044 assert( symtype == SYM_SYMTYPE_PERM || permvardomaincenter != NULL );
2045 assert( SCIPisTransformed(scip) );
2046
2047 /* resize component array if needed */
2048 if ( masterdata->nlexdatas == masterdata->maxnlexdatas )
2049 {
2050 int newsize;
2051
2052 newsize = SCIPcalcMemGrowSize(scip, masterdata->nlexdatas + 1);
2053 assert( newsize >= 0 );
2054
2055 if ( masterdata->nlexdatas == 0 )
2056 {
2057 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &masterdata->lexdatas, newsize) );
2058 }
2059 else
2060 {
2062 masterdata->maxnlexdatas, newsize) );
2063 }
2064
2065 masterdata->maxnlexdatas = newsize;
2066 }
2067
2068 /* prepare lexdatas */
2069 SCIP_CALL( lexdataCreate(scip, masterdata, &masterdata->lexdatas[masterdata->nlexdatas],
2070 permvars, npermvars, perm, symtype, permvardomaincenter, usedynamicorder, success) );
2071
2072 /* if not successfully added, undo increasing the counter */
2073 if ( *success )
2074 ++masterdata->nlexdatas;
2075
2076 return SCIP_OKAY;
2077}
2078
2079
2080/** resets lexicographic reduction propagation (removes all permutations) */
2082 SCIP* scip, /**< SCIP data structure */
2083 SCIP_LEXREDDATA* masterdata /**< pointer to global data for lexicographic reduction propagator */
2084 )
2085{
2086 assert( scip != NULL );
2087 assert( masterdata != NULL );
2088 assert( (masterdata->lexdatas == NULL) == (masterdata->nlexdatas == 0) );
2089 assert( masterdata->nlexdatas >= 0 );
2090 assert( masterdata->nlexdatas <= masterdata->maxnlexdatas );
2091 assert( masterdata->shadowtreeeventhdlr != NULL );
2092
2093 while ( masterdata->nlexdatas > 0 )
2094 {
2095 SCIP_CALL( lexdataFree(scip, &(masterdata->lexdatas[--masterdata->nlexdatas])) );
2096 }
2097 assert( masterdata->nlexdatas == 0 );
2098
2099 SCIPfreeBlockMemoryArrayNull(scip, &masterdata->lexdatas, masterdata->maxnlexdatas);
2100 masterdata->lexdatas = NULL;
2101 masterdata->maxnlexdatas = 0;
2102
2103 assert( masterdata->nsymvars >= 0 );
2104 assert( (masterdata->symvarmap == NULL) == (masterdata->nsymvars == 0) );
2105 if ( masterdata->symvarmap != NULL )
2106 {
2107 SCIPhashmapFree(&masterdata->symvarmap);
2108 masterdata->symvarmap = NULL;
2109 masterdata->nsymvars = 0;
2110 }
2111
2112 masterdata->hasdynamicperm = FALSE;
2113
2114 return SCIP_OKAY;
2115}
2116
2117
2118/** frees lexicographic reduction data */
2120 SCIP* scip, /**< SCIP data structure */
2121 SCIP_LEXREDDATA** masterdata /**< pointer to global data for lexicographic reduction propagator */
2122 )
2123{
2124 assert( scip != NULL );
2125 assert( masterdata != NULL );
2126 assert( *masterdata != NULL );
2127
2129 assert( (*masterdata)->lexdatas == NULL );
2130 assert( (*masterdata)->symvarmap == NULL );
2131
2133 return SCIP_OKAY;
2134}
2135
2136
2137/** initializes structures needed for lexicographic reduction propagation
2138 *
2139 *
2140 * This is only done exactly once.
2141 */
2143 SCIP* scip, /**< SCIP data structure */
2144 SCIP_LEXREDDATA** masterdata, /**< pointer to global data for lexicographic reduction propagator */
2145 SCIP_EVENTHDLR* shadowtreeeventhdlr /**< pointer to the shadow tree eventhdlr */
2146 )
2147{
2148 assert( scip != NULL );
2149 assert( masterdata != NULL );
2150 assert( shadowtreeeventhdlr != NULL );
2151
2152 SCIP_CALL( SCIPcheckStage(scip, "SCIPincludeLexicographicReduction", TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,
2154
2156
2157 (*masterdata)->shadowtreeeventhdlr = shadowtreeeventhdlr;
2158 (*masterdata)->symvarmap = NULL;
2159 (*masterdata)->nsymvars = 0;
2160 (*masterdata)->lexdatas = NULL;
2161 (*masterdata)->nlexdatas = 0;
2162 (*masterdata)->maxnlexdatas = 0;
2163 (*masterdata)->nred = 0;
2164 (*masterdata)->ncutoff = 0;
2165 (*masterdata)->hasdynamicperm = FALSE;
2166 (*masterdata)->treewarninggiven = FALSE;
2167
2168 return SCIP_OKAY;
2169}
methods for debugging
#define SCIPcheckStage(scip, method, init, problem, transforming, transformed, initpresolve, presolving, exitpresolve, presolved, initsolve, solving, solved, exitsolve, freetrans, freescip)
Definition: debug.h:364
#define NULL
Definition: def.h:248
#define SCIP_Bool
Definition: def.h:91
#define SCIP_Real
Definition: def.h:156
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define SCIP_CALL_ABORT(x)
Definition: def.h:334
#define SCIP_CALL(x)
Definition: def.h:355
SCIP_RETCODE SCIPactivateShadowTree(SCIP *scip, SCIP_EVENTHDLR *eventhdlr)
SCIP_SHADOWTREE * SCIPgetShadowTree(SCIP_EVENTHDLR *eventhdlr)
SCIP_SHADOWNODE * SCIPshadowTreeGetShadowNode(SCIP_SHADOWTREE *shadowtree, SCIP_NODE *node)
SCIP_Bool SCIPisTransformed(SCIP *scip)
Definition: scip_general.c:647
void SCIPhashmapFree(SCIP_HASHMAP **hashmap)
Definition: misc.c:3095
int SCIPhashmapGetImageInt(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3304
SCIP_RETCODE SCIPhashmapCreate(SCIP_HASHMAP **hashmap, BMS_BLKMEM *blkmem, int mapsize)
Definition: misc.c:3061
SCIP_Bool SCIPhashmapExists(SCIP_HASHMAP *hashmap, void *origin)
Definition: misc.c:3466
SCIP_RETCODE SCIPhashmapInsertInt(SCIP_HASHMAP *hashmap, void *origin, int image)
Definition: misc.c:3179
void SCIPverbMessage(SCIP *scip, SCIP_VERBLEVEL msgverblevel, FILE *file, const char *formatstr,...)
Definition: scip_message.c:225
void SCIPwarningMessage(SCIP *scip, const char *formatstr,...)
Definition: scip_message.c:120
#define SCIPfreeCleanBufferArray(scip, ptr)
Definition: scip_mem.h:146
#define SCIPallocCleanBufferArray(scip, ptr, num)
Definition: scip_mem.h:142
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
BMS_BLKMEM * SCIPblkmem(SCIP *scip)
Definition: scip_mem.c:57
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:139
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
#define SCIPreallocBlockMemoryArray(scip, ptr, oldnum, newnum)
Definition: scip_mem.h:99
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define SCIPfreeBlockMemoryArrayNull(scip, ptr, num)
Definition: scip_mem.h:111
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
int SCIPnodeGetDepth(SCIP_NODE *node)
Definition: tree.c:8493
SCIP_Bool SCIPsymGE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: symmetry.c:2350
SCIP_Bool SCIPsymEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: symmetry.c:2278
SCIP_Bool SCIPsymGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: symmetry.c:2426
SCIP_Bool SCIPsymLE(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
Definition: symmetry.c:2312
SCIP_Bool SCIPisIntegral(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_NODE * SCIPgetFocusNode(SCIP *scip)
Definition: scip_tree.c:72
SCIP_RETCODE SCIPtightenVarLb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:6401
SCIP_Real SCIPvarGetUbLocal(SCIP_VAR *var)
Definition: var.c:24268
SCIP_Bool SCIPvarIsTransformed(SCIP_VAR *var)
Definition: var.c:23430
SCIP_RETCODE SCIPtightenVarUb(SCIP *scip, SCIP_VAR *var, SCIP_Real newbound, SCIP_Bool force, SCIP_Bool *infeasible, SCIP_Bool *tightened)
Definition: scip_var.c:6651
const char * SCIPvarGetName(SCIP_VAR *var)
Definition: var.c:23267
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1887
SCIP_Bool SCIPvarIsIntegral(SCIP_VAR *var)
Definition: var.c:23490
SCIP_Real SCIPvarGetLbLocal(SCIP_VAR *var)
Definition: var.c:24234
SCIP_RETCODE SCIPmarkDoNotMultaggrVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:11057
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1853
void SCIPsortInd(int *indarray, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
memory allocation routines
public methods for managing constraints
public methods for message output
#define SCIPdebugMessage
Definition: pub_message.h:96
public methods for problem variables
SCIP callable library.
public methods for branching rule plugins and branching
public methods for conflict handler plugins and conflict analysis
public methods for constraint handler plugins and constraints
public methods for problem copies
public methods for cuts and aggregation rows
general public methods
public methods for the LP relaxation, rows and columns
public methods for memory management
public methods for message handling
public methods for numerical tolerances
public methods for SCIP parameter handling
public methods for global and local (sub)problems
public methods for the probing mode
public methods for solutions
public methods for SCIP variables
SCIP_Bool isdynamic
SCIP_Real * vardomaincenter
SCIP_HASHMAP * varmap
SYM_SYMTYPE symtype
SCIP_VAR ** vars
struct SCIP_ShadowNode ** children
SCIP_SHADOWBOUNDUPDATE * branchingdecisions
struct SCIP_ShadowNode * parent
NODEDEPTHBRANCHINDEX * nodedepthbranchindices
datastructures for block memory pools and memory buffers
SCIP main data structure.
data structures for branch and bound tree
datastructures for problem variables
methods for handling symmetries
static SCIP_Bool canGTshiftedVars(SCIP *scip, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real shift1, SCIP_Real shift2, SCIP_Bool isnegated, SCIP_Bool peekmode, int varidx1, int varidx2, SCIP_Real *peeklbs, SCIP_Real *peekubs, SCIP_Bool *peekbdset)
static SCIP_RETCODE propagateLowerBoundVar(SCIP *scip, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real center1, SCIP_Real center2, SCIP_Bool isnegated, SCIP_Bool *infeasible, int *nreductions, SCIP_Bool peekmode, int varidx1, int varidx2, SCIP_Real *peeklbs, SCIP_Real *peekubs, SCIP_Bool *peekbdset)
static SCIP_RETCODE propagateVariablePair(SCIP *scip, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real center1, SCIP_Real center2, SCIP_Bool isnegated, SCIP_Bool *infeasible, int *nreductions, SCIP_Bool peekmode, int varidx1, int varidx2, SCIP_Real *peeklbs, SCIP_Real *peekubs, SCIP_Bool *peekbdset)
static SCIP_RETCODE propagateLexredDynamic(SCIP *scip, SCIP_LEXREDDATA *masterdata, LEXDATA *lexdata, NODEDEPTHBRANCHINDEX *nodedepthbranchindices, int nvarstotal, SCIP_VAR **branchvars, int nbranchvars, SCIP_Bool *infeasible, int *nreductions)
SCIP_RETCODE SCIPlexicographicReductionPropagate(SCIP *scip, SCIP_LEXREDDATA *masterdata, SCIP_Bool *infeasible, int *nred, SCIP_Bool *didrun)
static SCIP_DECL_SORTINDCOMP(sortbynodedepthbranchindices)
static SCIP_Bool alwaysLTshiftedVars(SCIP *scip, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real shift1, SCIP_Real shift2, SCIP_Bool isnegated, SCIP_Bool peekmode, int varidx1, int varidx2, SCIP_Real *peeklbs, SCIP_Real *peekubs, SCIP_Bool *peekbdset)
SCIP_RETCODE SCIPlexicographicReductionGetStatistics(SCIP *scip, SCIP_LEXREDDATA *masterdata, int *nred, int *ncutoff)
static SCIP_RETCODE peekStaticLexredIsFeasible(SCIP *scip, LEXDATA *lexdata, int *varorder, int nselvars, int fixi, int fixj, int fixrow, SCIP_Real fixvaluei, SCIP_Real fixvaluej, SCIP_Bool *peekfeasible, SCIP_Real *peeklbs, SCIP_Real *peekubs, SCIP_Bool *peekbdset)
SCIP_RETCODE SCIPlexicographicReductionReset(SCIP *scip, SCIP_LEXREDDATA *masterdata)
static SCIP_RETCODE propagateUpperBoundSymVar(SCIP *scip, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Real center1, SCIP_Real center2, SCIP_Bool isnegated, SCIP_Bool *infeasible, int *nreductions, SCIP_Bool peekmode, int varidx1, int varidx2, SCIP_Real *peeklbs, SCIP_Real *peekubs, SCIP_Bool *peekbdset)
static SCIP_RETCODE getVarBounds(SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Bool peekmode, int varidx1, int varidx2, SCIP_Real *peeklbs, SCIP_Real *peekubs, SCIP_Bool *peekbdset, SCIP_Real *lb1, SCIP_Real *ub1, SCIP_Real *lb2, SCIP_Real *ub2)
SCIP_RETCODE SCIPlexicographicReductionPrintStatistics(SCIP *scip, SCIP_LEXREDDATA *masterdata)
static SCIP_RETCODE propagateLexredStatic(SCIP *scip, SCIP_LEXREDDATA *masterdata, LEXDATA *lexdata, SCIP_Bool *infeasible, int *nreductions)
static SCIP_RETCODE lexdataFree(SCIP *scip, LEXDATA **lexdata)
static SCIP_RETCODE getVarOrder(SCIP *scip, SCIP_LEXREDDATA *masterdata, LEXDATA *lexdata, NODEDEPTHBRANCHINDEX *nodedepthbranchindices, int nvarstotal, SCIP_VAR **branchvars, int nbranchvars, int *varorder, int *nselvars, int maxnselvars)
static SCIP_RETCODE shadowtreeUndoNodeDepthBranchIndices(SCIP *scip, SCIP_LEXREDDATA *masterdata, NODEDEPTHBRANCHINDEX *nodedepthbranchindices, SCIP_VAR **branchvars, int *nbranchvars, SCIP_SHADOWTREE *shadowtree, SCIP_NODE *focusnode)
SCIP_RETCODE SCIPlexicographicReductionFree(SCIP *scip, SCIP_LEXREDDATA **masterdata)
static SCIP_RETCODE propagateLexicographicReductionPerm(SCIP *scip, SCIP_LEXREDDATA *masterdata, LEXDATA *lexdata, NODEDEPTHBRANCHINDEX *nodedepthbranchindices, int nvarstotal, SCIP_VAR **branchvars, int nbranchvars, SCIP_Bool *infeasible, int *nreductions)
SCIP_RETCODE SCIPlexicographicReductionAddPermutation(SCIP *scip, SCIP_LEXREDDATA *masterdata, SCIP_VAR **permvars, int npermvars, int *perm, SYM_SYMTYPE symtype, SCIP_Real *permvardomaincenter, SCIP_Bool usedynamicorder, SCIP_Bool *success)
static SCIP_RETCODE propagateSelfReflectionVar(SCIP *scip, SCIP_VAR *var, SCIP_Real center, SCIP_Bool *infeasible, int *nreductions, SCIP_Bool peekmode, int varidx, SCIP_Real *peeklbs, SCIP_Real *peekubs, SCIP_Bool *peekbdset)
static SCIP_RETCODE propagateStaticLexred(SCIP *scip, LEXDATA *lexdata, int *varorder, int nselvars, SCIP_Bool *infeasible, int *nreductions)
static SCIP_RETCODE shadowtreeFillNodeDepthBranchIndices(SCIP *scip, SCIP_LEXREDDATA *masterdata, NODEDEPTHBRANCHINDEX *nodedepthbranchindices, SCIP_VAR **branchvars, int *nbranchvars, SCIP_SHADOWTREE *shadowtree, SCIP_NODE *focusnode, SCIP_Bool *inforesolved)
SCIP_RETCODE SCIPincludeLexicographicReduction(SCIP *scip, SCIP_LEXREDDATA **masterdata, SCIP_EVENTHDLR *shadowtreeeventhdlr)
static SCIP_RETCODE lexdataCreate(SCIP *scip, SCIP_LEXREDDATA *masterdata, LEXDATA **lexdata, SCIP_VAR *const *vars, int nvars, int *perm, SYM_SYMTYPE symtype, SCIP_Real *permvardomaincenter, SCIP_Bool usedynamicorder, SCIP_Bool *success)
static int varOrderGetIndex(int *varorder, int pos)
methods for handling symmetries by dynamic lexicographic ordering reduction
struct SCIP_LexRedData SCIP_LEXREDDATA
@ SCIP_VERBLEVEL_HIGH
Definition: type_message.h:61
@ SCIP_OKAY
Definition: type_retcode.h:42
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
enum SYM_Symtype SYM_SYMTYPE
Definition: type_symmetry.h:64
@ SYM_SYMTYPE_SIGNPERM
Definition: type_symmetry.h:62
@ SYM_SYMTYPE_PERM
Definition: type_symmetry.h:61
type definitions for problem variables