Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

SteinerTreeLowerBoundDualAscent.h
Go to the documentation of this file.
1 
32 #pragma once
33 
34 #include <ogdf/basic/ArrayBuffer.h>
35 #include <ogdf/basic/EpsilonTest.h>
36 #include <ogdf/basic/Graph.h>
37 #include <ogdf/basic/GraphList.h>
38 #include <ogdf/basic/List.h>
39 #include <ogdf/basic/Math.h>
40 #include <ogdf/basic/basic.h>
41 #include <ogdf/graphalg/Dijkstra.h>
42 
43 #include <limits>
44 
45 namespace ogdf {
46 template<typename T>
47 class EdgeWeightedGraph;
48 
49 namespace steiner_tree {
50 
52 template<typename T>
54  struct TerminalData;
55 
59  };
60 
61  struct TerminalData {
67 
69  : terminal(t), cutIterators(graph, nullptr), inCut(graph, false) { }
70  };
71 
79 
82  auto it = m_terminals.begin();
83  auto bestIt = it;
84  for (; it != m_terminals.end(); ++it) {
85  if ((*it).cut.size() < (*bestIt).cut.size()) {
86  bestIt = it;
87  }
88  }
89 
90  return bestIt;
91  }
92 
96  if (t == m_root) {
97  return false;
98  }
99  TerminalData& td = *it;
100  td.inCut[t] = true;
101  td.references.push({t, m_inTerminalCut[t].pushBack(it)});
102  for (adjEntry adj : t->adjEntries) {
103  node w = adj->twinNode();
104  if (!td.inCut[w]) {
105  // not in cut, so check (recursively) if we should add nodes
106  if (m_eps.equal(m_reducedCost[adj], T(0))) {
107  if (!addNode(it, w)) { // recurse
108  return false;
109  }
110  } else {
111  td.cutIterators[adj] = td.cut.pushBack(adj);
112  }
113  }
114  }
115 
116  // delete arcs that are inside the cut
117  for (adjEntry adj : t->adjEntries) {
118  node w = adj->twinNode();
119  if (td.inCut[w]) {
120  auto& cutAdjIt = td.cutIterators[adj->twin()];
121  if (cutAdjIt != td.cut.end()) {
122  td.cut.del(cutAdjIt);
123  cutAdjIt = nullptr;
124  }
125  }
126  }
127 
128  return true;
129  }
130 
132  if (!(*it).inCut[w]) {
133  if (!addNode(it, w)) {
134  return false;
135  }
136  }
137  return true;
138  }
139 
141  for (auto ref : (*it).references) {
142  m_inTerminalCut[ref.v].del(ref.it);
143  }
144 
145  m_terminals.del(it);
146  }
147 
154  void extendCut(adjEntry adj) {
155  OGDF_ASSERT(m_eps.equal(m_reducedCost[adj], T(0)));
156  node v = adj->theNode();
157  node w = adj->twinNode();
158  for (auto it = m_inTerminalCut[v].begin(); it.valid();) {
159  if (!addNodeChecked(*it, w)) {
160  auto nextIt = it;
161  ++nextIt;
162  removeTerminalData(*it);
163  it = nextIt;
164  } else {
165  ++it;
166  }
167  }
168  }
169 
172  OGDF_ASSERT(!td.cut.empty());
173  T cost = std::numeric_limits<T>::max();
174  for (adjEntry adj : td.cut) {
175  Math::updateMin(cost, m_reducedCost[adj]);
176  }
177  OGDF_ASSERT(cost > 0);
178  return cost;
179  }
180 
182  void update(TerminalData& td, T delta) {
183  // reduce costs
184  ArrayBuffer<adjEntry> zeroed;
185  for (adjEntry adj : td.cut) {
186  m_reducedCost[adj] -= delta;
187  OGDF_ASSERT(m_eps.geq(m_reducedCost[adj], T(0)));
188  if (m_eps.leq(m_reducedCost[adj], T(0))) {
189  zeroed.push(adj);
190  }
191  }
192  m_lower += delta;
193 
194  // extend
195  for (adjEntry adj : zeroed) {
196  extendCut(adj);
197  }
198  }
199 
200 public:
202  LowerBoundDualAscent(const EdgeWeightedGraph<T>& graph, const List<node>& terminals, node root,
203  double eps = 1e-6)
204  : m_eps(eps)
205  , m_lower(0)
206  , m_graph(graph)
207  , m_root(nullptr)
210  for (edge e : graph.edges) {
211  m_reducedCost[e->adjSource()] = m_reducedCost[e->adjTarget()] = graph.weight(e);
212  }
213 
214  for (node t : terminals) {
215  if (t == root) {
216  m_root = root;
217  } else {
218  auto it = m_terminals.pushBack(TerminalData(m_graph, t));
219  if (!addNode(it, t)) {
220  removeTerminalData(it);
221  }
222  }
223  }
224  OGDF_ASSERT(m_root != nullptr);
225  }
226 
228  LowerBoundDualAscent(const EdgeWeightedGraph<T>& graph, const List<node>& terminals,
229  double eps = 1e-6)
230  : LowerBoundDualAscent(graph, terminals, terminals.front(), eps) { }
231 
233  void compute() {
234  while (!m_terminals.empty()) {
235  auto it = chooseTerminal();
236  TerminalData& td = *it;
238  }
239  }
240 
243  T reducedCost(adjEntry adj) const { return m_reducedCost[adj]; }
244 
246  T get() const { return m_lower; }
247 };
248 }
249 
260 template<typename T>
262  int m_repetitions = 1;
263 
264  T compute(const EdgeWeightedGraph<T>& graph, const List<node>& terminals, node root) {
265  steiner_tree::LowerBoundDualAscent<T> alg(graph, terminals, root);
266  alg.compute();
267  return alg.get();
268  }
269 
270  void compute(const EdgeWeightedGraph<T>& graph, const List<node>& terminals, node root,
271  NodeArray<T>& lbNodes, EdgeArray<T>& lbEdges) {
272  OGDF_ASSERT(isConnected(graph));
273 
274  // compute first
275  steiner_tree::LowerBoundDualAscent<T> alg(graph, terminals, root);
276  alg.compute();
277 
278  // generate the auxiliary network
279  Graph network;
280  NodeArray<node> copy(graph);
281  EdgeArray<T> weights(network);
282  EdgeArray<edge> orig(network);
283 
284  for (node v : graph.nodes) {
285  copy[v] = network.newNode();
286  }
287  for (edge e : graph.edges) {
288  edge uv = network.newEdge(copy[e->source()], copy[e->target()]);
289  edge vu = network.newEdge(copy[e->target()], copy[e->source()]);
290  weights[uv] = alg.reducedCost(e->adjTarget());
291  weights[vu] = alg.reducedCost(e->adjSource());
292  orig[uv] = orig[vu] = e;
293  }
294 
295  // compute shortest path tree on network starting from root
296  Dijkstra<T> sssp;
297  NodeArray<edge> pred;
298  NodeArray<T> distance;
299  sssp.call(network, weights, copy[root], pred, distance, true);
300 
301  // set all lower bounds to global lower bound
302  lbNodes.init(graph, alg.get());
303  lbEdges.init(graph, alg.get());
304  EdgeArray<T> lbArcs(network, alg.get());
305 
306  // add cost of path root -> v
307  for (node v : graph.nodes) {
308  lbNodes[v] += distance[copy[v]];
309  }
310  // add cost of path root -> e
311  for (edge a : network.edges) {
312  lbArcs[a] += distance[a->source()] + weights[a];
313  }
314 
315  // to find the (reduced) distance from v / e to any (non-root) terminal,
316  // hence compute (directed) Voronoi regions
317  network.reverseAllEdges();
318 
319  List<node> nonRootTerminals;
320  for (node t : terminals) {
321  if (t != root) {
322  nonRootTerminals.pushBack(copy[t]);
323  }
324  }
325  sssp.call(network, weights, nonRootTerminals, pred, distance, true);
326 
327  // add cost of path v -> any terminal
328  for (node v : graph.nodes) {
329  lbNodes[v] += distance[copy[v]];
330  }
331  // add cost of path e -> any terminal
332  for (edge a : network.edges) {
333  lbArcs[a] += distance[a->source()]; // the former target is now the source
334 
335  // both lower bounds must be larger than the upper bound, so take the minimum
336  Math::updateMin(lbEdges[orig[a]], lbArcs[a]);
337  }
338  }
339 
340 public:
342  void setRepetitions(int num) { m_repetitions = num; }
343 
345  T call(const EdgeWeightedGraph<T>& graph, const List<node>& terminals) {
346  T lb(0);
347  int i = 0;
348  for (node root : terminals) {
349  Math::updateMax(lb, compute(graph, terminals, root));
350  if (++i >= m_repetitions) {
351  break;
352  }
353  }
354  return lb;
355  }
356 
361  void call(const EdgeWeightedGraph<T>& graph, const List<node>& terminals, NodeArray<T>& lbNodes,
362  EdgeArray<T>& lbEdges) {
363  if (m_repetitions <= 1) {
364  // catch this special case to avoid copying
365  compute(graph, terminals, terminals.front(), lbNodes, lbEdges);
366  } else {
367  lbNodes.init(graph, 0);
368  lbEdges.init(graph, 0);
369  int i = 0;
370  for (node root : terminals) {
371  NodeArray<T> nodes;
372  EdgeArray<T> edges;
373  compute(graph, terminals, root, nodes, edges);
374  for (node v : graph.nodes) {
375  Math::updateMax(lbNodes[v], nodes[v]);
376  }
377  for (edge e : graph.edges) {
378  Math::updateMax(lbEdges[e], edges[e]);
379  }
380  if (++i >= m_repetitions) {
381  break;
382  }
383  }
384  }
385  }
386 };
387 }
ogdf::steiner_tree::LowerBoundDualAscent::m_graph
const EdgeWeightedGraph< T > & m_graph
Definition: SteinerTreeLowerBoundDualAscent.h:74
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::steiner_tree::LowerBoundDualAscent::TerminalData::inCut
NodeArray< bool > inCut
Definition: SteinerTreeLowerBoundDualAscent.h:65
ArrayBuffer.h
Declaration and implementation of ArrayBuffer class.
EpsilonTest.h
Compare floating point numbers with epsilons and integral numbers with normal compare operators.
Graph.h
Includes declaration of graph class.
ogdf::EpsilonTest
Definition: EpsilonTest.h:39
ogdf::SteinerTreeLowerBoundDualAscent::compute
void compute(const EdgeWeightedGraph< T > &graph, const List< node > &terminals, node root, NodeArray< T > &lbNodes, EdgeArray< T > &lbEdges)
Definition: SteinerTreeLowerBoundDualAscent.h:270
OGDF_ASSERT
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition: basic.h:66
ogdf::EdgeWeightedGraph::weight
T weight(const edge e) const
Definition: EdgeWeightedGraph.h:59
ogdf::begin
HypergraphRegistry< HypernodeElement >::iterator begin(const HypergraphRegistry< HypernodeElement > &self)
ogdf::steiner_tree::LowerBoundDualAscent::TerminalDataReference::it
ListIterator< ListIterator< TerminalData > > it
Definition: SteinerTreeLowerBoundDualAscent.h:58
ogdf::Graph::reverseAllEdges
void reverseAllEdges()
Reverses all edges in the graph.
ogdf::steiner_tree::LowerBoundDualAscent::compute
void compute()
Computes the lower bound.
Definition: SteinerTreeLowerBoundDualAscent.h:233
ogdf::steiner_tree::LowerBoundDualAscent::TerminalData::cut
List< adjEntry > cut
Definition: SteinerTreeLowerBoundDualAscent.h:63
ogdf::steiner_tree::LowerBoundDualAscent::m_lower
T m_lower
Definition: SteinerTreeLowerBoundDualAscent.h:73
ogdf::steiner_tree::LowerBoundDualAscent::update
void update(TerminalData &td, T delta)
Updates reduced costs and cut data.
Definition: SteinerTreeLowerBoundDualAscent.h:182
ogdf::steiner_tree::LowerBoundDualAscent::findCheapestCutArcCost
T findCheapestCutArcCost(const TerminalData &td) const
Finds the cheapest arc in cut and returns its cost.
Definition: SteinerTreeLowerBoundDualAscent.h:171
ogdf::steiner_tree::LowerBoundDualAscent::TerminalData::cutIterators
AdjEntryArray< ListIterator< adjEntry > > cutIterators
Definition: SteinerTreeLowerBoundDualAscent.h:64
ogdf::isConnected
bool isConnected(const Graph &G)
Returns true iff G is connected.
ogdf::AdjElement::twin
adjEntry twin() const
Returns the corresponding adjacency element associated with the same edge.
Definition: Graph_d.h:172
ogdf::steiner_tree::LowerBoundDualAscent::TerminalData::TerminalData
TerminalData(const EdgeWeightedGraph< T > &graph, node t)
Definition: SteinerTreeLowerBoundDualAscent.h:68
ogdf::steiner_tree::LowerBoundDualAscent::m_reducedCost
AdjEntryArray< T > m_reducedCost
Definition: SteinerTreeLowerBoundDualAscent.h:77
ogdf::SteinerTreeLowerBoundDualAscent
Implementation of a dual-ascent-based lower bound heuristic for Steiner tree problems.
Definition: SteinerTreeLowerBoundDualAscent.h:261
ogdf::steiner_tree::LowerBoundDualAscent::LowerBoundDualAscent
LowerBoundDualAscent(const EdgeWeightedGraph< T > &graph, const List< node > &terminals, double eps=1e-6)
Initializes the algorithm (and takes the first terminal as root)
Definition: SteinerTreeLowerBoundDualAscent.h:228
ogdf::AdjElement
Class for adjacency list elements.
Definition: Graph_d.h:142
ogdf::Dijkstra
Dijkstra's single source shortest path algorithm.
Definition: Dijkstra.h:60
ogdf::SteinerTreeLowerBoundDualAscent::compute
T compute(const EdgeWeightedGraph< T > &graph, const List< node > &terminals, node root)
Definition: SteinerTreeLowerBoundDualAscent.h:264
ogdf::steiner_tree::LowerBoundDualAscent::removeTerminalData
void removeTerminalData(ListIterator< TerminalData > it)
Definition: SteinerTreeLowerBoundDualAscent.h:140
Minisat::Internal::copy
static void copy(const T &from, T &to)
Definition: Alg.h:61
ogdf::steiner_tree::LowerBoundDualAscent::m_terminals
List< TerminalData > m_terminals
Definition: SteinerTreeLowerBoundDualAscent.h:75
ogdf::EdgeWeightedGraph
Definition: GraphIO.h:56
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::Dijkstra::call
void call(const Graph &G, const EdgeArray< T > &weight, const List< node > &sources, NodeArray< edge > &predecessor, NodeArray< T > &distance, bool directed=false, bool arcsReversed=false, node target=nullptr, T maxLength=std::numeric_limits< T >::max())
Calculates, based on the graph G with corresponding edge costs and source nodes, the shortest paths a...
Definition: Dijkstra.h:253
ogdf::ArrayBuffer::push
void push(E e)
Puts a new element in the buffer.
Definition: ArrayBuffer.h:217
ogdf::steiner_tree::LowerBoundDualAscent::chooseTerminal
ListIterator< TerminalData > chooseTerminal()
Finds the terminal with the smallest cut arc set (of the last iteration)
Definition: SteinerTreeLowerBoundDualAscent.h:81
ogdf::SteinerTreeLowerBoundDualAscent::m_repetitions
int m_repetitions
Definition: SteinerTreeLowerBoundDualAscent.h:262
ogdf::EdgeElement::source
node source() const
Returns the source node of the edge.
Definition: Graph_d.h:398
ogdf::Math::updateMin
void updateMin(T &min, const T &newValue)
Stores the minimum of min and newValue in min.
Definition: Math.h:102
ogdf::SteinerTreeLowerBoundDualAscent::call
T call(const EdgeWeightedGraph< T > &graph, const List< node > &terminals)
Calls the algorithm and returns the lower bound.
Definition: SteinerTreeLowerBoundDualAscent.h:345
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::EdgeElement::adjSource
adjEntry adjSource() const
Returns the corresponding adjacancy entry at source node.
Definition: Graph_d.h:407
ogdf::steiner_tree::LowerBoundDualAscent::m_inTerminalCut
NodeArray< List< ListIterator< TerminalData > > > m_inTerminalCut
Mapping of nodes to the cuts they are in.
Definition: SteinerTreeLowerBoundDualAscent.h:78
ogdf::Graph
Data type for general directed graphs (adjacency list representation).
Definition: Graph_d.h:869
ogdf::steiner_tree::LowerBoundDualAscent::m_root
node m_root
Definition: SteinerTreeLowerBoundDualAscent.h:76
ogdf::steiner_tree::LowerBoundDualAscent::reducedCost
T reducedCost(adjEntry adj) const
Returns the reduced cost of the arc given by adj.
Definition: SteinerTreeLowerBoundDualAscent.h:243
Math.h
Mathematical Helpers.
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::EpsilonTest::leq
std::enable_if< std::is_integral< T >::value, bool >::type leq(const T &x, const T &y) const
Compare if x is LEQ than y for integral types.
Definition: EpsilonTest.h:81
ogdf::EdgeElement::adjTarget
adjEntry adjTarget() const
Returns the corresponding adjacancy entry at target node.
Definition: Graph_d.h:410
ogdf::SteinerTreeLowerBoundDualAscent::call
void call(const EdgeWeightedGraph< T > &graph, const List< node > &terminals, NodeArray< T > &lbNodes, EdgeArray< T > &lbEdges)
Compute the lower bounds under the assumption nodes or edges are included in the solution.
Definition: SteinerTreeLowerBoundDualAscent.h:361
ogdf::EpsilonTest::equal
std::enable_if< std::is_integral< T >::value, bool >::type equal(const T &x, const T &y) const
Compare if x is EQUAL to y for integral types.
Definition: EpsilonTest.h:107
ogdf::steiner_tree::LowerBoundDualAscent::extendCut
void extendCut(adjEntry adj)
Assumes that the reduced cost of arc adj is zeroed and hence updates (in relevant cuts) the set of ar...
Definition: SteinerTreeLowerBoundDualAscent.h:154
ogdf::Graph::edges
internal::GraphObjectContainer< EdgeElement > edges
The container containing all edge objects.
Definition: Graph_d.h:935
ogdf::Math::updateMax
void updateMax(T &max, const T &newValue)
Stores the maximum of max and newValue in max.
Definition: Math.h:94
basic.h
Basic declarations, included by all source files.
ogdf::steiner_tree::LowerBoundDualAscent::TerminalDataReference
Definition: SteinerTreeLowerBoundDualAscent.h:56
ogdf::Graph::newNode
node newNode(int index=-1)
Creates a new node and returns it.
Definition: Graph_d.h:1064
ogdf::steiner_tree::LowerBoundDualAscent::TerminalData::references
ArrayBuffer< TerminalDataReference > references
Definition: SteinerTreeLowerBoundDualAscent.h:66
ogdf::EdgeElement
Class for the representation of edges.
Definition: Graph_d.h:363
Dijkstra.h
Implementation of Dijkstra's single source shortest path algorithm.
List.h
Declaration of doubly linked lists and iterators.
ogdf::RegisteredArray< GraphRegistry< Key >, 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::steiner_tree::LowerBoundDualAscent::TerminalData
Definition: SteinerTreeLowerBoundDualAscent.h:61
ogdf::steiner_tree::LowerBoundDualAscent::m_eps
EpsilonTest m_eps
Definition: SteinerTreeLowerBoundDualAscent.h:72
ogdf::EpsilonTest::geq
std::enable_if< std::is_integral< T >::value, bool >::type geq(const T &x, const T &y) const
Compare if x is GEQ to y for integral types.
Definition: EpsilonTest.h:133
ogdf::steiner_tree::LowerBoundDualAscent
Computes lower bounds for minimum Steiner tree instances.
Definition: SteinerTreeLowerBoundDualAscent.h:53
ogdf::steiner_tree::LowerBoundDualAscent::get
T get() const
Returns the lower bound.
Definition: SteinerTreeLowerBoundDualAscent.h:246
ogdf::ListIteratorBase
Encapsulates a pointer to a list element.
Definition: List.h:51
ogdf::SteinerTreeLowerBoundDualAscent::setRepetitions
void setRepetitions(int num)
Sets the number of repeated calls to the lower bound algorithm (runs with different roots)
Definition: SteinerTreeLowerBoundDualAscent.h:342
ogdf::steiner_tree::LowerBoundDualAscent::TerminalDataReference::v
node v
Definition: SteinerTreeLowerBoundDualAscent.h:57
ogdf::steiner_tree::LowerBoundDualAscent::TerminalData::terminal
node terminal
Definition: SteinerTreeLowerBoundDualAscent.h:62
ogdf::steiner_tree::LowerBoundDualAscent::addNode
bool addNode(ListIterator< TerminalData > &it, node t)
Adds a node to the cut and add neighbors recursively.
Definition: SteinerTreeLowerBoundDualAscent.h:95
ogdf::EdgeElement::target
node target() const
Returns the target node of the edge.
Definition: Graph_d.h:401
ogdf::Graph::newEdge
edge newEdge(node v, node w, int index=-1)
Creates a new edge (v,w) and returns it.
Definition: Graph_d.h:1083
ogdf::steiner_tree::LowerBoundDualAscent::addNodeChecked
bool addNodeChecked(ListIterator< TerminalData > &it, node w)
Definition: SteinerTreeLowerBoundDualAscent.h:131
ogdf::NodeElement
Class for the representation of nodes.
Definition: Graph_d.h:240
ogdf::steiner_tree::LowerBoundDualAscent::LowerBoundDualAscent
LowerBoundDualAscent(const EdgeWeightedGraph< T > &graph, const List< node > &terminals, node root, double eps=1e-6)
Initializes the algorithm.
Definition: SteinerTreeLowerBoundDualAscent.h:202
ogdf::List::pushBack
iterator pushBack(const E &x)
Adds element x at the end of the list.
Definition: List.h:1547
ogdf::internal::EdgeArrayBase2
RegisteredArray for edges of a graph, specialized for EdgeArray<edge>.
Definition: Graph_d.h:716