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