Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

LPRelaxationSER.h
Go to the documentation of this file.
1 
32 #pragma once
33 
34 #include <ogdf/basic/Array.h>
35 #include <ogdf/basic/ArrayBuffer.h>
37 #include <ogdf/basic/Graph.h>
38 #include <ogdf/basic/GraphCopy.h>
39 #include <ogdf/basic/GraphList.h>
40 #include <ogdf/basic/List.h>
42 #include <ogdf/basic/basic.h>
45 
46 #include <ogdf/external/coin.h>
47 
48 #include <cstdio>
49 #include <iostream>
50 #include <limits>
51 
52 namespace ogdf::steiner_tree {
53 template<typename T, typename ExtraDataType>
54 class FullComponentWithExtraStore;
55 } // namespace ogdf::steiner_tree
56 
57 namespace ogdf {
58 template<typename T>
59 class EdgeWeightedGraph;
60 } // namespace ogdf
61 
62 //#define OGDF_STEINERTREE_LPRELAXATIONSER_LOGGING
63 //#define OGDF_STEINERTREE_LPRELAXATIONSER_OUTPUT_LP
64 #define OGDF_STEINERTREE_LPRELAXATIONSER_SEPARATE_CONNECTED_COMPONENTS // this is faster
65 #define OGDF_STEINERTREE_LPRELAXATIONSER_SEPARATE_YVAR_CONSTRAINTS // if not defined: generate all yvar constraints in the beginning
66 
67 namespace ogdf {
68 namespace steiner_tree {
69 
72 template<typename T>
78 
79  OsiSolverInterface* m_osiSolver;
80  CoinPackedMatrix* m_matrix;
81  double* m_objective;
82  double* m_lowerBounds;
83  double* m_upperBounds;
84 
85  const T m_upperBound;
87 #ifdef OGDF_STEINERTREE_LPRELAXATIONSER_SEPARATE_CONNECTED_COMPONENTS
89 #endif
90 
91  const double m_eps;
92 
94  void generateProblem();
98  bool addSubsetCoverConstraint(const ArrayBuffer<node>& subset);
100  void addYConstraint(const node t);
101 
104  bool separateConnected(const ArrayBuffer<int>& activeComponents);
105 
108  bool separateMinCut(const ArrayBuffer<int>& activeComponents);
109 
112  bool separateCycles(const ArrayBuffer<int>& activeComponents);
113 
116  bool separate();
117 
120  double generateMinCutSeparationGraph(const ArrayBuffer<int>& activeComponents, node& source,
121  node& target, GraphCopy& G, EdgeArray<double>& capacity, int& cutsFound) {
122  G.setOriginalGraph(m_G);
123  capacity.init(G);
124  source = G.newNode();
125  for (node t : m_terminals) { // generate all terminals
126  G.newNode(t);
127  }
128  target = G.newNode();
129  for (int j = 0; j < activeComponents.size(); ++j) {
130  const int i = activeComponents[j];
131  const double cap = m_fullCompStore.extra(i);
132  const Array<node>& terminals = m_fullCompStore.terminals(i);
133  // take the first terminal as root
134  // XXX: we may generate parallel edges but it's ok
135  const auto it0 = terminals.begin();
136  const node rC = G.copy(*it0);
137  capacity[G.newEdge(source, rC)] = cap;
138  if (terminals.size() > 2) {
139  const node v = G.newNode();
140  capacity[G.newEdge(rC, v)] = cap;
141  for (auto it = it0 + 1; it != terminals.end(); ++it) {
142  const node w = G.copy(*it);
143  capacity[G.newEdge(v, w)] = cap;
144  }
145  } else { // exactly two terminals: we do not need the inner Steiner node
146  capacity[G.newEdge(rC, G.copy(*terminals.rbegin()))] = cap;
147  }
148  }
149  double y_R = 0;
150  // TODO: perhaps better to compute y_v before
151  // add edges to target and compute y_R
152  for (node t : m_terminals) {
153  const node v = G.copy(t);
154  OGDF_ASSERT(v);
155  // compute y_v, simply the sum of all x_C where C contains v and then - 1
156  double y_v(-1);
157  for (adjEntry adj : v->adjEntries) {
158  if (adj->twinNode() != source) {
159  y_v += capacity[adj->theEdge()];
160  }
161  }
162 
163 #ifdef OGDF_STEINERTREE_LPRELAXATIONSER_SEPARATE_YVAR_CONSTRAINTS
164  if (y_v < -m_eps) {
165  addYConstraint(t);
166  ++cutsFound;
167  } else
168 #endif
169  if (y_v > 0) {
170  capacity[G.newEdge(v, target)] = y_v;
171  y_R += y_v;
172  }
173  }
174 #if 0
175  // just for output of blow-up graph
176  for (edge e : G.edges) {
177  if (G.original(e->source())) {
178  std::cout << " T:" << G.original(e->source());
179  } else {
180  std::cout << " " << e->source();
181  }
182  std::cout << " -> ";
183  if (G.original(e->target())) {
184  std::cout << "T:" << G.original(e->target());
185  } else {
186  std::cout << e->target();
187  }
188  std::cout << " " << capacity[e] << "\n";
189  }
190 #endif
191 
192  return y_R;
193  }
194 
195 public:
206  LPRelaxationSER(const EdgeWeightedGraph<T>& G, const List<node>& terminals,
207  const NodeArray<bool>& isTerminal, FullComponentWithExtraStore<T, double>& fullCompStore,
208  T upperBound = 0, int cliqueSize = 0, double eps = 1e-8)
209  : m_G(G)
210  , m_isTerminal(isTerminal)
211  , m_terminals(terminals)
212  , m_fullCompStore(fullCompStore)
213  , m_osiSolver(CoinManager::createCorrectOsiSolverInterface())
214  , m_matrix(new CoinPackedMatrix)
215  , m_objective(new double[m_fullCompStore.size()])
216  , m_lowerBounds(new double[m_fullCompStore.size()])
217  , m_upperBounds(new double[m_fullCompStore.size()])
218  , m_upperBound(upperBound)
219  , m_separateCliqueSize(cliqueSize)
221  , m_separationStage(0)
222 #endif
223  , m_eps(eps) {
224  generateProblem();
226 
227 #ifndef OGDF_STEINERTREE_LPRELAXATIONSER_SEPARATE_YVAR_CONSTRAINTS
228  for (node t : m_terminals) {
229  addYConstraint(t);
230  }
231 #endif
232  }
233 
235  delete[] m_objective;
236  delete m_matrix;
237  delete[] m_lowerBounds;
238  delete[] m_upperBounds;
239  delete m_osiSolver;
240  }
241 
244  bool solve();
245 };
246 
247 template<typename T>
249  const int n = m_fullCompStore.size();
250 
251  m_matrix->setDimensions(0, n);
252  for (int i = 0; i < n; ++i) {
253  m_lowerBounds[i] = 0;
254  m_upperBounds[i] = 1;
255  }
256  for (int i = 0; i < n; ++i) {
257  m_objective[i] = m_fullCompStore.cost(i);
258  }
259  m_osiSolver->loadProblem(*m_matrix, m_lowerBounds, m_upperBounds, m_objective, nullptr, nullptr);
260 
261  if (m_upperBound > 0) { // add upper bound
262  CoinPackedVector row;
263  row.setFull(m_fullCompStore.size(), m_objective);
264  m_osiSolver->addRow(row, 0, m_upperBound);
265  }
266 }
267 
268 template<typename T>
270  CoinPackedVector row;
271 
272  for (int i = 0; i < m_fullCompStore.size(); ++i) {
273  if (m_fullCompStore.isTerminal(i, t)) { // component spans terminal
274  row.insert(i, 1);
275  }
276  }
277 
278  m_osiSolver->addRow(row, 1, m_osiSolver->getInfinity());
279 }
280 
281 // add constraint if necessary and return if necessary
282 template<typename T>
284  CoinPackedVector row;
285  double test = 0;
286 
287  for (int i = 0; i < m_fullCompStore.size(); ++i) {
288  // compute the intersection cardinality (linear time because terminal sets are sorted by index)
289  int intersectionCard = 0;
290  auto terminals = m_fullCompStore.terminals(i);
291  node* it1 = terminals.begin();
292  auto it2 = subset.begin();
293  while (it1 != terminals.end() && it2 != subset.end()) {
294  if ((*it1)->index() < (*it2)->index()) {
295  ++it1;
296  } else if ((*it1)->index() > (*it2)->index()) {
297  ++it2;
298  } else { // ==
299  ++intersectionCard;
300  ++it1;
301  ++it2;
302  }
303  }
304  // and use it as a coefficient
305  if (intersectionCard > 1) {
306  row.insert(i, intersectionCard - 1);
307  test += (intersectionCard - 1) * m_fullCompStore.extra(i);
308  }
309  }
310  if (test > subset.size() - 1) {
311  m_osiSolver->addRow(row, 0, subset.size() - 1);
312  return true;
313  }
314  return false;
315 }
316 
317 template<typename T>
319  // we use the sum over all components C of (|C| - 1) * x_C = |R| - 1 constraint
320  // from the paper
321  CoinPackedVector row;
322 
323  for (int i = 0; i < m_fullCompStore.size(); ++i) {
324  row.insert(i, m_fullCompStore.terminals(i).size() - 1);
325  }
326 
327  int value = m_terminals.size() - 1;
328  m_osiSolver->addRow(row, value, value);
329 }
330 
331 template<typename T>
333  bool initialIteration = true;
334 
335  do {
336  if (initialIteration) {
337  m_osiSolver->initialSolve();
338 #ifdef OGDF_STEINERTREE_LPRELAXATIONSER_LOGGING
339  std::cout << "Objective value " << m_osiSolver->getObjValue() << " of initial solution."
340  << std::endl;
341 #endif
342  initialIteration = false;
343  } else {
344  m_osiSolver->resolve();
345 #ifdef OGDF_STEINERTREE_LPRELAXATIONSER_LOGGING
346  std::cout << "Objective value " << m_osiSolver->getObjValue() << " after resolve."
347  << std::endl;
348 #endif
349  }
350 
351  if (!m_osiSolver->isProvenOptimal()) {
352  if (m_upperBound > 0) { // failed due to better upper bound
353  return false;
354  } else { // failed due to infeasibility
355  std::cerr << "Failed to optimize LP!" << std::endl;
356  throw(-1);
357  }
358  }
359  } while (separate());
360 
361  const double* constSol = m_osiSolver->getColSolution();
362  const int numberOfColumns = m_osiSolver->getNumCols();
363 
364  for (int i = 0; i < numberOfColumns; ++i) {
365  m_fullCompStore.extra(i) = constSol[i];
366  }
367 
368 #ifdef OGDF_STEINERTREE_LPRELAXATIONSER_OUTPUT_LP
369  m_osiSolver->writeLp(stderr);
370 #endif
371 
372  return true;
373 }
374 
375 template<typename T>
377  const double* constSol = m_osiSolver->getColSolution();
378 
379  ArrayBuffer<int> activeComponents;
380  for (int i = 0; i < m_fullCompStore.size(); ++i) {
381  m_fullCompStore.extra(i) = constSol[i];
382  if (m_fullCompStore.extra(i) > m_eps) {
383  activeComponents.push(i);
384  }
385  }
386 
387 #ifdef OGDF_STEINERTREE_LPRELAXATIONSER_SEPARATE_CONNECTED_COMPONENTS
388  if (!m_separationStage) {
389  if (separateConnected(activeComponents)) {
390  return true;
391  }
392  m_separationStage = 1;
393  }
394 #endif
395  if (separateMinCut(activeComponents)) {
396  return true;
397  }
398  return m_separateCliqueSize > 2 ? separateCycles(activeComponents) : false;
399 }
400 
401 template<typename T>
403  NodeArray<int> setID(m_G, -1); // XXX: NodeArray over terminals only would be better
404  DisjointSets<> uf(m_terminals.size());
405  for (node t : m_terminals) {
406  setID[t] = uf.makeSet();
407  }
408 
409  // union all nodes within one component
410  for (int j = 0; j < activeComponents.size(); ++j) {
411  auto terminals = m_fullCompStore.terminals(activeComponents[j]);
412  auto it = terminals.begin();
413  const int s1 = setID[*it];
414  for (++it; it != terminals.end(); ++it) {
415  uf.link(uf.find(s1), uf.find(setID[*it]));
416  }
417  }
418 
419  if (uf.getNumberOfSets() == 1) { // solution is connected
420  return false;
421  }
422 
423  Array<ArrayBuffer<node>> components(m_terminals.size());
424  ArrayBuffer<int> usedComp;
425  for (node t : m_terminals) {
426  const int k = uf.find(setID[t]);
427  if (components[k].empty()) {
428  usedComp.push(k);
429  }
430  components[k].push(t);
431  }
432  int cutsFound = 0;
433  for (const int k : usedComp) {
434  cutsFound += addSubsetCoverConstraint(components[k]);
435  }
436  return true;
437 }
438 
439 template<typename T>
441  int cutsFound = 0;
442  node source;
443  node pseudotarget;
444  GraphCopy auxG;
445  EdgeArray<double> capacity;
446  double y_R = generateMinCutSeparationGraph(activeComponents, source, pseudotarget, auxG,
447  capacity, cutsFound);
448 
449 #ifdef OGDF_STEINERTREE_LPRELAXATIONSER_SEPARATE_YVAR_CONSTRAINTS
450  if (cutsFound > 0) {
451  return true;
452  }
453 #endif
454 
455  node target = auxG.newNode();
456  capacity[auxG.newEdge(pseudotarget, target)] = y_R;
457 
458  EdgeArray<double> flow;
460  MinSTCutMaxFlow<double> minSTCut;
461  for (node t : m_terminals) {
462  const node v = auxG.copy(t);
463 
464  edge v_to_target = auxG.newEdge(v, target);
465  capacity[v_to_target] = std::numeric_limits<double>::max(); // XXX: smaller is better
466 
467  maxFlow.init(auxG, &flow);
468 
469  const double cutVal = maxFlow.computeValue(capacity, source, target);
470  if (cutVal - y_R < 1 - m_eps) {
471  minSTCut.call(auxG, capacity, flow, source, target);
472  ArrayBuffer<node> subset;
473  for (node tOrig : m_terminals) {
474  const node tCopy = auxG.copy(tOrig);
475  if (tCopy && minSTCut.isInBackCut(tCopy)) {
476  subset.push(tOrig);
477  }
478  }
479 
480  cutsFound += addSubsetCoverConstraint(subset);
481  }
482 
483  auxG.delEdge(v_to_target);
484  }
485  return cutsFound != 0;
486 }
487 
488 template<typename T>
490  int count = 0;
491 
492  // generate auxiliary graph
493  Graph G;
494  NodeArray<int> id(G);
495  for (int i : activeComponents) {
496  id[G.newNode()] = i;
497  }
498  for (node u1 : G.nodes) {
499  const int i1 = id[u1];
500  const Array<node>& terminals1 = m_fullCompStore.terminals(i1);
501  for (node u2 = u1->succ(); u2; u2 = u2->succ()) {
502  const int i2 = id[u2];
503  const Array<node>& terminals2 = m_fullCompStore.terminals(i2);
504  // compute intersection cardinality (linear time because terminal sets are sorted by index)
505  int intersectionCard = 0;
506  const node* it1 = terminals1.begin();
507  const node* it2 = terminals2.begin();
508  while (it1 != terminals1.end() && it2 != terminals2.end()) {
509  if ((*it1)->index() < (*it2)->index()) {
510  ++it1;
511  } else if ((*it1)->index() > (*it2)->index()) {
512  ++it2;
513  } else { // ==
514  ++intersectionCard;
515  if (intersectionCard == 2) {
516  G.newEdge(u1, u2);
517  break;
518  }
519  ++it1;
520  ++it2;
521  }
522  }
523  }
524  }
525 
526  if (G.numberOfEdges() == 0) {
527  return false;
528  }
529 
530  // now find cliques
531  Array<List<node>> degrees(m_separateCliqueSize);
532  for (node v : G.nodes) {
533  int idx = v->degree();
534  if (idx == 0) { // ignore isolated nodes
535  continue;
536  }
537  if (idx >= m_separateCliqueSize) {
538  idx = m_separateCliqueSize - 1;
539  }
540  --idx;
541  degrees[idx].pushBack(v);
542  }
543  NodeArray<bool> test(G, false);
544  for (int k = degrees.size(); k >= 2; --k) {
545  degrees[k - 2].conc(degrees[k - 1]);
546  if (degrees[k - 2].size() >= k) {
547  SubsetEnumerator<node> nodeSubset(degrees[k - 2]);
548  for (nodeSubset.begin(k); nodeSubset.valid(); nodeSubset.next()) {
549  int countEdges = (k * (k - 1)) / 2;
550  for (int j = 0; j < nodeSubset.size(); ++j) {
551  test[nodeSubset[j]] = true;
552  }
553  for (edge e : G.edges) {
554  if (test[e->source()] && test[e->target()]) {
555  countEdges -= 1;
556  }
557  }
558  OGDF_ASSERT(countEdges >= 0);
559  if (countEdges == 0) {
560  // found clique, add constraint
561  double val(0);
562  CoinPackedVector row;
563 
564  for (int j = 0; j < nodeSubset.size(); ++j) {
565  int i = id[nodeSubset[j]];
566  val += m_fullCompStore.extra(i);
567  row.insert(i, 1);
568  }
569  if (val >= 1 + m_eps) {
570  m_osiSolver->addRow(row, 0, 1);
571  ++count;
572  }
573  }
574  for (int j = 0; j < nodeSubset.size(); ++j) {
575  test[nodeSubset[j]] = false;
576  }
577  }
578  }
579  }
580  return count > 0;
581 }
582 
583 }
584 }
ogdf::ArrayBuffer
An array that keeps track of the number of inserted elements; also usable as an efficient stack.
Definition: Array.h:53
ogdf
The namespace for all OGDF objects.
Definition: multilevelmixer.cpp:39
ogdf::SubsetEnumerator::size
int size() const
Returns the cardinality of the subset.
Definition: SubsetEnumerator.h:146
ArrayBuffer.h
Declaration and implementation of ArrayBuffer class.
ogdf::steiner_tree::LPRelaxationSER::generateMinCutSeparationGraph
double generateMinCutSeparationGraph(const ArrayBuffer< int > &activeComponents, node &source, node &target, GraphCopy &G, EdgeArray< double > &capacity, int &cutsFound)
Generates an auxiliary multi-graph for separation (during LP solving): directed, with special source ...
Definition: LPRelaxationSER.h:120
Graph.h
Includes declaration of graph class.
ogdf::SubsetEnumerator
Enumerator for k-subsets of a given type.
Definition: SubsetEnumerator.h:97
ogdf::steiner_tree::LPRelaxationSER::m_upperBounds
double * m_upperBounds
Definition: LPRelaxationSER.h:83
OGDF_ASSERT
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition: basic.h:66
ogdf::steiner_tree::FullComponentStore::terminals
const Array< node > & terminals(int id) const
Returns the list of terminals in the full component with given id.
Definition: FullComponentStore.h:254
ogdf::steiner_tree::LPRelaxationSER::m_isTerminal
const NodeArray< bool > & m_isTerminal
Definition: LPRelaxationSER.h:75
ogdf::steiner_tree::LPRelaxationSER::m_separationStage
int m_separationStage
Definition: LPRelaxationSER.h:88
ogdf::DisjointSets::find
int find(disjoint_sets::CompressionOption< CompressionOptions::PathCompression >, int set)
Definition: DisjointSets.h:332
ogdf::steiner_tree::LPRelaxationSER::generateProblem
void generateProblem()
Generate the basic LP model.
Definition: LPRelaxationSER.h:248
ogdf::SubsetEnumerator::begin
void begin(int low, int high)
Initializes the SubsetEnumerator to enumerate subsets of cardinalities from low to high.
Definition: SubsetEnumerator.h:129
ogdf::SubsetEnumerator::valid
bool valid() const
Checks if the current subset is valid. If not, the subset is either not initialized or all subsets ha...
Definition: SubsetEnumerator.h:154
ogdf::steiner_tree::LPRelaxationSER::separateMinCut
bool separateMinCut(const ArrayBuffer< int > &activeComponents)
Perform the general cut-based separation algorithm.
Definition: LPRelaxationSER.h:440
ogdf::GraphCopy
Copies of graphs supporting edge splitting.
Definition: GraphCopy.h:391
ogdf::steiner_tree::LPRelaxationSER::LPRelaxationSER
LPRelaxationSER(const EdgeWeightedGraph< T > &G, const List< node > &terminals, const NodeArray< bool > &isTerminal, FullComponentWithExtraStore< T, double > &fullCompStore, T upperBound=0, int cliqueSize=0, double eps=1e-8)
Initialize the LP.
Definition: LPRelaxationSER.h:206
ogdf::DisjointSets::makeSet
int makeSet()
Initializes a singleton set.
Definition: DisjointSets.h:235
ogdf::steiner_tree::LPRelaxationSER::m_separateCliqueSize
const int m_separateCliqueSize
Definition: LPRelaxationSER.h:86
ogdf::steiner_tree::LPRelaxationSER::addSubsetCoverConstraint
bool addSubsetCoverConstraint(const ArrayBuffer< node > &subset)
Add subset cover constraints to the LP for a given subset of terminals.
Definition: LPRelaxationSER.h:283
ogdf::CoinManager
If you use COIN-OR, you should use this class.
Definition: coin.h:46
ogdf::MaxFlowGoldbergTarjan
Computes a max flow via Preflow-Push (global relabeling and gap relabeling heuristic).
Definition: MaxFlowGoldbergTarjan.h:60
ogdf::steiner_tree::LPRelaxationSER::~LPRelaxationSER
~LPRelaxationSER()
Definition: LPRelaxationSER.h:234
ogdf::steiner_tree::LPRelaxationSER::separate
bool separate()
Perform all available separation algorithms.
Definition: LPRelaxationSER.h:376
ogdf::GraphCopy::newEdge
edge newEdge(edge eOrig)
Creates a new edge (v,w) with original edge eOrig.
ogdf::AdjElement
Class for adjacency list elements.
Definition: Graph_d.h:142
coin.h
Definition of ogdf::CoinManager.
ogdf::steiner_tree
Definition: MinSteinerTreeMehlhorn.h:297
ogdf::AdjElement::theEdge
edge theEdge() const
Returns the edge associated with this adjacency entry.
Definition: Graph_d.h:160
ogdf::MinSTCutMaxFlow::call
virtual bool call(const Graph &graph, const EdgeArray< TCost > &weight, node s, node t, List< edge > &edgeList, edge e_st=nullptr) override
The actual algorithm call.
Definition: MinSTCutMaxFlow.h:321
ogdf::steiner_tree::LPRelaxationSER
Class managing the component-based subtour elimination LP relaxation for the Steiner tree problem and...
Definition: LPRelaxationSER.h:73
ogdf::DisjointSets::link
int link(disjoint_sets::LinkOption< LinkOptions::Naive >, int set1, int set2)
Definition: DisjointSets.h:624
ogdf::steiner_tree::LPRelaxationSER::addTerminalCoverConstraint
void addTerminalCoverConstraint()
Add terminal cover constraints to the LP.
Definition: LPRelaxationSER.h:318
ogdf::steiner_tree::LPRelaxationSER::solve
bool solve()
Solve the LP. The solution will be written to the extra data of the full component store.
Definition: LPRelaxationSER.h:332
ogdf::NodeElement::degree
int degree() const
Returns the degree of the node (indegree + outdegree).
Definition: Graph_d.h:283
MaxFlowGoldbergTarjan.h
Declaration and implementation of Goldberg-Tarjan max-flow algorithm with global relabeling and gap r...
ogdf::steiner_tree::LPRelaxationSER::separateConnected
bool separateConnected(const ArrayBuffer< int > &activeComponents)
Separate to ensure that the solution is connected.
Definition: LPRelaxationSER.h:402
ogdf::steiner_tree::LPRelaxationSER::m_fullCompStore
FullComponentWithExtraStore< T, double > & m_fullCompStore
all enumerated full components, with solution
Definition: LPRelaxationSER.h:77
ogdf::DisjointSets
A Union/Find data structure for maintaining disjoint sets.
Definition: DisjointSets.h:90
ogdf::EdgeWeightedGraph
Definition: GraphIO.h:56
ogdf::steiner_tree::LPRelaxationSER::m_terminals
const List< node > & m_terminals
List of terminals.
Definition: LPRelaxationSER.h:76
ogdf::Array< node >
GraphList.h
Decralation of GraphElement and GraphList classes.
ogdf::NodeElement::adjEntries
internal::GraphObjectContainer< AdjElement > adjEntries
The container containing all entries in the adjacency list of this node.
Definition: Graph_d.h:271
ogdf::Array::rbegin
reverse_iterator rbegin()
Returns an reverse iterator to the last element.
Definition: Array.h:347
ogdf::steiner_tree::LPRelaxationSER::m_upperBound
const T m_upperBound
Definition: LPRelaxationSER.h:85
ogdf::DisjointSets::getNumberOfSets
int getNumberOfSets()
Returns the current number of disjoint sets.
Definition: DisjointSets.h:302
ogdf::steiner_tree::LPRelaxationSER::m_objective
double * m_objective
Definition: LPRelaxationSER.h:81
ogdf::ArrayBuffer::size
INDEX size() const
Returns number of elements in the buffer.
Definition: ArrayBuffer.h:244
ogdf::ArrayBuffer::push
void push(E e)
Puts a new element in the buffer.
Definition: ArrayBuffer.h:217
ogdf::ArrayBuffer::end
iterator end()
Returns an iterator to one past the last element.
Definition: ArrayBuffer.h:165
ogdf::Array::begin
iterator begin()
Returns an iterator to the first element.
Definition: Array.h:329
ogdf::steiner_tree::LPRelaxationSER::m_osiSolver
OsiSolverInterface * m_osiSolver
Definition: LPRelaxationSER.h:79
ogdf::EdgeElement::source
node source() const
Returns the source node of the edge.
Definition: Graph_d.h:398
ogdf::GraphCopyBase::newNode
node newNode(node vOrig)
Creates a new node in the graph copy with original node vOrig.
Definition: GraphCopy.h:192
ogdf::steiner_tree::LPRelaxationSER::m_eps
const double m_eps
epsilon for double operations
Definition: LPRelaxationSER.h:91
GraphCopy.h
Declaration of graph copy classes.
ogdf::steiner_tree::LPRelaxationSER::m_G
const EdgeWeightedGraph< T > & m_G
Definition: LPRelaxationSER.h:74
ogdf::List
Doubly linked lists (maintaining the length of the list).
Definition: DfsMakeBiconnected.h:40
ogdf::internal::GraphRegisteredArray
RegisteredArray for nodes, edges and adjEntries of a graph.
Definition: Graph_d.h:658
ogdf::Graph
Data type for general directed graphs (adjacency list representation).
Definition: Graph_d.h:869
ogdf::Array::end
iterator end()
Returns an iterator to one past the last element.
Definition: Array.h:338
ogdf::steiner_tree::FullComponentWithExtraStore::extra
ExtraDataType & extra(int i)
Returns a reference to the extra data of this full component.
Definition: FullComponentStore.h:366
ogdf::AdjElement::twinNode
node twinNode() const
Returns the associated node of the corresponding adjacency entry (shorthand for twin()->theNode()).
Definition: Graph_d.h:175
ogdf::steiner_tree::LPRelaxationSER::separateCycles
bool separateCycles(const ArrayBuffer< int > &activeComponents)
Perform the separation algorithm for cycle constraints (to obtain stronger LP solution)
Definition: LPRelaxationSER.h:489
ogdf::GraphCopy::copy
edge copy(edge e) const override
Returns the first edge in the list of edges corresponding to edge e.
Definition: GraphCopy.h:464
ogdf::ArrayBuffer::begin
iterator begin()
Returns an iterator to the first element.
Definition: ArrayBuffer.h:159
ogdf::GraphCopy::delEdge
void delEdge(edge e) override
Removes edge e and clears the list of edges corresponding to e's original edge.
ogdf::MaxFlowModule< TCap >::init
virtual void init(const Graph &graph, EdgeArray< TCap > *flow=nullptr)
Initialize the problem with a graph and optional flow array. If no flow array is given,...
Definition: MaxFlowModule.h:88
ogdf::steiner_tree::LPRelaxationSER::addYConstraint
void addYConstraint(const node t)
Add constraint that the sum of x_C over all components C spanning terminal t is at least 1 to ensure ...
Definition: LPRelaxationSER.h:269
basic.h
Basic declarations, included by all source files.
ogdf::steiner_tree::LPRelaxationSER::m_matrix
CoinPackedMatrix * m_matrix
Definition: LPRelaxationSER.h:80
ogdf::NodeElement::succ
node succ() const
Returns the successor in the list of all nodes.
Definition: Graph_d.h:292
DisjointSets.h
Implementation of disjoint sets data structures (union-find functionality).
Array.h
Declaration and implementation of Array class and Array algorithms.
MinSTCutMaxFlow.h
Declaration of min-st-cut algorithms parameterized by max-flow alorithm.
OGDF_STEINERTREE_LPRELAXATIONSER_SEPARATE_CONNECTED_COMPONENTS
#define OGDF_STEINERTREE_LPRELAXATIONSER_SEPARATE_CONNECTED_COMPONENTS
Definition: LPRelaxationSER.h:64
ogdf::EdgeElement
Class for the representation of edges.
Definition: Graph_d.h:363
List.h
Declaration of doubly linked lists and iterators.
ogdf::SubsetEnumerator::next
void next()
Obtains the next subset if possible. The result should be checked using the valid() method.
Definition: SubsetEnumerator.h:174
ogdf::RegisteredArray< GraphRegistry< EdgeElement >, Value, WithDefault, Graph >::init
void init(const Graph *base=nullptr)
Reinitializes the array. Associates the array with the matching registry of base.
Definition: RegisteredArray.h:858
ogdf::Array::size
INDEX size() const
Returns the size (number of elements) of the array.
Definition: Array.h:302
ogdf::MaxFlowGoldbergTarjan::computeValue
TCap computeValue(const EdgeArray< TCap > &cap, const node &s, const node &t)
Compute only the value of the flow.
Definition: MaxFlowGoldbergTarjan.h:244
ogdf::steiner_tree::LPRelaxationSER::m_lowerBounds
double * m_lowerBounds
Definition: LPRelaxationSER.h:82
ogdf::MinSTCutMaxFlow::isInBackCut
bool isInBackCut(const node v) const
Returns whether this node is part of the back cut.
Definition: MinSTCutMaxFlow.h:174
ogdf::EdgeElement::target
node target() const
Returns the target node of the edge.
Definition: Graph_d.h:401
ogdf::NodeElement
Class for the representation of nodes.
Definition: Graph_d.h:240
ogdf::steiner_tree::FullComponentWithExtraStore< T, double >
ogdf::MinSTCutMaxFlow
Min-st-cut algorithm, that calculates the cut via maxflow.
Definition: MinSTCutMaxFlow.h:60
ogdf::internal::EdgeArrayBase2
RegisteredArray for edges of a graph, specialized for EdgeArray<edge>.
Definition: Graph_d.h:716
SubsetEnumerator.h
A class that allows to enumerate k-subsets.