Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

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