Scippy

GCG

Branch-and-Price & Column Generation for Everyone

dec_hcgpartition.cpp
Go to the documentation of this file.
1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the program */
4 /* GCG --- Generic Column Generation */
5 /* a Dantzig-Wolfe decomposition based extension */
6 /* of the branch-cut-and-price framework */
7 /* SCIP --- Solving Constraint Integer Programs */
8 /* */
9 /* Copyright (C) 2010-2021 Operations Research, RWTH Aachen University */
10 /* Zuse Institute Berlin (ZIB) */
11 /* */
12 /* This program is free software; you can redistribute it and/or */
13 /* modify it under the terms of the GNU Lesser General Public License */
14 /* as published by the Free Software Foundation; either version 3 */
15 /* of the License, or (at your option) any later version. */
16 /* */
17 /* This program is distributed in the hope that it will be useful, */
18 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
19 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
20 /* GNU Lesser General Public License for more details. */
21 /* */
22 /* You should have received a copy of the GNU Lesser General Public License */
23 /* along with this program; if not, write to the Free Software */
24 /* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.*/
25 /* */
26 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
27 
28 /**@file dec_hcgpartition.cpp
29  * @ingroup DETECTORS
30  * @brief arrowhead and bordered detector via graph partitioning (uses hmetis)
31  * @author Martin Bergner
32  * @author Michael Bastubbe
33  *
34  * Detects arrowhead (double bordered) decompositions as well as decompositions
35  * with only linking variables or linking constraints.
36  *
37  * This detector needs hmetis and works only under Linux/MacOS, it further needs the Z-shell (zsh)
38  * to enforce memory and time limits on hmetis as this is the only shell reliably doing that.
39  */
40 
41 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
42 
43 
44 /* #define SCIP_DEBUG */
45 #include "dec_hcgpartition.h"
46 
47 
48 #if !defined(_WIN32) && !defined(_WIN64)
49 #include <cassert>
50 #include <cstring>
51 #include <cerrno>
52 #include <unistd.h>
53 #include <iostream>
54 #include <vector>
55 #include <algorithm>
56 #include <queue>
57 
58 #ifdef HMETIS_HEADER
59 #include "hmetis.h"
60 #else
61 #define HMETIS_EXECUTABLE "hmetis"
62 #endif
63 
64 #include "cons_decomp.h"
65 #include "struct_decomp.h"
66 #include "pub_decomp.h"
67 #include "scip_misc.h"
68 #include "scip/pub_misc.h"
69 #include "scip/cons_linear.h"
70 #include "scip/cons_setppc.h"
71 #include "graph/matrixgraph.h"
72 #include "graph/hypercolgraph.h"
73 #include "graph/graph_tclique.h"
74 #include "graph/weights.h"
75 #include "class_partialdecomp.h"
76 #include "class_detprobdata.h"
77 #include "scip/clock.h"
78 
79 
80 #include <set>
81 
82 using gcg::HypercolGraph;
83 using gcg::MatrixGraph;
84 using gcg::Weights;
85 
86 #define DEC_DETECTORNAME "hcgpartition" /**< name of the detector */
87 #define DEC_DESC "enforces arrowhead structures using graph partitioning" /**< description of detector */
88 #define DEC_FREQCALLROUND 1 /**< frequency the detector gets called in detection loop ,ie it is called in round r if and only if minCallRound <= r <= maxCallRound AND (r - minCallRound) mod freqCallRound == 0 */
89 #define DEC_MAXCALLROUND 0 /**< last round the detector gets called */
90 #define DEC_MINCALLROUND 0 /**< first round the detector gets called */
91 #define DEC_FREQCALLROUNDORIGINAL 1 /**< frequency the detector gets called in detection loop while detecting the original problem */
92 #define DEC_MAXCALLROUNDORIGINAL 0 /**< last round the detector gets called while detecting the original problem */
93 #define DEC_MINCALLROUNDORIGINAL 0 /**< first round the detector gets called while detecting the original problem */
94 #define DEC_PRIORITY 1000 /**< priority of the detector */
95 #define DEC_DECCHAR 'G' /**< display character of detector */
96 #define DEC_ENABLED FALSE /**< should detector be called by default */
97 #define DEC_ENABLEDFINISHING FALSE /**< should detector be called by default */
98 #define DEC_ENABLEDPOSTPROCESSING FALSE /**< should the postprocessing be enabled */
99 #define DEC_SKIP FALSE /**< should detector be skipped if others found detections */
100 #define DEC_USEFULRECALL TRUE /**< is it useful to call this detector on a descendant of the propagated partialdec */
101 
102 
103 /* Default parameter settings */
104 #define DEFAULT_VARWEIGHT 1 /**< weight for variable nodes */
105 #define DEFAULT_VARWEIGHTBIN 2 /**< weight for binary variable nodes */
106 #define DEFAULT_VARWEIGHTINT 2 /**< weight for integer variable nodes */
107 #define DEFAULT_VARWEIGHTIMPL 2 /**< weight for implicit integer variable nodes */
108 #define DEFAULT_VARWEIGHTCONT 1 /**< weight for continous variable nodes */
109 #define DEFAULT_CONSWEIGHT 5 /**< weight for constraint hyperedges */
110 #define DEFAULT_RANDSEED 1 /**< random seed for the hmetis call */
111 #define DEFAULT_TIDY TRUE /**< whether to clean up afterwards */
112 #define DEFAULT_DUMMYNODES 0.2 /**< percentage of dummy vertices*/
113 #define DEFAULT_CONSWEIGHT_SETPPC 5 /**< weight for constraint hyperedges that are setpartitioning or covering
114  constraints */
115 #define DEFAULT_MINBLOCKS 2 /**< value for the minimum number of blocks to be considered */
116 #define DEFAULT_MAXBLOCKS 20 /**< value for the maximum number of blocks to be considered */
117 #define DEFAULT_MAXNBLOCKCANDIDATES 1 /**< number of block number candidates to be considered */
118 #define DEFAULT_ALPHA 0.0 /**< factor for standard deviation of constraint weights */
119 #define DEFAULT_BETA 0.5 /**< factor of how the weight for equality and inequality constraints is
120  distributed (keep 1/2 for the same on both) */
121 #define DEFAULT_METIS_UBFACTOR 5.0 /**< default unbalance factor given to metis on the commandline */
122 #define DEFAULT_METIS_VERBOSE FALSE /**< should metis be verbose */
123 #define DEFAULT_METISUSEPTYPE_RB TRUE /**< Should metis use the rb or kway partitioning algorithm */
124 #define DEFAULT_REALNAME FALSE /**< whether the metis name should be real or temporary */
125 #define DEFAULT_TYPE 'r' /**< type of the decomposition 'c' column hypergraph (single bordered, no
126  linking constraints), 'r' row hypergraph (single bordered, no linking
127  variables) and 'a' column-row hypergraph (arrowhead) */
128 
129 #define SET_MULTIPLEFORSIZETRANSF 12500
130 
131 /*
132  * Data structures
133  */
134 
135 /** private detector data */
136 struct DEC_DetectorData
137 {
138  /* Graph stuff for hmetis */
139  /* weight parameters */
140  int varWeight; /**< weight of a variable hyperedge */
141  int varWeightBinary; /**< weight of a binary variable hyperedge */
142  int varWeightContinous; /**< weight of a continuous variable hyperedge */
143  int varWeightInteger; /**< weight of an integer variable hyperedge */
144  int varWeightImplint; /**< weight of an implicit integer variable hyperedge */
145  int consWeight; /**< weight of a constraint hyperedge */
146  int consWeightSetppc; /**< weight of a setppc constraint hyperedge */
147  SCIP_Real alpha; /**< factor for constraint coefficient value standard deviation */
148  SCIP_Real beta; /**< factor for equality od inequality constraints */
149 
150  /* general parameters */
151  SCIP_Real dummynodes; /**< percent of dummy nodes */
152  SCIP_Bool tidy; /**< whether tempory metis files should be cleaned up */
153  int maxnblockcandidates; /**< maximal number of block canddidates to test */
154  int maxblocks; /**< maximal number of blocks to test */
155  int minblocks; /**< minimal number of blocks to test */
156 
157  /* metis parameters */
158  int randomseed; /**< metis random seed */
159  SCIP_Real metisubfactor; /**< metis unbalance factor */
160  SCIP_Bool metisverbose; /**< should metis ouput be displayed */
161  SCIP_Bool metisuseptyperb; /**< flag to indicate whether metis uses kway or rb partitioning */
162  SCIP_Bool realname; /**< flag to indicate real problem name or temporary filename for metis files */
163 
164  /* various data */
165  SCIP_Bool found; /**< indicates whethere a decomposition has been found */
166  char type; /**< type of the decomposition 'c' column hypergraph (single bordered, no linking
167  constraints), 'r' row hypergraph (single bordered, no linking variables) and
168  'a' column-row hypergraph (arrowhead) */
169 };
170 
171 
172 
173 
174 /*
175  * Local methods
176  */
177 
178 /** destructor of detector to free user data (called when GCG is exiting) */
179 static
180 DEC_DECL_FREEDETECTOR(freeHcgpartition)
181 {
182  DEC_DETECTORDATA* detectordata;
183 
184  assert(scip != NULL);
185 
186  detectordata = DECdetectorGetData(detector);
187  assert(detectordata != NULL);
188  assert(strcmp(DECdetectorGetName(detector), DEC_DETECTORNAME) == 0);
189 
190  SCIPfreeMemory(scip, &detectordata);
191 
192  return SCIP_OKAY;
193 }
194 
195 /** detector initialization method (called after problem was transformed) */
196 static
197 
198 DEC_DECL_INITDETECTOR(initHcgpartition)
199 {
200  int nconss;
201  DEC_DETECTORDATA* detectordata;
202  assert(scip != NULL);
203 
204  detectordata = DECdetectorGetData(detector);
205  assert(detectordata != NULL);
206  assert(strcmp(DECdetectorGetName(detector), DEC_DETECTORNAME) == 0);
207 
208  detectordata->found = FALSE;
209 
210  nconss = SCIPgetNConss(scip);
211  detectordata->maxblocks = MIN(nconss, detectordata->maxblocks);
212 
213 
214  return SCIP_OKAY;
215 }
216 
217 /** detector deinitialization method (called before the transformed problem is freed) */
218 static
219 
220 DEC_DECL_EXITDETECTOR(exitHcgpartition)
221 {
222  assert(scip != NULL);
223 
224 
225  assert(strcmp(DECdetectorGetName(detector), DEC_DETECTORNAME) == 0);
226 
227 
228  return SCIP_OKAY;
229 }
230 
231 /** will call hmetis via a system call */
232 static
233 SCIP_RETCODE callMetis(
234  SCIP* scip, /**< SCIP data struture */
235  DEC_DETECTORDATA* detectordata, /**< detector data data structure */
236  MatrixGraph<gcg::GraphTclique>* graph, /**< the graph of the matrix */
237  char tempfile[SCIP_MAXSTRLEN], /**< filename for the metis input file */
238  int nblocks, /**< number of blocks */
239  SCIP_RESULT* result /**< result indicating whether the detection was successful */
240  )
241 {
242  char metiscall[SCIP_MAXSTRLEN];
243  char metisout[SCIP_MAXSTRLEN];
244 
245  SCIP_CLOCK* metisclock;
246 
247  int status;
248 
249  SCIP_Real remainingtime;
250 
251  assert(scip != NULL);
252  assert(detectordata != NULL);
253 
254  *result = SCIP_DIDNOTRUN;
255 
256  SCIPcreateWallClock(scip, &metisclock);
257  remainingtime = DECgetRemainingTime(scip);
258 
259  if( remainingtime <= 0 )
260  {
261  return SCIP_OKAY;
262  }
263 
264  /* call metis via syscall as there is no library usable ... */
265  if( !SCIPisInfinity(scip, DECgetRemainingTime(scip)) )
266  {
267  (void) SCIPsnprintf(metiscall, SCIP_MAXSTRLEN, "zsh -c \"ulimit -t %.0f;" HMETIS_EXECUTABLE " %s %d -seed %d -ptype %s -ufactor %f %s\"",
268  remainingtime,
269  tempfile,
270  nblocks,
271  detectordata->randomseed,
272  detectordata->metisuseptyperb ? "rb" : "kway",
273  detectordata->metisubfactor,
274  detectordata->metisverbose ? "" : "> /dev/null" );
275  }
276  else
277  {
278  (void) SCIPsnprintf(metiscall, SCIP_MAXSTRLEN, "zsh -c \"" HMETIS_EXECUTABLE " %s %d -seed %d -ptype %s -ufactor %f %s\"",
279  tempfile,
280  nblocks,
281  detectordata->randomseed,
282  detectordata->metisuseptyperb ? "rb" : "kway",
283  detectordata->metisubfactor,
284  detectordata->metisverbose ? "" : "> /dev/null" );
285  }
286 
287  SCIP_CALL( SCIPstartClock(scip, metisclock) );
288  SCIPdebugMessage("Calling metis with: %s\n", metiscall);
289  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " %d", nblocks );
290  status = system( metiscall );
291 
292  SCIP_CALL( SCIPstopClock(scip, metisclock) );
293  SCIPdebugMessage("time left before metis started: %f, time metis spend %f, remainingtime: %f\n", remainingtime, SCIPgetClockTime(scip, metisclock), remainingtime-SCIPgetClockTime(scip, metisclock) );
294 
295  SCIP_CALL( SCIPfreeClock(scip, &metisclock) );
296 
297  /* check error codes */
298  if( status == -1 )
299  {
300  SCIPerrorMessage("System call did not succed: %s\n", strerror( errno ));
301  SCIPerrorMessage("Call was %s\n", metiscall);
302  }
303  else if( status != 0 )
304  {
305 
306  SCIPerrorMessage("Calling hmetis unsuccessful! See the above error message for more details.\n");
307  SCIPerrorMessage("Call was %s\n", metiscall);
308  assert(false);
309  }
310 
311  /* exit gracefully in case of errors */
312  if( status != 0 )
313  {
314  return SCIP_ERROR;
315  }
316 
317  (void) SCIPsnprintf(metisout, SCIP_MAXSTRLEN, "%s.part.%d", tempfile, nblocks);
318  SCIP_CALL( graph->readPartition(metisout) );
319 
320  /* if desired delete the temoprary metis file */
321  if( detectordata->tidy )
322  {
323  status = remove( metisout );
324  if( status == -1 )
325  {
326  SCIPerrorMessage("Could not remove metis output file: %s\n", strerror( errno ));
327  return SCIP_WRITEERROR;
328  }
329  }
330  else
331  {
332  SCIPinfoMessage(scip, NULL, "Temporary file is in: %s\n", tempfile);
333  }
334  *result = SCIP_SUCCESS;
335  return SCIP_OKAY;
336 }
337 
338 /** creates the temporary metis input file */
339 static
340 SCIP_RETCODE createMetisFile(
341  SCIP* scip, /**< SCIP data struture */
342  DEC_DETECTORDATA* detectordata, /**< detector data structure */
343  int partialdecid, /**< used for speaking filenames */
344  MatrixGraph<gcg::GraphTclique>* graph, /**< the graph of the matrix */
345  char tempfile[SCIP_MAXSTRLEN] /**< filename for the metis input file */
346  )
347 {
348  int nvertices;
349  int ndummyvertices;
350  int fd;
351  nvertices = graph->getNNonzeroes();
352  /*lint --e{524}*/
353  ndummyvertices = SCIPceil(scip, detectordata->dummynodes*nvertices);
354  graph->setDummynodes(ndummyvertices);
355 
356  if( !detectordata->realname )
357  {
358  (void) SCIPsnprintf(tempfile, SCIP_MAXSTRLEN, "gcg-%c-%d.metis.XXXXXX", DEC_DECCHAR, partialdecid );
359  }
360  else
361  {
362  (void) SCIPsnprintf(tempfile, SCIP_MAXSTRLEN, "gcg-%s-%c-%d.metis.XXXXXX", SCIPgetProbName(scip), DEC_DECCHAR, partialdecid);
363  }
364 
365  fd = mkstemp(tempfile);
366 
367  SCIP_CALL( graph->writeToFile(fd, TRUE) );
368  close(fd);
369  return SCIP_OKAY;
370 }
371 
372 /** returns, whether the hypercolgraph is connected */
373 static
375  gcg::DETPROBDATA* detprobdata,
376  gcg::PARTIALDECOMP* partialdec
377  )
378 {
379  std::vector<int> queue;
380  std::vector<int> visited;
381  std::vector<bool> inqueue(detprobdata->getNConss(), false);
382  std::vector<bool> isvisited(detprobdata->getNConss(), false);
383  int start = -1;
384 
385  if(partialdec->getNOpenconss() < 2)
386  return false;
387 
388  start = partialdec->getOpenconss()[0];
389 
390  queue.push_back(start);
391  inqueue[start] = true;
392  do
393  {
394  int node = queue[0];
395  queue.erase(queue.begin());
396  inqueue[node] = false;
397  visited.push_back(node);
398  isvisited[node] = true;
399  for(int v = 0; v < detprobdata->getNVarsForCons(node); ++v)
400  {
401  int var = detprobdata->getVarsForCons(node)[v];
402  if(!partialdec->isVarOpenvar(var))
403  continue;
404  for(int c = 0; c < detprobdata->getNConssForVar(var); ++c)
405  {
406  int cons = detprobdata->getConssForVar(var)[c];
407  if(!partialdec->isConsOpencons(cons))
408  continue;
409  if( isvisited[cons] )
410  continue;
411  if( inqueue[cons] )
412  continue;
413  queue.push_back(cons);
414  inqueue[cons] = true;
415  }
416  }
417  } while(!queue.empty());
418 
419  if((int)visited.size() != partialdec->getNOpenconss())
420  return false;
421  else
422  return true;
423 }
424 
425 /** detection function for partialdecs */
426 static
427 SCIP_RETCODE detection(
428  SCIP* scip, /**< SCIP data structure */
429  DEC_DETECTORDATA* detectordata, /**< detectordata of the detector */
430  Partialdec_Detection_Data* partialdecdetectiondata, /**< partialdecdetectiondata where to store the new Partialdecs */
431  gcg::PARTIALDECOMP* partialdec, /**< partialdec to propagate */
432  bool allowopenpartialdecs, /**< whether new partialdecs should be stored in which this detector only assigns conss to master */
433  SCIP_RESULT* result /**< pointer where to store the result */
434 )
435 {
436  /* add hcgpartition presolver parameters */
437  char setstr[SCIP_MAXSTRLEN];
438  char decinfo[SCIP_MAXSTRLEN];
439  int maxnblockcandidates;
440  int k;
441  int j;
442  int s;
443  int nMaxPartialdecs;
444  gcg::PARTIALDECOMP** newpartialdecs;
445  SCIP_CLOCK* clock;
446  SCIP_CLOCK* temporaryClock;
447  std::vector<SCIP_Real> clockTimes; /* vector containing times in seconds */
448 
449  /* Graph stuff for hmetis */
450  MatrixGraph<gcg::GraphTclique>* graph; /* the graph of the matrix */
451  char tempfile[SCIP_MAXSTRLEN]; /**< filename for the metis input file */
452 
453  SCIP_CALL_ABORT( SCIPcreateClock(scip, &clock) );
454  SCIP_CALL_ABORT( SCIPstartClock(scip, clock) );
455 
456  *result = SCIP_DIDNOTFIND;
457 
458  std::vector<int> numberOfBlocks;
459  partialdecdetectiondata->detprobdata->getSortedCandidatesNBlocks(numberOfBlocks);
460  if(numberOfBlocks.empty())
461  numberOfBlocks.push_back(8);
462 
463  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/hcgpartition/maxnblockcandidates");
464  SCIP_CALL( SCIPgetIntParam(scip, setstr, &maxnblockcandidates) );
465 
466  maxnblockcandidates = MIN(maxnblockcandidates, (int) numberOfBlocks.size() );
467 
468  assert(scip != NULL);
469  assert(detectordata != NULL);
470 
471  SCIPdebugMessage("Detecting structure from %s\n", DEC_DETECTORNAME);
472  nMaxPartialdecs = detectordata->maxblocks-detectordata->minblocks+1;
473 
474  /* allocate space for output data */
475  SCIP_CALL( SCIPallocMemoryArray(scip, &(newpartialdecs), 2 * nMaxPartialdecs) );
476 
477  /* build the hypergraph structure from the original problem */
478 
479  Weights w(detectordata->varWeight, detectordata->varWeightBinary, detectordata->varWeightContinous,detectordata->varWeightInteger,detectordata->varWeightInteger,detectordata->consWeight);
480  graph = new HypercolGraph<gcg::GraphTclique>(scip, w);
481 
482  SCIP_CALL( graph->createFromPartialMatrix(partialdecdetectiondata->detprobdata, partialdec) );
483  SCIP_CALL( createMetisFile(scip, detectordata, partialdec->getID(), graph, tempfile) );
484 
485  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Detecting Arrowhead structure:");
486 
487  SCIP_CALL_ABORT( SCIPstopClock(scip, clock ) );
488  SCIP_CALL_ABORT( SCIPcreateClock(scip, &temporaryClock) );
489 
490  for( j = 0, k = 0; k < maxnblockcandidates; ++k)
491  {
492  int nblocks = numberOfBlocks[k] - partialdec->getNBlocks();
493  SCIP_CALL_ABORT( SCIPstartClock(scip, temporaryClock) );
494  SCIP_RETCODE retcode;
495 
496  if( nblocks > partialdec->getNOpenconss() || nblocks <= 1 )
497  {
498  SCIP_CALL_ABORT( SCIPstopClock(scip, temporaryClock ) );
499  SCIP_CALL_ABORT( SCIPresetClock(scip, temporaryClock ) );
500  continue;
501  }
502 
503  retcode = callMetis(scip, detectordata, graph, tempfile, nblocks, result);
504 
505  if( *result != SCIP_SUCCESS || retcode != SCIP_OKAY)
506  {
507  SCIP_CALL_ABORT( SCIPstopClock(scip, temporaryClock ) );
508  SCIP_CALL_ABORT( SCIPresetClock(scip, temporaryClock ) );
509  continue;
510  }
511 
512  if( allowopenpartialdecs )
513  {
514  SCIP_CALL( graph->createPartialdecFromPartition(partialdec, &newpartialdecs[j], &newpartialdecs[j+1], partialdecdetectiondata->detprobdata));
515  }
516  else
517  {
518  SCIP_CALL( graph->createPartialdecFromPartition(partialdec, &newpartialdecs[j], NULL, partialdecdetectiondata->detprobdata));
519  }
520 
521  if( newpartialdecs[j] != NULL )
522  {
523  if( !allowopenpartialdecs )
524  {
525  newpartialdecs[j]->considerImplicits();
526  newpartialdecs[j]->refineToBlocks();
527  assert(newpartialdecs[j]->getNOpenconss() == 0);
528  assert(newpartialdecs[j]->getNOpenvars() == 0);
529  }
530  SCIP_CALL_ABORT( SCIPstopClock(scip, temporaryClock) );
531 
532  detectordata->found = TRUE;
533  (void) SCIPsnprintf(decinfo, SCIP_MAXSTRLEN, "hc\\_%d", numberOfBlocks[k]);
534  newpartialdecs[j]->addDetectorChainInfo(decinfo);
535 
536  if( allowopenpartialdecs )
537  {
538  clockTimes.push_back(SCIPgetClockTime(scip, temporaryClock) / 2);
539  clockTimes.push_back(SCIPgetClockTime(scip, temporaryClock) / 2);
540  newpartialdecs[j + 1]->addDetectorChainInfo(decinfo);
541  j += 2;
542  }
543  else
544  {
545  clockTimes.push_back(SCIPgetClockTime(scip, temporaryClock));
546  j++;
547  }
548  }
549  SCIP_CALL_ABORT( SCIPresetClock(scip, temporaryClock) );
550  }
551  delete graph;
552 
553  int nnewpartialdecs = j;
554  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " done, %d partialdecs found.\n", nnewpartialdecs);
555  SCIP_CALL( SCIPallocMemoryArray(scip, &(partialdecdetectiondata->newpartialdecs), nnewpartialdecs) );
556  partialdecdetectiondata->nnewpartialdecs = nnewpartialdecs;
557  for( s = 0; s < nnewpartialdecs; ++s )
558  {
559  partialdecdetectiondata->newpartialdecs[s] = newpartialdecs[s];
560  partialdecdetectiondata->newpartialdecs[s]->addClockTime(clockTimes[s] + SCIPgetClockTime(scip, temporaryClock) / nnewpartialdecs);
561  }
562 
563  SCIPfreeMemoryArray(scip, &newpartialdecs);
564  SCIP_CALL_ABORT( SCIPfreeClock(scip, &temporaryClock) );
565  SCIP_CALL_ABORT( SCIPfreeClock(scip, &clock) );
566 
567  if( detectordata->tidy )
568  {
569  int status = remove( tempfile );
570  if( status == -1 )
571  {
572  SCIPerrorMessage("Could not remove metis input file: %s", strerror(errno));
573  return SCIP_WRITEERROR;
574  }
575  }
576 
577  *result = detectordata->found ? SCIP_SUCCESS: SCIP_DIDNOTFIND;
578  return SCIP_OKAY;
579 }
580 
581 
582 #endif
583 
584 
585 static
586 DEC_DECL_PROPAGATEPARTIALDEC(propagatePartialdecHcgpartition)
587 {
588  SCIP_CLOCK* temporaryClock;
589  gcg::PARTIALDECOMP* partialdec = partialdecdetectiondata->workonpartialdec;
590 
591  SCIP_CALL_ABORT( SCIPcreateClock(scip, &temporaryClock) );
592  SCIP_CALL_ABORT( SCIPstartClock(scip, temporaryClock) );
593 
594  partialdec->considerImplicits();
595  partialdec->refineToMaster();
596 
597  if( !connected(partialdecdetectiondata->detprobdata, partialdec) || partialdec->alreadyAssignedConssToBlocks() )
598  {
600  }
601 
602  detection(scip, DECdetectorGetData(detector), partialdecdetectiondata, partialdec, true, result);
603 
604  SCIP_CALL_ABORT( SCIPstopClock(scip, temporaryClock) );
605  partialdecdetectiondata->detectiontime = SCIPgetClockTime(scip, temporaryClock);
606  SCIP_CALL_ABORT(SCIPfreeClock(scip, &temporaryClock) );
607 
608  return SCIP_OKAY;
609 }
610 
611 
612 static
613 DEC_DECL_FINISHPARTIALDEC(finishPartialdecHcgpartition)
614 {
615  SCIP_CLOCK* temporaryClock;
616  gcg::PARTIALDECOMP* partialdec = partialdecdetectiondata->workonpartialdec;
617 
618  SCIP_CALL_ABORT(SCIPcreateClock(scip, &temporaryClock) );
619  SCIP_CALL_ABORT( SCIPstartClock(scip, temporaryClock) );
620 
621  partialdec->considerImplicits();
622  partialdec->refineToBlocks();
623 
624  if( !connected(partialdecdetectiondata->detprobdata, partialdec ) )
625  {
627  }
628 
629  detection(scip, DECdetectorGetData(detector), partialdecdetectiondata, partialdec, false, result);
630 
631  SCIP_CALL_ABORT( SCIPstopClock(scip, temporaryClock) );
632  partialdecdetectiondata->detectiontime = SCIPgetClockTime(scip, temporaryClock);
633  SCIP_CALL_ABORT(SCIPfreeClock(scip, &temporaryClock) );
634 
635  return SCIP_OKAY;
636 }
637 
638 #define detectorPostprocessPartialdecHcgpartition NULL
639 
640 static
641 DEC_DECL_SETPARAMAGGRESSIVE(setParamAggressiveHcgpartition)
642 {
643  char setstr[SCIP_MAXSTRLEN];
644  const char* name = DECdetectorGetName(detector);
645  int newval;
646  SCIP_Real modifier;
647 
648  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/enabled", name);
649  SCIP_CALL( SCIPsetBoolParam(scip, setstr, TRUE) );
650 
651  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/finishingenabled", name);
652  SCIP_CALL( SCIPsetBoolParam(scip, setstr, TRUE ) );
653 
654  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/maxcallround", name);
655  SCIP_CALL( SCIPgetIntParam(scip, setstr, &newval) );
656  ++newval;
657  SCIP_CALL( SCIPsetIntParam(scip, setstr, newval ) );
658  SCIPinfoMessage(scip, NULL, "After Setting %s = %d\n", setstr, newval);
659 
660 
661  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/origmaxcallround", name);
662  SCIP_CALL( SCIPgetIntParam(scip, setstr, &newval) );
663  ++newval;
664  SCIP_CALL( SCIPsetIntParam(scip, setstr, newval ) );
665  SCIPinfoMessage(scip, NULL, "%s = %d\n", setstr, newval);
666 
667  if( SCIPgetStage(scip) < SCIP_STAGE_PROBLEM )
668  {
669  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/maxnblockcandidates", name);
670  SCIP_CALL( SCIPsetIntParam(scip, setstr, newval ) );
671  SCIPinfoMessage(scip, NULL, "%s = %d\n", setstr, newval);
672  return SCIP_OKAY;
673  }
674 
675  modifier = ( (SCIP_Real)SCIPgetNConss(scip) + (SCIP_Real)SCIPgetNVars(scip) ) / SET_MULTIPLEFORSIZETRANSF;
676 
677  modifier = log(modifier) / log(2);
678 
679  if (!SCIPisFeasPositive(scip, modifier) )
680  modifier = -1.;
681 
682  modifier = SCIPfloor(scip, modifier);
683  modifier += 1;
684 
685  newval = MAX( 0, DEFAULT_MAXNBLOCKCANDIDATES - modifier + 2 );
686  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/maxnblockcandidates", name);
687  SCIP_CALL( SCIPsetIntParam(scip, setstr, newval ) );
688  SCIPinfoMessage(scip, NULL, "%s = %d\n", setstr, newval);
689 
690  return SCIP_OKAY;
691 
692 }
693 
694 
695 static
696 DEC_DECL_SETPARAMDEFAULT(setParamDefaultHcgpartition)
697 {
698  char setstr[SCIP_MAXSTRLEN];
699  int newval;
700  SCIP_Real modifier;
701 
702  const char* name = DECdetectorGetName(detector);
703 
704  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/enabled", name);
705  SCIP_CALL( SCIPsetBoolParam(scip, setstr, DEC_ENABLED) );
706 
707  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/finishingenabled", name);
708  SCIP_CALL( SCIPsetBoolParam(scip, setstr, DEC_ENABLEDFINISHING ) );
709 
710  if( SCIPgetStage(scip) < SCIP_STAGE_PROBLEM )
711  {
712  return SCIP_OKAY;
713  }
714 
715  modifier = ( (SCIP_Real)SCIPgetNConss(scip) + (SCIP_Real)SCIPgetNVars(scip) ) / SET_MULTIPLEFORSIZETRANSF;
716 
717  modifier = log(modifier) / log(2);
718 
719  if (!SCIPisFeasPositive(scip, modifier) )
720  modifier = -1.;
721 
722  modifier = SCIPfloor(scip, modifier);
723  modifier += 1;
724 
725  newval = MAX( 0, DEFAULT_MAXNBLOCKCANDIDATES - modifier );
726  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/maxnblockcandidates", name);
727  SCIP_CALL( SCIPsetIntParam(scip, setstr, newval ) );
728  SCIPinfoMessage(scip, NULL, "%s = %d\n", setstr, newval);
729 
730 
731 
732  return SCIP_OKAY;
733 
734 }
735 
736 static
737 DEC_DECL_SETPARAMFAST(setParamFastHcgpartition)
738 {
739  char setstr[SCIP_MAXSTRLEN];
740  int newval;
741  SCIP_Real modifier;
742 
743 
744  const char* name = DECdetectorGetName(detector);
745 
746  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/enabled", name);
747  SCIP_CALL( SCIPsetBoolParam(scip, setstr, FALSE) );
748 
749  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/finishingenabled", name);
750  SCIP_CALL( SCIPsetBoolParam(scip, setstr, FALSE ) );
751 
752  if( SCIPgetStage(scip) < SCIP_STAGE_PROBLEM )
753  {
754  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/maxnblockcandidates", name);
755  SCIP_CALL( SCIPsetIntParam(scip, setstr, DEFAULT_MAXNBLOCKCANDIDATES ) );
756  SCIPinfoMessage(scip, NULL, "%s = %d\n", setstr, DEFAULT_MAXNBLOCKCANDIDATES);
757  return SCIP_OKAY;
758  }
759 
760 
761  modifier = ( (SCIP_Real)SCIPgetNConss(scip) + (SCIP_Real)SCIPgetNVars(scip) ) / SET_MULTIPLEFORSIZETRANSF;
762 
763  modifier = log(modifier) / log(2);
764 
765  if (!SCIPisFeasPositive(scip, modifier) )
766  modifier = -1.;
767 
768  modifier = SCIPfloor(scip, modifier);
769  modifier += 1;
770 
771  newval = MAX( 0, DEFAULT_MAXNBLOCKCANDIDATES - modifier - 2 );
772  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/maxnblockcandidates", name);
773  SCIP_CALL( SCIPsetIntParam(scip, setstr, newval ) );
774  SCIPinfoMessage(scip, NULL, "%s = %d\n", setstr, newval);
775 
776  return SCIP_OKAY;
777 
778 }
779 
780 
781 
782 /** creates the hcgpartition presolver and includes it in SCIP */
783 extern "C"
785  SCIP* scip /**< SCIP data structure */
786  )
787 {
788 #if !defined(_WIN32) && !defined(_WIN64)
789  DEC_DETECTORDATA *detectordata = NULL;
790  assert(scip != NULL);
791 
792  SCIP_CALL( SCIPallocMemory(scip, &detectordata) );
793  assert(detectordata != NULL);
794 
795 
796  SCIP_CALL( DECincludeDetector(scip, DEC_DETECTORNAME, DEC_DECCHAR, DEC_DESC, DEC_FREQCALLROUND, DEC_MAXCALLROUND, DEC_MINCALLROUND, DEC_FREQCALLROUNDORIGINAL, DEC_MAXCALLROUNDORIGINAL, DEC_MINCALLROUNDORIGINAL, DEC_PRIORITY, DEC_ENABLED, DEC_ENABLEDFINISHING, DEC_ENABLEDPOSTPROCESSING, DEC_SKIP, DEC_USEFULRECALL, detectordata, freeHcgpartition, initHcgpartition, exitHcgpartition, propagatePartialdecHcgpartition, finishPartialdecHcgpartition, detectorPostprocessPartialdecHcgpartition, setParamAggressiveHcgpartition, setParamDefaultHcgpartition, setParamFastHcgpartition) );
797 
798 
799  /* add hcgpartition detector parameters */
800  SCIP_CALL( SCIPaddIntParam(scip, "detection/detectors/hcgpartition/maxnblockcandidates", "The maximal number of block number candidates", &detectordata->maxnblockcandidates, FALSE, DEFAULT_MAXNBLOCKCANDIDATES, 0, 1000000, NULL, NULL) );
801  SCIP_CALL( SCIPaddIntParam(scip, "detection/detectors/hcgpartition/maxblocks", "The maximal number of blocks (detector is called for all block numbers in [minblocks,maxblocks])", &detectordata->maxblocks, FALSE, DEFAULT_MAXBLOCKS, 2, 1000000, NULL, NULL) );
802  SCIP_CALL( SCIPaddIntParam(scip, "detection/detectors/hcgpartition/minblocks", "The minimal number of blocks (detector is called for all block numbers in [minblocks,maxblocks])", &detectordata->minblocks, FALSE, DEFAULT_MINBLOCKS, 2, 1000000, NULL, NULL) );
803  SCIP_CALL( SCIPaddRealParam(scip, "detection/detectors/hcgpartition/beta", "Factor on how heavy equality (beta) and inequality constraints are measured", &detectordata->beta, FALSE, DEFAULT_BETA, 0.0, 1.0, NULL, NULL ) );
804  SCIP_CALL( SCIPaddRealParam(scip, "detection/detectors/hcgpartition/alpha", "Factor on how heavy the standard deviation of the coefficients is measured", &detectordata->alpha, FALSE, DEFAULT_ALPHA, 0.0, 1E20, NULL, NULL ) );
805  SCIP_CALL( SCIPaddIntParam(scip, "detection/detectors/hcgpartition/varWeight", "Weight of a variable hyperedge", &detectordata->varWeight, FALSE, DEFAULT_VARWEIGHT, 0, 1000000, NULL, NULL) );
806  SCIP_CALL( SCIPaddIntParam(scip, "detection/detectors/hcgpartition/varWeightBinary", "Weight of a binary variable hyperedge", &detectordata->varWeightBinary, FALSE, DEFAULT_VARWEIGHTBIN, 0, 1000000, NULL, NULL) );
807  SCIP_CALL( SCIPaddIntParam(scip, "detection/detectors/hcgpartition/varWeightContinous", "Weight of a continuos variable hyperedge", &detectordata->varWeightContinous, FALSE, DEFAULT_VARWEIGHTCONT, 0, 1000000, NULL, NULL) );
808  SCIP_CALL( SCIPaddIntParam(scip, "detection/detectors/hcgpartition/varWeightImplint", "Weight of a implicit integer variable hyperedge", &detectordata->varWeightImplint, FALSE, DEFAULT_VARWEIGHTIMPL, 0, 1000000, NULL, NULL) );
809  SCIP_CALL( SCIPaddIntParam(scip, "detection/detectors/hcgpartition/varWeightInteger", "Weight of a integer variable hyperedge", &detectordata->varWeightInteger, FALSE, DEFAULT_VARWEIGHTINT, 0, 1000000, NULL, NULL) );
810  SCIP_CALL( SCIPaddIntParam(scip, "detection/detectors/hcgpartition/consWeight", "Weight of a constraint hyperedge", &detectordata->consWeight, FALSE, DEFAULT_CONSWEIGHT, 0, 1000000, NULL, NULL) );
811  SCIP_CALL( SCIPaddBoolParam(scip, "detection/detectors/hcgpartition/tidy", "Whether to clean up temporary files", &detectordata->tidy, FALSE, DEFAULT_TIDY, NULL, NULL) );
812  SCIP_CALL( SCIPaddIntParam(scip, "detection/detectors/hcgpartition/randomseed", "Random seed for hmetis", &detectordata->randomseed, FALSE, DEFAULT_RANDSEED, -1, INT_MAX, NULL, NULL) );
813  SCIP_CALL( SCIPaddRealParam(scip, "detection/detectors/hcgpartition/dummynodes", "Percentage of dummy nodes for metis", &detectordata->dummynodes, FALSE, DEFAULT_DUMMYNODES, 0.0, 1.0, NULL, NULL) );
814  SCIP_CALL( SCIPaddIntParam(scip, "detection/detectors/hcgpartition/consWeightSetppc", "Weight for constraint hyperedges that are setpartitioning or covering constraints", &detectordata->consWeightSetppc, FALSE, DEFAULT_CONSWEIGHT_SETPPC, 0, 1000000, NULL, NULL) );
815  SCIP_CALL( SCIPaddRealParam(scip, "detection/detectors/hcgpartition/ubfactor", "Unbalance factor for metis", &detectordata->metisubfactor, FALSE, DEFAULT_METIS_UBFACTOR, 0.0, 1E20, NULL, NULL ) );
816  SCIP_CALL( SCIPaddBoolParam(scip, "detection/detectors/hcgpartition/metisverbose", "Should the metis output be displayed", &detectordata->metisverbose, FALSE, DEFAULT_METIS_VERBOSE, NULL, NULL ) );
817  SCIP_CALL( SCIPaddBoolParam(scip, "detection/detectors/hcgpartition/metisuseptyperb", "Should the rb or kway method be used for partitioning by metis", &detectordata->metisuseptyperb, FALSE, DEFAULT_METISUSEPTYPE_RB, NULL, NULL) );
818  SCIP_CALL( SCIPaddBoolParam(scip, "detection/detectors/hcgpartition/realname", "Should the problem be used for metis files or a temporary name", &detectordata->realname, FALSE, DEFAULT_REALNAME, NULL, NULL) );
819 
820 #endif
821  return SCIP_OKAY;
822 }
void addClockTime(SCIP_Real clocktime)
adds detection time of one detector
int getNConss()
returns the number of variables considered in the detprobdata
const char * DECdetectorGetName(DEC_DETECTOR *detector)
returns the name of the provided detector
static DEC_DECL_SETPARAMDEFAULT(setParamDefaultHcgpartition)
static DEC_DECL_INITDETECTOR(initHcgpartition)
SCIP_RETCODE SCIPincludeDetectorHcgpartition(SCIP *scip)
static DEC_DECL_FINISHPARTIALDEC(finishPartialdecHcgpartition)
structure information for decomposition information in GCG projects
#define DEFAULT_METISUSEPTYPE_RB
#define DEC_FREQCALLROUND
#define DEFAULT_REALNAME
#define DEC_DETECTORNAME
void addDetectorChainInfo(const char *decinfo)
add information about the detector chain
miscellaneous matrixgraph methods for structure detection
#define DEC_MAXCALLROUNDORIGINAL
#define DEC_ENABLED
arrowhead and bordered detector via graph partitioning (uses hmetis)
constraint handler for structure detection
bool isVarOpenvar(int var)
Checks whether the var is an open var.
weight class for graphs
#define DEC_FREQCALLROUNDORIGINAL
void getSortedCandidatesNBlocks(std::vector< int > &candidates)
gets the candidates for number of blocks added by the user followed by the found ones sorted in desce...
virtual SCIP_RETCODE writeToFile(int fd, SCIP_Bool writeweights)
Definition: matrixgraph.h:79
static DEC_DECL_EXITDETECTOR(exitHcgpartition)
#define DEFAULT_VARWEIGHT
virtual SCIP_RETCODE createFromPartialMatrix(DETPROBDATA *detprobdata, PARTIALDECOMP *partialdec)
Definition: matrixgraph.h:146
std::vector< int > & getConssForVar(int varIndex)
returns the constraint indices of the coefficient matrix for a variable
various SCIP helper methods
#define DEC_ENABLEDFINISHING
#define SET_MULTIPLEFORSIZETRANSF
SCIP_Bool found
Definition: dec_dbscan.cpp:90
SCIP_Real DECgetRemainingTime(SCIP *scip)
returns the remaining time of scip that the decomposition may use
void considerImplicits()
: assigns every open cons/var
#define DEFAULT_MINBLOCKS
#define DEC_DESC
#define DEFAULT_TIDY
static SCIP_RETCODE createMetisFile(SCIP *scip, DEC_DETECTORDATA *detectordata, int partialdecid, MatrixGraph< gcg::GraphTclique > *graph, char tempfile[SCIP_MAXSTRLEN])
void setDummynodes(int dummynodes_)
Definition: matrixgraph.h:122
static bool connected(gcg::DETPROBDATA *detprobdata, gcg::PARTIALDECOMP *partialdec)
Column hypergraph.
#define DEC_MINCALLROUND
#define DEFAULT_MAXBLOCKS
static DEC_DECL_SETPARAMAGGRESSIVE(setParamAggressiveHcgpartition)
DEC_DETECTORDATA * DECdetectorGetData(DEC_DETECTOR *detector)
returns the data of the provided detector
static SCIP_RETCODE detection(SCIP *scip, DEC_DETECTORDATA *detectordata, Partialdec_Detection_Data *partialdecdetectiondata, gcg::PARTIALDECOMP *partialdec, bool allowopenpartialdecs, SCIP_RESULT *result)
#define DEFAULT_VARWEIGHTIMPL
interface data structure for the detector calling methods
#define DEFAULT_METIS_VERBOSE
#define DEFAULT_ALPHA
#define DEC_SKIP
static DEC_DECL_SETPARAMFAST(setParamFastHcgpartition)
#define DEC_PRIORITY
void refineToBlocks()
refine partialdec with focus on blocks
interface to the SCIP tclique graph library
gcg::DETPROBDATA * detprobdata
const int * getOpenconss()
Gets array containing constraints not assigned yet.
#define DEC_DECCHAR
#define DEC_MINCALLROUNDORIGINAL
void assignSmallestComponentsButOneConssAdjacency()
computes components by connectedness of conss and vars
virtual int getNNonzeroes() const
Definition: matrixgraph.h:152
#define DEFAULT_BETA
#define DEFAULT_CONSWEIGHT_SETPPC
#define detectorPostprocessPartialdecHcgpartition
class to manage partial decompositions
int getNBlocks()
Gets the number of blocks.
#define DEFAULT_DUMMYNODES
gcg::PARTIALDECOMP ** newpartialdecs
virtual SCIP_RETCODE readPartition(const char *filename)
Definition: matrixgraph.h:113
int getNVarsForCons(int consIndex)
returns the number of variables for a given constraint
SCIP_RETCODE DECincludeDetector(SCIP *scip, const char *name, const char decchar, const char *description, int freqCallRound, int maxCallRound, int minCallRound, int freqCallRoundOriginal, int maxCallRoundOriginal, int minCallRoundOriginal, int priority, SCIP_Bool enabled, SCIP_Bool enabledFinishing, SCIP_Bool enabledPostprocessing, SCIP_Bool skip, SCIP_Bool usefulRecall, DEC_DETECTORDATA *detectordata, DEC_DECL_FREEDETECTOR((*freeDetector)), DEC_DECL_INITDETECTOR((*initDetector)), DEC_DECL_EXITDETECTOR((*exitDetector)), DEC_DECL_PROPAGATEPARTIALDEC((*propagatePartialdecDetector)), DEC_DECL_FINISHPARTIALDEC((*finishPartialdecDetector)), DEC_DECL_POSTPROCESSPARTIALDEC((*postprocessPartialdecDetector)), DEC_DECL_SETPARAMAGGRESSIVE((*setParamAggressiveDetector)), DEC_DECL_SETPARAMDEFAULT((*setParamDefaultDetector)),)
int getNOpenconss()
Gets size of vector containing constraints not assigned yet.
static DEC_DECL_PROPAGATEPARTIALDEC(propagatePartialdecHcgpartition)
bool isConsOpencons(int cons)
Gets whether the cons is an open cons.
#define DEFAULT_VARWEIGHTINT
int getID()
returns the unique id of the partialdec
class storing (potentially incomplete) decompositions
#define DEC_MAXCALLROUND
#define DEFAULT_VARWEIGHTBIN
bool alreadyAssignedConssToBlocks()
method to check if at least one constraint is assigned to some block
#define DEFAULT_RANDSEED
int getNConssForVar(int varIndex)
returns the number of constraints for a given variable where the var has a nonzero entry in
std::vector< int > & getVarsForCons(int consIndex)
returns the variable indices of the coefficient matrix for a constraint
void refineToMaster()
refine partialdec with focus on master
#define DEFAULT_METIS_UBFACTOR
#define DEC_ENABLEDPOSTPROCESSING
class storing partialdecs and the problem matrix
static SCIP_RETCODE callMetis(SCIP *scip, DEC_DETECTORDATA *detectordata, MatrixGraph< gcg::GraphTclique > *graph, char tempfile[SCIP_MAXSTRLEN], int nblocks, SCIP_RESULT *result)
#define DEC_USEFULRECALL
#define DEFAULT_VARWEIGHTCONT
static DEC_DECL_FREEDETECTOR(freeHcgpartition)
virtual SCIP_RETCODE createPartialdecFromPartition(PARTIALDECOMP *oldpartialdec, PARTIALDECOMP **firstpartialdec, PARTIALDECOMP **secondpartialdec, DETPROBDATA *detprobdata)
Definition: matrixgraph.h:99
#define DEFAULT_MAXNBLOCKCANDIDATES
#define HMETIS_EXECUTABLE
public methods for working with decomposition structures
#define DEFAULT_CONSWEIGHT