Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

Loading...
Searching...
No Matches
SteinerTreeLowerBoundDualAscent.h
Go to the documentation of this file.
1
32#pragma once
33
36#include <ogdf/basic/Graph.h>
38#include <ogdf/basic/List.h>
39#include <ogdf/basic/Math.h>
40#include <ogdf/basic/basic.h>
42
43#include <limits>
44
45namespace ogdf {
46template<typename T>
47class EdgeWeightedGraph;
48
49namespace steiner_tree {
50
52template<typename T>
54 struct TerminalData;
55
60
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) {
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;
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
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
200public:
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)) {
221 }
222 }
223 }
224 OGDF_ASSERT(m_root != nullptr);
225 }
226
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
260template<typename T>
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
340public:
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}
Declaration and implementation of ArrayBuffer class.
Compare floating point numbers with epsilons and integral numbers with normal compare operators.
Includes declaration of graph class.
Decralation of GraphElement and GraphList classes.
Declaration of doubly linked lists and iterators.
Mathematical Helpers.
Basic declarations, included by all source files.
Class for adjacency list elements.
Definition Graph_d.h:143
node twinNode() const
Returns the associated node of the corresponding adjacency entry (shorthand for twin()->theNode()).
Definition Graph_d.h:176
node theNode() const
Returns the node whose adjacency list contains this element.
Definition Graph_d.h:167
An array that keeps track of the number of inserted elements; also usable as an efficient stack.
Definition ArrayBuffer.h:64
void push(E e)
Puts a new element in the buffer.
Dijkstra's single source shortest path algorithm.
Definition Dijkstra.h:60
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
Class for the representation of edges.
Definition Graph_d.h:364
T weight(const edge e) const
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
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.
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.
Data type for general directed graphs (adjacency list representation).
Definition Graph_d.h:866
internal::GraphObjectContainer< NodeElement > nodes
The container containing all node objects.
Definition Graph_d.h:929
node newNode(int index=-1)
Creates a new node and returns it.
Definition Graph_d.h:1061
edge newEdge(node v, node w, int index=-1)
Creates a new edge (v,w) and returns it.
Definition Graph_d.h:1080
void reverseAllEdges()
Reverses all edges in the graph.
internal::GraphObjectContainer< EdgeElement > edges
The container containing all edge objects.
Definition Graph_d.h:932
Doubly linked lists (maintaining the length of the list).
Definition List.h:1451
iterator pushBack(const E &x)
Adds element x at the end of the list.
Definition List.h:1547
Encapsulates a pointer to a list element.
Definition List.h:113
const_reference front() const
Returns a const reference to the first element.
Definition List.h:305
Class for the representation of nodes.
Definition Graph_d.h:241
internal::GraphObjectContainer< AdjElement > adjEntries
The container containing all entries in the adjacency list of this node.
Definition Graph_d.h:272
void init(const Base *base=nullptr)
Reinitializes the array. Associates the array with the matching registry of base.
Implementation of a dual-ascent-based lower bound heuristic for Steiner tree problems.
T call(const EdgeWeightedGraph< T > &graph, const List< node > &terminals)
Calls the algorithm and returns the lower bound.
void setRepetitions(int num)
Sets the number of repeated calls to the lower bound algorithm (runs with different roots)
void compute(const EdgeWeightedGraph< T > &graph, const List< node > &terminals, node root, NodeArray< T > &lbNodes, EdgeArray< T > &lbEdges)
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.
T compute(const EdgeWeightedGraph< T > &graph, const List< node > &terminals, node root)
RegisteredArray for edges of a graph, specialized for EdgeArray<edge>.
Definition Graph_d.h:717
RegisteredArray for nodes, edges and adjEntries of a graph.
Definition Graph_d.h:659
Computes lower bounds for minimum Steiner tree instances.
bool addNode(ListIterator< TerminalData > &it, node t)
Adds a node to the cut and add neighbors recursively.
T findCheapestCutArcCost(const TerminalData &td) const
Finds the cheapest arc in cut and returns its cost.
T reducedCost(adjEntry adj) const
Returns the reduced cost of the arc given by adj.
void removeTerminalData(ListIterator< TerminalData > it)
bool addNodeChecked(ListIterator< TerminalData > &it, node w)
ListIterator< TerminalData > chooseTerminal()
Finds the terminal with the smallest cut arc set (of the last iteration)
LowerBoundDualAscent(const EdgeWeightedGraph< T > &graph, const List< node > &terminals, double eps=1e-6)
Initializes the algorithm (and takes the first terminal as root)
LowerBoundDualAscent(const EdgeWeightedGraph< T > &graph, const List< node > &terminals, node root, double eps=1e-6)
Initializes the algorithm.
NodeArray< List< ListIterator< TerminalData > > > m_inTerminalCut
Mapping of nodes to the cuts they are in.
void extendCut(adjEntry adj)
Assumes that the reduced cost of arc adj is zeroed and hence updates (in relevant cuts) the set of ar...
void update(TerminalData &td, T delta)
Updates reduced costs and cut data.
Implementation of Dijkstra's single source shortest path algorithm.
bool isConnected(const Graph &G)
Returns true iff G is connected.
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition basic.h:52
void updateMin(T &min, const T &newValue)
Stores the minimum of min and newValue in min.
Definition Math.h:102
void updateMax(T &max, const T &newValue)
Stores the maximum of max and newValue in max.
Definition Math.h:94
The namespace for all OGDF objects.
HypergraphRegistry< HypernodeElement >::iterator begin(const HypergraphRegistry< HypernodeElement > &self)