Scippy

SCIP

Solving Constraint Integer Programs

symmetry_graph.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_graph.c
26 * @ingroup OTHER_CFILES
27 * @brief methods for dealing with symmetry detection graphs
28 * @author Christopher Hojny
29 */
30
31/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
32
33#include "scip/symmetry.h"
34#include "scip/symmetry_graph.h"
35#include "scip/scip.h"
36#include "scip/misc.h"
39
40
41
42/** creates and initializes a symmetry detection graph with memory for the given number of nodes and edges
43 *
44 * @note at some point, the graph needs to be freed!
45 */
47 SCIP* scip, /**< SCIP data structure */
48 SYM_SYMTYPE symtype, /**< type of symmetries encoded in graph */
49 SYM_GRAPH** graph, /**< pointer to hold symmetry detection graph */
50 SCIP_VAR** symvars, /**< variables used in symmetry detection */
51 int nsymvars, /**< number of variables used in symmetry detection */
52 int nopnodes, /**< number of operator nodes */
53 int nvalnodes, /**< number of value nodes */
54 int nconsnodes, /**< number of constraint nodes */
55 int nedges /**< number of edges */
56 )
57{
58 int nnodes;
59
60 assert(scip != NULL);
61 assert(graph != NULL);
62 assert(symvars != NULL);
63 assert(nopnodes >= 0);
64 assert(nvalnodes >= 0);
65 assert(nconsnodes >= 0);
66 assert(nedges >= 0);
67
68 nnodes = nopnodes + nvalnodes + nconsnodes;
69
71 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*graph)->nodetypes, nnodes) );
72 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*graph)->nodeinfopos, nnodes) );
73 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*graph)->ops, nopnodes) );
74 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*graph)->vals, nvalnodes) );
75 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*graph)->conss, nconsnodes) );
76 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*graph)->lhs, nconsnodes) );
77 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*graph)->rhs, nconsnodes) );
78 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*graph)->edgefirst, nedges) );
79 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*graph)->edgesecond, nedges) );
80 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*graph)->edgevals, nedges) );
81 SCIP_CALL( SCIPallocClearBlockMemoryArray(scip, &(*graph)->isfixedvar, nsymvars) );
82
83 (*graph)->nnodes = 0;
84 (*graph)->maxnnodes = nnodes;
85 (*graph)->nopnodes = 0;
86 (*graph)->maxnopnodes = nopnodes;
87 (*graph)->nvalnodes = 0;
88 (*graph)->maxnvalnodes = nvalnodes;
89 (*graph)->nconsnodes = 0;
90 (*graph)->maxnconsnodes = nconsnodes;
91 (*graph)->islocked = FALSE;
92 (*graph)->nedges = 0;
93 (*graph)->maxnedges = nedges;
94 (*graph)->symvars = symvars;
95 (*graph)->nsymvars = nsymvars;
96 (*graph)->nvarcolors = -1;
97 (*graph)->uniqueedgetype = FALSE;
98 (*graph)->symtype = symtype;
99 (*graph)->infinity = SCIPinfinity(scip);
100 (*graph)->consnodeperm = NULL;
101
102 /* to avoid reallocation, allocate memory for colors later */
103 (*graph)->varcolors = NULL;
104 (*graph)->opcolors = NULL;
105 (*graph)->valcolors = NULL;
106 (*graph)->conscolors = NULL;
107 (*graph)->edgecolors = NULL;
108
109 return SCIP_OKAY;
110}
111
112/** frees a symmetry detection graph */
114 SCIP* scip, /**< SCIP data structure */
115 SYM_GRAPH** graph /**< pointer to symmetry detection graph */
116 )
117{
118 assert(scip != NULL);
119 assert(graph != NULL);
120
121 SCIPfreeBlockMemoryArrayNull(scip, &(*graph)->edgecolors, (*graph)->nedges);
122 SCIPfreeBlockMemoryArrayNull(scip, &(*graph)->conscolors, (*graph)->nconsnodes);
123 SCIPfreeBlockMemoryArrayNull(scip, &(*graph)->valcolors, (*graph)->nvalnodes);
124 SCIPfreeBlockMemoryArrayNull(scip, &(*graph)->opcolors, (*graph)->nopnodes);
125 switch( (*graph)->symtype )
126 {
127 case SYM_SYMTYPE_PERM:
128 SCIPfreeBlockMemoryArrayNull(scip, &(*graph)->varcolors, (*graph)->nsymvars);
129 break;
130 default:
131 assert((*graph)->symtype == SYM_SYMTYPE_SIGNPERM);
132 SCIPfreeBlockMemoryArrayNull(scip, &(*graph)->varcolors, 2 * (*graph)->nsymvars);
133 } /*lint !e788*/
134
135 SCIPfreeBlockMemoryArrayNull(scip, &(*graph)->consnodeperm, (*graph)->nconsnodes);
136 SCIPfreeBlockMemoryArray(scip, &(*graph)->isfixedvar, (*graph)->nsymvars);
137 SCIPfreeBlockMemoryArray(scip, &(*graph)->edgevals, (*graph)->maxnedges);
138 SCIPfreeBlockMemoryArray(scip, &(*graph)->edgesecond, (*graph)->maxnedges);
139 SCIPfreeBlockMemoryArray(scip, &(*graph)->edgefirst, (*graph)->maxnedges);
140 SCIPfreeBlockMemoryArray(scip, &(*graph)->rhs, (*graph)->maxnconsnodes);
141 SCIPfreeBlockMemoryArray(scip, &(*graph)->lhs, (*graph)->maxnconsnodes);
142 SCIPfreeBlockMemoryArray(scip, &(*graph)->conss, (*graph)->maxnconsnodes);
143 SCIPfreeBlockMemoryArray(scip, &(*graph)->vals, (*graph)->maxnvalnodes);
144 SCIPfreeBlockMemoryArray(scip, &(*graph)->ops, (*graph)->maxnopnodes);
145 SCIPfreeBlockMemoryArray(scip, &(*graph)->nodeinfopos, (*graph)->maxnnodes);
146 SCIPfreeBlockMemoryArray(scip, &(*graph)->nodetypes, (*graph)->maxnnodes);
148
149 return SCIP_OKAY;
150}
151
152/** clears data of symmetry detection graph */
154 SCIP* scip, /**< SCIP data structure */
155 SYM_GRAPH* graph, /**< symmetry detection graph */
156 SCIP_VAR** symvars, /**< variables used in symmetry detection */
157 int nsymvars, /**< number of variables used in symmetry detection */
158 SYM_SYMTYPE symtype /**< type of symmetries encoded in graph */
159 )
160{
161 assert(scip != NULL);
162 assert(graph != NULL);
163
164 graph->nnodes = 0;
165 graph->nopnodes = 0;
166 graph->nvalnodes = 0;
167 graph->nconsnodes = 0;
168 graph->islocked = FALSE;
169 graph->nedges = 0;
170 graph->symvars = symvars;
171 graph->nsymvars = nsymvars;
172 graph->nvarcolors = -1;
173 graph->uniqueedgetype = FALSE;
174 graph->symtype = symtype;
175 graph->infinity = SCIPinfinity(scip);
177 graph->consnodeperm = NULL;
178
183 switch( graph->symtype )
184 {
185 case SYM_SYMTYPE_PERM:
187 break;
188 default:
189 assert(graph->symtype == SYM_SYMTYPE_SIGNPERM);
191 } /*lint !e788*/
192
193 graph->opcolors = NULL;
194 graph->valcolors = NULL;
195 graph->conscolors = NULL;
196 graph->edgecolors = NULL;
197 graph->varcolors = NULL;
198
199 return SCIP_OKAY;
200}
201
202/** copies an existing graph and changes variable nodes according to a permutation */
204 SCIP* scip, /**< SCIP data structure */
205 SYM_GRAPH** graph, /**< pointer to hold copy of symmetry detection graph */
206 SYM_GRAPH* origgraph, /**< graph to be copied */
207 int* perm, /**< permutation of variables */
208 SYM_SPEC fixedtype /**< variable types that must be fixed by symmetries */
209 )
210{ /*lint --e{788}*/
211 SYM_NODETYPE nodetype;
212 int* nodeinfopos;
213 int nnodes;
214 int first;
215 int second;
216 int nodeidx;
217 int i;
218
219 assert(scip != NULL);
220 assert(graph != NULL);
221 assert(origgraph != NULL);
222 assert(perm != NULL);
223
224 SCIP_CALL( SCIPcreateSymgraph(scip, origgraph->symtype, graph, origgraph->symvars, origgraph->nsymvars,
225 origgraph->nopnodes, origgraph->nvalnodes, origgraph->nconsnodes, origgraph->nedges) );
226
227 /* copy nodes */
228 nnodes = origgraph->nnodes;
229 nodeinfopos = origgraph->nodeinfopos;
230 for( i = 0; i < nnodes; ++i )
231 {
232 nodetype = origgraph->nodetypes[i];
233
234 switch( nodetype )
235 {
237 SCIP_CALL( SCIPaddSymgraphOpnode(scip, *graph, origgraph->ops[nodeinfopos[i]], &nodeidx) );
238 break;
239 case SYM_NODETYPE_VAL:
240 SCIP_CALL( SCIPaddSymgraphValnode(scip, *graph, origgraph->vals[nodeinfopos[i]], &nodeidx) );
241 break;
242 default:
243 assert(nodetype == SYM_NODETYPE_CONS);
244 SCIP_CALL( SCIPaddSymgraphConsnode(scip, *graph, origgraph->conss[nodeinfopos[i]],
245 origgraph->lhs[nodeinfopos[i]], origgraph->rhs[nodeinfopos[i]], &nodeidx) );
246 }
247 assert(0 <= nodeidx && nodeidx < nnodes);
248 }
249
250 /* copy edges */
251 for( i = 0; i < origgraph->nedges; ++i )
252 {
253 first = SCIPgetSymgraphEdgeFirst(origgraph, i);
254 second = SCIPgetSymgraphEdgeSecond(origgraph, i);
255
256 /* possibly adapt edges due to permutation of variables */
257 if( first < 0 )
258 first = -perm[-first - 1] - 1;
259 if( second < 0 )
260 second = -perm[-second - 1] - 1;
261
262 SCIP_CALL( SCIPaddSymgraphEdge(scip, *graph, first, second,
263 ! SCIPisInfinity(scip, origgraph->edgevals[i]), origgraph->edgevals[i]) );
264 }
265
266 SCIP_CALL( SCIPcomputeSymgraphColors(scip, *graph, fixedtype) );
267
268 return SCIP_OKAY;
269}
270
271/** copies a symmetry detection graph into another symmetry detection graph */
273 SCIP* scip, /**< SCIP pointer */
274 SYM_GRAPH* sourcegraph, /**< graph to be copied */
275 SYM_GRAPH* targetgraph, /**< graph into which copy shall be included */
276 SCIP_CONS* sourcecons, /**< constraint associated with sourcegraph */
277 int* rootidx /**< pointer to hold index of root node of sourcegraph in targetgraph
278 * (or -1 if root cannot be detected) */
279 )
280{ /*lint --e{788}*/
281 SYM_NODETYPE nodetype;
282 int* nodeinfopos;
283 int* nodemap;
284 int nnodes;
285 int first;
286 int second;
287 int nodeidx;
288 int i;
289
290 assert(scip != NULL);
291 assert(sourcegraph != NULL);
292 assert(targetgraph != NULL);
293 assert(sourcecons != NULL);
294 assert(rootidx != NULL);
295
296 *rootidx = -1;
297
298 /* copy nodes */
299 nnodes = sourcegraph->nnodes;
300 nodeinfopos = sourcegraph->nodeinfopos;
301
302 /* prepare map of node index from sourcegraph to indices in copied graph */
304
305 for( i = 0; i < nnodes; ++i )
306 {
307 nodetype = sourcegraph->nodetypes[i];
308
309 switch( nodetype )
310 {
312 SCIP_CALL( SCIPaddSymgraphOpnode(scip, targetgraph, sourcegraph->ops[nodeinfopos[i]], &nodeidx) );
313 break;
314 case SYM_NODETYPE_VAL:
315 SCIP_CALL( SCIPaddSymgraphValnode(scip, targetgraph, sourcegraph->vals[nodeinfopos[i]], &nodeidx) );
316 break;
317 default:
318 assert(nodetype == SYM_NODETYPE_CONS);
319 SCIP_CALL( SCIPaddSymgraphConsnode(scip, targetgraph, sourcegraph->conss[nodeinfopos[i]],
320 sourcegraph->lhs[nodeinfopos[i]], sourcegraph->rhs[nodeinfopos[i]], &nodeidx) );
321
322 if( sourcegraph->conss[nodeinfopos[i]] == sourcecons )
323 {
324 /* store the root node of sourcegraph; if there are multiple nodes that could qualify
325 * as root, stop; we cannot identify root node unambiguously
326 */
327 if( *rootidx == -1 )
328 *rootidx = nodeidx;
329 else
330 {
331 *rootidx = -1;
332 SCIPfreeBufferArray(scip, &nodemap);
333 return SCIP_OKAY;
334 }
335 }
336 }
337 assert(0 <= nodeidx && nodeidx < targetgraph->nnodes);
338
339 nodemap[i] = nodeidx;
340 }
341
342 /* terminate early if root node could not be detected */
343 if( *rootidx == -1 )
344 {
345 SCIPfreeBufferArray(scip, &nodemap);
346 return SCIP_OKAY;
347 }
348
349 /* copy edges */
350 for( i = 0; i < sourcegraph->nedges; ++i )
351 {
352 first = SCIPgetSymgraphEdgeFirst(sourcegraph, i);
353 second = SCIPgetSymgraphEdgeSecond(sourcegraph, i);
354
355 /* adapt indices from source graph to target graph in case of non-variable nodes */
356 if( first >= 0 )
357 first = nodemap[first];
358 if( second >= 0 )
359 second = nodemap[second];
360
361 SCIP_CALL( SCIPaddSymgraphEdge(scip, targetgraph, first, second,
362 !SCIPisInfinity(scip, sourcegraph->edgevals[i]), sourcegraph->edgevals[i]) );
363 }
364 SCIPfreeBufferArray(scip, &nodemap);
365
366 return SCIP_OKAY;
367}
368
369/** adds a symmetry detection graph for a linear constraint to existing graph
370 *
371 * For permutation symmetries, a constraint node is added that is connected to all
372 * variable nodes in the constraint. Edges are colored according to the variable coefficients.
373 * For signed permutation symmetries, also edges connecting the constraint node and
374 * the negated variable nodes are added, these edges are colored by the negative coefficients.
375 */
377 SCIP* scip, /**< SCIP data structure */
378 SYM_GRAPH* graph, /**< symmetry detection graph */
379 SCIP_VAR** vars, /**< variable array of linear constraint */
380 SCIP_Real* vals, /**< coefficients of linear constraint */
381 int nvars, /**< number of variables in linear constraint */
382 SCIP_CONS* cons, /**< constraint for which we encode symmetries */
383 SCIP_Real lhs, /**< left-hand side of constraint */
384 SCIP_Real rhs, /**< right-hand side of constraint */
385 SCIP_Bool* success /**< pointer to store whether graph could be built */
386 )
387{
388 int rhsnodeidx;
389 int varnodeidx;
390 int i;
391
392 assert(scip != NULL);
393 assert(graph != NULL);
394 assert(vars != NULL);
395 assert(vals != NULL);
396 assert(nvars >= 0);
397 assert(cons != NULL);
398 assert(success != NULL);
399 assert(! graph->islocked);
400
401 *success = TRUE;
402
403#ifndef NDEBUG
404 /* check whether variable nodes exist in the graph */
405 for( i = 0; i < nvars; ++i )
406 {
407 assert(0 <= SCIPvarGetProbindex(vars[i]) && SCIPvarGetProbindex(vars[i]) < graph->nsymvars);
408 }
409#endif
410
411 /* create node corresponding to right-hand side */
412 SCIP_CALL( SCIPaddSymgraphConsnode(scip, graph, cons, lhs, rhs, &rhsnodeidx) );
413
414 /* create edges */
415 for( i = 0; i < nvars; ++i )
416 {
418 {
419 varnodeidx = SCIPgetSymgraphNegatedVarnodeidx(scip, graph, vars[i]);
420 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, rhsnodeidx, varnodeidx, TRUE, -vals[i]) );
421
422 varnodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, vars[i]);
423 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, rhsnodeidx, varnodeidx, TRUE, vals[i]) );
424 }
425 else
426 {
428
429 varnodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, vars[i]);
430 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, rhsnodeidx, varnodeidx, TRUE, vals[i]) );
431 }
432 }
433
434 return SCIP_OKAY;
435}
436
437/** adds nodes and edges corresponding to the aggregation of a variable to a symmetry detection graph
438 *
439 * For permutation symmetries, the root node is connected with all variable nodes in the aggregation.
440 * Edges are colored according to the variable coefficients.
441 * For signed permutation symmetries, also edges connecting the root node and the negated variable
442 * nodes are added, these edges are colored by the negative coefficients.
443 * If the variable is fixed, a node representing the constant value is added.
444 */
446 SCIP* scip, /**< SCIP data structure */
447 SYM_GRAPH* graph, /**< symmetry detection graph */
448 int rootidx, /**< index of root node of the aggegration */
449 SCIP_VAR** vars, /**< array of variables in aggregation */
450 SCIP_Real* vals, /**< coefficients of variables */
451 int nvars, /**< number of variables in aggregation */
452 SCIP_Real constant /**< constant of aggregation */
453 )
454{
455 int nodeidx;
456 int j;
457
458 assert(scip != NULL);
459 assert(graph != NULL);
460 assert(rootidx >= 0);
461 assert(vars != NULL);
462 assert(vals != NULL);
463 assert(nvars >= 0);
464
465#ifndef NDEBUG
466 /* check whether variable nodes exist in the graph */
467 for( j = 0; j < nvars; ++j )
468 {
469 assert(0 <= SCIPvarGetProbindex(vars[j]) && SCIPvarGetProbindex(vars[j]) < graph->nsymvars);
470 }
471#endif
472
473 /* add edges incident to variables in aggregation */
474 for( j = 0; j < nvars; ++j )
475 {
477 {
478 nodeidx = SCIPgetSymgraphNegatedVarnodeidx(scip, graph, vars[j]);
479 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, rootidx, nodeidx, TRUE, -vals[j]) );
480
481 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, vars[j]);
482 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, rootidx, nodeidx, TRUE, vals[j]) );
483 }
484 else
485 {
487
488 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, vars[j]);
489 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, rootidx, nodeidx, TRUE, vals[j]) );
490 }
491 }
492
493 /* possibly add node for constant */
494 if( nvars == 0 || !SCIPisZero(scip, constant) )
495 {
496 SCIP_CALL( SCIPaddSymgraphValnode(scip, graph, constant, &nodeidx) );
497 SCIP_CALL( SCIPaddSymgraphEdge(scip, graph, rootidx, nodeidx, FALSE, 0.0) );
498 }
499
500 return SCIP_OKAY;
501}
502
503/*
504 * methods for adding and accessing nodes
505 */
506
507/** ensures that the node-based arrays in symmetry graph are sufficiently long */
508static
510 SCIP* scip, /**< SCIP data structure */
511 SYM_GRAPH* graph, /**< symmetry detection graph */
512 int addsize /**< required additional size of node-based arrays */
513 )
514{
515 assert(scip != NULL);
516 assert(graph != NULL);
517 assert(addsize > 0);
518
519 if( graph->nnodes + addsize > graph->maxnnodes )
520 {
521 int newsize;
522
523 newsize = SCIPcalcMemGrowSize(scip, graph->nnodes + addsize);
524 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &graph->nodetypes, graph->maxnnodes, newsize) );
525 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &graph->nodeinfopos, graph->maxnnodes, newsize) );
526 graph->maxnnodes = newsize;
527 }
528
529 return SCIP_OKAY;
530}
531
532/** adds an operator node to a symmetry detection graph and returns its node index */
534 SCIP* scip, /**< SCIP data structure */
535 SYM_GRAPH* graph, /**< symmetry detection graph */
536 int op, /**< int associated with operator of node */
537 int* nodeidx /**< pointer to hold index of created node */
538 )
539{
540 assert(scip != NULL);
541 assert(graph != NULL);
542 assert(nodeidx != NULL);
543
544 /* we can only add nodes if symmetry colors have not been computed yet */
545 if( graph->islocked )
546 {
547 SCIPerrorMessage("Cannot add nodes to a graph for which colors have already been computed.\n");
548 return SCIP_ERROR;
549 }
550
551 SCIP_CALL( ensureNodeArraysSize(scip, graph, 1) );
552
553 if( graph->nopnodes >= graph->maxnopnodes )
554 {
555 int newsize;
556
557 newsize = SCIPcalcMemGrowSize(scip, graph->nopnodes + 1);
558 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &graph->ops, graph->maxnopnodes, newsize) );
559 graph->maxnopnodes = newsize;
560 }
561
562 graph->nodetypes[graph->nnodes] = SYM_NODETYPE_OPERATOR;
563 graph->nodeinfopos[graph->nnodes] = graph->nopnodes;
564 graph->ops[graph->nopnodes] = op;
565
566 *nodeidx = graph->nnodes;
567 ++graph->nnodes;
568 ++graph->nopnodes;
569
570 return SCIP_OKAY;
571}
572
573/** adds a value node to a symmetry detection graph and returns its node index */
575 SCIP* scip, /**< SCIP data structure */
576 SYM_GRAPH* graph, /**< symmetry detection graph */
577 SCIP_Real val, /**< value of node */
578 int* nodeidx /**< pointer to hold index of created node */
579 )
580{
581 assert(scip != NULL);
582 assert(graph != NULL);
583 assert(nodeidx != NULL);
584
585 /* we can only add nodes if symmetry colors have not been computed yet */
586 if( graph->islocked )
587 {
588 SCIPerrorMessage("Cannot add nodes to a graph for which colors have already been computed.\n");
589 return SCIP_ERROR;
590 }
591
592 SCIP_CALL( ensureNodeArraysSize(scip, graph, 1) );
593
594 if( graph->nvalnodes >= graph->maxnvalnodes )
595 {
596 int newsize;
597
598 newsize = SCIPcalcMemGrowSize(scip, graph->nvalnodes + 1);
599 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &graph->vals, graph->maxnvalnodes, newsize) );
600 graph->maxnvalnodes = newsize;
601 }
602
603 graph->nodetypes[graph->nnodes] = SYM_NODETYPE_VAL;
604 graph->nodeinfopos[graph->nnodes] = graph->nvalnodes;
605 graph->vals[graph->nvalnodes] = val;
606
607 *nodeidx = graph->nnodes;
608 ++graph->nnodes;
609 ++graph->nvalnodes;
610
611 return SCIP_OKAY;
612}
613
614/** adds a constraint node to a symmetry detection graph and returns its node index */
616 SCIP* scip, /**< SCIP data structure */
617 SYM_GRAPH* graph, /**< symmetry detection graph */
618 SCIP_CONS* cons, /**< constraint of node */
619 SCIP_Real lhs, /**< left-hand side of node */
620 SCIP_Real rhs, /**< right-hand side of node */
621 int* nodeidx /**< pointer to hold index of created node */
622 )
623{
624 assert(scip != NULL);
625 assert(graph != NULL);
626 assert(cons != NULL);
627 assert(nodeidx != NULL);
628
629 /* we can only add nodes if symmetry colors have not been computed yet */
630 if( graph->islocked )
631 {
632 SCIPerrorMessage("Cannot add nodes to a graph for which colors have already been computed.\n");
633 return SCIP_ERROR;
634 }
635
636 SCIP_CALL( ensureNodeArraysSize(scip, graph, 1) );
637
638 if( graph->nconsnodes >= graph->maxnconsnodes )
639 {
640 int newsize;
641
642 newsize = SCIPcalcMemGrowSize(scip, graph->nconsnodes + 1);
643 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &graph->conss, graph->maxnconsnodes, newsize) );
644 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &graph->lhs, graph->maxnconsnodes, newsize) );
645 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &graph->rhs, graph->maxnconsnodes, newsize) );
646 graph->maxnconsnodes = newsize;
647 }
648
649 graph->nodetypes[graph->nnodes] = SYM_NODETYPE_CONS;
650 graph->nodeinfopos[graph->nnodes] = graph->nconsnodes;
651 graph->conss[graph->nconsnodes] = cons;
652 graph->lhs[graph->nconsnodes] = MAX(lhs, -graph->infinity);
653 graph->rhs[graph->nconsnodes] = MIN(rhs, graph->infinity);
654
655 *nodeidx = graph->nnodes;
656 ++graph->nnodes;
657 ++graph->nconsnodes;
658
659 return SCIP_OKAY;
660}
661
662/** returns the (hypothetical) node index of a variable */
664 SCIP* scip, /**< SCIP data structure */
665 SYM_GRAPH* graph, /**< symmetry detection graph */
666 SCIP_VAR* var /**< variable */
667 )
668{
669 int nodeidx;
670
671 assert(scip != NULL);
672 assert(graph != NULL);
673 assert(var != NULL);
674 assert(graph->symtype == SYM_SYMTYPE_PERM || graph->symtype == SYM_SYMTYPE_SIGNPERM);
675
676 nodeidx = -SCIPvarGetProbindex(var) - 1;
677 assert(nodeidx != INT_MAX);
678
679 return nodeidx;
680}
681
682/** returns the (hypothetical) node index of a negated variable */
684 SCIP* scip, /**< SCIP data structure */
685 SYM_GRAPH* graph, /**< symmetry detection graph */
686 SCIP_VAR* var /**< variable */
687 )
688{
689 int nodeidx;
690
691 assert(scip != NULL);
692 assert(graph != NULL);
693 assert(var != NULL);
694 assert(graph->symtype == SYM_SYMTYPE_SIGNPERM);
695 assert(SCIPgetSymgraphVarnodeidx(scip, graph, var) < 0 );
696
697 nodeidx = SCIPgetSymgraphVarnodeidx(scip, graph, var) - graph->nsymvars;
698 assert(nodeidx != INT_MAX);
699
700 return nodeidx;
701}
702
703/** updates the lhs of a constraint node */
705 SYM_GRAPH* graph, /**< symmetry detection graph */
706 int nodeidx, /**< index of constraint node in graph */
707 SCIP_Real newlhs /**< new left-hand side of node */
708 )
709{
710 assert(graph != NULL);
711 assert(nodeidx >= 0);
712 assert(graph->nodetypes[nodeidx] == SYM_NODETYPE_CONS);
713
714 graph->lhs[graph->nodeinfopos[nodeidx]] = newlhs;
715
716 return SCIP_OKAY;
717}
718
719/** updates the rhs of a constraint node */
721 SYM_GRAPH* graph, /**< symmetry detection graph */
722 int nodeidx, /**< index of constraint node in graph */
723 SCIP_Real newrhs /**< new reft-hand side of node */
724 )
725{
726 assert(graph != NULL);
727 assert(nodeidx >= 0);
728 assert(graph->nodetypes[nodeidx] == SYM_NODETYPE_CONS);
729
730 graph->rhs[graph->nodeinfopos[nodeidx]] = newrhs;
731
732 return SCIP_OKAY;
733}
734
735/** registers a variable node (corresponding to active variable) to be fixed by symmetry */
737 SYM_GRAPH* graph, /**< symmetry detection graph */
738 SCIP_VAR* var /**< active variable that needs to be fixed */
739 )
740{
741 int varidx;
742
743 assert(graph != NULL);
744 assert(var != NULL);
745
746 varidx = SCIPvarGetProbindex(var);
747 assert(0 <= varidx && varidx < graph->nsymvars);
748
749 graph->isfixedvar[varidx] = TRUE;
750
751 return SCIP_OKAY;
752}
753
754/*
755 * methods for adding edges
756 */
757
758/** ensures that the edge-based arrays in symmetry graph are sufficiently long */
759static
761 SCIP* scip, /**< SCIP data structure */
762 SYM_GRAPH* graph, /**< symmetry detection graph */
763 int addsize /**< required additional size of edge-based arrays */
764 )
765{
766 assert(scip != NULL);
767 assert(graph != NULL);
768 assert(addsize > 0);
769
770 if( graph->nedges + addsize > graph->maxnedges )
771 {
772 int newsize;
773
774 newsize = SCIPcalcMemGrowSize(scip, graph->nedges + addsize);
775 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &graph->edgefirst, graph->maxnedges, newsize) );
776 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &graph->edgesecond, graph->maxnedges, newsize) );
777 SCIP_CALL( SCIPreallocBlockMemoryArray(scip, &graph->edgevals, graph->maxnedges, newsize) );
778 graph->maxnedges = newsize;
779 }
780
781 return SCIP_OKAY;
782}
783
784/** adds an edge to a symmetry detection graph */
786 SCIP* scip, /**< SCIP data structure */
787 SYM_GRAPH* graph, /**< symmetry detection graph */
788 int first, /**< first node index of edge */
789 int second, /**< second node index of edge */
790 SCIP_Bool hasval, /**< whether the edge has a value */
791 SCIP_Real val /**< value of the edge (is it has a value) */
792 )
793{
794 assert(scip != NULL);
795 assert(graph != NULL);
796
797 /* we can only add edges if symmetry colors have not been computed yet */
798 if( graph->islocked )
799 {
800 SCIPerrorMessage("Cannot add edges to a graph for which colors have already been computed.\n");
801 return SCIP_ERROR;
802 }
803
804 SCIP_CALL( ensureEdgeArraysSize(scip, graph, 1) );
805
806 graph->edgefirst[graph->nedges] = first;
807 graph->edgesecond[graph->nedges] = second;
808 if( hasval )
809 graph->edgevals[graph->nedges] = val;
810 else
811 graph->edgevals[graph->nedges] = SCIPinfinity(scip);
812
813 graph->nedges += 1;
814
815 return SCIP_OKAY;
816}
817
818/*
819 * methods to compute colors
820 */
821
822/** compares two variables for permutation symmetry detection
823 *
824 * Variables are sorted first by their type, then by their objective coefficient,
825 * then by their lower bound, and then by their upper bound.
826 *
827 * result:
828 * < 0: ind1 comes before (is better than) ind2
829 * = 0: both indices have the same value
830 * > 0: ind2 comes after (is worse than) ind2
831 */
832static
834 SCIP* scip, /**< SCIP pointer (or NULL for exact comparison) */
835 SCIP_VAR* var1, /**< first variable for comparison */
836 SCIP_VAR* var2 /**< second variable for comparison */
837 )
838{
839 SCIP_VARTYPE type1;
840 SCIP_VARTYPE type2;
841
842 assert(var1 != NULL);
843 assert(var2 != NULL);
844
845 type1 = SCIPgetSymInferredVarType(var1);
846 type2 = SCIPgetSymInferredVarType(var2);
847
848 if( type1 < type2 )
849 return -1;
850 if( type1 > type2 )
851 return 1;
852
853 /* use SCIP's comparison functions if available */
854 if( scip == NULL )
855 {
856 if( SCIPvarGetObj(var1) < SCIPvarGetObj(var2) )
857 return -1;
858 if( SCIPvarGetObj(var1) > SCIPvarGetObj(var2) )
859 return 1;
860
861 if( SCIPvarGetLbGlobal(var1) < SCIPvarGetLbGlobal(var2) )
862 return -1;
863 if( SCIPvarGetLbGlobal(var1) > SCIPvarGetLbGlobal(var2) )
864 return 1;
865
866 if( SCIPvarGetUbGlobal(var1) < SCIPvarGetUbGlobal(var2) )
867 return -1;
868 if( SCIPvarGetUbGlobal(var1) > SCIPvarGetUbGlobal(var2) )
869 return 1;
870 }
871 else
872 {
873 if( SCIPisLT(scip, SCIPvarGetObj(var1), SCIPvarGetObj(var2)) )
874 return -1;
875 if( SCIPisGT(scip, SCIPvarGetObj(var1), SCIPvarGetObj(var2)) )
876 return 1;
877
879 return -1;
881 return 1;
882
884 return -1;
886 return 1;
887 }
888
889 return 0;
890}
891
892/** compares two variables for permutation symmetry detection
893 *
894 * Variables are sorted first by whether they are fixed, then by their type, then by
895 * their objective coefficient, then by their lower bound, and then by their upper bound.
896 *
897 * result:
898 * < 0: ind1 comes before (is better than) ind2
899 * = 0: both indices have the same value
900 * > 0: ind2 comes after (is worse than) ind2
901 */
902static
904 SCIP* scip, /**< SCIP pointer (or NULL for exact comparison) */
905 SCIP_VAR* var1, /**< first variable for comparison */
906 SCIP_VAR* var2, /**< second variable for comparison */
907 SCIP_Bool isfixed1, /**< whether var1 needs to be fixed */
908 SCIP_Bool isfixed2 /**< whether var2 needs to be fixed */
909 )
910{
911 assert(var1 != NULL);
912 assert(var2 != NULL);
913
914 if( (! isfixed1) && isfixed2 )
915 return -1;
916 if( isfixed1 && (! isfixed2) )
917 return 1;
918
919 return compareVars(scip, var1, var2);
920}
921
922/** sorts nodes of a permutation symmetry detection graph
923 *
924 * Variables are sorted first by whether they are fixed, then by their type, then by
925 * their objective coefficient, then by their lower bound, and then by their upper bound.
926 *
927 * result:
928 * < 0: ind1 comes before (is better than) ind2
929 * = 0: both indices have the same value
930 * > 0: ind2 comes after (is worse than) ind2
931 */
932static
933SCIP_DECL_SORTINDCOMP(SYMsortVarnodesPermsym)
934{
935 SYM_GRAPH* graph;
936 SCIP_VAR** vars;
937 SCIP_Bool* isfixedvar;
938
939 graph = (SYM_GRAPH*) dataptr;
940 assert(graph != NULL);
941
942 vars = graph->symvars;
943 assert(vars != NULL);
944
945 isfixedvar = graph->isfixedvar;
946 assert(isfixedvar != NULL);
947
948 return compareVarsFixed(NULL, vars[ind1], vars[ind2], isfixedvar[ind1], isfixedvar[ind2]);
949}
950
951/** compares two variables for signed permutation symmetry detection
952 *
953 * Variables are sorted first by their type, then by their objective coefficient,
954 * then by their lower bound, and then by their upper bound.
955 * To take signed permutations into account, variable domains are centered at origin
956 * if the domain is finite.
957 *
958 * result:
959 * < 0: ind1 comes before (is better than) ind2
960 * = 0: both indices have the same value
961 * > 0: ind2 comes after (is worse than) ind2
962 */
963static
965 SCIP* scip, /**< SCIP pointer (or NULL for exact comparison) */
966 SCIP_VAR* var1, /**< first variable for comparison */
967 SCIP_VAR* var2, /**< second variable for comparison */
968 SCIP_Bool isneg1, /**< whether var1 needs to be negated */
969 SCIP_Bool isneg2, /**< whether var2 needs to be negated */
970 SCIP_Real infinity /**< values as least as large as this are regarded as infinite */
971 )
972{
973 SCIP_Real ub1;
974 SCIP_Real ub2;
975 SCIP_Real lb1;
976 SCIP_Real lb2;
977 SCIP_Real obj1;
978 SCIP_Real obj2;
979 SCIP_Real mid;
980 SCIP_VARTYPE type1;
981 SCIP_VARTYPE type2;
982
983 assert(var1 != NULL);
984 assert(var2 != NULL);
985
986 type1 = SCIPgetSymInferredVarType(var1);
987 type2 = SCIPgetSymInferredVarType(var2);
988
989 if( type1 < type2 )
990 return -1;
991 if( type1 > type2 )
992 return 1;
993
994 obj1 = isneg1 ? -SCIPvarGetObj(var1) : SCIPvarGetObj(var1);
995 obj2 = isneg2 ? -SCIPvarGetObj(var2) : SCIPvarGetObj(var2);
996
997 /* use SCIP's comparison functions if available */
998 if( scip == NULL )
999 {
1000 if( obj1 < obj2 )
1001 return -1;
1002 if( obj1 > obj2 )
1003 return 1;
1004 }
1005 else
1006 {
1007 if( SCIPisLT(scip, obj1, obj2) )
1008 return -1;
1009 if( SCIPisGT(scip, obj1, obj2) )
1010 return 1;
1011 }
1012
1013 /* adapt lower and upper bounds if domain is finite */
1014 lb1 = SCIPvarGetLbGlobal(var1);
1015 lb2 = SCIPvarGetLbGlobal(var2);
1016 ub1 = SCIPvarGetUbGlobal(var1);
1017 ub2 = SCIPvarGetUbGlobal(var2);
1018 if( ub1 < infinity && -lb1 < infinity )
1019 {
1020 mid = (lb1 + ub1) / 2;
1021 lb1 -= mid;
1022 ub1 -= mid;
1023 }
1024 if( ub2 < infinity && -lb2 < infinity )
1025 {
1026 mid = (lb2 + ub2) / 2;
1027 lb2 -= mid;
1028 ub2 -= mid;
1029 }
1030
1031 /* for negated variables, flip upper and lower bounds */
1032 if( isneg1 )
1033 {
1034 mid = lb1;
1035 lb1 = -ub1;
1036 ub1 = -mid;
1037 }
1038 if( isneg2 )
1039 {
1040 mid = lb2;
1041 lb2 = -ub2;
1042 ub2 = -mid;
1043 }
1044
1045 /* use SCIP's comparison functions if available */
1046 if( scip == NULL )
1047 {
1048 if( lb1 < lb2 )
1049 return -1;
1050 if( lb1 > lb2 )
1051 return 1;
1052
1053 if( ub1 < ub2 )
1054 return -1;
1055 if( ub1 > ub2 )
1056 return 1;
1057 }
1058 else
1059 {
1060 if( SCIPisLT(scip, lb1, lb2) )
1061 return -1;
1062 if( SCIPisGT(scip, lb1, lb2) )
1063 return 1;
1064
1065 if( SCIPisLT(scip, ub1, ub2) )
1066 return -1;
1067 if( SCIPisGT(scip, ub1, ub2) )
1068 return 1;
1069 }
1070
1071 return 0;
1072}
1073
1074/** compares two variables for signed permutation symmetry detection
1075 *
1076 * Variables are sorted first by whether they are fixed, then by their type, then
1077 * by their objective coefficient, then by their lower bound and then by their upper bound.
1078 * To take signed permutations into account, variable domains are centered at origin
1079 * if the domain is finite.
1080 *
1081 * result:
1082 * < 0: ind1 comes before (is better than) ind2
1083 * = 0: both indices have the same value
1084 * > 0: ind2 comes after (is worse than) ind2
1085 */
1086static
1088 SCIP* scip, /**< SCIP pointer (or NULL for exact comparison) */
1089 SCIP_VAR* var1, /**< first variable for comparison */
1090 SCIP_VAR* var2, /**< second variable for comparison */
1091 SCIP_Bool isfixed1, /**< whether var1 needs to be fixed */
1092 SCIP_Bool isfixed2, /**< whether var2 needs to be fixed */
1093 SCIP_Bool isneg1, /**< whether var1 needs to be negated */
1094 SCIP_Bool isneg2, /**< whether var2 needs to be negated */
1095 SCIP_Real infinity /**< values as least as large as this are regarded as infinite */
1096 )
1097{
1098 assert(var1 != NULL);
1099 assert(var2 != NULL);
1100
1101 if( (! isfixed1) && isfixed2 )
1102 return -1;
1103 if( isfixed1 && (! isfixed2) )
1104 return 1;
1105
1106 return compareVarsSignedPerm(scip, var1, var2, isneg1, isneg2, infinity);
1107}
1108
1109/** sorts nodes of a signed permutation symmetry detection graph
1110 *
1111 * Variables are sorted first by whether they are fixed, then by their type, then
1112 * by their objective coefficient, then by their lower bound and then by their upper bound.
1113 * To take signed permutations into account, variable domains are centered at origin
1114 * if the domain is finite.
1115 *
1116 * result:
1117 * < 0: ind1 comes before (is better than) ind2
1118 * = 0: both indices have the same value
1119 * > 0: ind2 comes after (is worse than) ind2
1120 */
1121static
1122SCIP_DECL_SORTINDCOMP(SYMsortVarnodesSignedPermsym)
1123{
1124 SYM_GRAPH* graph;
1125 SCIP_VAR** vars;
1126 SCIP_Bool* isfixedvar;
1127 int nsymvars;
1128 int locind1;
1129 int locind2;
1130 SCIP_Bool isneg1 = FALSE;
1131 SCIP_Bool isneg2 = FALSE;
1132
1133 graph = (SYM_GRAPH*) dataptr;
1134 assert(graph != NULL);
1135
1136 nsymvars = graph->nsymvars;
1137 vars = graph->symvars;
1138 assert(nsymvars > 0);
1139 assert(vars != NULL);
1140
1141 isfixedvar = graph->isfixedvar;
1142 assert(isfixedvar != NULL);
1143
1144 locind1 = ind1;
1145 if( locind1 >= nsymvars )
1146 {
1147 isneg1 = TRUE;
1148 locind1 -= nsymvars;
1149 }
1150 locind2 = ind2;
1151 if( locind2 >= nsymvars )
1152 {
1153 isneg2 = TRUE;
1154 locind2 -= nsymvars;
1155 }
1156
1157 return compareVarsFixedSignedPerm(NULL, vars[locind1], vars[locind2], isfixedvar[locind1], isfixedvar[locind2],
1158 isneg1, isneg2, graph->infinity);
1159}
1160
1161/** compares two operators
1162 *
1163 * Operators are sorted by their int values.
1164 *
1165 * result:
1166 * < 0: ind1 comes before (is better than) ind2
1167 * = 0: both indices have the same value
1168 * > 0: ind2 comes after (is worse than) ind2
1169 */
1170static
1172 int op1, /**< first operator in comparison */
1173 int op2 /**< second operator in comparison */
1174 )
1175{
1176 if( op1 < op2 )
1177 return -1;
1178 else if( op1 > op2 )
1179 return 1;
1180
1181 return 0;
1182}
1183
1184/** sorts operators corresponding to SCIP_EXPRHDLR*
1185 *
1186 * result:
1187 * < 0: ind1 comes before (is better than) ind2
1188 * = 0: both indices have the same value
1189 * > 0: ind2 comes after (is worse than) ind2
1190 */
1191static
1193{
1194 int* vals;
1195
1196 vals = (int*) dataptr;
1197
1198 return compareOps(vals[ind1], vals[ind2]);
1199}
1200
1201/** sorts real values
1202 *
1203 * result:
1204 * < 0: ind1 comes before (is better than) ind2
1205 * = 0: both indices have the same value
1206 * > 0: ind2 comes after (is worse than) ind2
1207 */
1208static
1210{
1211 SCIP_Real* vals;
1212
1213 vals = (SCIP_Real*) dataptr;
1214
1215 if( vals[ind1] < vals[ind2] )
1216 return -1;
1217 if( vals[ind1] > vals[ind2] )
1218 return 1;
1219
1220 return 0;
1221}
1222
1223/** compares constraint nodes
1224 *
1225 * Nodes are sorted by their type of constraint, then by the lhs, and then by the rhs.
1226 *
1227 * result:
1228 * < 0: ind1 comes before (is better than) ind2
1229 * = 0: both indices have the same value
1230 * > 0: ind2 comes after (is worse than) ind2
1231 */
1232static
1234 SCIP* scip, /**< SCIP data structure */
1235 SYM_GRAPH* graph, /**< underlying symmetry detection graph */
1236 int ind1, /**< index of first constraint node */
1237 int ind2 /**< index of second constraint node */
1238 )
1239{
1240 SCIP_CONS* cons1;
1241 SCIP_CONS* cons2;
1242
1243 assert(graph != NULL);
1244 assert(0 <= ind1 && ind1 < graph->nconsnodes);
1245 assert(0 <= ind2 && ind2 < graph->nconsnodes);
1246
1247 cons1 = graph->conss[ind1];
1248 cons2 = graph->conss[ind2];
1249
1250 if( SCIPconsGetHdlr(cons1) < SCIPconsGetHdlr(cons2) )
1251 return -1;
1252 if( SCIPconsGetHdlr(cons1) > SCIPconsGetHdlr(cons2) )
1253 return 1;
1254
1255 /* use SCIP's comparison functions if available */
1256 if( scip != NULL )
1257 {
1258 if( SCIPisLT(scip, graph->lhs[ind1], graph->lhs[ind2]) )
1259 return -1;
1260 if( SCIPisGT(scip, graph->lhs[ind1], graph->lhs[ind2]) )
1261 return 1;
1262
1263 if( SCIPisLT(scip, graph->rhs[ind1], graph->rhs[ind2]) )
1264 return -1;
1265 if( SCIPisGT(scip, graph->rhs[ind1], graph->rhs[ind2]) )
1266 return 1;
1267 }
1268 else
1269 {
1270 if( graph->lhs[ind1] < graph->lhs[ind2] )
1271 return -1;
1272 if( graph->lhs[ind1] > graph->lhs[ind2] )
1273 return 1;
1274
1275 if( graph->rhs[ind1] < graph->rhs[ind2] )
1276 return -1;
1277 if( graph->rhs[ind1] > graph->rhs[ind2] )
1278 return 1;
1279 }
1280
1281 return 0;
1282}
1283
1284/** sorts constraint nodes
1285 *
1286 * Nodes are sorted by their type of constraint, then by the lhs, and then by the rhs.
1287 *
1288 * result:
1289 * < 0: ind1 comes before (is better than) ind2
1290 * = 0: both indices have the same value
1291 * > 0: ind2 comes after (is worse than) ind2
1292 */
1293static
1294SCIP_DECL_SORTINDCOMP(SYMsortConsnodes)
1295{
1296 return compareConsnodes(NULL, (SYM_GRAPH*) dataptr, ind1, ind2);
1297}
1298
1299/** sorts edges
1300 *
1301 * Edges are sorted by their weights.
1302 *
1303 * result:
1304 * < 0: ind1 comes before (is better than) ind2
1305 * = 0: both indices have the same value
1306 * > 0: ind2 comes after (is worse than) ind2
1307 */
1308static
1310{
1311 SYM_GRAPH* G;
1312
1313 G = (SYM_GRAPH*) dataptr;
1314
1315 if( G->edgevals[ind1] < G->edgevals[ind2] )
1316 return -1;
1317 if( G->edgevals[ind1] > G->edgevals[ind2] )
1318 return 1;
1319
1320 return 0;
1321}
1322
1323/** returns whether a node of the symmetry detection graph needs to be fixed */
1324static
1326 SCIP_VAR* var, /**< active problem variable */
1327 SYM_SPEC fixedtype /**< variable types that must be fixed by symmetries */
1328 )
1329{
1330 assert(var != NULL);
1331
1333 return TRUE;
1334 if( (fixedtype & SYM_SPEC_BINARY) && SCIPvarGetType(var) == SCIP_VARTYPE_BINARY && !SCIPvarIsImpliedIntegral(var) )
1335 return TRUE;
1336 if( (fixedtype & SYM_SPEC_REAL) && ( SCIPvarGetType(var) == SCIP_VARTYPE_CONTINUOUS || SCIPvarIsImpliedIntegral(var) ) )
1337 return TRUE;
1338 return FALSE;
1339}
1340
1341/** computes colors of nodes and edges
1342 *
1343 * Colors are detected by sorting different types of nodes (variables, operators, values, and constraint) and edges.
1344 * If two consecutive nodes of the same type differ (e.g., different variable type), they are assigned a new color.
1345 */
1347 SCIP* scip, /**< SCIP data structure */
1348 SYM_GRAPH* graph, /**< symmetry detection graph */
1349 SYM_SPEC fixedtype /**< variable types that must be fixed by symmetries */
1350 )
1351{
1352 SCIP_VAR* prevvar;
1353 SCIP_VAR* thisvar;
1354 SCIP_Real prevval;
1355 SCIP_Real thisval;
1356 SCIP_Bool previsneg;
1357 SCIP_Bool thisisneg;
1358 int* perm;
1359 int nusedvars;
1360 int len;
1361 int i;
1362 int color = 0;
1363
1364 assert(scip != NULL);
1365 assert(graph != NULL);
1366
1367 /* terminate early if colors have already been computed */
1368 if( graph->islocked )
1369 return SCIP_OKAY;
1370
1371 /* lock graph to be extended */
1372 graph->islocked = TRUE;
1373
1374 /* possibly fix variables */
1375 for( i = 0; i < graph->nsymvars; ++i )
1376 {
1377 if( isFixedVar(graph->symvars[i], fixedtype) )
1378 graph->isfixedvar[i] = TRUE;
1379 }
1380
1381 /* get number of variables used in symmetry detection graph */
1382 switch( graph->symtype )
1383 {
1384 case SYM_SYMTYPE_PERM:
1385 nusedvars = graph->nsymvars;
1386 break;
1387 default:
1388 assert(graph->symtype == SYM_SYMTYPE_SIGNPERM);
1389 nusedvars = 2 * graph->nsymvars;
1390 } /*lint !e788*/
1391
1392 /* allocate memory for colors */
1393 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &graph->varcolors, nusedvars) );
1398
1399 /* allocate permutation of arrays, will be initialized by SCIPsort() */
1400 len = graph->nedges;
1401 if ( graph->nopnodes > len )
1402 len = graph->nopnodes;
1403 if ( graph->nvalnodes > len )
1404 len = graph->nvalnodes;
1405 if ( graph->nconsnodes > len )
1406 len = graph->nconsnodes;
1407 if ( nusedvars > len )
1408 len = nusedvars;
1409
1410 SCIP_CALL( SCIPallocBufferArray(scip, &perm, len) );
1411
1412 /* find colors of variable nodes */
1413 assert(graph->nsymvars > 0);
1414 switch( graph->symtype )
1415 {
1416 case SYM_SYMTYPE_PERM:
1417 SCIPsort(perm, SYMsortVarnodesPermsym, (void*) graph, nusedvars);
1418
1419 graph->varcolors[perm[0]] = color;
1420 prevvar = graph->symvars[perm[0]];
1421
1422 for( i = 1; i < nusedvars; ++i )
1423 {
1424 thisvar = graph->symvars[perm[i]];
1425
1426 if( graph->isfixedvar[i] || compareVars(scip, prevvar, thisvar) != 0 )
1427 ++color;
1428
1429 graph->varcolors[perm[i]] = color;
1430 prevvar = thisvar;
1431 }
1432 graph->nvarcolors = color;
1433 break;
1434 default:
1435 assert(graph->symtype == SYM_SYMTYPE_SIGNPERM);
1436
1437 SCIPsort(perm, SYMsortVarnodesSignedPermsym, (void*) graph, nusedvars);
1438
1439 graph->varcolors[perm[0]] = color;
1440
1441 /* store information about first variable */
1442 if( perm[0] < graph->nsymvars )
1443 {
1444 previsneg = FALSE;
1445 prevvar = graph->symvars[perm[0]];
1446 }
1447 else
1448 {
1449 previsneg = TRUE;
1450 prevvar = graph->symvars[perm[0] - graph->nsymvars];
1451 }
1452
1453 /* compute colors of remaining variables */
1454 for( i = 1; i < nusedvars; ++i )
1455 {
1456 if( perm[i] < graph->nsymvars )
1457 {
1458 thisisneg = FALSE;
1459 thisvar = graph->symvars[perm[i]];
1460 }
1461 else
1462 {
1463 thisisneg = TRUE;
1464 thisvar = graph->symvars[perm[i] - graph->nsymvars];
1465 }
1466
1467 if( graph->isfixedvar[i % graph->nsymvars]
1468 || compareVarsSignedPerm(scip, prevvar, thisvar, previsneg, thisisneg, graph->infinity) != 0 )
1469 ++color;
1470
1471 graph->varcolors[perm[i]] = color;
1472 prevvar = thisvar;
1473 previsneg = thisisneg;
1474 }
1475 graph->nvarcolors = color;
1476 } /*lint !e788*/
1477
1478 /* find colors of operator nodes */
1479 if( graph->nopnodes > 0 )
1480 {
1481 int prevop;
1482 int thisop;
1483
1484 SCIPsort(perm, SYMsortOpnodes, (void*) graph->ops, graph->nopnodes);
1485
1486 graph->opcolors[perm[0]] = ++color;
1487 prevop = graph->ops[perm[0]];
1488
1489 for( i = 1; i < graph->nopnodes; ++i )
1490 {
1491 thisop = graph->ops[perm[i]];
1492
1493 if( compareOps(prevop, thisop) != 0 )
1494 ++color;
1495
1496 graph->opcolors[perm[i]] = color;
1497 prevop = thisop;
1498 }
1499 }
1500
1501 /* find colors of value nodes */
1502 if( graph->nvalnodes > 0 )
1503 {
1504 SCIPsort(perm, SYMsortReals, (void*) graph->vals, graph->nvalnodes);
1505
1506 graph->valcolors[perm[0]] = ++color;
1507 prevval = graph->vals[perm[0]];
1508
1509 for( i = 1; i < graph->nvalnodes; ++i )
1510 {
1511 thisval = graph->vals[perm[i]];
1512
1513 if( ! SCIPisEQ(scip, prevval, thisval) )
1514 ++color;
1515
1516 graph->valcolors[perm[i]] = color;
1517 prevval = thisval;
1518 }
1519 }
1520
1521 /* find colors of constraint nodes */
1522 if( graph->nconsnodes > 0 )
1523 {
1524 SCIPsort(perm, SYMsortConsnodes, (void*) graph, graph->nconsnodes);
1525
1526 graph->conscolors[perm[0]] = ++color;
1527
1528 for( i = 1; i < graph->nconsnodes; ++i )
1529 {
1530 if( compareConsnodes(scip, graph, perm[i-1], perm[i]) != 0 )
1531 ++color;
1532
1533 graph->conscolors[perm[i]] = color;
1534 }
1535 }
1536
1537 /* find colors of edges */
1538 if( graph->nedges > 0 )
1539 {
1540 SCIPsort(perm, SYMsortEdges, (void*) graph, graph->nedges);
1541
1542 /* check for uncolored or uniformly colored edges, which is easy due to sorting */
1543 if( SCIPisInfinity(scip, graph->edgevals[perm[0]]) ||
1544 SCIPisEQ(scip, graph->edgevals[perm[0]], graph->edgevals[perm[graph->nedges - 1]]) )
1545 {
1546 /* when all edges are uncolored or uniformly colored, we can ignore edge colors */
1547 graph->uniqueedgetype = TRUE;
1548 for( i = 0; i < graph->nedges; ++i )
1549 graph->edgecolors[i] = -1;
1550 }
1551 else
1552 {
1553 /* first edge is colored */
1554 graph->edgecolors[perm[0]] = ++color;
1555 prevval = graph->edgevals[perm[0]];
1556
1557 for( i = 1; i < graph->nedges; ++i )
1558 {
1559 thisval = graph->edgevals[perm[i]];
1560
1561 /* terminate if edges are not colored anymore */
1562 if( SCIPisInfinity(scip, thisval) )
1563 break;
1564
1565 if( ! SCIPisEQ(scip, prevval, thisval) )
1566 ++color;
1567
1568 graph->edgecolors[perm[i]] = color;
1569 prevval = thisval;
1570 }
1571
1572 /* assign uncolored edges color -1 */
1573 for( ; i < graph->nedges; ++i )
1574 graph->edgecolors[perm[i]] = -1;
1575 }
1576 }
1577
1578 SCIPfreeBufferArray(scip, &perm);
1579
1580 return SCIP_OKAY;
1581}
1582
1583
1584/* general methods */
1585
1586/** returns the type of symmetries encoded in graph */
1588 SYM_GRAPH* graph /**< symmetry detection graph */
1589 )
1590{
1591 assert(graph != NULL);
1592
1593 return graph->symtype;
1594}
1595
1596/** returns the variables in a symmetry detection graph */
1598 SYM_GRAPH* graph /**< symmetry detection graph */
1599 )
1600{
1601 assert(graph != NULL);
1602
1603 return graph->symvars;
1604}
1605
1606/** returns the number of variables in a symmetry detection graph */
1608 SYM_GRAPH* graph /**< symmetry detection graph */
1609 )
1610{
1611 assert(graph != NULL);
1612
1613 return graph->nsymvars;
1614}
1615
1616/** returns the number of constraint nodes in a symmetry detection graph */
1618 SYM_GRAPH* graph /**< symmetry detection graph */
1619 )
1620{
1621 assert(graph != NULL);
1622
1623 return graph->nconsnodes;
1624}
1625
1626/** returns the number of non-variable nodes in a graph */
1628 SYM_GRAPH* graph /**< symmetry detection graph */
1629 )
1630{
1631 assert(graph != NULL);
1632
1633 return graph->nnodes;
1634}
1635
1636/** returns the number of edges in a graph */
1638 SYM_GRAPH* graph /**< symmetry detection graph */
1639 )
1640{
1641 assert(graph != NULL);
1642
1643 return graph->nedges;
1644}
1645
1646/** return the first node index of an edge */
1648 SYM_GRAPH* graph, /**< symmetry detection graph */
1649 int edgeidx /**< index of edge */
1650 )
1651{
1652 assert(graph != NULL);
1653 assert(0 <= edgeidx && edgeidx < graph->nedges);
1654
1655 return graph->edgefirst[edgeidx];
1656}
1657
1658/** return the second node index of an edge */
1660 SYM_GRAPH* graph, /**< symmetry detection graph */
1661 int edgeidx /**< index of edge */
1662 )
1663{
1664 assert(graph != NULL);
1665 assert(0 <= edgeidx && edgeidx < graph->nedges);
1666
1667 return graph->edgesecond[edgeidx];
1668}
1669
1670/** returns the color of a variable node */
1672 SYM_GRAPH* graph, /**< symmetry detection graph */
1673 int nodeidx /**< index of variable node */
1674 )
1675{
1676 assert(graph != NULL);
1677 assert(graph->islocked);
1678
1679 switch( graph->symtype )
1680 {
1681 case SYM_SYMTYPE_PERM:
1682 assert(0 <= nodeidx && nodeidx < graph->nsymvars);
1683 break;
1684 default:
1685 assert(graph->symtype == SYM_SYMTYPE_SIGNPERM);
1686 assert(0 <= nodeidx && nodeidx < 2 * graph->nsymvars);
1687 } /*lint !e788*/
1688
1689 return graph->varcolors[nodeidx];
1690}
1691
1692/** returns the type of a node */
1694 SYM_GRAPH* graph, /**< symmetry detection graph */
1695 int nodeidx /**< index of node */
1696 )
1697{
1698 assert(graph != NULL);
1699 assert(nodeidx < graph->nnodes);
1700
1701 if( nodeidx < 0 )
1702 return SYM_NODETYPE_VAR;
1703
1704 return graph->nodetypes[nodeidx];
1705}
1706
1707/** returns the color of a non-variable node */
1709 SYM_GRAPH* graph, /**< symmetry detection graph */
1710 int nodeidx /**< index of node */
1711 )
1712{ /*lint --e{788}*/
1713 assert(graph != NULL);
1714 assert(0 <= nodeidx && nodeidx < graph->nnodes);
1715 assert(graph->islocked);
1716
1717 switch( graph->nodetypes[nodeidx] )
1718 {
1720 return graph->opcolors[graph->nodeinfopos[nodeidx]];
1721 case SYM_NODETYPE_VAL:
1722 return graph->valcolors[graph->nodeinfopos[nodeidx]];
1723 default:
1724 assert(graph->nodetypes[nodeidx] == SYM_NODETYPE_CONS);
1725 }
1726
1727 return graph->conscolors[graph->nodeinfopos[nodeidx]];
1728}
1729
1730/** returns whether an edge is colored */
1732 SYM_GRAPH* graph, /**< symmetry detection graph */
1733 int edgeidx /**< index of edge */
1734 )
1735{
1736 assert(graph != NULL);
1737 assert(0 <= edgeidx && edgeidx < graph->nedges);
1738
1739 if( ! graph->islocked || graph->edgecolors[edgeidx] == -1 )
1740 return FALSE;
1741
1742 return TRUE;
1743}
1744
1745/** returns color of an edge */
1747 SYM_GRAPH* graph, /**< symmetry detection graph */
1748 int edgeidx /**< index of edge */
1749 )
1750{
1751 assert(graph != NULL);
1752 assert(0 <= edgeidx && edgeidx < graph->nedges);
1753 assert(SCIPisSymgraphEdgeColored(graph, edgeidx));
1754
1755 return graph->edgecolors[edgeidx];
1756}
1757
1758/** returns the number of unique variable colors in the graph */
1760 SYM_GRAPH* graph /**< symmetry detection graph */
1761 )
1762{
1763 assert(graph != NULL);
1764
1765 if( graph->nvarcolors < 0 )
1766 return graph->nsymvars;
1767
1768 return graph->nvarcolors;
1769}
1770
1771/** returns whether the graph has a unique edge type */
1773 SYM_GRAPH* graph /**< symmetry detection graph */
1774 )
1775{
1776 assert(graph != NULL);
1777
1778 return graph->uniqueedgetype;
1779}
1780
1781/** creates consnodeperm array for symmetry detection graph
1782 *
1783 * @note @p colors of symmetry detection graph must have been computed
1784 */
1786 SCIP* scip, /**< SCIP data structure */
1787 SYM_GRAPH* graph /**< symmetry detection graph */
1788 )
1789{
1790 assert(scip != NULL);
1791 assert(graph != NULL);
1792 assert(graph->islocked);
1793
1794 /* either there are no constraint nodes or we have already computed the permutation */
1795 if( graph->nconsnodes <= 0 || graph->consnodeperm != NULL )
1796 return SCIP_OKAY;
1797
1799 SCIPsort(graph->consnodeperm, SYMsortConsnodes, (void*) graph, graph->nconsnodes);
1800
1801 return SCIP_OKAY;
1802}
1803
1804/** frees consnodeperm array for symmetry detection graph */
1806 SCIP* scip, /**< SCIP data structure */
1807 SYM_GRAPH* graph /**< symmetry detection graph */
1808 )
1809{
1810 assert(scip != NULL);
1811 assert(graph != NULL);
1812 assert(graph->islocked);
1813
1815
1816 return SCIP_OKAY;
1817}
1818
1819/** returns consnodeperm array for symmetry detection graph
1820 *
1821 * @note @p colors of symmetry detection graph must have been computed
1822 */
1824 SCIP* scip, /**< SCIP data structure */
1825 SYM_GRAPH* graph /**< symmetry detection graph */
1826 )
1827{
1828 assert(scip != NULL);
1829 assert(graph != NULL);
1830 assert(graph->islocked);
1831
1833
1834 return graph->consnodeperm;
1835}
1836
1837/** Transforms given variables, scalars, and constant to the corresponding active variables, scalars, and constant.
1838 *
1839 * For permutation symmetries, active variables as encoded in SCIP are used. For signed permutation symmetries,
1840 * active variables are shifted such that their domain is centered at 0 (if both their upper and lower bounds
1841 * are finite).
1842 *
1843 * @note @p constant needs to be initialized!
1844 */
1846 SCIP* scip, /**< SCIP data structure */
1847 SYM_SYMTYPE symtype, /**< type of symmetries for which variables are required */
1848 SCIP_VAR*** vars, /**< pointer to vars array to get active variables for */
1849 SCIP_Real** scalars, /**< pointer to scalars a_1, ..., a_n in linear sum a_1*x_1 + ... + a_n*x_n + c */
1850 int* nvars, /**< pointer to number of variables and values in vars and vals array */
1851 SCIP_Real* constant, /**< pointer to constant c in linear sum a_1*x_1 + ... + a_n*x_n + c */
1852 SCIP_Bool transformed /**< transformed constraint? */
1853 )
1854{
1855 SCIP_Real ub;
1856 SCIP_Real lb;
1857 int requiredsize;
1858 int v;
1859
1860 assert(scip != NULL);
1861 assert(vars != NULL);
1862 assert(scalars != NULL);
1863 assert(*vars != NULL);
1864 assert(*scalars != NULL);
1865 assert(nvars != NULL);
1866 assert(constant != NULL);
1867
1868 if( transformed )
1869 {
1870 SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, *nvars, constant, &requiredsize) );
1871
1872 if( requiredsize > *nvars )
1873 {
1874 SCIP_CALL( SCIPreallocBufferArray(scip, vars, requiredsize) );
1875 SCIP_CALL( SCIPreallocBufferArray(scip, scalars, requiredsize) );
1876
1877 SCIP_CALL( SCIPgetProbvarLinearSum(scip, *vars, *scalars, nvars, requiredsize, constant, &requiredsize) );
1878 }
1879 assert( requiredsize == *nvars );
1880 }
1881 else
1882 {
1883 for( v = 0; v < *nvars; ++v )
1884 {
1885 SCIP_CALL( SCIPvarGetOrigvarSum(&(*vars)[v], &(*scalars)[v], constant) );
1886 }
1887 }
1888
1889 /* possibly post-process active variables */
1890 if( symtype == SYM_SYMTYPE_SIGNPERM )
1891 {
1892 /* center variables at origin if their domain is finite */
1893 for (v = 0; v < *nvars; ++v)
1894 {
1895 ub = SCIPvarGetUbGlobal((*vars)[v]);
1896 lb = SCIPvarGetLbGlobal((*vars)[v]);
1897
1898 if ( SCIPisInfinity(scip, ub) || SCIPisInfinity(scip, -lb) )
1899 continue;
1900
1901 *constant += (*scalars)[v] * (ub + lb) / 2;
1902 }
1903 }
1904
1905 return SCIP_OKAY;
1906}
1907
1908/** frees symmetry information of an expression */
1910 SCIP* scip, /**< SCIP data structure */
1911 SYM_EXPRDATA** symdata /**< symmetry information of an expression */
1912 )
1913{
1914 assert(scip != NULL);
1915 assert(symdata != NULL);
1916
1917 if( (*symdata)->nconstants > 0 )
1918 {
1919 SCIPfreeBlockMemoryArrayNull(scip, &(*symdata)->constants, (*symdata)->nconstants);
1920 }
1921 if( (*symdata)->ncoefficients > 0 )
1922 {
1923 SCIPfreeBlockMemoryArrayNull(scip, &(*symdata)->coefficients, (*symdata)->ncoefficients);
1924 SCIPfreeBlockMemoryArrayNull(scip, &(*symdata)->children, (*symdata)->ncoefficients);
1925 }
1926 SCIPfreeBlockMemory(scip, symdata);
1927
1928 return SCIP_OKAY;
1929}
1930
1931/** returns number of coefficients from exprdata */
1933 SYM_EXPRDATA* symdata /**< symmetry information of an expression */
1934 )
1935{
1936 assert(symdata != NULL);
1937
1938 return symdata->nconstants;
1939}
1940
1941/** returns number of coefficients form exprdata */
1943 SYM_EXPRDATA* symdata /**< symmetry information of an expression */
1944 )
1945{
1946 assert(symdata != NULL);
1947
1948 return symdata->constants;
1949}
1950
1951/** gets coefficient of expression from parent expression */
1953 SCIP* scip, /**< SCIP data structure */
1954 SCIP_EXPR* expr, /**< expression for which coefficient needs to be found */
1955 SCIP_EXPR* parentexpr, /**< parent of expr */
1956 SCIP_Real* coef, /**< buffer to store coefficient */
1957 SCIP_Bool* success /**< whether a coefficient is found */
1958 )
1959{
1960 SYM_EXPRDATA* symdata;
1961 int i;
1962
1963 assert(scip != NULL);
1964 assert(expr != NULL);
1965 assert(parentexpr != NULL);
1966 assert(coef != NULL);
1967 assert(success != NULL);
1968
1969 *success = FALSE;
1970
1971 /* parent does not assign coefficients to its children */
1972 if( ! SCIPexprhdlrHasGetSymData(SCIPexprGetHdlr(parentexpr)) )
1973 return SCIP_OKAY;
1974
1975 SCIP_CALL( SCIPgetSymDataExpr(scip, parentexpr, &symdata) );
1976
1977 /* parent does not assign coefficients to its children */
1978 if( symdata->ncoefficients < 1 )
1979 {
1980 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
1981
1982 return SCIP_OKAY;
1983 }
1984
1985 /* search for expr in the children of parentexpr */
1986 for( i = 0; i < symdata->ncoefficients; ++i )
1987 {
1988 if( symdata->children[i] == expr )
1989 {
1990 *coef = symdata->coefficients[i];
1991 *success = TRUE;
1992 break;
1993 }
1994 }
1995
1996 SCIP_CALL( SCIPfreeSymDataExpr(scip, &symdata) );
1997
1998 return SCIP_OKAY;
1999}
#define NULL
Definition: def.h:248
#define SCIP_Bool
Definition: def.h:91
#define MIN(x, y)
Definition: def.h:224
#define SCIP_Real
Definition: def.h:156
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:220
#define SCIP_CALL_ABORT(x)
Definition: def.h:334
#define SCIP_CALL(x)
Definition: def.h:355
#define infinity
Definition: gastrans.c:80
#define nnodes
Definition: gastrans.c:74
SCIP_CONSHDLR * SCIPconsGetHdlr(SCIP_CONS *cons)
Definition: cons.c:8409
SCIP_Bool SCIPexprhdlrHasGetSymData(SCIP_EXPRHDLR *exprhdlr)
Definition: expr.c:685
SCIP_RETCODE SCIPgetSymDataExpr(SCIP *scip, SCIP_EXPR *expr, SYM_EXPRDATA **symdata)
Definition: scip_expr.c:1817
SCIP_EXPRHDLR * SCIPexprGetHdlr(SCIP_EXPR *expr)
Definition: expr.c:3895
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
#define SCIPallocClearBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:97
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:139
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
#define SCIPreallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:128
#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
SCIP_VARTYPE SCIPgetSymInferredVarType(SCIP_VAR *var)
Definition: symmetry.c:45
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Bool SCIPisInfinity(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisGT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisEQ(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_Bool SCIPisZero(SCIP *scip, SCIP_Real val)
SCIP_Bool SCIPisLT(SCIP *scip, SCIP_Real val1, SCIP_Real val2)
SCIP_RETCODE SCIPvarGetOrigvarSum(SCIP_VAR **var, SCIP_Real *scalar, SCIP_Real *constant)
Definition: var.c:18320
SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
Definition: var.c:23498
SCIP_Real SCIPvarGetObj(SCIP_VAR *var)
Definition: var.c:23900
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:23453
SCIP_Real SCIPvarGetUbGlobal(SCIP_VAR *var)
Definition: var.c:24142
int SCIPvarGetProbindex(SCIP_VAR *var)
Definition: var.c:23662
SCIP_RETCODE SCIPgetProbvarLinearSum(SCIP *scip, SCIP_VAR **vars, SCIP_Real *scalars, int *nvars, int varssize, SCIP_Real *constant, int *requiredsize)
Definition: scip_var.c:2378
SCIP_Real SCIPvarGetLbGlobal(SCIP_VAR *var)
Definition: var.c:24120
void SCIPsort(int *perm, SCIP_DECL_SORTINDCOMP((*indcomp)), void *dataptr, int len)
Definition: misc.c:5581
SYM_NODETYPE SCIPgetSymgraphNodeType(SYM_GRAPH *graph, int nodeidx)
SCIP_RETCODE SCIPaddSymgraphEdge(SCIP *scip, SYM_GRAPH *graph, int first, int second, SCIP_Bool hasval, SCIP_Real val)
SCIP_RETCODE SCIPfreeSymgraph(SCIP *scip, SYM_GRAPH **graph)
int SCIPgetSymgraphEdgeFirst(SYM_GRAPH *graph, int edgeidx)
SCIP_RETCODE SCIPaddSymgraphOpnode(SCIP *scip, SYM_GRAPH *graph, int op, int *nodeidx)
int * SCIPgetSymgraphConsnodeperm(SCIP *scip, SYM_GRAPH *graph)
SCIP_RETCODE SCIPgetSymActiveVariables(SCIP *scip, SYM_SYMTYPE symtype, SCIP_VAR ***vars, SCIP_Real **scalars, int *nvars, SCIP_Real *constant, SCIP_Bool transformed)
SCIP_Bool SCIPhasGraphUniqueEdgetype(SYM_GRAPH *graph)
int SCIPgetSymgraphVarnodeColor(SYM_GRAPH *graph, int nodeidx)
SCIP_RETCODE SCIPaddSymgraphValnode(SCIP *scip, SYM_GRAPH *graph, SCIP_Real val, int *nodeidx)
SCIP_RETCODE SCIPcreateSymgraph(SCIP *scip, SYM_SYMTYPE symtype, SYM_GRAPH **graph, SCIP_VAR **symvars, int nsymvars, int nopnodes, int nvalnodes, int nconsnodes, int nedges)
int SCIPgetSymgraphNEdges(SYM_GRAPH *graph)
int SCIPgetSymgraphVarnodeidx(SCIP *scip, SYM_GRAPH *graph, SCIP_VAR *var)
SCIP_RETCODE SCIPcomputeSymgraphColors(SCIP *scip, SYM_GRAPH *graph, SYM_SPEC fixedtype)
SYM_SYMTYPE SCIPgetSymgraphSymtype(SYM_GRAPH *graph)
SCIP_RETCODE SCIPcopySymgraphAsSubgraph(SCIP *scip, SYM_GRAPH *sourcegraph, SYM_GRAPH *targetgraph, SCIP_CONS *sourcecons, int *rootidx)
SCIP_RETCODE SCIPaddSymgraphConsnode(SCIP *scip, SYM_GRAPH *graph, SCIP_CONS *cons, SCIP_Real lhs, SCIP_Real rhs, int *nodeidx)
SCIP_RETCODE SCIPcreateSymgraphConsnodeperm(SCIP *scip, SYM_GRAPH *graph)
int SCIPgetSymgraphEdgeSecond(SYM_GRAPH *graph, int edgeidx)
int SCIPgetSymgraphNConsnodes(SYM_GRAPH *graph)
SCIP_RETCODE SCIPaddSymgraphVarAggregation(SCIP *scip, SYM_GRAPH *graph, int rootidx, SCIP_VAR **vars, SCIP_Real *vals, int nvars, SCIP_Real constant)
int SCIPgetSymExprdataNConstants(SYM_EXPRDATA *symdata)
SCIP_RETCODE SCIPupdateSymgraphRhs(SYM_GRAPH *graph, int nodeidx, SCIP_Real newrhs)
SCIP_RETCODE SCIPfreeSymgraphConsnodeperm(SCIP *scip, SYM_GRAPH *graph)
SCIP_RETCODE SCIPupdateSymgraphLhs(SYM_GRAPH *graph, int nodeidx, SCIP_Real newlhs)
int SCIPgetSymgraphNVars(SYM_GRAPH *graph)
int SCIPgetSymgraphNegatedVarnodeidx(SCIP *scip, SYM_GRAPH *graph, SCIP_VAR *var)
SCIP_Bool SCIPisSymgraphEdgeColored(SYM_GRAPH *graph, int edgeidx)
SCIP_RETCODE SCIPfreeSymDataExpr(SCIP *scip, SYM_EXPRDATA **symdata)
SCIP_VAR ** SCIPgetSymgraphVars(SYM_GRAPH *graph)
int SCIPgetSymgraphNodeColor(SYM_GRAPH *graph, int nodeidx)
int SCIPgetSymgraphEdgeColor(SYM_GRAPH *graph, int edgeidx)
SCIP_RETCODE SCIPextendPermsymDetectionGraphLinear(SCIP *scip, SYM_GRAPH *graph, SCIP_VAR **vars, SCIP_Real *vals, int nvars, SCIP_CONS *cons, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool *success)
int SCIPgetSymgraphNNodes(SYM_GRAPH *graph)
SCIP_Real * SCIPgetSymExprdataConstants(SYM_EXPRDATA *symdata)
SCIP_RETCODE SCIPclearSymgraph(SCIP *scip, SYM_GRAPH *graph, SCIP_VAR **symvars, int nsymvars, SYM_SYMTYPE symtype)
SCIP_RETCODE SCIPcopySymgraph(SCIP *scip, SYM_GRAPH **graph, SYM_GRAPH *origgraph, int *perm, SYM_SPEC fixedtype)
SCIP_RETCODE SCIPfixSymgraphVarnode(SYM_GRAPH *graph, SCIP_VAR *var)
int SCIPgetSymgraphNVarcolors(SYM_GRAPH *graph)
SCIP_RETCODE SCIPgetCoefSymData(SCIP *scip, SCIP_EXPR *expr, SCIP_EXPR *parentexpr, SCIP_Real *coef, SCIP_Bool *success)
static const SCIP_Real scalars[]
Definition: lp.c:5959
internal miscellaneous methods
#define SCIPerrorMessage
Definition: pub_message.h:64
SCIP callable library.
SCIP_EXPR ** children
SCIP_Real * coefficients
SCIP_Real * constants
int * nodeinfopos
int * conscolors
SCIP_Real infinity
SYM_NODETYPE * nodetypes
int * valcolors
SCIP_Real * edgevals
int * varcolors
int * consnodeperm
int * edgefirst
SCIP_VAR ** symvars
SCIP_Bool * isfixedvar
SCIP_Real * vals
int * edgecolors
SCIP_Real * rhs
SCIP_Bool islocked
SCIP_Bool uniqueedgetype
SCIP_Real * lhs
SCIP_CONS ** conss
int * opcolors
SYM_SYMTYPE symtype
int * edgesecond
structs for symmetry computations
methods for handling symmetries
static SCIP_RETCODE ensureNodeArraysSize(SCIP *scip, SYM_GRAPH *graph, int addsize)
static SCIP_Bool isFixedVar(SCIP_VAR *var, SYM_SPEC fixedtype)
static int compareOps(int op1, int op2)
static int compareVarsFixed(SCIP *scip, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Bool isfixed1, SCIP_Bool isfixed2)
static int compareVarsSignedPerm(SCIP *scip, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Bool isneg1, SCIP_Bool isneg2, SCIP_Real infinity)
static int compareVars(SCIP *scip, SCIP_VAR *var1, SCIP_VAR *var2)
static SCIP_RETCODE ensureEdgeArraysSize(SCIP *scip, SYM_GRAPH *graph, int addsize)
static int compareConsnodes(SCIP *scip, SYM_GRAPH *graph, int ind1, int ind2)
static int compareVarsFixedSignedPerm(SCIP *scip, SCIP_VAR *var1, SCIP_VAR *var2, SCIP_Bool isfixed1, SCIP_Bool isfixed2, SCIP_Bool isneg1, SCIP_Bool isneg2, SCIP_Real infinity)
static SCIP_DECL_SORTINDCOMP(SYMsortVarnodesPermsym)
methods for dealing with symmetry detection graphs
@ SCIP_OKAY
Definition: type_retcode.h:42
@ SCIP_ERROR
Definition: type_retcode.h:43
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
type definitions for symmetry computations
enum SYM_Symtype SYM_SYMTYPE
Definition: type_symmetry.h:64
#define SYM_SPEC_BINARY
Definition: type_symmetry.h:44
#define SYM_SPEC_INTEGER
Definition: type_symmetry.h:43
enum SYM_Nodetype SYM_NODETYPE
Definition: type_symmetry.h:74
@ SYM_NODETYPE_CONS
Definition: type_symmetry.h:71
@ SYM_NODETYPE_VAR
Definition: type_symmetry.h:72
@ SYM_NODETYPE_OPERATOR
Definition: type_symmetry.h:69
@ SYM_NODETYPE_VAL
Definition: type_symmetry.h:70
@ SYM_SYMTYPE_SIGNPERM
Definition: type_symmetry.h:62
@ SYM_SYMTYPE_PERM
Definition: type_symmetry.h:61
uint32_t SYM_SPEC
Definition: type_symmetry.h:47
#define SYM_SPEC_REAL
Definition: type_symmetry.h:45
@ SCIP_VARTYPE_INTEGER
Definition: type_var.h:65
@ SCIP_VARTYPE_CONTINUOUS
Definition: type_var.h:71
@ SCIP_VARTYPE_BINARY
Definition: type_var.h:64
enum SCIP_Vartype SCIP_VARTYPE
Definition: type_var.h:73