Scippy

GCG

Branch-and-Price & Column Generation for Everyone

hypercolgraph_def.h
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 hypercolgraph_def.h
29  * @brief Column hypergraph
30  * @author Martin Bergner
31  * @author Annika Thome
32  *
33  * A hypergraph structure with a node for every constraint and a hyperedge for every variable.
34  */
35 
36 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/
37 
38 #ifndef GCG_HYPERCOLGRAPH_DEF_H_
39 #define GCG_HYPERCOLGRAPH_DEF_H_
40 
41 #include "hypercolgraph.h"
42 #include "class_partialdecomp.h"
43 #include "class_detprobdata.h"
44 #include <set>
45 #include <algorithm>
46 #include <vector>
47 #include <iostream>
48 
49 namespace gcg
50 {
51 template <class T>
53  SCIP* scip, /**< SCIP data structure */
54  Weights w /**< weights for the given graph */
55 ): MatrixGraph<T>(scip, w), graph(scip)
56 {
57  this->graphiface = &graph;
58  this->name = std::string("hypercol");
59 }
60 
61 template <class T>
63 {
64  // TODO Auto-generated destructor stub
65 }
66 
67 
68 /** writes the graph to the given file.
69  * The format is graph dependent
70  */
71 template <class T>
73  int fd, /**< filename where the graph should be written to */
74  SCIP_Bool edgeweights /**< whether to write edgeweights */
75  )
76 {
77  function f(this->nvars);
78  FILE* file;
79  file = fdopen(fd, "w");
80  if( file == NULL )
81  return SCIP_FILECREATEERROR;
82 
83  SCIPinfoMessage(this->scip_, file, "%d %d %d\n", getNEdges(), getNNodes()+this->dummynodes, edgeweights ? 1 :0);
84 
85  for( int i = 0; i < getNEdges(); ++i )
86  {
87  std::vector<int> neighbors = getHyperedgeNodes(i);
88 
89  if( edgeweights )
90  {
91  SCIPinfoMessage(this->scip_, file, "%d ", graph.getHyperedgeWeight(i));
92  }
93  for( size_t j = 0; j < neighbors.size(); ++j )
94  {
95  SCIPinfoMessage(this->scip_, file, "%d ",neighbors[j]+1);
96  }
97  SCIPinfoMessage(this->scip_, file, "\n");
98  }
99  if( !fclose(file) )
100  return SCIP_OKAY;
101  else
102  return SCIP_WRITEERROR;
103 }
104 
105 template <class T>
107 {
108  return this->nvars;
109 }
110 
111 template <class T>
113 {
114  return this->nconss;
115 }
116 
117 
118 template <class T>
120  int i
121 )
122 {
123  assert(i >= 0);
124  assert(i < getNEdges());
125 
126  std::vector<int> neighbors = graph.getHyperedgeNodes(i);
127  return neighbors;
128 }
129 
130 
131 template <class T>
133  SCIP_CONS** conss, /**< constraints for which graph should be created */
134  SCIP_VAR** vars, /**< variables for which graph should be created */
135  int nconss_, /**< number of constraints */
136  int nvars_ /**< number of variables */
137  )
138 {
139  int i;
140  int k;
141  SCIP_Bool success;
142  std::vector< std::vector<int> > hyperedges;
143 
144  assert(conss != NULL);
145  assert(vars != NULL);
146  assert(nvars_ > 0);
147  assert(nconss_ > 0);
148 
149  this->nvars = nvars_;
150  this->nconss = nconss_;
151 
152  /* go through all constraints */
153  for( i = 0; i < this->nconss; ++i )
154  {
155  TCLIQUE_WEIGHT weight;
156 
157  /* calculate weight of node */
158  weight = this->weights.calculate(conss[i]);
159 
160  this->graph.addNode(i, weight);
161  }
162 
163  hyperedges.resize(this->nvars);
164 
165  /* go through all constraints */
166  for( i = 0; i < this->nconss; ++i )
167  {
168  SCIP_VAR **curvars1;
169 
170  int ncurvars1;
171  SCIP_CALL( SCIPgetConsNVars(this->scip_, conss[i], &ncurvars1, &success) );
172  assert(success);
173  if( ncurvars1 == 0 )
174  continue;
175 
176  /*
177  * may work as is, as we are copying the constraint later regardless
178  * if there are variables in it or not
179  */
180  SCIP_CALL( SCIPallocBufferArray(this->scip_, &curvars1, ncurvars1) );
181  SCIP_CALL( SCIPgetConsVars(this->scip_, conss[i], curvars1, ncurvars1, &success) );
182  assert(success);
183 
184  /** @todo skip all variables that have a zero coeffient or where all coefficients add to zero */
185  /** @todo Do more then one entry per variable actually work? */
186 
187  for( k = 0; k < ncurvars1; ++k )
188  {
189  SCIP_VAR* var1;
190  int varIndex1;
191 
192  if( SCIPgetStage(this->scip_) >= SCIP_STAGE_TRANSFORMED)
193  var1 = SCIPvarGetProbvar(curvars1[k]);
194  else
195  var1 = curvars1[k];
196 
197  if( !GCGisVarRelevant(var1) )
198  continue;
199 
200  assert(var1 != NULL);
201  varIndex1 = SCIPvarGetProbindex(var1);
202  assert(varIndex1 >= 0);
203  assert(varIndex1 < this->nvars);
204 
205  hyperedges[varIndex1].insert(hyperedges[varIndex1].end(), i);
206  }
207  SCIPfreeBufferArray(this->scip_, &curvars1);
208  }
209 
210  /* go through all variables */
211  for( i = 0; i < this->nvars; ++i )
212  {
213  TCLIQUE_WEIGHT weight;
214 
215  /* calculate weight of node */
216  weight = this->weights.calculate(vars[i]);
217 
218  this->graph.addHyperedge(hyperedges[i], weight);
219  }
220  this->graph.flush();
221 
222  return SCIP_OKAY;
223 }
224 
225 template <class T>
227  DETPROBDATA* detprobdata,
228  PARTIALDECOMP* partialdec
229  )
230 {
231  int i;
232  int j;
233  TCLIQUE_WEIGHT weight;
234  std::vector< std::vector<int> > hyperedges;
235  unordered_map<int, int> oldToNewConsIndex;
236  vector<bool> varsBool(partialdec->getNVars(), false); /**< true, if the var will be part of the graph */
237  vector<bool> conssBool(partialdec->getNConss(), false); /**< true, if the cons will be part of the graph */
238  vector<int> conssForGraph; /** stores the conss included by the graph */
239  vector<int> varsForGraph; /** stores the vars included by the graph */
240 
241  //fillout conssForGraph and varsForGraph
242  for(int c = 0; c < partialdec->getNOpenconss(); ++c)
243  {
244  int cons = partialdec->getOpenconss()[c];
245  for(int v = 0; v < partialdec->getNOpenvars(); ++v)
246  {
247  int var = partialdec->getOpenvars()[v];
248  for(i = 0; i < detprobdata->getNVarsForCons(cons); ++i)
249  {
250  if(var == detprobdata->getVarsForCons(cons)[i])
251  {
252  varsBool[var] = true;
253  conssBool[cons] = true;
254  }
255  }
256  }
257  }
258 
259  for(int v = 0; v < partialdec->getNOpenvars(); ++v)
260  {
261  int var = partialdec->getOpenvars()[v];
262  if(varsBool[var])
263  varsForGraph.push_back(var);
264  }
265  for(int c = 0; c < partialdec->getNOpenconss(); ++c)
266  {
267  int cons = partialdec->getOpenconss()[c];
268  if(conssBool[cons])
269  conssForGraph.push_back(cons);
270  }
271 
272  this->nconss = (int)conssForGraph.size();
273  this->nvars = (int)varsForGraph.size();
274 
275  /* go through all open constraints */
276  for( i = 0; i < this->nconss; ++i )
277  {
278  int oldConsId = conssForGraph[i];
279 
280  /* calculate weight of node */
281  weight = this->weights.calculate(detprobdata->getCons(oldConsId));
282 
283  oldToNewConsIndex.insert({oldConsId,i});
284 
285  this->graph.addNode(i, weight);
286  }
287 
288 
289 
290  /* go through all open variables */
291  for( i = 0; i < this->nvars; ++i )
292  {
293  std::vector<int> hyperedge;
294  int oldVarId = varsForGraph[i];
295 
296  for( j = 0; j < detprobdata->getNConssForVar(oldVarId); ++j )
297  {
298  int oldConsId = detprobdata->getConssForVar(oldVarId)[j];
299  if(!conssBool[oldConsId])
300  continue;
301  hyperedge.insert(hyperedge.end(), oldToNewConsIndex[oldConsId]);
302  }
303  /* calculate weight of hyperedge */
304  weight = this->weights.calculate(detprobdata->getVar(oldVarId));
305  this->graph.addHyperedge(hyperedge, weight);
306  }
307 
308 
309  this->graph.flush();
310 
311  return SCIP_OKAY;
312 }
313 
314 
315 template <class T>
317  DEC_DECOMP** decomp /**< decomposition structure to generate */
318  )
319 {
320  SCIP_HASHMAP* constoblock;
321  SCIP_CONS** conss;
322  int nblocks;
323 
324  assert(decomp != NULL);
325  std::vector<int> partition = this->getPartition();
326  conss = SCIPgetConss(this->scip_);
327 
328  SCIP_CALL( SCIPhashmapCreate(&constoblock, SCIPblkmem(this->scip_), this->nconss) );
329 
330  assert((size_t)SCIPgetNConss(this->scip_) == partition.size());
331  nblocks = 1+*std::max_element(partition.begin(), partition.end() );
332 
333  for( int c = 0; c < this->nconss; ++c )
334  {
335  int consblock = partition[c]+1;
336 
337  SCIP_CALL( SCIPhashmapInsert(constoblock, conss[c], (void*) (size_t) consblock) );
338  }
339 
340  SCIP_CALL( DECdecompCreate(this->scip_, decomp) );
341  SCIP_CALL( DECfilloutDecompFromConstoblock(this->scip_, *decomp, constoblock, nblocks, FALSE) );
342 
343  return SCIP_OKAY;
344 }
345 
346 template <class T>
348  PARTIALDECOMP** firstpartialdec,
349  PARTIALDECOMP** secondpartialdec,
350  DETPROBDATA* detprobdata
351  )
352 {
353  SCIP_HASHMAP* constoblock;
354  SCIP_CONS** conss;
355  int nblocks;
356 
357  std::vector<int> partition = this->getPartition();
358  conss = SCIPgetConss(this->scip_);
359  std::vector<bool> isEmptyBlock;
360  std::vector<int> nEmptyBlocksBefore;
361 
362  SCIP_CALL( SCIPhashmapCreate(&constoblock, SCIPblkmem(this->scip_), this->nconss) );
363 
364  assert((size_t)SCIPgetNConss(this->scip_) == partition.size());
365  nblocks = 1+*std::max_element(partition.begin(), partition.end() );
366 
367  /** add data structures to handle empty blocks */
368 
369  isEmptyBlock = std::vector<bool>(nblocks, true);
370  nEmptyBlocksBefore = std::vector<int>(nblocks, 0);
371 
372  for( int c = 0; c < this->nconss; ++c )
373  {
374  int consblock = partition[c]+1;
375  isEmptyBlock[consblock-1] = false;
376  }
377 
378  for(int b1 = 0; b1 < nblocks; ++b1)
379  {
380  if (isEmptyBlock[b1] )
381  {
382  std::cout << "block " << b1 << " is an empty block " << std::endl;
383  for(int b2 = b1+1; b2 < nblocks; ++b2)
384  nEmptyBlocksBefore[b2]++;
385  }
386  }
387 
388  for( int c = 0; c < this->nconss; ++c )
389  {
390  int consblock = partition[c]+1;
391  consblock -= nEmptyBlocksBefore[partition[c] ];
392  SCIP_CALL( SCIPhashmapInsert(constoblock, (void*) (size_t) detprobdata->getIndexForCons(conss[c]), (void*) (size_t) consblock) );
393  }
394 
395  bool original = detprobdata->isAssignedToOrigProb();
396  if( firstpartialdec != NULL )
397  {
398  (*firstpartialdec) = new PARTIALDECOMP(this->scip_, original);
399  SCIP_CALL((*firstpartialdec)->filloutPartialdecFromConstoblock(constoblock, nblocks));
400  }
401  if( secondpartialdec != NULL )
402  {
403  (*secondpartialdec) = new PARTIALDECOMP(this->scip_, original);
404  SCIP_CALL((*secondpartialdec)->filloutBorderFromConstoblock(constoblock, nblocks));
405  }
406  SCIPhashmapFree(&constoblock);
407 
408  return SCIP_OKAY;
409 }
410 
411 template <class T>
413  PARTIALDECOMP* oldpartialdec,
414  PARTIALDECOMP** firstpartialdec,
415  PARTIALDECOMP** secondpartialdec,
416  DETPROBDATA* detprobdata
417  )
418 {
419  SCIP_HASHMAP* constoblock;
420  int nblocks;
421  std::vector<bool> isEmptyBlock;
422  std::vector<int> nEmptyBlocksBefore;
423  int nEmptyBlocks = 0;
424 
425  if(this->nconss == 0)
426  {
427  (*firstpartialdec) = NULL;
428  (*secondpartialdec) = NULL;
429  return SCIP_OKAY;
430  }
431 
432  std::vector<int> partition = this->getPartition();
433 
434  //fillout conssForGraph
435  vector<int> conssForGraph; /** stores the conss included by the graph */
436  vector<bool> conssBool(oldpartialdec->getNConss(), false); /**< true, if the cons will be part of the graph */
437  bool found;
438 
439  for(int c = 0; c < oldpartialdec->getNOpenconss(); ++c)
440  {
441  int cons = oldpartialdec->getOpenconss()[c];
442  found = false;
443  for(int v = 0; v < oldpartialdec->getNOpenvars() && !found; ++v)
444  {
445  int var = oldpartialdec->getOpenvars()[v];
446  for(int i = 0; i < detprobdata->getNVarsForCons(cons) && !found; ++i)
447  {
448  if(var == detprobdata->getVarsForCons(cons)[i])
449  {
450  conssBool[cons] = true;
451  found = true;
452  }
453  }
454  }
455  }
456 
457  for(int c = 0; c < oldpartialdec->getNOpenconss(); ++c)
458  {
459  int cons = oldpartialdec->getOpenconss()[c];
460  if(conssBool[cons])
461  conssForGraph.push_back(cons);
462  }
463 
464  SCIP_CALL( SCIPhashmapCreate(&constoblock, SCIPblkmem(this->scip_), this->nconss) );
465  nblocks = 1+*std::max_element(partition.begin(), partition.end() );
466  /** add data structures to handle empty blocks */
467 
468  isEmptyBlock = std::vector<bool>(nblocks, true);
469  nEmptyBlocksBefore = std::vector<int>(nblocks, 0);
470 
471  for( int c = 0; c < this->nconss; ++c )
472  {
473  int consblock = partition[c]+1;
474  isEmptyBlock[consblock-1] = false;
475  }
476 
477  for(int b1 = 0; b1 < nblocks; ++b1)
478  {
479  if (isEmptyBlock[b1] )
480  {
481  nEmptyBlocks++;
482  for(int b2 = b1+1; b2 < nblocks; ++b2)
483  nEmptyBlocksBefore[b2]++;
484  }
485  }
486 
487  for( int c = 0; c < this->nconss; ++c )
488  {
489  int consblock = partition[c]+1;
490  consblock -= nEmptyBlocksBefore[partition[c] ];
491  SCIP_CALL( SCIPhashmapInsert(constoblock, (void*) (size_t) conssForGraph[c], (void*) (size_t) consblock) );
492  }
493 
494  nblocks -= nEmptyBlocks;
495 
496  if( firstpartialdec != NULL )
497  {
498  (*firstpartialdec) = new PARTIALDECOMP(oldpartialdec);
499  SCIP_CALL((*firstpartialdec)->assignPartialdecFromConstoblock(constoblock, nblocks));
500  }
501  if( secondpartialdec != NULL )
502  {
503  (*secondpartialdec) = new PARTIALDECOMP(oldpartialdec);
504  SCIP_CALL((*secondpartialdec)->assignBorderFromConstoblock(constoblock, nblocks));
505  }
506  SCIPhashmapFree(&constoblock);
507 
508  return SCIP_OKAY;
509 }
510 
511 
512 } /* namespace gcg */
513 
514 #endif
int getNOpenvars()
Gets size of vector containing variables not assigned yet.
SCIP_Bool isAssignedToOrigProb()
returns true if the matrix structure corresponds to the presolved problem
virtual std::vector< int > getHyperedgeNodes(int i)
virtual SCIP_RETCODE createFromMatrix(SCIP_CONS **conss, SCIP_VAR **vars, int nconss_, int nvars_)
virtual SCIP_RETCODE createPartialdecFromPartition(PARTIALDECOMP **firstpartialdec, PARTIALDECOMP **secondpartialdec, DETPROBDATA *detprobdata)
SCIP_Bool GCGisVarRelevant(SCIP_VAR *var)
Definition: scip_misc.c:41
std::vector< int > & getConssForVar(int varIndex)
returns the constraint indices of the coefficient matrix for a variable
HypercolGraph(SCIP *scip, Weights w)
GraphInterface * graphiface
Definition: matrixgraph.h:63
static SCIP_RETCODE partition(SCIP *scip, SCIP_VAR **J, int *Jsize, SCIP_Longint *priority, SCIP_VAR **F, int Fsize, SCIP_VAR **origvar, SCIP_Real *median)
SCIP_CONS * getCons(int consIndex)
returns the SCIP constraint related to a constraint index
SCIP_RETCODE writeToFile(int fd, SCIP_Bool edgeweights)
Column hypergraph.
int getIndexForCons(SCIP_CONS *cons)
returns the constraint index related to a SCIP constraint
SCIP_RETCODE DECfilloutDecompFromConstoblock(SCIP *scip, DEC_DECOMP *decomp, SCIP_HASHMAP *constoblock, int nblocks, SCIP_Bool staircase)
Definition: decomp.c:1455
const int * getOpenconss()
Gets array containing constraints not assigned yet.
int getNConss()
Gets the number of constraints.
std::string name
Definition: matrixgraph.h:56
class to manage partial decompositions
int getNVarsForCons(int consIndex)
returns the number of variables for a given constraint
int getNOpenconss()
Gets size of vector containing constraints not assigned yet.
SCIP_RETCODE DECdecompCreate(SCIP *scip, DEC_DECOMP **decdecomp)
Definition: decomp.c:471
class storing (potentially incomplete) decompositions
virtual SCIP_RETCODE createFromPartialMatrix(DETPROBDATA *detprobdata, PARTIALDECOMP *partialdec)
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
virtual int getNEdges()
const int * getOpenvars()
Gets array containing variables not assigned yet.
SCIP_VAR * getVar(int varIndex)
returns SCIP variable related to a variable index
class storing partialdecs and the problem matrix
virtual SCIP_RETCODE createDecompFromPartition(DEC_DECOMP **decomp)
virtual int getNNodes()
int getNVars()
Gets number of vars.