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