Scippy

SCIP

Solving Constraint Integer Programs

sepa_clique.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 sepa_clique.c
26 * @ingroup DEFPLUGINS_SEPA
27 * @brief clique separator
28 * @author Kati Wolter
29 * @author Tobias Achterberg
30 */
31
32/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
33
35#include "scip/pub_implics.h"
36#include "scip/pub_lp.h"
37#include "scip/pub_message.h"
38#include "scip/pub_misc.h"
39#include "scip/pub_sepa.h"
40#include "scip/pub_var.h"
41#include "scip/scip_branch.h"
42#include "scip/scip_cut.h"
43#include "scip/scip_general.h"
44#include "scip/scip_lp.h"
45#include "scip/scip_mem.h"
46#include "scip/scip_message.h"
47#include "scip/scip_numerics.h"
48#include "scip/scip_param.h"
49#include "scip/scip_prob.h"
50#include "scip/scip_sepa.h"
51#include "scip/scip_sol.h"
52#include "scip/scip_var.h"
53#include "scip/sepa_clique.h"
54#include "tclique/tclique.h"
55#include <string.h>
56#ifndef _WIN32
57#include <strings.h> /*lint --e{766}*/
58#endif
59
60
61#define SEPA_NAME "clique"
62#define SEPA_DESC "clique separator of stable set relaxation"
63#define SEPA_PRIORITY -5000
64#define SEPA_FREQ 0
65#define SEPA_MAXBOUNDDIST 0.0
66#define SEPA_USESSUBSCIP FALSE /**< does the separator use a secondary SCIP instance? */
67#define SEPA_DELAY FALSE /**< should separation method be delayed, if other separators found cuts? */
68
69#define DEFAULT_SCALEVAL 1000.0 /**< factor for scaling weights */
70#define DEFAULT_MAXTREENODES 10000 /**< maximal number of nodes in branch and bound tree (-1: no limit) */
71#define DEFAULT_BACKTRACKFREQ 1000 /**< frequency for premature backtracking up to tree level 1 (0: no backtracking) */
72#define DEFAULT_MAXSEPACUTS 10 /**< maximal number of clique cuts separated per separation round (-1: no limit) */
73#define DEFAULT_MAXZEROEXTENSIONS 1000 /**< maximal number of zero-valued variables extending the clique (-1: no limit) */
74#define DEFAULT_CLIQUETABLEMEM 20000.0 /**< maximal memory size of dense clique table (in kb) */
75#define DEFAULT_CLIQUEDENSITY 0.00 /**< minimal density of cliques to use a dense clique table */
76
77
78/*
79 * Data structures
80 */
81
82/** separator data */
83struct SCIP_SepaData
84{
85 TCLIQUE_GRAPH* tcliquegraph; /**< tclique graph data structure */
86 SCIP* scip; /**< SCIP data structure */
87 SCIP_SEPA* sepa; /**< separator */
88 SCIP_SOL* sol; /**< primal solution that is currently separated */
89 SCIP_Real* varsolvals; /**< LP solution of binary variables (contained in a 3-clique in implgraph) */
90 SCIP_Real scaleval; /**< factor for scaling weights */
91 SCIP_Longint ncalls; /**< number of calls to the clique separator */
92 int maxtreenodes; /**< maximal number of nodes in branch and bound tree (-1: no limit) */
93 int backtrackfreq; /**< frequency for premature backtracking up to tree level 1 (0: no backtracking) */
94 int maxsepacuts; /**< maximal number of clique cuts separated per separation round (-1: no limit) */
95 int maxzeroextensions; /**< maximal number of zero-valued variables extending the clique (-1: no limit) */
96 SCIP_Real cliquetablemem; /**< maximal memory size of dense clique table (in kb) */
97 SCIP_Real cliquedensity; /**< minimal density of cliques to use a dense clique table */
98 int ncuts; /**< number of cuts found */
99 SCIP_Bool tcliquegraphloaded; /**< TRUE if tcliquegraph is already loaded (tcliquegraph can be NULL),
100 * FALSE otherwise */
101 SCIP_Bool cutoff; /**< whether the clique algorithm detected a cutoff */
102 SCIP_RETCODE retcode; /**< error code which might occur during the maximal clique algorithm */
103};
104
105/** tclique graph data */
106struct TCLIQUE_Graph
107{
108 SCIP_VAR** vars; /**< active problem variables (or negated variables) the nodes belong to */
109 TCLIQUE_WEIGHT* weights; /**< weight of nodes */
110 int* adjnodesidxs; /**< indices in adjnodes array of first adjacent nodes for each node */
111 int* cliqueidsidxs; /**< indices in cliqueids array of first clique the node is contained in */
112 int* adjnodes; /**< adjacent nodes of edges */
113 unsigned int* cliqueids; /**< unique ids of cliques */
114 unsigned int* cliquetable; /**< dense bitvector clique table (array stored as a vector) */
115 int adjnodessize; /**< size of adjnodes array */
116 int cliqueidssize; /**< size of cliqueids array */
117 int nnodes; /**< number of nodes in graph */
118 int tablewidth; /**< number of unsigned ints per row in the table */
119
120 int maxnnodes; /**< allocated memory for some arrays */
121};
122
123
124/*
125 * Methods for tclique graph
126 */
127
128/** creates an empty tclique graph data structure */
129static
131 SCIP* scip, /**< SCIP data structure */
132 TCLIQUE_GRAPH** tcliquegraph /**< pointer to tclique graph data */
133 )
134{
135 int maxnnodes;
136
137 assert(tcliquegraph != NULL);
138
139 SCIP_CALL( SCIPallocBlockMemory(scip, tcliquegraph) );
140
141 /* there are at most 2*nbinvars nodes in the graph */
142 maxnnodes = 2*SCIPgetNBinVars(scip);
143 assert(maxnnodes > 0);
144
145 /* allocate memory for tclique graph arrays */
146 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*tcliquegraph)->vars, maxnnodes) );
147 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*tcliquegraph)->weights, maxnnodes) );
148 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*tcliquegraph)->adjnodesidxs, maxnnodes+1) );
149 SCIP_CALL( SCIPallocBlockMemoryArray(scip, &(*tcliquegraph)->cliqueidsidxs, maxnnodes+1) );
150 (*tcliquegraph)->adjnodesidxs[0] = 0; /* the last slot defines the end of the last node */
151 (*tcliquegraph)->cliqueidsidxs[0] = 0; /* the last slot defines the end of the last node */
152 (*tcliquegraph)->adjnodes = NULL;
153 (*tcliquegraph)->cliqueids = NULL;
154 (*tcliquegraph)->cliquetable = NULL;
155 (*tcliquegraph)->adjnodessize = 0;
156 (*tcliquegraph)->cliqueidssize = 0;
157 (*tcliquegraph)->nnodes = 0;
158 (*tcliquegraph)->tablewidth = 0;
159 (*tcliquegraph)->maxnnodes = maxnnodes; /* remember allocated memory */
160
161 return SCIP_OKAY;
162}
163
164/** frees the tclique graph data structure and releases all captured variables */
165static
167 SCIP* scip, /**< SCIP data structure */
168 TCLIQUE_GRAPH** tcliquegraph /**< pointer to tclique graph data */
169 )
170{
171 int v;
172
173 assert(tcliquegraph != NULL);
174 assert(*tcliquegraph != NULL);
175
176 /* release variables */
177 for( v = 0; v < (*tcliquegraph)->nnodes; ++v )
178 {
179 SCIP_CALL( SCIPreleaseVar(scip, &(*tcliquegraph)->vars[v]) );
180 }
181
182 /* free memory */
183 SCIPfreeBlockMemoryArray(scip, &(*tcliquegraph)->vars, (*tcliquegraph)->maxnnodes);
184 SCIPfreeBlockMemoryArray(scip, &(*tcliquegraph)->weights, (*tcliquegraph)->maxnnodes);
185 SCIPfreeBlockMemoryArray(scip, &(*tcliquegraph)->adjnodesidxs, (*tcliquegraph)->maxnnodes + 1);
186 SCIPfreeBlockMemoryArray(scip, &(*tcliquegraph)->cliqueidsidxs, (*tcliquegraph)->maxnnodes + 1);
187 SCIPfreeMemoryArrayNull(scip, &(*tcliquegraph)->adjnodes);
188 SCIPfreeMemoryArrayNull(scip, &(*tcliquegraph)->cliqueids);
189 SCIPfreeMemoryArrayNull(scip, &(*tcliquegraph)->cliquetable);
190 SCIPfreeBlockMemory(scip, tcliquegraph);
191
192 return SCIP_OKAY;
193}
194
195
196/** ensures that the cliqueids array can store at least num entries */
197static
199 SCIP* scip, /**< SCIP data structure */
200 TCLIQUE_GRAPH* tcliquegraph, /**< tclique graph data */
201 int num /**< minimal number of adjacent nodes to be able to store in the array */
202 )
203{
204 assert(tcliquegraph != NULL);
205
206 if( num > tcliquegraph->cliqueidssize )
207 {
208 tcliquegraph->cliqueidssize = SCIPcalcMemGrowSize(scip, num);
209 SCIP_CALL( SCIPreallocMemoryArray(scip, &tcliquegraph->cliqueids, tcliquegraph->cliqueidssize) );
210 }
211 assert(num <= tcliquegraph->cliqueidssize);
212
213 return SCIP_OKAY;
214}
215
216/** adds a node to the tclique graph defined as a variable-value pair; adds all cliques to the cliqueids array the
217 * variable is contained in with the given value
218 */
219static
221 SCIP* scip, /**< SCIP data structure */
222 TCLIQUE_GRAPH** tcliquegraph, /**< pointer to tclique graph data */
223 SCIP_VAR* var, /**< active binary problem variable */
224 SCIP_Bool value, /**< value of the variable in the node */
225 int* nodeidx /**< pointer to store the index of the new node */
226 )
227{
228 SCIP_VAR* nodevar;
229 unsigned int* cliqueids;
230 SCIP_CLIQUE** cliques;
231 int ncliques;
232 int nadjnodes;
233 int ncliqueids;
234 int i;
235
236 assert(tcliquegraph != NULL);
238 assert(SCIPvarIsActive(var));
239 assert(nodeidx != NULL);
240
241 /* create tclique graph data if not yet existing */
242 if( *tcliquegraph == NULL )
243 {
244 SCIP_CALL( tcliquegraphCreate(scip, tcliquegraph) );
245 }
246 assert(*tcliquegraph != NULL);
247 assert((*tcliquegraph)->nnodes < 2*SCIPgetNBinVars(scip));
248
249 /* if the value is FALSE, use the negated variable for the node */
250 if( !value )
251 {
252 SCIP_CALL( SCIPgetNegatedVar(scip, var, &nodevar) );
253 }
254 else
255 nodevar = var;
256
257 /* get the current number of used entries in adjnodes and cliqueids arrays */
258 nadjnodes = (*tcliquegraph)->adjnodesidxs[(*tcliquegraph)->nnodes];
259 ncliqueids = (*tcliquegraph)->cliqueidsidxs[(*tcliquegraph)->nnodes];
260
261 /* insert the variable into the tclique graph */
262 *nodeidx = (*tcliquegraph)->nnodes;
263 SCIP_CALL( SCIPcaptureVar(scip, nodevar) );
264 (*tcliquegraph)->vars[*nodeidx] = nodevar;
265 (*tcliquegraph)->weights[*nodeidx] = 0;
266 (*tcliquegraph)->nnodes++;
267
268 /* store the ids of the variable's cliques in the cliqueids array */
269 ncliques = SCIPvarGetNCliques(var, value);
270 cliques = SCIPvarGetCliques(var, value);
271 SCIP_CALL( tcliquegraphEnsureCliqueidsSize(scip, *tcliquegraph, ncliqueids + ncliques) );
272 cliqueids = (*tcliquegraph)->cliqueids;
273 for( i = 0; i < ncliques; ++i )
274 {
275 assert(ncliqueids < (*tcliquegraph)->cliqueidssize);
276 cliqueids[ncliqueids] = SCIPcliqueGetId(cliques[i]);
277 assert(i == 0 || cliqueids[ncliqueids-1] <= cliqueids[ncliqueids]);
278 ncliqueids++;
279 }
280
281 /* store the new number of used entries in adjnodes and cliqueids arrays */
282 (*tcliquegraph)->adjnodesidxs[(*tcliquegraph)->nnodes] = nadjnodes;
283 (*tcliquegraph)->cliqueidsidxs[(*tcliquegraph)->nnodes] = ncliqueids;
284
285 return SCIP_OKAY;
286}
287
288/** adds all variable/value pairs to the tclique graph that are contained in an existing 3-clique */
289static
291 SCIP* scip, /**< SCIP data structure */
292 TCLIQUE_GRAPH** tcliquegraph, /**< pointer to tclique graph data */
293 int** cliquegraphidx /**< array to store tclique graph node index of variable/value pairs */
294 )
295{
296 SCIP_VAR** vars;
297 int nvars;
298 int i;
299
300 assert(tcliquegraph != NULL);
301 assert(cliquegraphidx != NULL);
302 assert(cliquegraphidx[0] != NULL);
303 assert(cliquegraphidx[1] != NULL);
304
305 /* get binary problem variables */
306 vars = SCIPgetVars(scip);
307 nvars = SCIPgetNBinVars(scip);
308
309 for( i = 0; i < nvars; ++i )
310 {
311 SCIP_VAR* var;
312 int value;
313
314 var = vars[i];
315
316 for( value = 0; value < 2; ++value )
317 {
318 assert(cliquegraphidx[value][i] == -1);
319
320 if( SCIPvarGetNCliques(var, (SCIP_Bool)value) >= 1 )
321 {
322 /* all cliques stored in the clique table are at least 3-cliques */
323 SCIP_CALL( tcliquegraphAddNode(scip, tcliquegraph, var, (SCIP_Bool)value, &cliquegraphidx[value][i]) );
324 }
325 }
326 }
327
328 return SCIP_OKAY;
329}
330
331/** constructs dense clique incidence matrix
332 *
333 * @todo add implicit and integer variables appearing in cliques also to the clique table
334 */
335static
337 SCIP* scip, /**< SCIP data structure */
338 TCLIQUE_GRAPH* tcliquegraph, /**< tclique graph data */
339 SCIP_Real cliquetablemem, /**< maximal memory size of dense clique table (in kb) */
340 SCIP_Real cliquedensity /**< minimal density of cliques to store as dense table */
341 )
342{
343 SCIP_CLIQUE** cliques;
344 int* varids;
345 unsigned int* cliquetable;
347 int nbits;
348 int tablesize;
349 int tablewidth;
350 int ncliques;
351 int nelems;
352 int i;
353
354 cliques = SCIPgetCliques(scip);
355 ncliques = SCIPgetNCliques(scip);
356 if( ncliques == 0 )
357 return SCIP_OKAY;
358
359 assert(tcliquegraph != NULL);
360
361 /* calculate size of dense clique table */
362 nbits = 8*sizeof(unsigned int);
363 tcliquegraph->tablewidth = (tcliquegraph->nnodes + nbits-1) / nbits; /* number of ints needed */
364
365 /* check if dense clique table is too large (calculate as Reals to avoid overflow) */
366 if( (SCIP_Real)tcliquegraph->nnodes * (SCIP_Real)tcliquegraph->tablewidth/1024.0 > cliquetablemem )
367 return SCIP_OKAY;
368
369 /* calculate clique entry density */
370 nelems = 0;
371 for( i = 0; i < ncliques; ++i )
372 nelems += SCIPcliqueGetNVars(cliques[i]);
373 density = (SCIP_Real)nelems / ((SCIP_Real)ncliques * (SCIP_Real)tcliquegraph->nnodes);
374 if( density < cliquedensity )
375 return SCIP_OKAY;
376
377 /* allocate memory */
378 tablesize = tcliquegraph->nnodes * tcliquegraph->tablewidth;
379 SCIPdebugMsg(scip, "clique separator: constructing dense clique table (%d kb, %d cliques, %d nodes, density: %.2f)\n",
380 tablesize/1024, SCIPgetNCliques(scip), tcliquegraph->nnodes, density);
381
382 SCIP_CALL( SCIPallocMemoryArray(scip, &tcliquegraph->cliquetable, tablesize) );
383 BMSclearMemoryArray(tcliquegraph->cliquetable, tablesize);
384
385 /* insert the cliques as complete graphs to the incidence matrix */
386 SCIP_CALL( SCIPallocBufferArray(scip, &varids, tcliquegraph->nnodes) );
387 cliquetable = tcliquegraph->cliquetable;
388 tablewidth = tcliquegraph->tablewidth;
389 for( i = 0; i < ncliques && !SCIPisStopped(scip); ++i )
390 {
391 SCIP_VAR** vars;
392 SCIP_Bool* vals;
393 int nvars;
394 int u;
395 int v;
396
397 vars = SCIPcliqueGetVars(cliques[i]);
398 vals = SCIPcliqueGetValues(cliques[i]);
399 nvars = SCIPcliqueGetNVars(cliques[i]);
400
401 /* get the node numbers of the variables */
402 for( u = 0; u < nvars && !SCIPisStopped(scip); ++u )
403 {
404 SCIP_VAR* var;
405
406 /* implicit integer and integer variables are currently not present in the constructed tclique graph */
408 continue;
409
410 var = (vals[u] ? vars[u] : SCIPvarGetNegatedVar(vars[u]));
411 assert(var != NULL); /* var must exist even if negated, since it is stored in the tcliquegraph */
412 for( v = 0; v < tcliquegraph->nnodes && var != tcliquegraph->vars[v]; ++v )
413 {}
414 assert(v < tcliquegraph->nnodes);
415 varids[u] = v;
416 }
417
418 /* flag the edges in the incidence matrix (excluding diagonal entries) */
419 for( u = 0; u < nvars-1 && !SCIPisStopped(scip); ++u )
420 {
421 int nu;
422 int rowstart;
423 int colofs;
424 unsigned int colmask;
425
426 /* implicit integer and integer variables are currently not present in the constructed tclique graph */
428 continue;
429
430 nu = varids[u];
431 rowstart = nu*tablewidth;
432 colofs = nu/nbits;
433 colmask = 1U << (nu % nbits); /*lint !e701*/
434 for( v = u+1; v < nvars; ++v )
435 {
436 int nv;
437 unsigned int mask;
438
439 /* implicit integer and integer variables are currently not present in the constructed tclique graph */
441 continue;
442
443 nv = varids[v];
444 mask = 1U << (nv % nbits); /*lint !e701*/
445 cliquetable[rowstart+nv/nbits] |= mask;
446 cliquetable[nv*tablewidth+colofs] |= colmask;
447 }
448 }
449 }
450 SCIPfreeBufferArray(scip, &varids);
451
452 SCIPdebugMsg(scip, "clique separator: finished constructing dense clique table\n");
453
454 return SCIP_OKAY;
455}
456
457/** creates tclique data structure using the implication graph;
458 * only variables that are contained in a 3-clique are added as nodes to the clique graph
459 */
460static
462 SCIP* scip, /**< SCIP data structure */
463 SCIP_SEPADATA* sepadata /**< separator data */
464 )
465{
466 int* cliquegraphidx[2];
467 int nvars;
468 int i;
469
470 assert(sepadata != NULL);
471 assert(sepadata->tcliquegraph == NULL);
472
473 /* there is nothing to do, if no binary variables are present in the problem */
474 nvars = SCIPgetNBinVars(scip);
475 if( nvars == 0 )
476 return SCIP_OKAY;
477
478 /* get temporary memory for mapping variable/value pairs to clique graph nodes */
479 SCIP_CALL( SCIPallocBufferArray(scip, &cliquegraphidx[0], nvars) );
480 SCIP_CALL( SCIPallocBufferArray(scip, &cliquegraphidx[1], nvars) );
481 for( i = 0; i < nvars; ++i )
482 {
483 cliquegraphidx[0][i] = -1;
484 cliquegraphidx[1][i] = -1;
485 }
486
487 /* insert all variable/value pairs that are contained in an existing 3-clique */
488 SCIP_CALL( tcliquegraphAddCliqueVars(scip, &sepadata->tcliquegraph, cliquegraphidx) );
489
490 /* it occurs that it might be that some cliques were not yet removed from the global clique array, so SCIPgetNClique
491 * can be greater than 0, even if there is no clique with some variables left */
492 /** @todo clean up empty cliques */
493 if( sepadata->tcliquegraph != NULL )
494 {
495 /* construct the dense clique table */
496 SCIP_CALL( tcliquegraphConstructCliqueTable(scip, sepadata->tcliquegraph, sepadata->cliquetablemem, sepadata->cliquedensity) );
497 }
498
499 /* free temporary memory */
500 SCIPfreeBufferArray(scip, &cliquegraphidx[1]);
501 SCIPfreeBufferArray(scip, &cliquegraphidx[0]);
502 if( SCIPisStopped(scip) && sepadata->tcliquegraph != NULL )
503 SCIP_CALL( tcliquegraphFree(scip,&sepadata->tcliquegraph) );
504 return SCIP_OKAY;
505}
506
507/** updates the weights in the tclique graph data structure */
508static
510 SCIP* scip, /**< SCIP data structure */
511 SCIP_SEPADATA* sepadata /**< separator data */
512 )
513{
514 TCLIQUE_GRAPH* tcliquegraph;
515 int i;
516
517 assert(sepadata != NULL);
518 assert(sepadata->varsolvals != NULL);
519
520 tcliquegraph = sepadata->tcliquegraph;
521 assert(tcliquegraph != NULL);
522
523 /* updates weight of all nodes in tclique data structure */
524 for( i = 0; i < tcliquegraph->nnodes; i++ )
525 {
526 int weight;
527
528 weight = (TCLIQUE_WEIGHT)SCIPfeasFloor(scip, sepadata->varsolvals[i] * sepadata->scaleval);
529 tcliquegraph->weights[i] = MAX(weight, 0);
530 }
531}
532
533
534/*
535 * TClique Graph Callbacks
536 */
537
538/** gets number of nodes in the graph */
539static
540TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
541{
542 assert(tcliquegraph != NULL);
543
544 return tcliquegraph->nnodes;
545}
546
547/** gets weight of nodes in the graph */
548static
549TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
550{
551 assert(tcliquegraph != NULL);
552
553 return tcliquegraph->weights;
554}
555
556/** returns whether the nodes are member of a common clique */
557static
559 TCLIQUE_GRAPH* tcliquegraph, /**< tclique graph data */
560 int node1, /**< first node */
561 int node2 /**< second node */
562 )
563{
564 assert(tcliquegraph != NULL);
565
566 /* return TRUE for equal nodes */
567 if( node1 == node2 )
568 return TRUE;
569
570 /* check whether the dense clique table was constructed */
571 if( tcliquegraph->cliquetable != NULL )
572 {
573 int nbits;
574 unsigned int mask;
575 int colofs;
576
577 /* check entry in the table */
578 nbits = 8*sizeof(unsigned int);
579 mask = (1U << (node2 % nbits)); /*lint !e701*/
580 colofs = node2 / nbits;
581 assert(((tcliquegraph->cliquetable[node1*tcliquegraph->tablewidth + colofs] & mask) != 0)
582 == ((tcliquegraph->cliquetable[node2*tcliquegraph->tablewidth + node1/nbits] & (1U << (node1 % nbits))) != 0)); /*lint !e701*/
583 return ((tcliquegraph->cliquetable[node1*tcliquegraph->tablewidth + colofs] & mask) != 0);
584 }
585 else
586 {
587 unsigned int* cliqueids;
588 int i1;
589 int i2;
590 int endi1;
591 int endi2;
592
593 cliqueids = tcliquegraph->cliqueids;
594 i1 = tcliquegraph->cliqueidsidxs[node1];
595 endi1 = tcliquegraph->cliqueidsidxs[node1+1];
596 i2 = tcliquegraph->cliqueidsidxs[node2];
597 endi2 = tcliquegraph->cliqueidsidxs[node2+1];
598 while( i1 < endi1 && i2 < endi2 )
599 {
600 while( i1 < endi1 && cliqueids[i1] < cliqueids[i2] )
601 i1++;
602 if( i1 == endi1 )
603 break;
604
605 while( i2 < endi2 && cliqueids[i2] < cliqueids[i1] )
606 i2++;
607 if( i2 == endi2 )
608 break;
609
610 if( cliqueids[i1] == cliqueids[i2] )
611 return TRUE;
612 }
613
614 return FALSE;
615 }
616}
617
618/** returns whether the edge (node1, node2) is in the graph */
619static
620TCLIQUE_ISEDGE(tcliqueIsedgeClique)
621{
622 int left;
623 int right;
624
625 assert(tcliquegraph != NULL);
626 assert(0 <= node1 && node1 < tcliquegraph->nnodes);
627 assert(0 <= node2 && node2 < tcliquegraph->nnodes);
628
629 /* check if node2 is contained in adjacency list of node1 (list is ordered by adjacent nodes) */
630 left = tcliquegraph->adjnodesidxs[node1];
631 right = tcliquegraph->adjnodesidxs[node1+1]-1;
632 while( left <= right )
633 {
634 int middle;
635 int node;
636
637 middle = (left+right)/2;
638 node = tcliquegraph->adjnodes[middle];
639 if( node < node2 )
640 left = middle+1;
641 else if( node > node2 )
642 right = middle-1;
643 else
644 return TRUE;
645 }
646
647 /* check if the nodes are member of a common clique */
648 return nodesHaveCommonClique(tcliquegraph, node1, node2);
649}
650
651/** selects all nodes from a given set of nodes which are adjacent to a given node
652 * and returns the number of selected nodes
653 */
654static
655TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
656{
657 int* graphadjnodes;
658 int nadjnodes;
659 int nodeadjindex;
660 int nodeadjend;
661 int i;
662
663 assert(tcliquegraph != NULL);
664 assert(0 <= node && node < tcliquegraph->nnodes);
665 assert(nnodes == 0 || nodes != NULL);
666 assert(adjnodes != NULL);
667
668 nadjnodes = 0;
669
670 /* check for each node in given nodes set, if it is adjacent to the given node or shares a common clique */
671 graphadjnodes = tcliquegraph->adjnodes;
672 nodeadjindex = tcliquegraph->adjnodesidxs[node];
673 nodeadjend = tcliquegraph->adjnodesidxs[node+1];
674 for( i = 0; i < nnodes; i++ )
675 {
676 /* check if the node is adjacent to the given node (nodes and adjacent nodes are ordered by node index) */
677 assert(0 <= nodes[i] && nodes[i] < tcliquegraph->nnodes);
678 assert(i == 0 || nodes[i-1] < nodes[i]);
679 while( nodeadjindex < nodeadjend && graphadjnodes[nodeadjindex] < nodes[i] )
680 nodeadjindex++;
681 if( nodeadjindex < nodeadjend && graphadjnodes[nodeadjindex] == nodes[i] )
682 {
683 /* current node is adjacent to given node */
684 adjnodes[nadjnodes] = nodes[i];
685 nadjnodes++;
686 }
687 else
688 {
689 /* current node is not adjacent to given node: check if they share a common clique */
690 if( nodesHaveCommonClique(tcliquegraph, node, nodes[i]) )
691 {
692 adjnodes[nadjnodes] = nodes[i];
693 nadjnodes++;
694 }
695 }
696 }
697
698 return nadjnodes;
699}
700
701/** basic code for new cliques (needed because of error handling) */
702static
704 SCIP* scip, /**< SCIP data structure */
705 SCIP_SEPA* sepa, /**< the cut separator itself */
706 SCIP_SEPADATA* sepadata, /**< data of separator */
707 int ncliquenodes, /**< number of nodes in clique */
708 int* cliquenodes /**< nodes in clique */
709 )
710{
711 SCIP_VAR** vars;
712 SCIP_ROW* cut;
713 char cutname[SCIP_MAXSTRLEN];
714 int i;
715
716 vars = sepadata->tcliquegraph->vars;
717 assert(sepadata->tcliquegraph->nnodes > 0);
718 assert(vars != NULL);
719
720 /* create the cut (handle retcode since we do not have a backtrace) */
721 (void) SCIPsnprintf(cutname, SCIP_MAXSTRLEN, "clique%" SCIP_LONGINT_FORMAT "_%d", sepadata->ncalls, sepadata->ncuts);
722 SCIP_CALL( SCIPcreateEmptyRowSepa(scip, &cut, sepa, cutname, -SCIPinfinity(scip), 1.0, FALSE, FALSE, TRUE) );
723
725
726 assert(ncliquenodes <= sepadata->tcliquegraph->nnodes);
727 /*SCIPdebugMsg(scip, " -> clique in graph:");*/
728 for( i = 0; i < ncliquenodes; ++i )
729 {
730 assert(cliquenodes[i] < sepadata->tcliquegraph->nnodes);
731 SCIP_CALL( SCIPaddVarToRow(scip, cut, vars[cliquenodes[i]], 1.0) );
732 /*SCIPdebugMsgPrint(scip, " [%d]<%s>", cliquenodes[i], SCIPvarGetName(vars[cliquenodes[i]]));*/
733 }
734 /*SCIPdebugMsgPrint(scip, "\n");*/
736
737 /* set cut rank: for clique cuts we always set to 1 */
738 SCIProwChgRank(cut, 1);
739
740 /*SCIPdebug( SCIP_CALL(SCIPprintRow(scip, cut, NULL)) );*/
741
743
744 /* release the row */
745 SCIP_CALL( SCIPreleaseRow(scip, &cut) );
746
747 return SCIP_OKAY;
748}
749
750/** generates cuts using a clique found by algorithm for maximum weight clique
751 * and decides whether to stop generating cliques with the algorithm for maximum weight clique
752 */
753static
754TCLIQUE_NEWSOL(tcliqueNewsolClique)
755{
756 SCIP_SEPADATA* sepadata;
757 TCLIQUE_WEIGHT minweightinc;
758
759 assert(acceptsol != NULL);
760 assert(stopsolving != NULL);
761
762 sepadata = (SCIP_SEPADATA*)tcliquedata;
763 assert(sepadata != NULL);
764 assert(sepadata->scip != NULL);
765 assert(sepadata->sepa != NULL);
766 assert(sepadata->tcliquegraph != NULL);
767 assert(sepadata->ncuts >= 0);
768
769 /* we don't accept the solution as new incumbent, because we want to find many violated clique inequalities */
770 *acceptsol = FALSE;
771 *stopsolving = FALSE;
772
773 /* slightly increase the minimal weight for additional cliques */
774 minweightinc = (cliqueweight - *minweight)/10;
775 minweightinc = MAX(minweightinc, 1);
776 *minweight += minweightinc;
777
778 /* adds cut if weight of the clique is greater than 1 */
779 if( cliqueweight > sepadata->scaleval )
780 {
781 SCIP* scip;
782 SCIP_SEPA* sepa;
783 SCIP_Real* varsolvals;
784 SCIP_Real unscaledweight;
785 int i;
786
787 scip = sepadata->scip;
788 sepa = sepadata->sepa;
789 varsolvals = sepadata->varsolvals;
790 assert(varsolvals != NULL);
791
792 /* calculate the weight of the clique in unscaled fractional variable space */
793 unscaledweight = 0.0;
794 for( i = 0; i < ncliquenodes; i++ )
795 unscaledweight += varsolvals[cliquenodes[i]];
796
797 if( SCIPisEfficacious(scip, unscaledweight - 1.0) )
798 {
799 SCIP_RETCODE retcode;
800
801 /* explicitly handle return code */
802 retcode = newsolCliqueAddRow(scip, sepa, sepadata, ncliquenodes, cliquenodes);
803 if ( retcode == SCIP_OKAY )
804 {
805 SCIPdebugMsg(scip, " -> found clique cut (act=%g)\n", unscaledweight);
806 sepadata->ncuts++;
807
808 /* if we found more than half the cuts we are allowed to generate, we accept the clique as new incumbent,
809 * such that only more violated cuts are generated afterwards */
810 if( sepadata->maxsepacuts >= 0 )
811 {
812 if( sepadata->ncuts > sepadata->maxsepacuts/2 )
813 *acceptsol = TRUE;
814 if( sepadata->ncuts >= sepadata->maxsepacuts )
815 *stopsolving = TRUE;
816 }
817 }
818 else
819 {
820 /* in case an internal SCIP error occurred we stop the algorithm and store the error code for later
821 * evaluation
822 */
823 sepadata->retcode = retcode;
824 *stopsolving = TRUE;
825 }
826 }
827 }
828}
829
830
831/*
832 * main separation method
833 */
834
835/** searches and adds clique cuts that separate the given primal solution
836 *
837 * @todo Should the existing cliques in the table be separated before starting the tclique algorithm?
838 * Is this done somewhere else?
839 */
840static
842 SCIP* scip, /**< SCIP data structure */
843 SCIP_SEPA* sepa, /**< the cut separator itself */
844 SCIP_SOL* sol, /**< primal solution that should be separated, or NULL for LP solution */
845 SCIP_RESULT* result /**< pointer to store the result of the separation call */
846 )
847{ /*lint --e{715}*/
848 SCIP_SEPADATA* sepadata;
849 TCLIQUE_GRAPH* tcliquegraph;
850 int* cliquenodes;
851 TCLIQUE_WEIGHT cliqueweight;
852 TCLIQUE_STATUS tcliquestatus;
853 int ncliquenodes;
854 int maxtreenodes;
855 int maxzeroextensions;
856 SCIP_Bool infeasible;
857
858 assert(scip != NULL);
859 assert(*result == SCIP_DIDNOTRUN);
860
861 infeasible = FALSE;
862 /* get clique table */
863 SCIP_CALL( SCIPcleanupCliques(scip, &infeasible) );
864 if( infeasible )
865 return SCIP_OKAY;
866
867 /* get separator data */
868 sepadata = SCIPsepaGetData(sepa);
869 assert(sepadata != NULL);
870
871 sepadata->sol = sol;
872 sepadata->ncalls = SCIPsepaGetNCalls(sepa);
873 sepadata->cutoff = FALSE;
874 sepadata->ncuts = 0;
875
876 /* if we already detected that no implications between binary variables exist, nothing has to be done */
877 if( sepadata->tcliquegraph == NULL && sepadata->tcliquegraphloaded )
878 return SCIP_OKAY;
879
880 *result = SCIP_DIDNOTFIND;
881
882 /* load tclique data structure */
883 if( !sepadata->tcliquegraphloaded )
884 {
885 assert(sepadata->tcliquegraph == NULL);
886
887 SCIPdebugMsg(scip, "loading implication and clique graph\n");
888 SCIP_CALL( loadTcliquegraph(scip, sepadata) );
889 sepadata->tcliquegraphloaded = TRUE;
890
891 if( sepadata->tcliquegraph == NULL )
892 {
893 if( SCIPisStopped(scip) )
894 sepadata->tcliquegraphloaded = FALSE;
895 /* we did not find any variables that are contained in a clique with at least 3 variables in the
896 * implication graph or in the clique table -> nothing has to be done
897 */
898 else
899 {
900 SCIPdebugMsg(scip, "no 3-cliques found in implication graph\n");
901 }
902
903 return SCIP_OKAY;
904 }
905 }
906 tcliquegraph = sepadata->tcliquegraph;
907 assert(tcliquegraph != NULL);
908
909 /* store LP-solution in sepadata and update weights in tclique data structure */
910 SCIP_CALL( SCIPallocBufferArray(scip, &sepadata->varsolvals, tcliquegraph->nnodes) );
911 SCIP_CALL( SCIPgetSolVals(scip, sol, tcliquegraph->nnodes, tcliquegraph->vars, sepadata->varsolvals) );
912 updateTcliquegraph(scip, sepadata);
913
914 /* get maximal number of tree nodes and maximal zero-extensions */
915 maxtreenodes = (sepadata->maxtreenodes == -1 ? INT_MAX : sepadata->maxtreenodes);
916 maxzeroextensions = (sepadata->maxzeroextensions == -1 ? INT_MAX : sepadata->maxzeroextensions);
917
918 SCIPdebugMsg(scip, "searching for violated clique cuts\n");
919
920 sepadata->retcode = SCIP_OKAY;
921
922 /* finds maximum weight clique in tclique */
923 SCIP_CALL( SCIPallocBufferArray(scip, &cliquenodes, tcliquegraph->nnodes) );
924 tcliqueMaxClique(tcliqueGetnnodesClique, tcliqueGetweightsClique, tcliqueIsedgeClique, tcliqueSelectadjnodesClique,
925 tcliquegraph, tcliqueNewsolClique, (TCLIQUE_DATA*)sepadata,
926 cliquenodes, &ncliquenodes, &cliqueweight, (int)sepadata->scaleval-1, (int)sepadata->scaleval+1,
927 maxtreenodes, sepadata->backtrackfreq, maxzeroextensions, -1, NULL, &tcliquestatus);
928
929 /* in case an internal error occurred during the maximal clique computation, evaluate that one */
930 SCIP_CALL( sepadata->retcode );
931
932 SCIPdebugMsg(scip, "finished searching clique cuts: found %d cuts\n", sepadata->ncuts);
933
934 /* frees data structures */
935 SCIPfreeBufferArray(scip, &cliquenodes);
936 SCIPfreeBufferArray(scip, &sepadata->varsolvals);
937
938 /* adjust result code */
939 if ( sepadata->cutoff )
940 *result = SCIP_CUTOFF;
941 else if( sepadata->ncuts > 0 )
942 *result = SCIP_SEPARATED;
943
944 /* better reset the sol pointer in sepadata to avoid having an invalid pointer */
945 sepadata->sol = NULL;
946
947 return SCIP_OKAY;
948}
949
950
951/*
952 * Callback methods of separator
953 */
954
955/** copy method for separator plugins (called when SCIP copies plugins) */
956static
957SCIP_DECL_SEPACOPY(sepaCopyClique)
958{ /*lint --e{715}*/
959 assert(scip != NULL);
960 assert(sepa != NULL);
961 assert(strcmp(SCIPsepaGetName(sepa), SEPA_NAME) == 0);
962
963 /* call inclusion method of constraint handler */
965
966 return SCIP_OKAY;
967}
968
969
970/** destructor of separator to free user data (called when SCIP is exiting) */
971static
972SCIP_DECL_SEPAFREE(sepaFreeClique)
973{ /*lint --e{715}*/
974 SCIP_SEPADATA* sepadata;
975
976 sepadata = SCIPsepaGetData(sepa);
977 assert(sepadata != NULL);
978 assert(sepadata->tcliquegraph == NULL);
979
980 SCIPfreeBlockMemory(scip, &sepadata);
981 SCIPsepaSetData(sepa, NULL);
982
983 return SCIP_OKAY;
984}
985
986
987/** solving process deinitialization method of separator (called before branch and bound process data is freed) */
988static
989SCIP_DECL_SEPAEXITSOL(sepaExitsolClique)
990{ /*lint --e{715}*/
991 SCIP_SEPADATA* sepadata;
992
993 sepadata = SCIPsepaGetData(sepa);
994 assert(sepadata != NULL);
995
996 /* free tclique data */
997 if( sepadata->tcliquegraph != NULL )
998 {
999 SCIP_CALL( tcliquegraphFree(scip, &sepadata->tcliquegraph) );
1000 }
1001 assert(sepadata->tcliquegraph == NULL);
1002 sepadata->tcliquegraphloaded = FALSE;
1003
1004 return SCIP_OKAY;
1005}
1006
1007
1008/** LP solution separation method of separator */
1009static
1010SCIP_DECL_SEPAEXECLP(sepaExeclpClique)
1011{
1012 /*lint --e{715}*/
1013
1014 *result = SCIP_DIDNOTRUN;
1015
1016 /* only call separator, if we are not close to terminating */
1017 if( SCIPisStopped(scip) )
1018 return SCIP_OKAY;
1019
1020 /* only call separator, if an optimal LP solution is at hand */
1022 return SCIP_OKAY;
1023
1024 /* only call separator, if there are fractional variables */
1025 if( SCIPgetNLPBranchCands(scip) == 0 )
1026 return SCIP_OKAY;
1027
1028 /* separate cuts on the LP solution */
1029 SCIP_CALL( separateCuts(scip, sepa, NULL, result) );
1030
1031 return SCIP_OKAY;
1032}
1033
1034
1035/** arbitrary primal solution separation method of separator */
1036static
1037SCIP_DECL_SEPAEXECSOL(sepaExecsolClique)
1038{
1039 /*lint --e{715}*/
1040
1041 *result = SCIP_DIDNOTRUN;
1042
1043 /* separate cuts on the given primal solution */
1044 SCIP_CALL( separateCuts(scip, sepa, sol, result) );
1045
1046 return SCIP_OKAY;
1047}
1048
1049
1050/*
1051 * separator specific interface methods
1052 */
1053
1054/** creates the clique separator and includes it in SCIP */
1056 SCIP* scip /**< SCIP data structure */
1057 )
1058{
1059 SCIP_SEPADATA* sepadata;
1060 SCIP_SEPA* sepa;
1061
1062 /* create clique separator data */
1063 SCIP_CALL( SCIPallocBlockMemory(scip, &sepadata) );
1064 sepadata->tcliquegraph = NULL;
1065 sepadata->scip = scip;
1066 sepadata->sol = NULL;
1067 sepadata->varsolvals = NULL;
1068 sepadata->ncalls = 0;
1069 sepadata->ncuts = 0;
1070 sepadata->tcliquegraphloaded = FALSE;
1071
1072 /* include separator */
1075 sepaExeclpClique, sepaExecsolClique,
1076 sepadata) );
1077
1078 assert(sepa != NULL);
1079 sepadata->sepa = sepa;
1080
1081 /* set non-NULL pointers to callback methods */
1082 SCIP_CALL( SCIPsetSepaCopy(scip, sepa, sepaCopyClique) );
1083 SCIP_CALL( SCIPsetSepaFree(scip, sepa, sepaFreeClique) );
1084 SCIP_CALL( SCIPsetSepaExitsol(scip, sepa, sepaExitsolClique) );
1085
1086 /* add clique separator parameters */
1088 "separating/clique/scaleval",
1089 "factor for scaling weights",
1090 &sepadata->scaleval, TRUE, DEFAULT_SCALEVAL, 1.0, SCIP_REAL_MAX, NULL, NULL) );
1092 "separating/clique/maxtreenodes",
1093 "maximal number of nodes in branch and bound tree (-1: no limit)",
1094 &sepadata->maxtreenodes, TRUE, DEFAULT_MAXTREENODES, -1, INT_MAX, NULL, NULL) );
1096 "separating/clique/backtrackfreq",
1097 "frequency for premature backtracking up to tree level 1 (0: no backtracking)",
1098 &sepadata->backtrackfreq, TRUE, DEFAULT_BACKTRACKFREQ, 0, INT_MAX, NULL, NULL) );
1100 "separating/clique/maxsepacuts",
1101 "maximal number of clique cuts separated per separation round (-1: no limit)",
1102 &sepadata->maxsepacuts, FALSE, DEFAULT_MAXSEPACUTS, -1, INT_MAX, NULL, NULL) );
1104 "separating/clique/maxzeroextensions",
1105 "maximal number of zero-valued variables extending the clique (-1: no limit)",
1106 &sepadata->maxzeroextensions, TRUE, DEFAULT_MAXZEROEXTENSIONS, -1, INT_MAX, NULL, NULL) );
1108 "separating/clique/cliquetablemem",
1109 "maximal memory size of dense clique table (in kb)",
1110 &sepadata->cliquetablemem, TRUE, DEFAULT_CLIQUETABLEMEM, 0.0, (SCIP_Real)INT_MAX/1024.0, NULL, NULL) );
1112 "separating/clique/cliquedensity",
1113 "minimal density of cliques to use a dense clique table",
1114 &sepadata->cliquedensity, TRUE, DEFAULT_CLIQUEDENSITY, 0.0, 1.0, NULL, NULL) );
1115
1116 return SCIP_OKAY;
1117}
#define NULL
Definition: def.h:248
#define SCIP_MAXSTRLEN
Definition: def.h:269
#define SCIP_Longint
Definition: def.h:141
#define SCIP_REAL_MAX
Definition: def.h:158
#define SCIP_Bool
Definition: def.h:91
#define SCIP_Real
Definition: def.h:156
#define TRUE
Definition: def.h:93
#define FALSE
Definition: def.h:94
#define MAX(x, y)
Definition: def.h:220
#define SCIP_LONGINT_FORMAT
Definition: def.h:148
#define SCIP_CALL(x)
Definition: def.h:355
#define nnodes
Definition: gastrans.c:74
static const SCIP_Real density
Definition: gastrans.c:145
SCIP_Bool SCIPisStopped(SCIP *scip)
Definition: scip_general.c:759
SCIP_VAR ** SCIPgetVars(SCIP *scip)
Definition: scip_prob.c:2201
int SCIPgetNBinVars(SCIP *scip)
Definition: scip_prob.c:2293
#define SCIPdebugMsg
Definition: scip_message.h:78
SCIP_RETCODE SCIPaddIntParam(SCIP *scip, const char *name, const char *desc, int *valueptr, SCIP_Bool isadvanced, int defaultvalue, int minvalue, int maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:83
SCIP_RETCODE SCIPaddRealParam(SCIP *scip, const char *name, const char *desc, SCIP_Real *valueptr, SCIP_Bool isadvanced, SCIP_Real defaultvalue, SCIP_Real minvalue, SCIP_Real maxvalue, SCIP_DECL_PARAMCHGD((*paramchgd)), SCIP_PARAMDATA *paramdata)
Definition: scip_param.c:139
int SCIPgetNLPBranchCands(SCIP *scip)
Definition: scip_branch.c:436
SCIP_RETCODE SCIPaddPoolCut(SCIP *scip, SCIP_ROW *row)
Definition: scip_cut.c:336
SCIP_Bool SCIPisEfficacious(SCIP *scip, SCIP_Real efficacy)
Definition: scip_cut.c:135
SCIP_LPSOLSTAT SCIPgetLPSolstat(SCIP *scip)
Definition: scip_lp.c:174
#define SCIPfreeMemoryArrayNull(scip, ptr)
Definition: scip_mem.h:81
#define SCIPfreeBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:110
#define SCIPreallocMemoryArray(scip, ptr, newnum)
Definition: scip_mem.h:70
#define SCIPallocMemoryArray(scip, ptr, num)
Definition: scip_mem.h:64
int SCIPcalcMemGrowSize(SCIP *scip, int num)
Definition: scip_mem.c:139
#define SCIPallocBufferArray(scip, ptr, num)
Definition: scip_mem.h:124
#define SCIPfreeBufferArray(scip, ptr)
Definition: scip_mem.h:136
#define SCIPallocBlockMemoryArray(scip, ptr, num)
Definition: scip_mem.h:93
#define SCIPfreeBlockMemory(scip, ptr)
Definition: scip_mem.h:108
#define SCIPallocBlockMemory(scip, ptr)
Definition: scip_mem.h:89
SCIP_RETCODE SCIPcacheRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1581
SCIP_RETCODE SCIPflushRowExtensions(SCIP *scip, SCIP_ROW *row)
Definition: scip_lp.c:1604
SCIP_RETCODE SCIPaddVarToRow(SCIP *scip, SCIP_ROW *row, SCIP_VAR *var, SCIP_Real val)
Definition: scip_lp.c:1646
SCIP_RETCODE SCIPreleaseRow(SCIP *scip, SCIP_ROW **row)
Definition: scip_lp.c:1508
SCIP_RETCODE SCIPcreateEmptyRowSepa(SCIP *scip, SCIP_ROW **row, SCIP_SEPA *sepa, const char *name, SCIP_Real lhs, SCIP_Real rhs, SCIP_Bool local, SCIP_Bool modifiable, SCIP_Bool removable)
Definition: scip_lp.c:1429
void SCIProwChgRank(SCIP_ROW *row, int rank)
Definition: lp.c:17928
SCIP_RETCODE SCIPincludeSepaBasic(SCIP *scip, SCIP_SEPA **sepa, const char *name, const char *desc, int priority, int freq, SCIP_Real maxbounddist, SCIP_Bool usessubscip, SCIP_Bool delay, SCIP_DECL_SEPAEXECLP((*sepaexeclp)), SCIP_DECL_SEPAEXECSOL((*sepaexecsol)), SCIP_SEPADATA *sepadata)
Definition: scip_sepa.c:115
const char * SCIPsepaGetName(SCIP_SEPA *sepa)
Definition: sepa.c:746
SCIP_RETCODE SCIPsetSepaFree(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPAFREE((*sepafree)))
Definition: scip_sepa.c:173
SCIP_RETCODE SCIPsetSepaExitsol(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPAEXITSOL((*sepaexitsol)))
Definition: scip_sepa.c:237
SCIP_SEPADATA * SCIPsepaGetData(SCIP_SEPA *sepa)
Definition: sepa.c:636
void SCIPsepaSetData(SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata)
Definition: sepa.c:646
SCIP_RETCODE SCIPsetSepaCopy(SCIP *scip, SCIP_SEPA *sepa, SCIP_DECL_SEPACOPY((*sepacopy)))
Definition: scip_sepa.c:157
SCIP_Longint SCIPsepaGetNCalls(SCIP_SEPA *sepa)
Definition: sepa.c:873
SCIP_RETCODE SCIPgetSolVals(SCIP *scip, SCIP_SOL *sol, int nvars, SCIP_VAR **vars, SCIP_Real *vals)
Definition: scip_sol.c:1846
SCIP_Real SCIPinfinity(SCIP *scip)
SCIP_Real SCIPfeasFloor(SCIP *scip, SCIP_Real val)
SCIP_VAR * SCIPvarGetNegatedVar(SCIP_VAR *var)
Definition: var.c:23868
SCIP_Bool SCIPvarIsActive(SCIP_VAR *var)
Definition: var.c:23642
SCIP_Bool SCIPvarIsImpliedIntegral(SCIP_VAR *var)
Definition: var.c:23498
SCIP_CLIQUE ** SCIPgetCliques(SCIP *scip)
Definition: scip_var.c:9566
SCIP_VARTYPE SCIPvarGetType(SCIP_VAR *var)
Definition: var.c:23453
SCIP_RETCODE SCIPcleanupCliques(SCIP *scip, SCIP_Bool *infeasible)
Definition: scip_var.c:9469
SCIP_RETCODE SCIPreleaseVar(SCIP *scip, SCIP_VAR **var)
Definition: scip_var.c:1887
SCIP_RETCODE SCIPgetNegatedVar(SCIP *scip, SCIP_VAR *var, SCIP_VAR **negvar)
Definition: scip_var.c:2166
int SCIPvarGetNCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:24642
int SCIPgetNCliques(SCIP *scip)
Definition: scip_var.c:9512
SCIP_CLIQUE ** SCIPvarGetCliques(SCIP_VAR *var, SCIP_Bool varfixing)
Definition: var.c:24653
SCIP_RETCODE SCIPcaptureVar(SCIP *scip, SCIP_VAR *var)
Definition: scip_var.c:1853
SCIP_RETCODE SCIPincludeSepaClique(SCIP *scip)
Definition: sepa_clique.c:1055
int SCIPsnprintf(char *t, int len, const char *s,...)
Definition: misc.c:10827
SCIP_VAR ** SCIPcliqueGetVars(SCIP_CLIQUE *clique)
Definition: implics.c:3384
int SCIPcliqueGetNVars(SCIP_CLIQUE *clique)
Definition: implics.c:3374
SCIP_Bool * SCIPcliqueGetValues(SCIP_CLIQUE *clique)
Definition: implics.c:3396
unsigned int SCIPcliqueGetId(SCIP_CLIQUE *clique)
Definition: implics.c:3406
memory allocation routines
#define BMSclearMemoryArray(ptr, num)
Definition: memory.h:130
public methods for implications, variable bounds, and cliques
public methods for LP management
public methods for message output
public data structures and miscellaneous methods
public methods for separators
public methods for problem variables
public methods for branching rule plugins and branching
public methods for cuts and aggregation rows
general public methods
public methods for the LP relaxation, rows and columns
public methods for memory management
public methods for message handling
public methods for numerical tolerances
public methods for SCIP parameter handling
public methods for global and local (sub)problems
public methods for separator plugins
public methods for solutions
public methods for SCIP variables
static SCIP_DECL_SEPAEXITSOL(sepaExitsolClique)
Definition: sepa_clique.c:989
#define SEPA_PRIORITY
Definition: sepa_clique.c:63
#define DEFAULT_SCALEVAL
Definition: sepa_clique.c:69
static SCIP_RETCODE tcliquegraphAddNode(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph, SCIP_VAR *var, SCIP_Bool value, int *nodeidx)
Definition: sepa_clique.c:220
#define DEFAULT_MAXTREENODES
Definition: sepa_clique.c:70
static SCIP_RETCODE tcliquegraphCreate(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph)
Definition: sepa_clique.c:130
#define SEPA_DELAY
Definition: sepa_clique.c:67
#define DEFAULT_CLIQUEDENSITY
Definition: sepa_clique.c:75
static SCIP_RETCODE tcliquegraphAddCliqueVars(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph, int **cliquegraphidx)
Definition: sepa_clique.c:290
static TCLIQUE_ISEDGE(tcliqueIsedgeClique)
Definition: sepa_clique.c:620
static SCIP_RETCODE tcliquegraphConstructCliqueTable(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, SCIP_Real cliquetablemem, SCIP_Real cliquedensity)
Definition: sepa_clique.c:336
#define SEPA_DESC
Definition: sepa_clique.c:62
#define DEFAULT_BACKTRACKFREQ
Definition: sepa_clique.c:71
#define DEFAULT_CLIQUETABLEMEM
Definition: sepa_clique.c:74
#define SEPA_USESSUBSCIP
Definition: sepa_clique.c:66
static SCIP_DECL_SEPAEXECLP(sepaExeclpClique)
Definition: sepa_clique.c:1010
#define DEFAULT_MAXZEROEXTENSIONS
Definition: sepa_clique.c:73
static TCLIQUE_SELECTADJNODES(tcliqueSelectadjnodesClique)
Definition: sepa_clique.c:655
static SCIP_RETCODE tcliquegraphEnsureCliqueidsSize(SCIP *scip, TCLIQUE_GRAPH *tcliquegraph, int num)
Definition: sepa_clique.c:198
static SCIP_RETCODE newsolCliqueAddRow(SCIP *scip, SCIP_SEPA *sepa, SCIP_SEPADATA *sepadata, int ncliquenodes, int *cliquenodes)
Definition: sepa_clique.c:703
static SCIP_Bool nodesHaveCommonClique(TCLIQUE_GRAPH *tcliquegraph, int node1, int node2)
Definition: sepa_clique.c:558
static SCIP_RETCODE separateCuts(SCIP *scip, SCIP_SEPA *sepa, SCIP_SOL *sol, SCIP_RESULT *result)
Definition: sepa_clique.c:841
static TCLIQUE_GETWEIGHTS(tcliqueGetweightsClique)
Definition: sepa_clique.c:549
#define SEPA_MAXBOUNDDIST
Definition: sepa_clique.c:65
#define SEPA_FREQ
Definition: sepa_clique.c:64
static SCIP_DECL_SEPACOPY(sepaCopyClique)
Definition: sepa_clique.c:957
static TCLIQUE_GETNNODES(tcliqueGetnnodesClique)
Definition: sepa_clique.c:540
#define DEFAULT_MAXSEPACUTS
Definition: sepa_clique.c:72
#define SEPA_NAME
Definition: sepa_clique.c:61
static SCIP_DECL_SEPAFREE(sepaFreeClique)
Definition: sepa_clique.c:972
static SCIP_DECL_SEPAEXECSOL(sepaExecsolClique)
Definition: sepa_clique.c:1037
static TCLIQUE_NEWSOL(tcliqueNewsolClique)
Definition: sepa_clique.c:754
static SCIP_RETCODE loadTcliquegraph(SCIP *scip, SCIP_SEPADATA *sepadata)
Definition: sepa_clique.c:461
static SCIP_RETCODE tcliquegraphFree(SCIP *scip, TCLIQUE_GRAPH **tcliquegraph)
Definition: sepa_clique.c:166
static void updateTcliquegraph(SCIP *scip, SCIP_SEPADATA *sepadata)
Definition: sepa_clique.c:509
clique separator
tclique user interface
enum TCLIQUE_Status TCLIQUE_STATUS
Definition: tclique.h:68
int TCLIQUE_WEIGHT
Definition: tclique.h:48
void tcliqueMaxClique(TCLIQUE_GETNNODES((*getnnodes)), TCLIQUE_GETWEIGHTS((*getweights)), TCLIQUE_ISEDGE((*isedge)), TCLIQUE_SELECTADJNODES((*selectadjnodes)), TCLIQUE_GRAPH *tcliquegraph, TCLIQUE_NEWSOL((*newsol)), TCLIQUE_DATA *tcliquedata, int *maxcliquenodes, int *nmaxcliquenodes, TCLIQUE_WEIGHT *maxcliqueweight, TCLIQUE_WEIGHT maxfirstnodeweight, TCLIQUE_WEIGHT minweight, int maxntreenodes, int backtrackfreq, int maxnzeroextensions, int fixednode, int *ntreenodes, TCLIQUE_STATUS *status)
struct TCLIQUE_Graph TCLIQUE_GRAPH
Definition: tclique.h:49
@ SCIP_LPSOLSTAT_OPTIMAL
Definition: type_lp.h:44
@ SCIP_DIDNOTRUN
Definition: type_result.h:42
@ SCIP_CUTOFF
Definition: type_result.h:48
@ SCIP_DIDNOTFIND
Definition: type_result.h:44
@ SCIP_SEPARATED
Definition: type_result.h:49
enum SCIP_Result SCIP_RESULT
Definition: type_result.h:61
@ SCIP_OKAY
Definition: type_retcode.h:42
enum SCIP_Retcode SCIP_RETCODE
Definition: type_retcode.h:63
struct SCIP_SepaData SCIP_SEPADATA
Definition: type_sepa.h:52
@ SCIP_VARTYPE_BINARY
Definition: type_var.h:64