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