Scippy

GCG

Branch-and-Price & Column Generation for Everyone

dec_stairheur.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_stairheur.cpp
29  * @ingroup DETECTORS
30  * @brief detector for staircase structures via ROC algorithms
31  * @author Martin Bergner
32  * @author Mathias Luers
33  *
34  * This detector is based on Jayakumar, Maliyakal D., and Ranga V. Ramasesh.
35  * A clustering heuristic to detect staircase structures in large scale
36  * linear programming models. European journal of operational research 76.1 (1994): 229-239.
37  */
38 
39 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
40 
41 #include <cassert>
42 #include <cstring>
43 #include <algorithm>
44 #include <vector>
45 #include <iostream>
46 
47 #include "dec_stairheur.h"
48 #include "cons_decomp.h"
49 #include "struct_decomp.h"
50 #include "pub_decomp.h"
51 #include "scip_misc.h"
52 #include "scip/pub_misc.h"
53 #include "scip/struct_var.h"
54 #include "gcg.h"
55 #include "class_partialdecomp.h"
56 #include "class_detprobdata.h"
57 #include "scip/clock.h"
58 
59 #define DEC_DETECTORNAME "stairheur" /**< name of the detector */
60 #define DEC_DESC "detects staircase matrices via matrix reordering" /**< detector description */
61 #define DEC_PRIORITY 1200 /**< priority of the detector */
62 #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 */
63 #define DEC_MAXCALLROUND INT_MAX /**< last round the detector gets called */
64 #define DEC_MINCALLROUND 0 /**< first round the detector gets called */
65 #define DEC_FREQCALLROUNDORIGINAL 1 /**< frequency the detector gets called in detection loop while detecting the original problem */
66 #define DEC_MAXCALLROUNDORIGINAL INT_MAX /**< last round the detector gets called while detecting the original problem */
67 #define DEC_MINCALLROUNDORIGINAL 0 /**< first round the detector gets called while detecting the original problem */
68 #define DEC_DECCHAR 's' /**< display character of detector */
69 #define DEC_ENABLED FALSE /**< should detector be called by default */
70 #define DEC_ENABLEDFINISHING FALSE /**< should the finishing be enabled */
71 #define DEC_ENABLEDPOSTPROCESSING FALSE /**< should the postprocessing be enabled */
72 #define DEC_SKIP FALSE /**< should detector be skipped if others found detections */
73 #define DEC_USEFULRECALL FALSE /**< is it useful to call this detector on a descendant of the propagated partialdec */
74 
75 /* Default parameter settings*/
76 #define DEFAULT_NCONSSPERBLOCK 32 /**< number of constraints per block (static blocking only) */
77 #define DEFAULT_MAXBLOCKS 20 /**< value for the maximum number of blocks to be considered */
78 #define DEFAULT_MINBLOCKS 2 /**< value for the minimum number of blocks to be considered */
79 #define DEFAULT_DESIREDBLOCKS 0 /**< value for the desired number of blocks (for all blocking types). Set to zero for self determination of block number */
80 #define DEFAULT_DYNAMICBLOCKING FALSE /**< Enable blocking type 'dynamic' */
81 #define DEFAULT_STATICBLOCKING TRUE /**< Enable blocking type 'static' */
82 #define DEFAULT_BLOCKINGASSOONASPOSSIBLE FALSE /**< Enable blocking type 'as soon as possible' */
83 #define DEFAULT_MULTIPLEDECOMPS TRUE /**< Enables multiple decompositions for all enabled blocking types. Ranging from minblocks to maxblocks' */
84 #define DEFAULT_MAXITERATIONSROC 1000000 /**< The maximum of iterations of the ROC-algorithm. -1 for no iteration limit */
85 
86 using std::find;
87 using std::vector;
88 using std::swap;
89 
90 //#define WRITEALLOUTPUT
91 
92 
93 #ifdef WRITEALLOUTPUT
94 #define DWSOLVER_REFNAME(name, blocks, cons, dummy) "%s_%d_%d_%.1f_ref.txt", (name), (blocks), (cons), (dummy)
95 #define GP_NAME(name, blocks, cons, dummy) "%s_%d_%d_%.1f_%d.gp", (name), (blocks), (cons), (dummy)
96 #endif
97 /*
98  * Data structures
99  */
100 
101 /** A struct that contains 4 hashmaps, which maps variables and constraints to their position in the constraint matrix (Ax<=b) and vice versa */
102 struct IndexMap
103 {
104  SCIP_HASHMAP* indexcons; /**< index in problem -> constraint */
105  SCIP_HASHMAP* consindex; /**< constraint -> index in problem */
106  SCIP_HASHMAP* indexvar; /**< index in problem -> variable */
107  SCIP_HASHMAP* varindex; /**< variable -> index in problem */
108 };
109 typedef struct IndexMap INDEXMAP;
110 
111 /** detector data */
112 struct DEC_DetectorData
113 {
114  SCIP_HASHMAP* constoblock; /**< hashmap mapping constraints to blocks */
115  int blocks; /**< number of blocks */
116  int nconssperblock; /**< number of constraints per block (static blocking only) */
117  int maxblocks; /**< maximum number of constraints per block */
118  int minblocks; /**< minimum number of constraints per block */
119  INDEXMAP* indexmap; /**< index map (contains 4 hashmaps) */
120  int* ibegin; /**< array, ibegin[i]: index of first nonzero entry in row i */
121  int* iend; /**< array, iend[i]: index of last nonzero entry in row i */
122  int* jbegin; /**< array, jbegin[j]: index of first nonzero entry in column j */
123  int* jend; /**< array, jend[j]: index of last nonzero entry in column j */
124  int* jmin; /**< array, jmin[i]: index of first nonzero column of the i-th row */
125  int* jmax; /**< array, jmax[i]: the last nonzero entry among all rows prior to and including the i-th row */
126  int* minV; /**< array, minV[i]: number of linking variables corresponding to a partitioning after the i-th row */
127  int* width; /**< array, width[i]: width of the band (of nonzero entries after ROC) at row i */
128  int* hashmapindices; /**< array with integers running from 0 to maximum(nvars, ncons)+1 (for usage of hash maps) */
129  vector<int>* rowsWithConstrictions;
130  vector<int>* blockedAfterrow;
132  SCIP_Bool dynamicblocking; /**< Enable blocking type 'dynamic' */
133  SCIP_Bool staticblocking; /**< Enable blocking type 'static' */
134  SCIP_Bool blockingassoonaspossible; /**< Enable blocking type 'as soon as possible' */
135  SCIP_Bool multipledecomps; /**< Enables multiple decompositions for all enabled blocking types. Ranging from minblocks to maxblocks */
137 };
138 
139 /*
140  * Local methods
141  */
142 
143 
144 /* debugging methods */
146  vector<vector<int> > l
147  )
148 {
149  vector<int>::iterator inner;
150  vector<vector<int> >::iterator outer;
151  SCIPdebugPrintf("S:");
152  for( outer = l.begin(); outer != l.end(); ++outer)
153  {
154  SCIPdebugPrintf("\t");
155  for( inner = outer->begin(); inner != outer->end(); ++inner)
156  {
157  SCIPdebugPrintf(" %d", *inner);
158  }
159  SCIPdebugPrintf(".\n");
160  }
161  SCIPdebugPrintf("Done\n");
162 }
163 
165  vector<int > l
166  )
167 {
168  vector<int>::iterator inner;
169  for( inner = l.begin(); inner != l.end(); ++inner)
170  {
171  SCIPdebugPrintf(" %d", *inner);
172  }
173 }
174 
175 
176 /** TODO:
177  * currently, all vars from the first column where a linking var appears until the end of the block are considered as linking vars, although there might be empty columns. This could be changed so that these empty columns are considered as subscipvars and not linking vars.
178  *
179  * In some cases a block can consist of linking vars exclusively. This makes no real sense.
180  *
181  * For some instances the assertion regarding the consistency of the arrays ibegin and jbegin fails
182  * */
183 
184 
185 /** creates a list with integers running from 'from' to 'to'. */
186 static
188  int from, /**< Start index */
189  int to /**< End index */
190  )
191 {
192  vector<int> v;
193 
194  for( int i = from; i <= to; ++i )
195  {
196  v.push_back(i);
197  }
198  return v;
199 }
200 
201 
202 /** rearranges elements of vector according to the ordering of order.
203  *
204  * example: vector = (a b c d); order = (3 2 4 1)
205  * after calling SCIPvectorRearrange(vector, order): vector = (c b d a)
206  * both vectors must have the same size
207  * order must have elements from 1 to vector->size */
208 static
210  vector<vector<int> > &l,
211  vector<int> order)
212 {
213 
214  vector<vector<int> > new_vector;
215  vector<int>::iterator it1;
216 
217  for( it1 = order.begin(); it1 != order.end(); ++it1 )
218  {
219  new_vector.push_back(l[(size_t)*it1-1]);
220 
221  }
222  l.swap(new_vector);
223 
224 }
225 
226 /** allocates memory for an indexmap. */
227 static
228 SCIP_RETCODE indexmapCreate(
229  SCIP* scip, /**< SCIP data structure */
230  INDEXMAP** indexmap, /**< address of the pointer which shall store the index map*/
231  int nconss, /**< number of constraints */
232  int nvars /**< number of variables */
233 )
234 {
235  INDEXMAP* imap = NULL;
236  assert(scip != NULL);
237  assert(nconss > 0);
238  assert(nvars > 0);
239  SCIP_CALL( SCIPallocMemory(scip, &imap) );
240  assert(imap != NULL);
241 
242  SCIP_CALL( SCIPhashmapCreate(&imap->indexvar, SCIPblkmem(scip), nvars) );
243  SCIP_CALL( SCIPhashmapCreate(&imap->varindex, SCIPblkmem(scip), nvars) );
244  SCIP_CALL( SCIPhashmapCreate(&imap->indexcons, SCIPblkmem(scip), nconss) );
245  SCIP_CALL( SCIPhashmapCreate(&imap->consindex, SCIPblkmem(scip), nconss) );
246 
247  *indexmap = imap;
248  return SCIP_OKAY;
249 }
250 
251 /** deallocates memory of indexmap. */
252 static
254  SCIP* scip, /**< SCIP data structure */
255  INDEXMAP** indexmap /**< index map */
256  )
257 {
258  SCIPhashmapFree(&(*indexmap)->indexvar);
259  SCIPhashmapFree(&(*indexmap)->varindex);
260  SCIPhashmapFree(&(*indexmap)->indexcons);
261  SCIPhashmapFree(&(*indexmap)->consindex);
262  SCIPfreeMemory(scip, indexmap);
263 }
264 
265 
266 /** initialization method for the indexmap for partialdecs */
267 static
268 SCIP_RETCODE indexmapInit(
269  INDEXMAP* indexmap, /**< index map */
270  gcg::PARTIALDECOMP* partialdec, /**< partial decomposition to create indexmap for */
271  int* hashmapindices /**< indices of variables and constraints */
272  )
273 {
274  int i;
275  int* hashmapindex;
276  int nvars = partialdec->getNOpenvars();
277  int nconss = partialdec->getNOpenconss();
278 
279  for( i = 0; i < nvars; ++i )
280  {
281  int var = partialdec->getOpenvars()[i];
282  /* careful: hashmapindex+1, because '0' is treated as an empty hashmap entry, which causes an error */
283  hashmapindex = hashmapindices + i+1;
284  assert( ! SCIPhashmapExists(indexmap->indexvar, (void*) hashmapindex));
285  SCIP_CALL( SCIPhashmapInsert(indexmap->indexvar, (void*) hashmapindex, (void*)(size_t) var) );
286  assert( ! SCIPhashmapExists(indexmap->varindex, (void*)(size_t) var));
287  SCIP_CALL( SCIPhashmapInsert(indexmap->varindex, (void*)(size_t) var, (void*) hashmapindex) );
288  }
289 
290  for( i = 0; i < nconss; ++i )
291  {
292  int cons = partialdec->getOpenconss()[i];
293  /* careful: hashmapindex+1, because '0' is treated as an empty hashmap entry, which causes an error */
294  hashmapindex = hashmapindices + i+1;
295  assert( ! SCIPhashmapExists(indexmap->indexcons, (void*) hashmapindex));
296  SCIP_CALL( SCIPhashmapInsert(indexmap->indexcons, (void*) hashmapindex, (void*)(size_t) cons) );
297  assert( ! SCIPhashmapExists(indexmap->consindex, (void*)(size_t) cons));
298  SCIP_CALL( SCIPhashmapInsert(indexmap->consindex, (void*)(size_t) cons, (void*) hashmapindex) );
299  }
300 
301  return SCIP_OKAY;
302 }
303 
304 /* debug ? */
305 #ifdef WRITEALLOUTPUT
306 /** returns the problem name without the path */
307 static const char* getProbNameWithoutPath(
308  SCIP* scip
309 )
310 {
311  const char* pname;
312  /* remove '/' from problem name */
313  pname = strrchr(SCIPgetProbName(scip), '/');
314  if( pname == NULL )
315  {
316  pname = SCIPgetProbName(scip);
317  }
318  else
319  {
320  pname = pname+1;
321  }
322  return pname;
323 }
324 
325 
326 static void checkConsistencyOfIndexarrays(DEC_DETECTORDATA* detectordata, int nvars, int nconss)
327 {
328  int i;
329  for( i = 0; i < nconss - 1; ++i )
330  {
331  assert(detectordata->ibegin[i] <= detectordata->ibegin[i+1]);
332  }
333  for( i = 0; i < nvars - 1; ++i )
334  {
335  assert(detectordata->jbegin[i] <= detectordata->jbegin[i+1]);
336  }
337 }
338 
339 
340 /* debug ? */
341 /** creates a data and a gnuplot file for the initial problem.
342  * @param scip < SCIP data structure
343  * @param detectordata < detector data data structure
344  * @param filename name of the output files (without any filename extension) */
345 static
346 SCIP_RETCODE plotInitialProblem(
347  SCIP* scip,
348  DEC_DETECTORDATA* detectordata,
349  char* filename
350 )
351 {
352  FILE* output;
353  char datafile[256];
354  char gpfile[256];
355  char pdffile[256];
356 
357  int nconss;
358  nconss = SCIPgetNConss(scip);
359 
360  /* filenames */
361  sprintf(datafile, "%s.dat", filename);
362  sprintf(gpfile, "%s.gp", filename);
363  sprintf(pdffile, "%s.pdf", filename);
364  output = fopen(datafile, "w");
365  if (output == NULL)
366  {
367  SCIPinfoMessage(scip, NULL, "Can't open file for output in plotProblem!\n");
368  }
369  else
370  {
371  int i;
372 
373  for( i = 0; i < nconss; ++i )
374  {
375  int j;
376  SCIP_Bool success;
377  SCIP_VAR** curvars;
378  int ncurvars;
379  int consindex;
380  SCIP_CONS* cons = SCIPgetConss(scip)[i];
381  consindex = *((int*) SCIPhashmapGetImage(detectordata->indexmap->consindex, cons));
382  assert(SCIPhashmapExists(detectordata->indexmap->consindex, cons));
383 
384  /* Get array of variables from constraint */
385  SCIP_CALL( SCIPgetConsNVars(scip, cons, &ncurvars, &success) );
386  assert(success);
387  SCIP_CALL( SCIPallocMemoryArray(scip, &curvars, ncurvars) );
388  SCIP_CALL( SCIPgetConsVars(scip, cons, curvars, ncurvars, &success) );
389  assert(success);
390  for( j = 0; j < ncurvars; ++j )
391  {
392  SCIP_VAR* var = SCIPvarGetProbvar(curvars[j]);
393  assert(SCIPhashmapExists(detectordata->indexmap->varindex, var));
394  int varindex = *((int*) SCIPhashmapGetImage(detectordata->indexmap->varindex, var));
395  assert(varindex <= SCIPgetNVars(scip));
396  assert(varindex > 0);
397  assert(consindex <= SCIPgetNConss(scip));
398  assert(consindex > 0);
399  fprintf(output, "%d %d\n", varindex, consindex);
400  }
401  SCIPfreeMemoryArray(scip, &curvars);
402  }
403  }
404  fclose(output);
405 
406  /* write Gnuplot file */
407  output = fopen(gpfile, "w");
408  fprintf(output, "set terminal pdf\nset output \"%s\"\nunset xtics\nunset ytics\nunset border\nset pointsize 0.05\nset xrange [0:%i]\nset yrange[%i:0]\nplot '%s' lt 0 pt 5 notitle", pdffile, SCIPgetNVars(scip), nconss, datafile);
409  fclose(output);
410  return SCIP_OKAY;
411 }
412 
413 /** creates a data and a gnuplot file for the graph representing the array minV (number of linking variables).
414  * @param detectordata < detector data data structure
415  * @param filename name of the output files (without any filename extension) */
416 static
417 void plotMinV(
418  SCIP* scip,
419  DEC_DETECTORDATA* detectordata,
420  char* filename
421 )
422 {
423  FILE* output;
424  char datafile[256];
425  char blockingfile[256];
426  char gpfile[256];
427  char pdffile[256];
428  int nconss;
429  vector<int>::iterator it1;
430 
431  nconss = SCIPgetNConss(scip);
432 
433  /* filenames */
434  sprintf(datafile, "%s.dat", filename);
435  sprintf(blockingfile, "%s_blocked_at.dat", filename);
436  sprintf(gpfile, "%s.gp", filename);
437  sprintf(pdffile, "%s.pdf", filename);
438 
439  /* datafile */
440  output = fopen(datafile, "w");
441  if (output == NULL)
442  {
443  SCIPinfoMessage(scip, NULL, "Can't open file for output in plotMinV!\n");
444  }
445  else
446  {
447  int i;
448 
449  /* write data to datafile */
450  for( i = 0; i < nconss -1; ++i )
451  {
452  fprintf(output, "%d\n", detectordata->minV[i]);
453  }
454  }
455  fclose(output);
456 
457  /* blocking points */
458  output = fopen(blockingfile, "w");
459  if (output == NULL)
460  {
461  SCIPinfoMessage(scip, NULL, "Can't open file for blocking output in plotMinV!\n");
462  }
463  else
464  {
465  /* write data to blockingfile */
466  for( it1 = detectordata->blockedAfterrow->begin(); it1 != detectordata->blockedAfterrow->end(); ++it1 )
467  {
468  fprintf(output, "%d %d\n", *it1-1, detectordata->minV[*it1-1]);
469  }
470  }
471  fclose(output);
472  /* write Gnuplot file */
473  output = fopen(gpfile, "w");
474  fprintf(output, "set terminal pdf\nset output \"%s\"\nset style line 1 lt 1 lc rgb \"black\"\nplot '%s' title '# verb. Variablen' ls 1 with lines, \\\n '%s' lt 0 pt 4 with points title \"Blockgrenze\"", pdffile, datafile, blockingfile);
475  fclose(output);
476 }
477 
478 
479 #endif
480 
481 
482 /** initialization method of detector data for partialdecs */
483 static
484 SCIP_RETCODE initData(
485  SCIP* scip, /**< SCIP data structure */
486  gcg::PARTIALDECOMP* partialdec, /**< partial decomposition to use for initialization */
487  DEC_DETECTORDATA* detectordata /**< detector data structure */
488  )
489 {
490  int i;
491  int nvars;
492  int nconss;
493 
494  assert(partialdec != NULL);
495  assert(detectordata != NULL);
496 
497  nvars = partialdec->getNOpenvars();
498  nconss = partialdec->getNOpenconss();
499  detectordata->maxblocks = MIN(nconss, detectordata->maxblocks);
500 
501  SCIP_CALL( SCIPallocMemoryArray(scip, &detectordata->ibegin, nconss) );
502  SCIP_CALL( SCIPallocMemoryArray(scip, &detectordata->iend, nconss) );
503  SCIP_CALL( SCIPallocMemoryArray(scip, &detectordata->jbegin, nvars) );
504  SCIP_CALL( SCIPallocMemoryArray(scip, &detectordata->jend, nvars) );
505  SCIP_CALL( SCIPallocMemoryArray(scip, &detectordata->jmin, nconss) );
506  SCIP_CALL( SCIPallocMemoryArray(scip, &detectordata->jmax, nconss) );
507  SCIP_CALL( SCIPallocMemoryArray(scip, &detectordata->minV, nconss-1) );
508  SCIP_CALL( SCIPallocMemoryArray(scip, &detectordata->width, nconss) );
509  SCIP_CALL( SCIPallocMemoryArray(scip, &detectordata->hashmapindices, (size_t)MAX(nvars, nconss) + 1) );
510  for( i = 0; i < MAX(nvars, nconss)+1; ++i )
511  {
512  detectordata->hashmapindices[i] = i;
513  }
514  detectordata->rowsWithConstrictions = new vector<int>();
515  detectordata->blockedAfterrow = new vector<int>();
516 
517  /* create hash tables */
518  SCIP_CALL( indexmapCreate(scip, &detectordata->indexmap, nconss, nvars) );
519 
520  return SCIP_OKAY;
521 }
522 
523 /** deinitialization method of detector data (called after detection has been finished) */
524 static
525 SCIP_RETCODE freeData(
526  SCIP* scip, /**< SCIP data structure */
527  DEC_DETECTORDATA* detectordata /**< detector data structure */
528  )
529 {
530  assert(scip != NULL);
531  assert(detectordata != NULL);
532 
533  indexmapFree(scip, &detectordata->indexmap);
534 
535  /* delete vectors */
536  delete detectordata->rowsWithConstrictions;
537  detectordata->rowsWithConstrictions = NULL;
538  delete detectordata->blockedAfterrow;
539  detectordata->blockedAfterrow = NULL;
540 
541  if (detectordata->constoblock != NULL)
542  {
543  SCIPhashmapFree(&detectordata->constoblock);
544  detectordata->constoblock = NULL;
545  }
546 
547  SCIPfreeMemoryArray(scip, &detectordata->ibegin);
548  SCIPfreeMemoryArray(scip, &detectordata->iend);
549  SCIPfreeMemoryArray(scip, &detectordata->jbegin);
550  SCIPfreeMemoryArray(scip, &detectordata->jend);
551  SCIPfreeMemoryArray(scip, &detectordata->jmin);
552  SCIPfreeMemoryArray(scip, &detectordata->jmax);
553  SCIPfreeMemoryArray(scip, &detectordata->minV);
554  SCIPfreeMemoryArray(scip, &detectordata->width);
555  SCIPfreeMemoryArray(scip, &detectordata->hashmapindices);
556 
557  return SCIP_OKAY;
558 }
559 
560 
561 /** creates a nested vector with the indices of the nonzero entries of each row.
562  *
563  * example:
564  * constraint matrix:
565  *
566  * 1 1 0 1 0
567  *
568  * 0 1 1 0 0
569  *
570  * 0 0 0 0 1
571  *
572  * resulting vector:
573  * ( (1 2 4)
574  * (2 3)
575  * (5) )
576  */
577 static
578 SCIP_RETCODE createRowindexList(
579  SCIP* scip, /**< SCIP data structure */
580  gcg::PARTIALDECOMP* partialdec, /**< partial decomposition to use for matrix */
581  gcg::DETPROBDATA* detprobdata, /**< detection process information and data */
582  DEC_DETECTORDATA* detectordata, /**< detector data data structure */
583  SCIP_HASHMAP* indexcons, /**< hashmap index -> constraint */
584  SCIP_HASHMAP* varindex, /**< hashmap variable -> index*/
585  vector<vector<int> > &rowindices /**< vector to store the row indices vector*/
586  )
587 {
588  int i;
589  int nconss = partialdec->getNOpenconss();
590 
591  for( i = 0; i < nconss; ++i )
592  {
593  int j;
594  int ncurrvars;
595  int* probindices = NULL;
596  int cons;
597  vector<int> rowindices_row;
598  int* hashmapindex = &detectordata->hashmapindices[(size_t)i+1];
599 
600  cons = (int)(size_t) SCIPhashmapGetImage(indexcons, (void*) hashmapindex);
601  ncurrvars = detprobdata->getNVarsForCons(cons);
602 
603  SCIP_CALL( SCIPallocMemoryArray(scip, &probindices, ncurrvars) );
604 
605  /* fill the array with the indices of the variables of the current constraint */
606  for( j = 0; j < ncurrvars; ++j )
607  {
608  if(!partialdec->isVarOpenvar(detprobdata->getVarsForCons(cons)[j]))
609  continue;
610  probindices[j] = *(int*) SCIPhashmapGetImage(varindex, (void*)(size_t)detprobdata->getVarsForCons(cons)[j]);
611  }
612 
613  std::sort(probindices, probindices+ncurrvars);
614 
615  /* store a copy of the elements of probindices in the vector rowindices_row */
616  for( j = 0; j < ncurrvars; ++j )
617  {
618  if(!partialdec->isVarOpenvar(detprobdata->getVarsForCons(cons)[j]))
619  continue;
620  rowindices_row.push_back(probindices[j]);
621  }
622 
623  SCIPfreeMemoryArray(scip, &probindices);
624 
625  /* add rowindices_row to the vector rowindices */
626  rowindices.push_back(rowindices_row);
627  rowindices_row.clear();
628  }
629 
630  return SCIP_OKAY;
631 }
632 
633 
634 /** creates a nested vector with the indices of the nonzero entries of each column.
635  *
636  * example:
637  *
638  * constraint matrix:
639  *
640  * 1 1 0 1 0
641  *
642  * 0 1 1 0 0
643  *
644  * 0 0 0 0 1
645  *
646  * resulting vector:
647  * ( (1)
648  * (1 2)
649  * (2)
650  * (1)
651  * (3) )
652  */
653 static
655  SCIP* scip, /**< SCIP data structure */
656  gcg::PARTIALDECOMP* partialdec, /**< partial decomposition to create column index for */
657  vector<vector<int> > &rowindices, /**< A vector with the row indices (achieved from calling rowindices_vector() ) */
658  vector<vector<int> > &columnindices /**< vector to store the column indices vector*/
659 )
660 {
661  int position;
662  int nvars;
663  int i;
664  vector<vector<int> >::iterator outer;
665  vector<int>::iterator inner;
666  nvars = partialdec->getNOpenvars();
667 
668  vector<vector<int> > columnindices_array((size_t)nvars);
669 
670  for( outer = rowindices.begin(), i = 1; outer != rowindices.end(); ++outer, ++i )
671  {
672  for( inner = outer->begin(); inner != outer->end(); ++inner )
673  {
674  position = (*inner)-1;
675  columnindices_array[(size_t) position].push_back(i);
676  }
677  }
678 
679  /* create a columnindices vector instead of an array */
680  for( i = 0; i < nvars; ++i )
681  {
682  columnindices.push_back(columnindices_array[(size_t)i]); /** @todo broken */
683  }
684 
685  return SCIP_OKAY;
686 }
687 
688 
689 /** does the row ordering of the ROC2 algorithm.
690  *
691  * It also works for the column ordering. In this case the terms row<->column have to be exchanged.
692  *
693  * @return A vector with the new row order. E.g. (2 3 1) means the second row comes first now, and so on. */
694 static
695 vector<int> rowOrdering(
696  SCIP* scip, /**< SCIP data structure */
697  vector<vector<int> > &columnindices, /**< A vector of the nonzero entries in each column */
698  int nrows /**< The number of rows of the constraint matrix (=number of relevant constraints) */
699  )
700 {
701  vector<int> roworder;
702  vector<int> new_roworder;
703  vector<vector<int> >::reverse_iterator it1;
704  vector<int>::reverse_iterator it2;
705 
706  /* create a vector for the order of the rows ( 1 2 3 ... nrows ) */
707  roworder = SCIPvectorCreateInt(1, nrows);
708  new_roworder = SCIPvectorCreateInt(1, nrows);
709 
710  /* first from back to front */
711  for( it1 = columnindices.rbegin(); it1 != columnindices.rend(); ++it1 )
712  {
713 
714  /* second from back to front */
715  for( it2 = it1->rbegin(); it2 != it1->rend(); ++it2 )
716  {
717  vector<int>::iterator tmp;
718 
719  tmp = std::find(new_roworder.begin(), new_roworder.end(), *it2); /*lint !e864*/
720  std::rotate(new_roworder.begin(), tmp, tmp+1); /*lint !e1702 !e747*/
721  }
722  roworder = new_roworder;
723  }
724 
725  return roworder;
726 }
727 
728 /** stores the first and last entry of the i-th column(row) in begin[i] and end[i] respectively.
729  *
730  * @param begin Array to store the first nonzero entry of the i-th column (row)
731  * @param end Array to store the last nonzero entry of the i-th column (row)
732  * @param indices columnindices vector (rowindices vector) */
733 static
734 SCIP_RETCODE formIndexArray(
735  int* begin,
736  int* end,
737  vector<vector<int> > &indices
738  )
739 {
740  vector<vector<int> >::iterator it1;
741  int i;
742  assert(begin != NULL && end != NULL);
743  for( it1 = indices.begin(), i = 0; it1 != indices.end(); ++it1, ++i )
744  {
745  /* case: vector not empty */
746  if( !it1->empty() )
747  {
748  begin[i] = it1->front();
749  end[i] = it1->back();
750  }
751  /* case: vector empty */
752  else
753  {
754  begin[i] = 0;
755  end[i] = 0;
756  }
757  }
758  return SCIP_OKAY;
759 }
760 
761 
762 /**returns FALSE if at least one entry of new_array and old_array are different.*/
763 static
764 SCIP_Bool arraysAreEqual(
765  int* new_array, /**< new array */
766  int* old_array, /**< old array */
767  int num_elements /**< length of arrays */
768  )
769 {
770  int i;
771  for( i = 0; i < num_elements; ++i )
772  {
773  if( new_array[i] != old_array[i] )
774  {
775  return FALSE;
776  }
777  }
778  /* case: all entries of old and new are equal */
779  return TRUE;
780 }
781 
782 
783 /**permutes the order of rows and columns in inputmap and stores the result in outputmap.
784  *
785  * One call of this function is equivalent to one iteration of the ROC2-algortihm. */
786 static
788  SCIP* scip, /**< SCIP data structure */
789  gcg::PARTIALDECOMP* partialdec, /**< partial decomposition to use for permutation */
790  gcg::DETPROBDATA* detprobdata, /**< detection process information and data */
791  DEC_DETECTORDATA* detectordata, /**< detector data data structure */
792  INDEXMAP* inputmap, /**< indexmap for input */
793  INDEXMAP* outputmap /**< indexmap for output */
794  )
795 {
796  vector<int> roworder;
797  vector<int> columnorder;
798  vector<vector<int> > rowindices;
799  vector<vector<int> > columnindices;
800  vector<int>::iterator it1;
801  int nvars;
802  int ncons;
803  size_t i;
804  int position;
805  int* hashmapindex;
806 
807  SCIPdebugMessage("Entering rankOrderClusteringIteration\n");
808 
809  assert(scip != NULL);
810  assert(detectordata != NULL);
811  nvars = partialdec->getNOpenvars();
812  ncons = partialdec->getNOpenconss();
813 
814  /* create the vectors containing the positions of nonzero entries; row and column ordering */
815  SCIP_CALL( createRowindexList(scip, partialdec, detprobdata, detectordata, inputmap->indexcons, inputmap->varindex, rowindices) );
816  SCIP_CALL( createColumnindexList(scip, partialdec, rowindices, columnindices) );
817 
818  roworder = rowOrdering(scip, columnindices, ncons);
819  SCIPvectorRearrange(rowindices, roworder);
820 
821  columnorder = rowOrdering(scip, rowindices, nvars);
822  SCIPvectorRearrange(columnindices, columnorder);
823 
824  /* consindex and indexcons */
825  for( it1 = roworder.begin(), i = 0; it1 != roworder.end() && i < (size_t) ncons; ++i,++it1 )
826  {
827  int cons;
828  position = *it1;
829  hashmapindex = &detectordata->hashmapindices[position];
830 
831  cons = (int)(size_t) SCIPhashmapGetImage(inputmap->indexcons, (void*) hashmapindex);
832 
833  /* consindex */
834  hashmapindex = &detectordata->hashmapindices[i+1];
835  assert( SCIPhashmapExists(outputmap->consindex, (void*)(size_t) cons));
836  assert(*hashmapindex <= ncons);
837  SCIP_CALL( SCIPhashmapSetImage(outputmap->consindex, (void*)(size_t) cons, (void*) hashmapindex) );
838 
839  /* indexcons */
840  assert( SCIPhashmapExists(outputmap->indexcons, (void*) hashmapindex ));
841  SCIP_CALL( SCIPhashmapSetImage(outputmap->indexcons, (void*) hashmapindex, (void*)(size_t) cons) );
842  }
843 
844  /* varindex and indexvar */
845  for( it1 = columnorder.begin(), i = 0; it1 != columnorder.end() &&i < (size_t) nvars; ++i, ++it1 )
846  {
847  int var;
848  position = *it1;
849  hashmapindex = &detectordata->hashmapindices[position];
850  var = (int)(size_t) SCIPhashmapGetImage(inputmap->indexvar, (void*) hashmapindex);
851  assert(*hashmapindex <= nvars);
852  /* varindex */
853  hashmapindex = &detectordata->hashmapindices[i+1];
854  assert( SCIPhashmapExists(outputmap->varindex, (void*)(size_t) var) );
855  SCIP_CALL( SCIPhashmapSetImage(outputmap->varindex, (void*)(size_t) var, (void*) hashmapindex) );
856 
857  /* indexvar */
858  assert( SCIPhashmapExists(outputmap->indexvar, (void*) hashmapindex ));
859  SCIP_CALL( SCIPhashmapSetImage(outputmap->indexvar, (void*) hashmapindex, (void*)(size_t) var) );
860  }
861 
862  return SCIP_OKAY;
863 }
864 
865 
866 static
867 SCIP_RETCODE rankOrderClustering(
868  SCIP* scip, /**< SCIP data structure */
869  gcg::PARTIALDECOMP* partialdec, /**< partial decomposition to use for clustering */
870  gcg::DETPROBDATA* detprobdata, /**< detection process information and data */
871  DEC_DETECTORDATA* detectordata, /**< detector data structure */
872  int max_iterations, /**< number of maximal iterations */
873  int* iterations /**< number of performed iterations */
874  )
875 {
876  int i;
877  INDEXMAP* indexmap_permuted;
878  vector<vector<int> > rowindices;
879  vector<vector<int> > columnindices;
880  int* ibegin_permuted = NULL;
881  int* iend_permuted = NULL;
882  int* jbegin_permuted = NULL;
883  int* jend_permuted = NULL;
884  assert(scip != NULL);
885  assert(detectordata != NULL);
886 
887  int nvars = partialdec->getNOpenvars();
888  int nconss = partialdec->getNOpenconss();
889 
890  if( iterations != NULL )
891  *iterations = -1;
892 
893  if( max_iterations <= 0 )
894  {
895  return SCIP_OKAY;
896  }
897 
898 
899 
900  SCIP_CALL( indexmapCreate(scip, &indexmap_permuted, nconss, nvars) );
901  SCIP_CALL( SCIPallocMemoryArray(scip, &ibegin_permuted, nconss) );
902  SCIP_CALL( SCIPallocMemoryArray(scip, &iend_permuted, nconss) );
903  SCIP_CALL( SCIPallocMemoryArray(scip, &jbegin_permuted, nvars) );
904  SCIP_CALL( SCIPallocMemoryArray(scip, &jend_permuted, nvars) );
905  SCIP_CALL( indexmapInit(indexmap_permuted, partialdec, detectordata->hashmapindices) );
906  i = 0;
907 
908  do
909  {
910  ++i;
911  /* not more than max_iterations loops. no iteration limit for max_iterations == -1 */
912  if(i > max_iterations && max_iterations != -1)
913  break;
914 
915  SCIPdebugMessage("Iteration # %i of ROC2\n", i);
916  SCIP_CALL( rankOrderClusteringIteration(scip, partialdec, detprobdata, detectordata, detectordata->indexmap, indexmap_permuted) );
917 
918  /* form the new index arrays after the permutation */
919  SCIP_CALL( createRowindexList(scip, partialdec, detprobdata, detectordata, indexmap_permuted->indexcons, indexmap_permuted->varindex, rowindices) );
920  SCIP_CALL( createColumnindexList(scip, partialdec, rowindices, columnindices) );
921  SCIP_CALL( formIndexArray(ibegin_permuted, iend_permuted, rowindices) );
922  SCIP_CALL( formIndexArray(jbegin_permuted, jend_permuted, columnindices) );
923  rowindices.clear();
924  columnindices.clear();
925 
926  /* switch between index arrays containing new and old indices */
927  swap( detectordata->ibegin, ibegin_permuted);
928  swap( detectordata->iend, iend_permuted);
929  swap( detectordata->jbegin, jbegin_permuted);
930  swap( detectordata->jend, jend_permuted);
931 
932  /* switch between hash maps containing new and old indices */
933  swap(detectordata->indexmap, indexmap_permuted);
934  }
935  /* while Index Arrays change */
936  while( ! (arraysAreEqual(detectordata->ibegin, ibegin_permuted, nconss )
937  && arraysAreEqual(detectordata->iend, iend_permuted, nconss)
938  && arraysAreEqual(detectordata->jbegin, jbegin_permuted, nvars)
939  && arraysAreEqual(detectordata->jend, jend_permuted, nvars)));
940 
941  indexmapFree(scip, &indexmap_permuted);
942  SCIPfreeMemoryArray(scip, &ibegin_permuted);
943  SCIPfreeMemoryArray(scip, &iend_permuted);
944  SCIPfreeMemoryArray(scip, &jbegin_permuted);
945  SCIPfreeMemoryArray(scip, &jend_permuted);
946 
947 
948  if( iterations != NULL )
949  *iterations = i-1;
950 
951  return SCIP_OKAY;
952 }
953 
954 
955 /** finds rows with local minima regarding the number of linking variables and stores them in detectordata->rowsWithConstrictions */
956 static
957 SCIP_RETCODE rowsWithConstriction(
958  SCIP* scip, /**< SCIP data structure */
959  gcg::PARTIALDECOMP* partialdec, /**< partial decomposition to use */
960  DEC_DETECTORDATA* detectordata /**< detector data structure */
961  )
962 {
963  /* if blocking is performed after row i+1; local minima */
964  size_t i;
965  size_t nconss = (size_t) partialdec->getNOpenconss();
966  for( i = 1; i < nconss - 2; ++i )
967  {
968  /* is minV[i] a local minimum? < or <= ? What does make more sense? */
969  if( detectordata->minV[i] < detectordata->minV[i-1] && detectordata->minV[i] < detectordata->minV[i+1] )
970  {
971  detectordata->rowsWithConstrictions->push_back((int)(i+1));
972  }
973  }
974  return SCIP_OKAY;
975 }
976 
977 
978 /** assigns constraints in the interval [first_cons, last_cons] to 'block'. (for partialdecs) */
979 static
980 SCIP_RETCODE assignConsToBlock(
981  SCIP* scip, /**< SCIP data structure */
982  gcg::PARTIALDECOMP* partialdec, /**< partial decomposition to use */
983  DEC_DETECTORDATA* detectordata, /**< detector data structure */
984  int block, /**< id of block */
985  int first_cons, /**< index of first constraint to assign */
986  int last_cons /**< index of last constraint to assign */
987  )
988 {
989  int i;
990 
991  /* assign the constraints to the current block */
992  for( i = first_cons; i <= last_cons; ++i )
993  {
994  int* hashmapindex = &detectordata->hashmapindices[i];
995  int cons = (int)(size_t) SCIPhashmapGetImage(detectordata->indexmap->indexcons, (void*) hashmapindex);
996  /* insert cons into hash map vartoblock */
997  assert(!SCIPhashmapExists(detectordata->constoblock, (void*)(size_t) cons));
998  SCIP_CALL( SCIPhashmapInsert(detectordata->constoblock, (void*)(size_t) cons, (void*) (size_t) (detectordata->hashmapindices[block])) );
999  }
1000  detectordata->blockedAfterrow->push_back(detectordata->hashmapindices[last_cons]);
1001  return SCIP_OKAY;
1002 }
1003 
1004 /** returns the largest column index of a nonzero entry between rows [from_row, to_row] */
1005 static
1007  DEC_DETECTORDATA* detectordata, /**< detector data structure */
1008  int from_row, /**< index of starting row to check */
1009  int to_row /**< index of last row to check */
1010  )
1011 {
1012  /* some pointer arithmetic */
1013  return std::max_element(detectordata->iend + (from_row), detectordata->iend+((size_t)to_row + 1))-detectordata->iend; /*lint !e712*/
1014 }
1015 
1016 /** returns the column index of the first nonzero entry in 'row'. Rows start counting at 1, not 0. */
1017 static
1019  DEC_DETECTORDATA* detectordata, /**< detector data structure */
1020  int row /**< index of row */
1021  )
1022 {
1023  return detectordata->ibegin[row-1];
1024 }
1025 
1026 /** determines if a blocking at 'block_at_row' is a valid blocking
1027  *
1028  * @return TRUE if blocking is valid, else FALSE
1029  */
1030 static
1032  DEC_DETECTORDATA* detectordata, /**< detector data structure */
1033  int prev_block_first_row, /**< first row of the previous block */
1034  int prev_block_last_row, /**< last row of the previous block */
1035  int block_at_row /**< the row for which you want to determine if the blocking is valid */
1036  )
1037 {
1038  int last_column_prev_block;
1039  int first_column_current_block;
1040 
1041  /* if the function is called for the first block, the blocking is always valid */
1042  if( prev_block_last_row == 0 )
1043  {
1044  return TRUE;
1045  }
1046  last_column_prev_block = getMaxColIndex(detectordata, prev_block_first_row, prev_block_last_row);
1047  first_column_current_block = getMinColIndex(detectordata, block_at_row);
1048  return ( first_column_current_block > last_column_prev_block ? TRUE : FALSE);
1049 }
1050 
1051 /** this functions looks for rows to block at, which creates block of size min_block_size or bigger
1052  *
1053  * @return Iterator pointing to a node which contains a suitable row for blocking; If the iterator points after the last element, no candidate was found
1054  */
1055 static
1056 vector<int>::iterator findBlockingCandidate(
1057  vector<int>::iterator it_constrictions, /**< Iterator pointing to a vector of constraints (detectordata->rowsWithConstrictions) */
1058  vector<int>* it_vector, /**< minimum number of rows to be in a block */
1059  int min_block_size, /**< the last row of the preceding block */
1060  int prev_block_last_row /**< the last row of the preceding block */
1061  )
1062 {
1063  for( ;; )
1064  {
1065  /* end of the vector? */
1066  if( it_constrictions == it_vector->end() )
1067  {
1068  return it_constrictions;
1069  }
1070  /* does a blocking to the next row forming a constriction comprise more rows than min_block_size */
1071  if( (*it_constrictions - prev_block_last_row) >= min_block_size )
1072  {
1073  return it_constrictions;
1074  }
1075  /* advance iterator to next element */
1076  ++it_constrictions;
1077  }
1078 }
1079 
1080 /** this functions determines the next row to block at
1081  *
1082  * @return Iterator pointing to a node which contains a suitable row for blocking; If the iterator points after the last element, no row was found
1083  */
1084 static
1085 vector<int>::iterator nextRowToBlockAt(
1086  DEC_DETECTORDATA* detectordata, /**< detector data structure */
1087  vector<int>::iterator it_constrictions, /**< Iterator pointing to a vector of constraints (detectordata->rowsWithConstrictions) */
1088  vector<int>* it_vector, /**< vector of constrictions */
1089  int min_block_size, /**< minimum number of rows to be in a block */
1090  int prev_block_first_row, /**< the first row of the preceding block */
1091  int prev_block_last_row /**< the last row of the preceding block*/
1092  )
1093 {
1094 
1095  /* end of the constriction vector? */
1096  if( it_constrictions == it_vector->end() )
1097  {
1098  return it_constrictions;
1099  }
1100 
1101  for( ;; )
1102  {
1103  /* find a blocking candidate */
1104  it_constrictions = findBlockingCandidate(it_constrictions, it_vector, min_block_size, prev_block_last_row);
1105  /* case: no candidate found */
1106  if( it_constrictions == it_vector->end() )
1107  {
1108  break;
1109  }
1110  /* case: candidate found */
1111  else
1112  {
1113  /* valid blocking */
1114  if( isValidBlocking(detectordata, prev_block_first_row, prev_block_last_row, *it_constrictions) )
1115  {
1116  break;
1117  }
1118  /* invalid blocking */
1119  else
1120  {
1121  ++it_constrictions;
1122  }
1123  }
1124  }
1125  return it_constrictions;
1126 }
1127 
1128 /** calculate the number of decompositions in order to allocate decomps array */
1129 static
1131  DEC_DETECTORDATA* detectordata /**< detector data structure */
1132  )
1133 {
1134  int nblockingtypes;
1135  int nblockingspertype;
1136 
1137  nblockingtypes = 0;
1138  /* get the number of enabled blocking types */
1139  if( detectordata->dynamicblocking )
1140  {
1141  ++nblockingtypes;
1142  }
1143  if( detectordata->staticblocking )
1144  {
1145  ++nblockingtypes;
1146  }
1147  if( detectordata->blockingassoonaspossible )
1148  {
1149  ++nblockingtypes;
1150  }
1151 
1152  /* get the number of blockings per blocking type */
1153  if( detectordata->multipledecomps )
1154  {
1155  nblockingspertype = detectordata->maxblocks - detectordata->minblocks + 1;
1156  }
1157  else
1158  {
1159  nblockingspertype = 1;
1160  }
1161 
1162  return nblockingtypes * nblockingspertype;
1163 }
1164 
1165 /** check the consistency of the parameters */
1166 static
1168  DEC_DETECTORDATA* detectordata, /**< detector data structure */
1169  SCIP_RESULT* result /**< pointer to store result */
1170  )
1171 {
1172  /* maxblocks < nRelevantsCons? */
1173 
1174  /* desired blocks <= maxblocks? */
1175 
1176  /* is minblocks <= maxblocks? */
1177  if( detectordata->multipledecomps )
1178  {
1179  if( detectordata->minblocks > detectordata->maxblocks )
1180  {
1181  SCIPerrorMessage("minblocks > maxblocks. Setting minblocks = maxblocks.\n");
1182  detectordata->minblocks = detectordata->maxblocks;
1183  }
1184  }
1185 
1186  /* is at least one blocking type enabled? */
1187  if( ! detectordata->blockingassoonaspossible && ! detectordata->staticblocking &&! detectordata->dynamicblocking )
1188  {
1189  SCIPerrorMessage("No blocking type enabled, cannot perform blocking.\n");
1190  *result = SCIP_DIDNOTRUN;
1191  }
1192 }
1193 
1194 
1195 /** tries to dynamically divide the problem into subproblems (blocks)*/
1196 static
1197 SCIP_RETCODE blockingDynamic(
1198  SCIP* scip, /**< SCIP data structure */
1199  gcg::PARTIALDECOMP* partialdec, /**< partial decomposition to use */
1200  DEC_DETECTORDATA* detectordata, /**< detector data data structure */
1201  int tau, /**< desired number of blocks */
1202  int nvars /**< number of variables in the problem*/
1203  )
1204 { /*lint -e715*/
1205  int block;
1206  int prev_block_first_row;
1207  int prev_block_last_row;
1208  int min_block_size;
1209  /* notation: i=current block; im1=i-1=previous block; ip1=i+1=next block */
1210 #ifdef SCIP_DEBUG
1211  int max_col_index_im1 = 0;
1212 #endif
1213  vector<int>::iterator it1;
1214  /* debug */
1215  SCIPdebugMessage("Starting Blocking...\n");
1216  SCIPdebugMessage("Max blocks: %i\n", detectordata->maxblocks);
1217  block = 1;
1218  prev_block_first_row = 0;
1219  prev_block_last_row = 0;
1220 
1221  assert(tau > 0);
1222  min_block_size = (int) SCIPround(scip, ((SCIP_Real)partialdec->getNOpenconss()) / (2.0 * tau ));
1223  it1 = detectordata->rowsWithConstrictions->begin();
1224 
1225  for( it1 = nextRowToBlockAt(detectordata, it1, detectordata->rowsWithConstrictions, min_block_size, prev_block_first_row, prev_block_last_row);
1226  it1 != detectordata->rowsWithConstrictions->end() && block < detectordata->maxblocks;
1227  it1 = nextRowToBlockAt(detectordata, it1, detectordata->rowsWithConstrictions, min_block_size, prev_block_first_row, prev_block_last_row) )
1228  {
1229  int current_row = * it1;
1230 #ifdef SCIP_DEBUG
1231  int max_col_index_i = getMaxColIndex(detectordata, prev_block_last_row + 1, current_row);
1232  int min_col_index_ip1 = getMinColIndex(detectordata, current_row + 1);
1233  SCIPdebugMessage("vars in block: %i - %i, linking vars: %i - %i\n", max_col_index_im1+1, max_col_index_i, min_col_index_ip1, max_col_index_i);
1234 #endif
1235  /* assign the variables and constraints to block */
1236  SCIP_CALL( assignConsToBlock(scip, partialdec, detectordata, block, prev_block_last_row + 1, current_row) );
1237  /* update variables in the while loop */
1238  prev_block_first_row = prev_block_last_row + 1;
1239  prev_block_last_row = current_row;
1240  ++block;
1241 
1242 #ifdef SCIP_DEBUG
1243  max_col_index_im1 = max_col_index_i;
1244 #endif
1245  }
1246  /* assign the remaining (< M/2tau) cons and vars to the last block; no new linking vars are added */
1247 #ifdef SCIP_DEBUG
1248  SCIPdebugMessage("last time: vars in block: %i - %i, linking vars: %i - %i\n", max_col_index_im1+1, nvars, nvars+1, nvars);
1249 #endif
1250  SCIP_CALL( assignConsToBlock(scip, partialdec, detectordata, block, prev_block_last_row + 1, SCIPgetNConss(scip)) );
1251  detectordata->blockedAfterrow->pop_back();
1252 
1253  detectordata->blocks = block;
1254 
1255  /* debug plot the blocking plot for [i=1:2:1] 'test.dat' every :::i::i lt i pt 5 */
1256 #ifdef WRITEALLOUTPUT
1257  {
1258  char filename[256];
1259  char paramfile[256];
1260 
1261  sprintf(filename, "%s_dynamic_minV", getProbNameWithoutPath(scip));
1262  sprintf(paramfile, "%s_dynamic.params", getProbNameWithoutPath(scip));
1263  plotMinV(scip, detectordata, filename);
1264  }
1265 #endif
1266 
1267  return SCIP_OKAY;
1268 }
1269 
1270 
1271 /** creates blocks with the same number of rows (for partialdecs) */
1272 static
1273 SCIP_RETCODE blockingStatic(
1274  SCIP* scip, /**< SCIP data structure */
1275  gcg::PARTIALDECOMP* partialdec, /**< partial decomposition to create block in */
1276  DEC_DETECTORDATA* detectordata /**< detector data data structure */
1277  )
1278 {
1279  int nblocks;
1280  int block;
1281  int prev_block_last_row;
1282  int current_row;
1283  int nconss;
1284  /* notation: i=current block; im1=i-1=previous block; ip1=i+1=next block */
1285 
1286  assert(scip != NULL);
1287  assert(detectordata != NULL);
1288  nconss = partialdec->getNOpenconss();
1289  nblocks = nconss/detectordata->nconssperblock;
1290  prev_block_last_row = 0;
1291  current_row = 0;
1292 
1293  /* blocks 1 to (desired_blocks-1) */
1294  for( block = 1; block <= nblocks; ++block )
1295  {
1296  current_row += detectordata->nconssperblock;
1297  SCIPdebugMessage("Blocking from %d to %d in block %d",prev_block_last_row + 1, current_row, block);
1298  SCIP_CALL( assignConsToBlock(scip, partialdec, detectordata, block, prev_block_last_row + 1, current_row) );
1299 
1300 
1301  prev_block_last_row = current_row;
1302  }
1303  /* last block */
1304  /* assign the remaining cons and vars to the last block; no new linking vars are added */
1305  if( prev_block_last_row + 1 <= nconss)
1306  {
1307  SCIPdebugMessage("last time: assignVarsToBlock: block, from_row, to_row: %i, %i, %i\n", block, prev_block_last_row + 1, SCIPgetNConss(scip));
1308 
1309  SCIP_CALL( assignConsToBlock(scip, partialdec, detectordata, block, prev_block_last_row + 1, nconss) );
1310  detectordata->blockedAfterrow->pop_back();
1311  ++block;
1312  }
1313  detectordata->blocks = block-1;
1314 
1315 #ifdef WRITEALLOUTPUT
1316  {
1317  char filename[256];
1318  char paramfile[256];
1319 
1320  /* debug */
1321  sprintf(filename, "%s_static_minV_%i", getProbNameWithoutPath(scip), detectordata->blocks);
1322  sprintf(paramfile, "%s_static.params", getProbNameWithoutPath(scip));
1323  plotMinV(scip, detectordata, filename);
1324  }
1325 #endif
1326 
1327  return SCIP_OKAY;
1328 }
1329 
1330 static
1332  SCIP* scip, /**< SCIP data structure */
1333  DEC_DETECTORDATA* detectordata, /**< detector data data structure */
1334  int desired_blocks, /**< desired number of blocks */
1335  int nvars /**< number of variables in the problem*/
1336 )
1337 {
1338  int block;
1339  block = 0;
1340  detectordata->blocks = block;
1341 
1342  return SCIP_OKAY;
1343 }
1344 
1345 /** resets detectordata such that it can be used for the next decomposition */
1346 static
1347 SCIP_RETCODE resetDetectordata(
1348  SCIP* scip, /**< SCIP data structure */
1349  DEC_DETECTORDATA* detectordata /**< detector data structure */
1350  )
1351 {
1352  if(detectordata->constoblock != NULL)
1353  {
1354  SCIP_CALL( SCIPhashmapRemoveAll(detectordata->constoblock) );
1355  }
1356  else
1357  {
1358  SCIP_CALL( SCIPhashmapCreate(&(detectordata->constoblock), SCIPblkmem(scip), SCIPgetNConss(scip)) );
1359  }
1360  return SCIP_OKAY;
1361 }
1362 
1363 static
1364 SCIP_RETCODE blocking(
1365  SCIP* scip, /**< SCIP data structure */
1366  DEC_DETECTORDATA* detectordata, /**< detector data structure */
1367  gcg::PARTIALDECOMP* partialdec, /**< partialdec to propagate */
1368  PARTIALDEC_DETECTION_DATA* detectiondata, /**< detection data */
1369  SCIP_Real time, /**< previous time */
1370  int maxndecs, /**< capacity of detectiondata->newpartialdecs */
1371  SCIP_RESULT* result /**< pointer to store result */
1372  )
1373 {
1374  std::vector<SCIP_Real> clocktimes;
1375  SCIP_CLOCK* temporaryClock;
1376  int* nnewpartialdecs = &detectiondata->nnewpartialdecs;
1377  char decinfo[SCIP_MAXSTRLEN];
1378  int tau = 1; /* desired number of blocks */
1379  int ncons = partialdec->getNOpenconss();
1380  int nvars = partialdec->getNOpenvars();
1381 
1382  SCIP_CALL_ABORT( SCIPcreateClock(scip, &temporaryClock) );
1383  SCIP_CALL_ABORT( SCIPstartClock(scip, temporaryClock) );
1384 
1385  assert(*nnewpartialdecs == 0);
1386  clocktimes.reserve(maxndecs);
1387 
1388  SCIPdebugMessage("Entering Blocking\n");
1389 
1390  /* if multiple decompositions disabled */
1391  if( detectordata->multipledecomps == FALSE )
1392  {
1393  /* if desiredblocks == 0 let the algorithm determine the desired number of blocks */
1394  if( detectordata->desiredblocks == 0 )
1395  {
1396  int n = *std::max_element(detectordata->width, detectordata->width+ncons);
1397  int v = *std::min_element(detectordata->width, detectordata->width+ncons);
1398  tau = (int)SCIPround(scip, ((SCIP_Real)nvars - v)/((SCIP_Real)n - v));
1399  SCIPdebugMessage("<n><v><tau>: <%i><%i><%i>\n", n, v, tau);
1400  if( tau > detectordata->maxblocks )
1401  {
1402  tau = detectordata->maxblocks;
1403  }
1404 
1405  SCIPdebugMessage("detectordata->enablemultipledecomps = 0. detectordata->desiredblocks == 0. Calculating tau = %i\n", tau);
1406  /* continue only if tau >= 2 */
1407  if( tau < 2 )
1408  {
1409  *result = SCIP_DIDNOTFIND;
1410  SCIP_CALL_ABORT( SCIPstopClock(scip, temporaryClock) );
1411  SCIP_CALL_ABORT(SCIPfreeClock(scip, &temporaryClock) );
1412  return SCIP_OKAY;
1413  }
1414  }
1415  else
1416  {
1417  tau = detectordata->desiredblocks;
1418  }
1419  }
1420 
1421  SCIP_CALL_ABORT( SCIPstopClock(scip, temporaryClock) );
1422  SCIP_Real tempTime = SCIPgetClockTime(scip, temporaryClock);
1423  SCIP_CALL_ABORT( SCIPresetClock(scip, temporaryClock) );
1424  /* variant 2 */
1425  /* dynamic blocking */
1426  SCIP_Real tempTimeDynamicBlocking = 0;
1427  int ndynamicblocking = 0;
1428  if( detectordata->dynamicblocking )
1429  {
1430  SCIP_CALL_ABORT( SCIPstartClock(scip, temporaryClock) );
1431  SCIPdebugMessage("detectordata->enableblockingdynamic = 1.\n");
1432  SCIP_CALL( rowsWithConstriction(scip, partialdec, detectordata) );
1433 
1434  SCIPdebugMessage("detectordata->enablemultipledecomps = %ud.\n", detectordata->multipledecomps);
1435 
1436  SCIP_CALL_ABORT( SCIPstopClock(scip, temporaryClock) );
1437  tempTimeDynamicBlocking = SCIPgetClockTime(scip, temporaryClock);
1438  SCIP_CALL_ABORT( SCIPresetClock(scip, temporaryClock) );
1439 
1440  if( detectordata->multipledecomps )
1441  {
1442  for( tau = detectordata->minblocks; tau <= detectordata->maxblocks; ++tau )
1443  {
1444  SCIP_CALL_ABORT( SCIPstartClock(scip, temporaryClock) );
1445  SCIPdebugMessage("tau = %i, dec = %i\n", tau, *nnewpartialdecs);
1446  SCIP_CALL( resetDetectordata(scip, detectordata) );
1447 
1448  SCIP_CALL( blockingDynamic(scip, partialdec, detectordata, tau, nvars) );
1449  if( detectordata->blocks <= 1 )
1450  {
1451  SCIP_CALL_ABORT( SCIPstopClock(scip, temporaryClock) );
1452  SCIP_CALL_ABORT( SCIPresetClock(scip, temporaryClock) );
1453  continue;
1454  }
1455 
1456  detectiondata->newpartialdecs[*nnewpartialdecs] = new gcg::PARTIALDECOMP(partialdec);
1457  SCIP_CALL(detectiondata->newpartialdecs[*nnewpartialdecs]->assignPartialdecFromConstoblock(detectordata->constoblock, detectordata->blocks) );
1458  detectiondata->newpartialdecs[*nnewpartialdecs]->assignCurrentStairlinking();
1459 
1460  SCIP_CALL_ABORT( SCIPstopClock(scip, temporaryClock) );
1461  clocktimes.push_back(SCIPgetClockTime(scip, temporaryClock));
1462  SCIP_CALL_ABORT( SCIPresetClock(scip, temporaryClock) );
1463 
1464  (void) SCIPsnprintf(decinfo, SCIP_MAXSTRLEN, "stairheu_db_md_%d", tau);
1465  detectiondata->newpartialdecs[*nnewpartialdecs]->addDetectorChainInfo(decinfo);
1466 
1467  (*nnewpartialdecs) += 1;
1468  ndynamicblocking++;
1469  }
1470  }
1471  else
1472  {
1473  SCIP_CALL_ABORT( SCIPstartClock(scip, temporaryClock) );
1474  SCIPdebugMessage("tau = %i, dec = %i\n", tau, *nnewpartialdecs);
1475  SCIP_CALL( resetDetectordata(scip, detectordata) );
1476 
1477  SCIP_CALL( blockingDynamic(scip, partialdec, detectordata, tau, nvars) );
1478  if( detectordata->blocks > 1 )
1479  {
1480  detectiondata->newpartialdecs[*nnewpartialdecs] = new gcg::PARTIALDECOMP(partialdec);
1481  SCIP_CALL(detectiondata->newpartialdecs[*nnewpartialdecs]->assignPartialdecFromConstoblock(detectordata->constoblock, detectordata->blocks) );
1482  detectiondata->newpartialdecs[*nnewpartialdecs]->assignCurrentStairlinking();
1483 
1484  SCIP_CALL_ABORT( SCIPstopClock(scip, temporaryClock) );
1485  clocktimes.push_back(SCIPgetClockTime(scip, temporaryClock));
1486  SCIP_CALL_ABORT( SCIPresetClock(scip, temporaryClock) );
1487 
1488  (void) SCIPsnprintf(decinfo, SCIP_MAXSTRLEN, "stairheu_db");
1489  detectiondata->newpartialdecs[*nnewpartialdecs]->addDetectorChainInfo(decinfo);
1490 
1491  (*nnewpartialdecs) += 1;
1492  ndynamicblocking++;
1493  }
1494  else
1495  {
1496  SCIP_CALL_ABORT( SCIPstopClock(scip, temporaryClock) );
1497  SCIP_CALL_ABORT( SCIPresetClock(scip, temporaryClock) );
1498  }
1499  }
1500  }
1501 
1502  /* static blocking */
1503  SCIPdebugMessage("detectordata->staticblocking = %ud. \n", detectordata->staticblocking);
1504 
1505  if( detectordata->staticblocking )
1506  {
1507  SCIP_CALL_ABORT( SCIPstartClock(scip, temporaryClock) );
1508  SCIPdebugMessage("nconssperblock = %i, dec = %i\n", detectordata->nconssperblock, *nnewpartialdecs);
1509 
1510  SCIP_CALL( resetDetectordata(scip, detectordata) );
1511  SCIP_CALL( blockingStatic(scip, partialdec, detectordata) );
1512 
1513  if( detectordata->blocks > 1 )
1514  {
1515  detectiondata->newpartialdecs[*nnewpartialdecs] = new gcg::PARTIALDECOMP(partialdec);
1516  SCIP_CALL(detectiondata->newpartialdecs[*nnewpartialdecs]->assignPartialdecFromConstoblock(detectordata->constoblock, detectordata->blocks) );
1517  detectiondata->newpartialdecs[*nnewpartialdecs]->assignCurrentStairlinking();
1518 
1519  SCIP_CALL_ABORT( SCIPstopClock(scip, temporaryClock) );
1520  clocktimes.push_back(SCIPgetClockTime(scip, temporaryClock));
1521  SCIP_CALL_ABORT( SCIPresetClock(scip, temporaryClock) );
1522 
1523  (void) SCIPsnprintf(decinfo, SCIP_MAXSTRLEN, "stairheu_sb");
1524  detectiondata->newpartialdecs[*nnewpartialdecs]->addDetectorChainInfo(decinfo);
1525 
1526  (*nnewpartialdecs) += 1;
1527  }
1528  else
1529  {
1530  SCIP_CALL_ABORT( SCIPstopClock(scip, temporaryClock) );
1531  SCIP_CALL_ABORT( SCIPresetClock(scip, temporaryClock) );
1532  }
1533  }
1534 
1535  /* blocking ASAP */
1536  SCIPdebugMessage("detectordata->blockingassoonaspossible = %ud. \n", detectordata->blockingassoonaspossible);
1537 
1538  if( detectordata->blockingassoonaspossible )
1539  {
1540  if( detectordata->multipledecomps )
1541  {
1542  for( tau = detectordata->minblocks; tau <= detectordata->maxblocks; ++tau )
1543  {
1544  SCIP_CALL_ABORT( SCIPstartClock(scip, temporaryClock) );
1545  SCIPdebugMessage("tau = %i, dec = %i\n", tau, *nnewpartialdecs);
1546  SCIP_CALL( resetDetectordata(scip, detectordata) );
1547 
1548  SCIP_CALL( blockingAsSoonAsPossible(scip, detectordata, tau, nvars) );
1549  if( detectordata->blocks <= 1)
1550  {
1551  SCIP_CALL_ABORT( SCIPstopClock(scip, temporaryClock) );
1552  SCIP_CALL_ABORT( SCIPresetClock(scip, temporaryClock) );
1553  continue;
1554  }
1555 
1556  detectiondata->newpartialdecs[*nnewpartialdecs] = new gcg::PARTIALDECOMP(partialdec);
1557  SCIP_CALL(detectiondata->newpartialdecs[*nnewpartialdecs]->assignPartialdecFromConstoblock(detectordata->constoblock, detectordata->blocks) );
1558  detectiondata->newpartialdecs[*nnewpartialdecs]->assignCurrentStairlinking();
1559 
1560  SCIP_CALL_ABORT( SCIPstopClock(scip, temporaryClock) );
1561  clocktimes.push_back(SCIPgetClockTime(scip, temporaryClock));
1562  SCIP_CALL_ABORT( SCIPresetClock(scip, temporaryClock) );
1563 
1564  (void) SCIPsnprintf(decinfo, SCIP_MAXSTRLEN, "stairheu_asap_md_%d", tau);
1565  detectiondata->newpartialdecs[*nnewpartialdecs]->addDetectorChainInfo(decinfo);
1566 
1567  *nnewpartialdecs += 1;
1568  }
1569  }
1570  else
1571  {
1572  SCIP_CALL_ABORT( SCIPstartClock(scip, temporaryClock) );
1573  SCIPdebugMessage("tau = %i, dec = %i\n", tau, *nnewpartialdecs);
1574  SCIP_CALL( resetDetectordata(scip, detectordata) );
1575  SCIP_CALL( blockingAsSoonAsPossible(scip, detectordata, tau, nvars) );
1576  if( detectordata->blocks > 1)
1577  {
1578  detectiondata->newpartialdecs[*nnewpartialdecs] = new gcg::PARTIALDECOMP(partialdec);
1579  SCIP_CALL(detectiondata->newpartialdecs[*nnewpartialdecs]->assignPartialdecFromConstoblock(detectordata->constoblock, detectordata->blocks) );
1580  detectiondata->newpartialdecs[*nnewpartialdecs]->assignCurrentStairlinking();
1581  if( detectordata->constoblock != NULL )
1582  SCIPhashmapFree( &detectordata->constoblock );
1583  detectordata->constoblock = NULL;
1584 
1585  SCIP_CALL_ABORT( SCIPstopClock(scip, temporaryClock) );
1586  clocktimes.push_back(SCIPgetClockTime(scip, temporaryClock));
1587  SCIP_CALL_ABORT( SCIPresetClock(scip, temporaryClock) );
1588 
1589  (void) SCIPsnprintf(decinfo, SCIP_MAXSTRLEN, "stairheu_asap");
1590  detectiondata->newpartialdecs[*nnewpartialdecs]->addDetectorChainInfo(decinfo);
1591 
1592  *nnewpartialdecs += 1;
1593  }
1594  else
1595  {
1596  SCIP_CALL_ABORT( SCIPstopClock(scip, temporaryClock) );
1597  SCIP_CALL_ABORT( SCIPresetClock(scip, temporaryClock) );
1598  }
1599  }
1600  }
1601 
1602  SCIP_Real timeperdec = (time + tempTime) / detectiondata->nnewpartialdecs;
1603  SCIP_Real timeperdecdyn = tempTimeDynamicBlocking / ndynamicblocking;
1604  assert(detectiondata->nnewpartialdecs == (int) clocktimes.size());
1605  for( int i = 0; i < detectiondata->nnewpartialdecs; ++i)
1606  {
1607  if( i < ndynamicblocking )
1608  {
1609  detectiondata->newpartialdecs[i]->addClockTime(timeperdec + timeperdecdyn + clocktimes[i]);
1610  }
1611  else
1612  {
1613  detectiondata->newpartialdecs[i]->addClockTime(timeperdec + clocktimes[i]);
1614  }
1615  }
1616  SCIP_CALL_ABORT(SCIPfreeClock(scip, &temporaryClock) );
1617  return SCIP_OKAY;
1618 }
1619 
1620 
1621 /** destructor of detector to free user data (called when GCG is exiting) */
1622 static
1623 DEC_DECL_FREEDETECTOR(detectorFreeStairheur)
1624 {
1625  DEC_DETECTORDATA* detectordata;
1626 
1627  assert(scip != NULL);
1628 
1629  detectordata = DECdetectorGetData(detector);
1630  assert(detectordata != NULL);
1631 
1632  if (detectordata->constoblock != NULL)
1633  {
1634  SCIPhashmapFree(&detectordata->constoblock);
1635  detectordata->constoblock = NULL;
1636  }
1637 
1638  assert(strcmp(DECdetectorGetName(detector), DEC_DETECTORNAME) == 0);
1639 
1640  SCIPfreeMemory(scip, &detectordata);
1641  return SCIP_OKAY;
1642 }
1643 
1644 /** detector initialization method (called after problem was transformed) */
1645 static
1646 DEC_DECL_INITDETECTOR(detectorInitStairheur)
1647 {
1648  DEC_DETECTORDATA* detectordata;
1649 
1650  assert(scip != NULL);
1651 
1652  detectordata = DECdetectorGetData(detector);
1653  assert(detectordata != NULL);
1654 
1655  detectordata->constoblock = NULL;
1656  detectordata->ibegin = NULL;
1657  detectordata->iend = NULL;
1658  detectordata->jbegin = NULL;
1659  detectordata->jend = NULL;
1660  detectordata->jmin = NULL;
1661  detectordata->jmax = NULL;
1662  detectordata->minV = NULL;
1663  detectordata->width = NULL;
1664  detectordata->hashmapindices = NULL;
1665  detectordata->indexmap = NULL;
1666  detectordata->rowsWithConstrictions = NULL;
1667  detectordata->blockedAfterrow = NULL;
1668 
1669  return SCIP_OKAY;
1670 }
1671 
1672 
1673 static DEC_DECL_PROPAGATEPARTIALDEC(detectorPropagatePartialdecStairheur)
1674 {
1675  int i;
1676  int nconss; /* number of constraints in the problem */
1677  int nPartialdecs;
1678  vector<vector<int> > rowindices;
1679  vector<vector<int> > columnindices;
1680  DEC_DETECTORDATA* detectordata = DECdetectorGetData(detector);
1681  gcg::PARTIALDECOMP* partialdec;
1682  SCIP_Real temptime;
1683 
1684  SCIP_CLOCK* temporaryClock;
1685  SCIP_CALL_ABORT( SCIPcreateClock(scip, &temporaryClock) );
1686  SCIP_CALL_ABORT( SCIPstartClock(scip, temporaryClock) );
1687 
1688  partialdec = partialdecdetectiondata->workonpartialdec;
1689  partialdec->refineToMaster();
1690 
1691 #ifdef WRITEALLOUTPUT
1692  int ROC_iterations;
1693  SCIPwarningMessage(scip, "WRITEALLOUTPUT in detector stairheur is not implemented for partialdecs.\n");
1694 #endif
1695 
1696  if( partialdec->getNOpenconss() == 0 || partialdec->getNOpenvars() == 0 )
1697  {
1698  partialdecdetectiondata->nnewpartialdecs = 0;
1699  SCIP_CALL_ABORT( SCIPstopClock(scip, temporaryClock ) );
1700  SCIP_CALL_ABORT(SCIPfreeClock(scip, &temporaryClock) );
1701  *result = SCIP_SUCCESS;
1702  return SCIP_OKAY;
1703  }
1704 
1705  assert(scip != NULL);
1706  assert(detectordata != NULL);
1707 
1708  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, "Detecting stairheur structure:");
1709 
1710  SCIP_CALL( initData(scip, partialdec, detectordata) );
1711 
1712  checkParameterConsistency(detectordata, result);
1713  nPartialdecs = calculateNdecompositions(detectordata);
1714  SCIPdebugMessage("%i decompositions will be created\n", nPartialdecs);
1715  partialdecdetectiondata->nnewpartialdecs = 0;
1716 
1717  /* allocate space for output data */
1718  SCIP_CALL( SCIPallocMemoryArray(scip, &(partialdecdetectiondata->newpartialdecs), nPartialdecs) );
1719 
1720  nconss = partialdec->getNOpenconss();
1721 
1722  /* initialize hash maps for keeping track of variables and constraints and their corresponding indices after being permuted by the ROC2-algorithm */
1723  SCIP_CALL( indexmapInit(detectordata->indexmap, partialdec, detectordata->hashmapindices) );
1724 
1725 #ifdef WRITEALLOUTPUT
1726  {
1727  //char filename[256];
1728  //sprintf(filename, "%s_initial_problem", getProbNameWithoutPath(scip));
1729  }
1730 #endif
1731 
1732  /* initialize index arrays ibegin, iend, jbegin, jend */
1733  SCIP_CALL( createRowindexList(scip, partialdec, partialdecdetectiondata->detprobdata, detectordata, detectordata->indexmap->indexcons, detectordata->indexmap->varindex, rowindices) );
1734 
1735  SCIP_CALL( createColumnindexList(scip, partialdec, rowindices, columnindices) );
1736 
1737  SCIP_CALL( formIndexArray(detectordata->ibegin, detectordata->iend, rowindices) );
1738  SCIP_CALL( formIndexArray(detectordata->jbegin, detectordata->jend, columnindices) );
1739 
1740  /* ==================== */
1741  /* ===ROC2 algorithm=== */
1742  /* ==================== */
1743  SCIPdebugMessage("starting ROC2 algorithm\n");
1744 
1745 
1746 #ifdef WRITEALLOUTPUT
1747  SCIP_CALL( rankOrderClustering(scip, partialdec, partialdecdetectiondata->detprobdata, detectordata, detectordata->maxiterationsROC, &ROC_iterations) );
1748 
1749  /* check conditions for arrays ibegin and jbegin: ibegin[i]<=ibegin[i+k] for all positive k */
1750  //if( ROC_iterations < detectordata->maxiterationsROC || detectordata->maxiterationsROC == -1 )
1751  //{
1752  // checkConsistencyOfIndexarrays(detectordata, partialdec->getNOpenvars(), nconss);
1753  //}
1754 #else
1755  SCIP_CALL( rankOrderClustering(scip, partialdec, partialdecdetectiondata->detprobdata, detectordata, detectordata->maxiterationsROC, NULL) );
1756 #endif
1757  /* arrays jmin, jmax and minV */
1758  SCIPdebugMessage("calculating index arrays\n");
1759  detectordata->jmin[0] = detectordata->ibegin[0];
1760  detectordata->jmax[0] = detectordata->iend[0];
1761  detectordata->width[0] = detectordata->iend[0] - detectordata->ibegin[0];
1762  for( i = 1; i < nconss; ++i )
1763  {
1764  detectordata->width[i] = detectordata->iend[i] - detectordata->ibegin[i];
1765  detectordata->jmin[i] = detectordata->ibegin[i];
1766  detectordata->jmax[i] = MAX(detectordata->iend[i], detectordata->jmax[i-1]);
1767  detectordata->minV[i-1]=1 + (detectordata->jmax[i-1] - detectordata->jmin[i]);
1768  }
1769  /* ==================== */
1770  /* =====BLOCKING======= */
1771  /* ==================== */
1772 
1773  SCIP_CALL_ABORT( SCIPstopClock(scip, temporaryClock) );
1774  temptime = SCIPgetClockTime(scip, temporaryClock);
1775  SCIP_CALL_ABORT( SCIPstartClock(scip, temporaryClock) );
1776  SCIP_CALL( blocking(scip, detectordata, partialdec, partialdecdetectiondata, temptime, nPartialdecs, result) );
1777  SCIP_CALL_ABORT( SCIPstopClock(scip, temporaryClock ) );
1778  partialdecdetectiondata->detectiontime = SCIPgetClockTime(scip, temporaryClock);
1779  SCIP_CALL_ABORT(SCIPfreeClock(scip, &temporaryClock) );
1780  SCIPverbMessage(scip, SCIP_VERBLEVEL_NORMAL, NULL, " found %d partialdecs.\n", partialdecdetectiondata->nnewpartialdecs);
1781  #ifdef WRITEALLOUTPUT
1782  {
1783  //char filename[256];
1784  //sprintf(filename, "%s_ROC", getProbNameWithoutPath(scip));
1785  //plotInitialProblem(scip, detectordata, filename);
1786  }
1787 #endif
1788 
1789  SCIP_CALL( SCIPreallocMemoryArray(scip, &(partialdecdetectiondata->newpartialdecs), partialdecdetectiondata->nnewpartialdecs) );
1790 
1791  SCIP_CALL( freeData(scip, detectordata) );
1792 
1793  *result = SCIP_SUCCESS;
1794  return SCIP_OKAY;
1795 }
1796 #define detectorExitStairheur NULL
1797 #define detectorFinishPartialdecStairheur NULL
1798 #define detectorPostprocessPartialdecStairheur NULL
1799 
1800 
1801 static
1802 DEC_DECL_SETPARAMFAST(setParamAggressiveStairheur)
1803 {
1804  char setstr[SCIP_MAXSTRLEN];
1805  const char* name = DECdetectorGetName(detector);
1806 
1807  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/enabled", name);
1808  SCIP_CALL( SCIPsetBoolParam(scip, setstr, TRUE) );
1809 
1810  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/finishingenabled", name);
1811  SCIP_CALL( SCIPsetBoolParam(scip, setstr, FALSE ) );
1812 
1813  return SCIP_OKAY;
1814 }
1815 
1816 
1817 static
1818 DEC_DECL_SETPARAMFAST(setParamDefaultStairheur)
1819 {
1820  char setstr[SCIP_MAXSTRLEN];
1821  const char* name = DECdetectorGetName(detector);
1822 
1823  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/enabled", name);
1824  SCIP_CALL( SCIPsetBoolParam(scip, setstr, DEC_ENABLED) );
1825 
1826  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/finishingenabled", name);
1827  SCIP_CALL( SCIPsetBoolParam(scip, setstr, DEC_ENABLEDFINISHING ) );
1828 
1829  return SCIP_OKAY;
1830 }
1831 
1832 
1833 static
1834 DEC_DECL_SETPARAMFAST(setParamFastStairheur)
1835 {
1836  char setstr[SCIP_MAXSTRLEN];
1837  const char* name = DECdetectorGetName(detector);
1838 
1839  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/enabled", name);
1840  SCIP_CALL( SCIPsetBoolParam(scip, setstr, FALSE) );
1841 
1842  (void) SCIPsnprintf(setstr, SCIP_MAXSTRLEN, "detection/detectors/%s/finishingenabled", name);
1843  SCIP_CALL( SCIPsetBoolParam(scip, setstr, FALSE ) );
1844 
1845  return SCIP_OKAY;
1846 }
1847 
1848 
1849 /** creates the stairheur detector and includes it in SCIP */
1850 
1851 extern "C"
1853  SCIP* scip /**< SCIP data structure */
1854  )
1855 {
1856  DEC_DETECTORDATA *detectordata = NULL;
1857  assert(scip != NULL);
1858 
1859  SCIP_CALL( SCIPallocMemory(scip, &detectordata) );
1860  assert(detectordata != NULL);
1861 
1862  detectordata->constoblock = NULL;
1863 
1865  detectordata, detectorFreeStairheur, detectorInitStairheur, detectorExitStairheur, detectorPropagatePartialdecStairheur, detectorFinishPartialdecStairheur, detectorPostprocessPartialdecStairheur, setParamAggressiveStairheur, setParamDefaultStairheur, setParamFastStairheur) );
1866 
1867 
1868  /* add stairheur detector parameters */
1869  SCIP_CALL( SCIPaddIntParam(scip, "detection/detectors/stairheur/nconssperblock",
1870  "The number of constraints per block (static blocking only)",
1871  &detectordata->nconssperblock, FALSE, DEFAULT_NCONSSPERBLOCK, 2, 1000000, NULL, NULL) );
1872  SCIP_CALL( SCIPaddIntParam(scip, "detection/detectors/stairheur/maxblocks",
1873  "The maximal number of blocks",
1874  &detectordata->maxblocks, FALSE, DEFAULT_MAXBLOCKS, 2, 1000000, NULL, NULL) );
1875  SCIP_CALL( SCIPaddIntParam(scip, "detection/detectors/stairheur/minblocks", "The minimal number of blocks",
1876  &detectordata->minblocks, FALSE, DEFAULT_MINBLOCKS, 2, 1000000, NULL, NULL) );
1877  SCIP_CALL( SCIPaddIntParam(scip, "detection/detectors/stairheur/desiredblocks",
1878  "The desired number of blocks. 0 means automatic determination of the number of blocks.",
1879  &detectordata->desiredblocks, FALSE, DEFAULT_DESIREDBLOCKS, 0, 1000000, NULL, NULL) );
1880  SCIP_CALL( SCIPaddBoolParam(scip, "detection/detectors/stairheur/dynamicblocking",
1881  "Enable blocking type 'dynamic'",
1882  &detectordata->dynamicblocking, FALSE, DEFAULT_DYNAMICBLOCKING, NULL, NULL) );
1883  SCIP_CALL( SCIPaddBoolParam(scip, "detection/detectors/stairheur/staticblocking",
1884  "Enable blocking type 'static'",
1885  &detectordata->staticblocking, FALSE, DEFAULT_STATICBLOCKING, NULL, NULL) );
1886  SCIP_CALL( SCIPaddBoolParam(scip, "detection/detectors/stairheur/blockingassoonaspossible",
1887  "Enable blocking type 'as soon as possible", &detectordata->blockingassoonaspossible,
1888  FALSE, DEFAULT_BLOCKINGASSOONASPOSSIBLE, NULL, NULL) );
1889  SCIP_CALL( SCIPaddBoolParam(scip, "detection/detectors/stairheur/multipledecomps",
1890  "Enables multiple decompositions for all enabled blocking types. Ranging from minblocks to maxblocks",
1891  &detectordata->multipledecomps, FALSE, DEFAULT_MULTIPLEDECOMPS, NULL, NULL) );
1892  SCIP_CALL( SCIPaddIntParam(scip, "detection/detectors/stairheur/maxiterationsROC",
1893  "The maximum number of iterations of the ROC-algorithm. -1 for no limit",
1894  &detectordata->maxiterationsROC, FALSE, DEFAULT_MAXITERATIONSROC, -1, 1000000, NULL, NULL) );
1895 
1896  return SCIP_OKAY;
1897 }
void addClockTime(SCIP_Real clocktime)
adds detection time of one detector
#define DEC_ENABLED
const char * DECdetectorGetName(DEC_DETECTOR *detector)
returns the name of the provided detector
#define DEFAULT_MINBLOCKS
structure information for decomposition information in GCG projects
#define DEC_FREQCALLROUND
#define DEFAULT_DYNAMICBLOCKING
GCG interface methods.
static SCIP_Bool isValidBlocking(DEC_DETECTORDATA *detectordata, int prev_block_first_row, int prev_block_last_row, int block_at_row)
int getNOpenvars()
Gets size of vector containing variables not assigned yet.
#define detectorExitStairheur
#define DEC_USEFULRECALL
void addDetectorChainInfo(const char *decinfo)
add information about the detector chain
static SCIP_Bool arraysAreEqual(int *new_array, int *old_array, int num_elements)
vector< int > * blockedAfterrow
static SCIP_RETCODE createRowindexList(SCIP *scip, gcg::PARTIALDECOMP *partialdec, gcg::DETPROBDATA *detprobdata, DEC_DETECTORDATA *detectordata, SCIP_HASHMAP *indexcons, SCIP_HASHMAP *varindex, vector< vector< int > > &rowindices)
static SCIP_RETCODE createColumnindexList(SCIP *scip, gcg::PARTIALDECOMP *partialdec, vector< vector< int > > &rowindices, vector< vector< int > > &columnindices)
constraint handler for structure detection
bool isVarOpenvar(int var)
Checks whether the var is an open var.
static SCIP_RETCODE blockingDynamic(SCIP *scip, gcg::PARTIALDECOMP *partialdec, DEC_DETECTORDATA *detectordata, int tau, int nvars)
SCIP_RETCODE SCIPincludeDetectorStairheur(SCIP *scip)
detector for staircase structures via ROC algorithms
static DEC_DECL_FREEDETECTOR(detectorFreeStairheur)
SCIP_HASHMAP * indexcons
#define DEC_MAXCALLROUND
various SCIP helper methods
#define detectorPostprocessPartialdecStairheur
SCIP_HASHMAP * indexvar
#define DEC_MINCALLROUNDORIGINAL
static SCIP_RETCODE initData(SCIP *scip, gcg::PARTIALDECOMP *partialdec, DEC_DETECTORDATA *detectordata)
static SCIP_RETCODE rankOrderClustering(SCIP *scip, gcg::PARTIALDECOMP *partialdec, gcg::DETPROBDATA *detprobdata, DEC_DETECTORDATA *detectordata, int max_iterations, int *iterations)
#define DEFAULT_BLOCKINGASSOONASPOSSIBLE
#define DEFAULT_STATICBLOCKING
#define DEC_DESC
SCIP_HASHMAP * consindex
SCIP_Bool staticblocking
#define DEC_PRIORITY
#define DEFAULT_MAXBLOCKS
DEC_DETECTORDATA * DECdetectorGetData(DEC_DETECTOR *detector)
returns the data of the provided detector
#define DEC_ENABLEDPOSTPROCESSING
static SCIP_RETCODE indexmapCreate(SCIP *scip, INDEXMAP **indexmap, int nconss, int nvars)
static vector< int > SCIPvectorCreateInt(int from, int to)
interface data structure for the detector calling methods
SCIP_Bool multipledecomps
bool assignCurrentStairlinking()
assigns open vars to stairlinking if appropriate
static SCIP_RETCODE indexmapInit(INDEXMAP *indexmap, gcg::PARTIALDECOMP *partialdec, int *hashmapindices)
SCIP_Bool dynamicblocking
const int * getOpenconss()
Gets array containing constraints not assigned yet.
static vector< int > rowOrdering(SCIP *scip, vector< vector< int > > &columnindices, int nrows)
#define DEC_SKIP
static SCIP_RETCODE blockingStatic(SCIP *scip, gcg::PARTIALDECOMP *partialdec, DEC_DETECTORDATA *detectordata)
#define DEFAULT_MULTIPLEDECOMPS
void printnested(vector< vector< int > > l)
static SCIP_RETCODE formIndexArray(int *begin, int *end, vector< vector< int > > &indices)
#define DEC_MINCALLROUND
static SCIP_RETCODE resetDetectordata(SCIP *scip, DEC_DETECTORDATA *detectordata)
class to manage partial decompositions
static SCIP_RETCODE blocking(SCIP *scip, DEC_DETECTORDATA *detectordata, gcg::PARTIALDECOMP *partialdec, PARTIALDEC_DETECTION_DATA *detectiondata, SCIP_Real time, int maxndecs, SCIP_RESULT *result)
gcg::PARTIALDECOMP ** newpartialdecs
#define DEC_ENABLEDFINISHING
#define detectorFinishPartialdecStairheur
#define DEFAULT_DESIREDBLOCKS
static DEC_DECL_INITDETECTOR(detectorInitStairheur)
SCIP_HASHMAP * varindex
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.
SCIP_RETCODE assignPartialdecFromConstoblock(SCIP_HASHMAP *constoblock, int additionalNBlocks)
assigns conss structure according to given hashmap
static int getMinColIndex(DEC_DETECTORDATA *detectordata, int row)
#define DEC_DETECTORNAME
#define DEC_DECCHAR
static SCIP_RETCODE freeData(SCIP *scip, DEC_DETECTORDATA *detectordata)
static int getMaxColIndex(DEC_DETECTORDATA *detectordata, int from_row, int to_row)
#define DEC_MAXCALLROUNDORIGINAL
class storing (potentially incomplete) decompositions
SCIP_Bool blockingassoonaspossible
static vector< int >::iterator nextRowToBlockAt(DEC_DETECTORDATA *detectordata, vector< int >::iterator it_constrictions, vector< int > *it_vector, int min_block_size, int prev_block_first_row, int prev_block_last_row)
static void checkParameterConsistency(DEC_DETECTORDATA *detectordata, SCIP_RESULT *result)
SCIP_HASHMAP * constoblock
std::vector< int > & getVarsForCons(int consIndex)
returns the variable indices of the coefficient matrix for a constraint
static DEC_DECL_PROPAGATEPARTIALDEC(detectorPropagatePartialdecStairheur)
void refineToMaster()
refine partialdec with focus on master
const int * getOpenvars()
Gets array containing variables not assigned yet.
static SCIP_RETCODE assignConsToBlock(SCIP *scip, gcg::PARTIALDECOMP *partialdec, DEC_DETECTORDATA *detectordata, int block, int first_cons, int last_cons)
static void indexmapFree(SCIP *scip, INDEXMAP **indexmap)
class storing partialdecs and the problem matrix
static DEC_DECL_SETPARAMFAST(setParamAggressiveStairheur)
static SCIP_RETCODE rankOrderClusteringIteration(SCIP *scip, gcg::PARTIALDECOMP *partialdec, gcg::DETPROBDATA *detprobdata, DEC_DETECTORDATA *detectordata, INDEXMAP *inputmap, INDEXMAP *outputmap)
static SCIP_RETCODE rowsWithConstriction(SCIP *scip, gcg::PARTIALDECOMP *partialdec, DEC_DETECTORDATA *detectordata)
void printvector(vector< int > l)
#define DEFAULT_MAXITERATIONSROC
static SCIP_RETCODE blockingAsSoonAsPossible(SCIP *scip, DEC_DETECTORDATA *detectordata, int desired_blocks, int nvars)
static void SCIPvectorRearrange(vector< vector< int > > &l, vector< int > order)
static int calculateNdecompositions(DEC_DETECTORDATA *detectordata)
vector< int > * rowsWithConstrictions
static vector< int >::iterator findBlockingCandidate(vector< int >::iterator it_constrictions, vector< int > *it_vector, int min_block_size, int prev_block_last_row)
#define DEFAULT_NCONSSPERBLOCK
#define DEC_FREQCALLROUNDORIGINAL
public methods for working with decomposition structures