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/EpsilonTest.h>
35 #include <ogdf/basic/Math.h>
36 #include <ogdf/graphalg/Dijkstra.h>
38 
39 namespace ogdf {
40 namespace steiner_tree {
41 
43 template<typename T>
45  struct TerminalData;
46 
50  };
51 
52  struct TerminalData {
58 
60  : terminal(t), cutIterators(graph, nullptr), inCut(graph, false) { }
61  };
62 
70 
73  auto it = m_terminals.begin();
74  auto bestIt = it;
75  for (; it != m_terminals.end(); ++it) {
76  if ((*it).cut.size() < (*bestIt).cut.size()) {
77  bestIt = it;
78  }
79  }
80 
81  return bestIt;
82  }
83 
87  if (t == m_root) {
88  return false;
89  }
90  TerminalData& td = *it;
91  td.inCut[t] = true;
92  td.references.push({t, m_inTerminalCut[t].pushBack(it)});
93  for (adjEntry adj : t->adjEntries) {
94  node w = adj->twinNode();
95  if (!td.inCut[w]) {
96  // not in cut, so check (recursively) if we should add nodes
97  if (m_eps.equal(m_reducedCost[adj], T(0))) {
98  if (!addNode(it, w)) { // recurse
99  return false;
100  }
101  } else {
102  td.cutIterators[adj] = td.cut.pushBack(adj);
103  }
104  }
105  }
106 
107  // delete arcs that are inside the cut
108  for (adjEntry adj : t->adjEntries) {
109  node w = adj->twinNode();
110  if (td.inCut[w]) {
111  auto& cutAdjIt = td.cutIterators[adj->twin()];
112  if (cutAdjIt != td.cut.end()) {
113  td.cut.del(cutAdjIt);
114  cutAdjIt = nullptr;
115  }
116  }
117  }
118 
119  return true;
120  }
121 
123  if (!(*it).inCut[w]) {
124  if (!addNode(it, w)) {
125  return false;
126  }
127  }
128  return true;
129  }
130 
132  for (auto ref : (*it).references) {
133  m_inTerminalCut[ref.v].del(ref.it);
134  }
135 
136  m_terminals.del(it);
137  }
138 
145  void extendCut(adjEntry adj) {
146  OGDF_ASSERT(m_eps.equal(m_reducedCost[adj], T(0)));
147  node v = adj->theNode();
148  node w = adj->twinNode();
149  for (auto it = m_inTerminalCut[v].begin(); it.valid();) {
150  if (!addNodeChecked(*it, w)) {
151  auto nextIt = it;
152  ++nextIt;
153  removeTerminalData(*it);
154  it = nextIt;
155  } else {
156  ++it;
157  }
158  }
159  }
160 
163  OGDF_ASSERT(!td.cut.empty());
164  T cost = std::numeric_limits<T>::max();
165  for (adjEntry adj : td.cut) {
166  Math::updateMin(cost, m_reducedCost[adj]);
167  }
168  OGDF_ASSERT(cost > 0);
169  return cost;
170  }
171 
173  void update(TerminalData& td, T delta) {
174  // reduce costs
175  ArrayBuffer<adjEntry> zeroed;
176  for (adjEntry adj : td.cut) {
177  m_reducedCost[adj] -= delta;
178  OGDF_ASSERT(m_eps.geq(m_reducedCost[adj], T(0)));
179  if (m_eps.leq(m_reducedCost[adj], T(0))) {
180  zeroed.push(adj);
181  }
182  }
183  m_lower += delta;
184 
185  // extend
186  for (adjEntry adj : zeroed) {
187  extendCut(adj);
188  }
189  }
190 
191 public:
193  LowerBoundDualAscent(const EdgeWeightedGraph<T>& graph, const List<node>& terminals, node root,
194  double eps = 1e-6)
195  : m_eps(eps)
196  , m_lower(0)
197  , m_graph(graph)
198  , m_root(nullptr)
201  for (edge e : graph.edges) {
202  m_reducedCost[e->adjSource()] = m_reducedCost[e->adjTarget()] = graph.weight(e);
203  }
204 
205  for (node t : terminals) {
206  if (t == root) {
207  m_root = root;
208  } else {
209  auto it = m_terminals.pushBack(TerminalData(m_graph, t));
210  if (!addNode(it, t)) {
211  removeTerminalData(it);
212  }
213  }
214  }
215  OGDF_ASSERT(m_root != nullptr);
216  }
217 
219  LowerBoundDualAscent(const EdgeWeightedGraph<T>& graph, const List<node>& terminals,
220  double eps = 1e-6)
221  : LowerBoundDualAscent(graph, terminals, terminals.front(), eps) { }
222 
224  void compute() {
225  while (!m_terminals.empty()) {
226  auto it = chooseTerminal();
227  TerminalData& td = *it;
229  }
230  }
231 
234  T reducedCost(adjEntry adj) const { return m_reducedCost[adj]; }
235 
237  T get() const { return m_lower; }
238 };
239 }
240 
251 template<typename T>
253  int m_repetitions = 1;
254 
255  T compute(const EdgeWeightedGraph<T>& graph, const List<node>& terminals, node root) {
256  steiner_tree::LowerBoundDualAscent<T> alg(graph, terminals, root);
257  alg.compute();
258  return alg.get();
259  }
260 
261  void compute(const EdgeWeightedGraph<T>& graph, const List<node>& terminals, node root,
262  NodeArray<T>& lbNodes, EdgeArray<T>& lbEdges) {
263  OGDF_ASSERT(isConnected(graph));
264 
265  // compute first
266  steiner_tree::LowerBoundDualAscent<T> alg(graph, terminals, root);
267  alg.compute();
268 
269  // generate the auxiliary network
270  Graph network;
271  NodeArray<node> copy(graph);
272  EdgeArray<T> weights(network);
273  EdgeArray<edge> orig(network);
274 
275  for (node v : graph.nodes) {
276  copy[v] = network.newNode();
277  }
278  for (edge e : graph.edges) {
279  edge uv = network.newEdge(copy[e->source()], copy[e->target()]);
280  edge vu = network.newEdge(copy[e->target()], copy[e->source()]);
281  weights[uv] = alg.reducedCost(e->adjTarget());
282  weights[vu] = alg.reducedCost(e->adjSource());
283  orig[uv] = orig[vu] = e;
284  }
285 
286  // compute shortest path tree on network starting from root
287  Dijkstra<T> sssp;
288  NodeArray<edge> pred;
289  NodeArray<T> distance;
290  sssp.call(network, weights, copy[root], pred, distance, true);
291 
292  // set all lower bounds to global lower bound
293  lbNodes.init(graph, alg.get());
294  lbEdges.init(graph, alg.get());
295  EdgeArray<T> lbArcs(network, alg.get());
296 
297  // add cost of path root -> v
298  for (node v : graph.nodes) {
299  lbNodes[v] += distance[copy[v]];
300  }
301  // add cost of path root -> e
302  for (edge a : network.edges) {
303  lbArcs[a] += distance[a->source()] + weights[a];
304  }
305 
306  // to find the (reduced) distance from v / e to any (non-root) terminal,
307  // hence compute (directed) Voronoi regions
308  network.reverseAllEdges();
309 
310  List<node> nonRootTerminals;
311  for (node t : terminals) {
312  if (t != root) {
313  nonRootTerminals.pushBack(copy[t]);
314  }
315  }
316  sssp.call(network, weights, nonRootTerminals, pred, distance, true);
317 
318  // add cost of path v -> any terminal
319  for (node v : graph.nodes) {
320  lbNodes[v] += distance[copy[v]];
321  }
322  // add cost of path e -> any terminal
323  for (edge a : network.edges) {
324  lbArcs[a] += distance[a->source()]; // the former target is now the source
325 
326  // both lower bounds must be larger than the upper bound, so take the minimum
327  Math::updateMin(lbEdges[orig[a]], lbArcs[a]);
328  }
329  }
330 
331 public:
333  void setRepetitions(int num) { m_repetitions = num; }
334 
336  T call(const EdgeWeightedGraph<T>& graph, const List<node>& terminals) {
337  T lb(0);
338  int i = 0;
339  for (node root : terminals) {
340  Math::updateMax(lb, compute(graph, terminals, root));
341  if (++i >= m_repetitions) {
342  break;
343  }
344  }
345  return lb;
346  }
347 
352  void call(const EdgeWeightedGraph<T>& graph, const List<node>& terminals, NodeArray<T>& lbNodes,
353  EdgeArray<T>& lbEdges) {
354  if (m_repetitions <= 1) {
355  // catch this special case to avoid copying
356  compute(graph, terminals, terminals.front(), lbNodes, lbEdges);
357  } else {
358  lbNodes.init(graph, 0);
359  lbEdges.init(graph, 0);
360  int i = 0;
361  for (node root : terminals) {
362  NodeArray<T> nodes;
363  EdgeArray<T> edges;
364  compute(graph, terminals, root, nodes, edges);
365  for (node v : graph.nodes) {
366  Math::updateMax(lbNodes[v], nodes[v]);
367  }
368  for (edge e : graph.edges) {
369  Math::updateMax(lbEdges[e], edges[e]);
370  }
371  if (++i >= m_repetitions) {
372  break;
373  }
374  }
375  }
376  }
377 };
378 }
ogdf::steiner_tree::LowerBoundDualAscent::m_graph
const EdgeWeightedGraph< T > & m_graph
Definition: SteinerTreeLowerBoundDualAscent.h:65
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::steiner_tree::LowerBoundDualAscent::TerminalData::inCut
NodeArray< bool > inCut
Definition: SteinerTreeLowerBoundDualAscent.h:56
EpsilonTest.h
Compare floating point numbers with epsilons and integral numbers with normal compare operators.
ogdf::EpsilonTest
Definition: EpsilonTest.h:41
ogdf::SteinerTreeLowerBoundDualAscent::compute
void compute(const EdgeWeightedGraph< T > &graph, const List< node > &terminals, node root, NodeArray< T > &lbNodes, EdgeArray< T > &lbEdges)
Definition: SteinerTreeLowerBoundDualAscent.h:261
OGDF_ASSERT
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition: basic.h:54
ogdf::EdgeWeightedGraph::weight
T weight(const edge e) const
Definition: EdgeWeightedGraph.h:58
ogdf::begin
HypergraphRegistry< HypernodeElement >::iterator begin(const HypergraphRegistry< HypernodeElement > &self)
ogdf::steiner_tree::LowerBoundDualAscent::TerminalDataReference::it
ListIterator< ListIterator< TerminalData > > it
Definition: SteinerTreeLowerBoundDualAscent.h:49
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:224
ogdf::steiner_tree::LowerBoundDualAscent::TerminalData::cut
List< adjEntry > cut
Definition: SteinerTreeLowerBoundDualAscent.h:54
ogdf::steiner_tree::LowerBoundDualAscent::m_lower
T m_lower
Definition: SteinerTreeLowerBoundDualAscent.h:64
ogdf::steiner_tree::LowerBoundDualAscent::update
void update(TerminalData &td, T delta)
Updates reduced costs and cut data.
Definition: SteinerTreeLowerBoundDualAscent.h:173
ogdf::steiner_tree::LowerBoundDualAscent::findCheapestCutArcCost
T findCheapestCutArcCost(const TerminalData &td) const
Finds the cheapest arc in cut and returns its cost.
Definition: SteinerTreeLowerBoundDualAscent.h:162
ogdf::steiner_tree::LowerBoundDualAscent::TerminalData::cutIterators
AdjEntryArray< ListIterator< adjEntry > > cutIterators
Definition: SteinerTreeLowerBoundDualAscent.h:55
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:165
ogdf::steiner_tree::LowerBoundDualAscent::TerminalData::TerminalData
TerminalData(const EdgeWeightedGraph< T > &graph, node t)
Definition: SteinerTreeLowerBoundDualAscent.h:59
ogdf::steiner_tree::LowerBoundDualAscent::m_reducedCost
AdjEntryArray< T > m_reducedCost
Definition: SteinerTreeLowerBoundDualAscent.h:68
ogdf::SteinerTreeLowerBoundDualAscent
Implementation of a dual-ascent-based lower bound heuristic for Steiner tree problems.
Definition: SteinerTreeLowerBoundDualAscent.h:252
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:219
ogdf::AdjElement
Class for adjacency list elements.
Definition: Graph_d.h:135
ogdf::Dijkstra
Dijkstra's single source shortest path algorithm.
Definition: Dijkstra.h:53
ogdf::SteinerTreeLowerBoundDualAscent::compute
T compute(const EdgeWeightedGraph< T > &graph, const List< node > &terminals, node root)
Definition: SteinerTreeLowerBoundDualAscent.h:255
ogdf::steiner_tree::LowerBoundDualAscent::removeTerminalData
void removeTerminalData(ListIterator< TerminalData > it)
Definition: SteinerTreeLowerBoundDualAscent.h:131
ogdf::Graph::nodes
internal::GraphObjectContainer< NodeElement > nodes
The container containing all node objects.
Definition: Graph_d.h:924
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:66
ogdf::EdgeWeightedGraph
Definition: EdgeWeightedGraph.h:39
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::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:246
ogdf::ArrayBuffer::push
void push(E e)
Puts a new element in the buffer.
Definition: ArrayBuffer.h:209
ogdf::steiner_tree::LowerBoundDualAscent::chooseTerminal
ListIterator< TerminalData > chooseTerminal()
Finds the terminal with the smallest cut arc set (of the last iteration)
Definition: SteinerTreeLowerBoundDualAscent.h:72
ogdf::SteinerTreeLowerBoundDualAscent::m_repetitions
int m_repetitions
Definition: SteinerTreeLowerBoundDualAscent.h:253
ogdf::EdgeElement::source
node source() const
Returns the source node of the edge.
Definition: Graph_d.h:391
ogdf::Math::updateMin
void updateMin(T &min, const T &newValue)
Stores the minimum of min and newValue in min.
Definition: Math.h:98
ogdf::SteinerTreeLowerBoundDualAscent::call
T call(const EdgeWeightedGraph< T > &graph, const List< node > &terminals)
Calls the algorithm and returns the lower bound.
Definition: SteinerTreeLowerBoundDualAscent.h:336
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::EdgeElement::adjSource
adjEntry adjSource() const
Returns the corresponding adjacancy entry at source node.
Definition: Graph_d.h:400
ogdf::steiner_tree::LowerBoundDualAscent::m_inTerminalCut
NodeArray< List< ListIterator< TerminalData > > > m_inTerminalCut
Mapping of nodes to the cuts they are in.
Definition: SteinerTreeLowerBoundDualAscent.h:69
ogdf::Graph
Data type for general directed graphs (adjacency list representation).
Definition: Graph_d.h:862
ogdf::steiner_tree::LowerBoundDualAscent::m_root
node m_root
Definition: SteinerTreeLowerBoundDualAscent.h:67
ogdf::steiner_tree::LowerBoundDualAscent::reducedCost
T reducedCost(adjEntry adj) const
Returns the reduced cost of the arc given by adj.
Definition: SteinerTreeLowerBoundDualAscent.h:234
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:168
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:83
ogdf::EdgeElement::adjTarget
adjEntry adjTarget() const
Returns the corresponding adjacancy entry at target node.
Definition: Graph_d.h:403
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:352
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:109
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:145
ogdf::Graph::edges
internal::GraphObjectContainer< EdgeElement > edges
The container containing all edge objects.
Definition: Graph_d.h:927
ogdf::Math::updateMax
void updateMax(T &max, const T &newValue)
Stores the maximum of max and newValue in max.
Definition: Math.h:90
EdgeWeightedGraph.h
Declaration of class EdgeWeightedGraph.
ogdf::steiner_tree::LowerBoundDualAscent::TerminalDataReference
Definition: SteinerTreeLowerBoundDualAscent.h:47
ogdf::Graph::newNode
node newNode(int index=-1)
Creates a new node and returns it.
Definition: Graph_d.h:1056
ogdf::steiner_tree::LowerBoundDualAscent::TerminalData::references
ArrayBuffer< TerminalDataReference > references
Definition: SteinerTreeLowerBoundDualAscent.h:57
ogdf::EdgeElement
Class for the representation of edges.
Definition: Graph_d.h:356
Dijkstra.h
Implementation of Dijkstra's single source shortest path algorithm.
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:849
ogdf::steiner_tree::LowerBoundDualAscent::TerminalData
Definition: SteinerTreeLowerBoundDualAscent.h:52
ogdf::steiner_tree::LowerBoundDualAscent::m_eps
EpsilonTest m_eps
Definition: SteinerTreeLowerBoundDualAscent.h:63
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:135
ogdf::steiner_tree::LowerBoundDualAscent
Computes lower bounds for minimum Steiner tree instances.
Definition: SteinerTreeLowerBoundDualAscent.h:44
ogdf::steiner_tree::LowerBoundDualAscent::get
T get() const
Returns the lower bound.
Definition: SteinerTreeLowerBoundDualAscent.h:237
ogdf::ListIteratorBase
Encapsulates a pointer to a list element.
Definition: List.h:46
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:333
ogdf::steiner_tree::LowerBoundDualAscent::TerminalDataReference::v
node v
Definition: SteinerTreeLowerBoundDualAscent.h:48
ogdf::steiner_tree::LowerBoundDualAscent::TerminalData::terminal
node terminal
Definition: SteinerTreeLowerBoundDualAscent.h:53
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:86
ogdf::EdgeElement::target
node target() const
Returns the target node of the edge.
Definition: Graph_d.h:394
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:1075
ogdf::steiner_tree::LowerBoundDualAscent::addNodeChecked
bool addNodeChecked(ListIterator< TerminalData > &it, node w)
Definition: SteinerTreeLowerBoundDualAscent.h:122
ogdf::NodeElement
Class for the representation of nodes.
Definition: Graph_d.h:233
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:193
ogdf::List::pushBack
iterator pushBack(const E &x)
Adds element x at the end of the list.
Definition: List.h:1537
ogdf::internal::EdgeArrayBase2
RegisteredArray for edges of a graph, specialized for EdgeArray<edge>.
Definition: Graph_d.h:709