Loading [MathJax]/extensions/tex2jax.js

Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Loading...
Searching...
No Matches
MinSteinerTreeRZLoss.h
Go to the documentation of this file.
1
33#pragma once
34
42
43#include <memory>
44#include <set>
45
46#define OGDF_STEINERTREE_RZLOSS_REDUCE_ON
47
48namespace ogdf {
49
61template<typename T>
64
65 class Main;
66 std::unique_ptr<Main> m_alg;
67
68public:
70
72
74
79 void setMaxComponentSize(int k) { m_restricted = k; }
80
83 if (m_alg == nullptr) {
84 return 0;
85 }
86 return m_alg->numberOfGeneratedComponents();
87 }
88
91 if (m_alg == nullptr) {
92 return 0;
93 }
94 return m_alg->numberOfContractedComponents();
95 }
96
99 if (m_alg == nullptr) {
100 return 0;
101 }
102 return m_alg->numberOfComponentLookUps();
103 }
104
105protected:
114 virtual T computeSteinerTree(const EdgeWeightedGraph<T>& G, const List<node>& terminals,
115 const NodeArray<bool>& isTerminal, EdgeWeightedGraphCopy<T>*& finalSteinerTree) override {
116 m_alg.reset(new Main(G, terminals, isTerminal, m_restricted));
117 return m_alg->getApproximation(finalSteinerTree);
118 }
119};
120
121template<typename T>
123 template<typename TYPE>
125
128
135 void findFullComponentsDW(const EdgeWeightedGraphCopy<T>& tree,
136 const NodeArray<NodeArray<T>>& distance, const NodeArray<NodeArray<edge>>& pred);
138 void findFullComponentsEMV(const EdgeWeightedGraphCopy<T>& tree);
140 void findFull3Components(const EdgeWeightedGraphCopy<T>& tree,
141 const NodeArray<NodeArray<T>>& distance, const NodeArray<NodeArray<edge>>& pred);
143 template<typename FCG>
144 void retrieveComponents(const FCG& fcg, const EdgeWeightedGraphCopy<T>& tree);
145
147
154 void generateInitialTerminalSpanningTree(EdgeWeightedGraphCopy<T>& steinerTree,
155 const NodeArray<NodeArray<T>>& distance, const NodeArray<NodeArray<edge>>& pred);
156
159 tree.createEmpty(m_G);
160
161 if (m_restricted >= 4
163 m_G.numberOfEdges())) {
165 m_save.reset(new steiner_tree::SaveStatic<T>(tree));
166 findFullComponentsEMV(tree);
167 } else {
168 NodeArray<NodeArray<T>> distance;
170
172 m_G, m_terminals, m_isTerminal, m_restricted);
173
174 generateInitialTerminalSpanningTree(tree, distance, pred);
175 m_save.reset(new steiner_tree::SaveStatic<T>(tree));
176
177 if (m_restricted >= 4) { // use Dreyfus-Wagner based full component generation
178 findFullComponentsDW(tree, distance, pred);
179 } else {
180 findFull3Components(tree, distance, pred);
181 }
182 }
183
184 m_fullCompStore.computeAllLosses();
185 m_componentsGenerated = m_fullCompStore.size();
186 }
187
192 void multiPass(EdgeWeightedGraphCopy<T>& steinerTree);
193
200 double extractMaxComponent(const EdgeWeightedGraphCopy<T>& steinerTree, int& maxCompId);
201
208 template<typename TERMINAL_CONTAINER>
209 T gain(const TERMINAL_CONTAINER& terminals, const EdgeWeightedGraphCopy<T>& steinerTree);
210
216 void contractLoss(EdgeWeightedGraphCopy<T>& steinerTree, int compId);
217
222 std::unique_ptr<steiner_tree::SaveStatic<T>> m_save;
225
229
230public:
231 Main(const EdgeWeightedGraph<T>& G, const List<node>& terminals,
232 const NodeArray<bool>& isTerminal, int restricted);
233
235 // obtain final Steiner Tree using (MST-based) Steiner tree approximation algorithm
236 return steiner_tree::obtainFinalSteinerTree(m_G, m_isNewTerminal, m_isTerminal,
238 }
239
241 long numberOfGeneratedComponents() { return m_componentsGenerated; }
242
244 long numberOfContractedComponents() { return m_componentsContracted; }
245
247 long numberOfComponentLookUps() { return m_componentsLookUps; }
248};
249
250template<typename T>
252 const NodeArray<bool>& isTerminal, int restricted)
253 : m_G(G)
254 , m_isTerminal(isTerminal)
255 , m_terminals(terminals)
256 , // copy
257 m_restricted(min(restricted, terminals.size()))
258 , m_fullCompStore(m_G, m_terminals, m_isTerminal)
259 , m_isNewTerminal(m_G, false)
260 , m_componentsGenerated(0)
261 , m_componentsContracted(0)
262 , m_componentsLookUps(0) {
264
265 for (node v : terminals) {
266 m_isNewTerminal[v] = true;
267 }
268
269 // init terminal-spanning tree and its save-edge data structure
270 EdgeWeightedGraphCopy<T> steinerTree; // the terminal-spanning tree to be modified
271
273
274 // contraction phase
276
277 m_save.reset();
278}
279
280template<typename T>
283 const NodeArray<NodeArray<edge>>& pred) {
284 // generate complete graph
285 for (node v : m_terminals) {
286 steinerTree.newNode(v);
287 }
288 for (node u : steinerTree.nodes) {
289 const node uO = steinerTree.original(u);
290 const NodeArray<T>& dist = distance[uO];
291 const NodeArray<edge>& p = pred[uO];
292 for (node v = u->succ(); v; v = v->succ()) {
293 const node vO = steinerTree.original(v);
294 if (p[vO] != nullptr) {
295 steinerTree.newEdge(u, v, dist[vO]);
296 }
297 }
298 }
299 // compute MST
301 OGDF_ASSERT(steinerTree.numberOfNodes() == steinerTree.numberOfEdges() + 1);
302}
303
304template<typename T>
306 const NodeArray<NodeArray<T>>& distance, const NodeArray<NodeArray<edge>>& pred) {
308 fcg.call(m_G, m_terminals, m_isTerminal, distance, pred,
309 [&](node t0, node t1, node t2, node minCenter, T minCost) {
310 // create a full 3-component
312 minComp.createEmpty(m_G);
313 node minCenterC = minComp.newNode(minCenter);
314 minComp.newEdge(minComp.newNode(t0), minCenterC, distance[t0][minCenter]);
315 minComp.newEdge(minComp.newNode(t1), minCenterC, distance[t1][minCenter]);
316 minComp.newEdge(minComp.newNode(t2), minCenterC, distance[t2][minCenter]);
318#ifdef OGDF_STEINERTREE_RZLOSS_REDUCE_ON
319 if (gain(std::vector<node> {t0, t1, t2}, tree) > minCost) { // reduction
320 m_fullCompStore.insert(minComp);
321 }
322#else
323 m_fullCompStore.insert(minComp);
324#endif
325 });
326}
327
328template<typename T>
329template<typename FCG>
333 for (terminalSubset.begin(3, m_restricted); terminalSubset.valid(); terminalSubset.next()) {
334 EdgeWeightedGraphCopy<T> component;
335 List<node> terminals;
336 terminalSubset.list(terminals);
337#ifdef OGDF_STEINERTREE_RZLOSS_REDUCE_ON
338 T cost =
339#endif
340 fcg.getSteinerTreeFor(terminals, component);
341 if (
343 gain(terminals, tree) > cost &&
344#endif
345 fcg.isValidComponent(component)) {
346 m_fullCompStore.insert(component);
347 }
348 }
349}
350
351template<typename T>
353 const NodeArray<NodeArray<T>>& distance, const NodeArray<NodeArray<edge>>& pred) {
354 steiner_tree::FullComponentGeneratorDreyfusWagner<T> fcg(m_G, m_terminals, m_isTerminal,
355 distance, pred);
356 fcg.call(m_restricted);
357 retrieveComponents(fcg, tree);
358}
359
360template<typename T>
367
368template<typename T>
370 while (!m_fullCompStore.isEmpty()) {
371 int maxCompId;
372 double r = extractMaxComponent(steinerTree, maxCompId);
373 if (r > 1e-9) {
374 ++m_componentsContracted;
375
376 // convert nodes of component to terminals
377 m_fullCompStore.foreachNode(maxCompId, [&](node v) { m_isNewTerminal[v] = true; });
378
379 contractLoss(steinerTree, maxCompId);
380 m_fullCompStore.remove(maxCompId);
381
382 if (!m_fullCompStore.isEmpty()) {
383 m_save->rebuild();
384 }
385 } else {
386 return;
387 }
388 }
389}
390
391template<typename T>
394 maxCompId = -1;
395 double max(0);
396 for (int i = 0; i < m_fullCompStore.size();) {
397 ++m_componentsLookUps;
398 const double winAbs =
399 gain(m_fullCompStore.terminals(i), steinerTree) - m_fullCompStore.cost(i);
400 if (winAbs > 1e-9) {
401 const double r = winAbs / m_fullCompStore.loss(i);
402 if (r > max) {
403 max = r;
404 maxCompId = i;
405 }
406 ++i;
407 }
408#ifdef OGDF_STEINERTREE_RZLOSS_REDUCE_ON
409 else {
410 // reduction
411 m_fullCompStore.remove(i);
412 }
413#endif
414 }
415 return max;
416}
417
418template<typename T>
419template<typename TERMINAL_CONTAINER>
422 std::set<edge> saveEdges;
423 T result(0);
424
425 // extract edges and compute their sum (result value)
426 for (auto it1 = terminals.begin(); it1 != terminals.end(); ++it1) {
427 auto next = it1;
428 ++next;
429 for (auto it2 = next; it2 != terminals.end(); ++it2) {
430 const edge e = m_save->saveEdge(*it1, *it2);
431 saveEdges.insert(e);
432 }
433 }
434
435 for (edge e : saveEdges) {
436 result += steinerTree.weight(e);
437 }
438 return result;
439}
440
441template<typename T>
443 // for every non-loss edge {st} in the component,
444 // where s belongs to the loss component of terminal u
445 // and t belongs to the loss component of terminal v,
446 // we insert edges from u to v in the terminal-spanning tree
447 for (edge e : m_fullCompStore.lossBridges(compId)) {
448 const node u = m_fullCompStore.lossTerminal(e->source());
449 OGDF_ASSERT(u);
450 const node v = m_fullCompStore.lossTerminal(e->target());
451 OGDF_ASSERT(v);
452 steinerTree.newEdge(steinerTree.copy(u), steinerTree.copy(v),
453 m_fullCompStore.graph().weight(e));
454 // parallel edges are ok, will be removed by MST
455 }
456 if (steinerTree.numberOfNodes() != steinerTree.numberOfEdges() + 1) {
458 }
459}
460
461}
Definition of ogdf::steiner_tree::Full3ComponentGeneratorVoronoi class template.
Definition of the FullComponentGeneratorCaller class template.
Definition of the ogdf::steiner_tree::FullComponentGeneratorDreyfusWagner class template.
Definition of the ogdf::steiner_tree::FullComponentGeneratorDreyfusWagnerWithoutMatrix class template...
Definition of the FullComponentStore class template.
Implementation of Mehlhorn's minimum Steiner tree 2(1-1/l)-approximation algorithm.
#define OGDF_STEINERTREE_RZLOSS_REDUCE_ON
Implementation of the staticLCATree option for calculating save edges in Zelikovsky's 11/6-approximat...
Class for the representation of edges.
Definition Graph_d.h:300
Doubly linked lists (maintaining the length of the list).
Definition List.h:1435
iterator insert(const E &x, iterator it, Direction dir=Direction::after)
Inserts element x before or after it.
Definition List.h:1544
Serves as an interface for various methods to compute or approximate minimum Steiner trees on undirec...
static void sortTerminals(List< node > &terminals)
Sort terminals by index.
double extractMaxComponent(const EdgeWeightedGraphCopy< T > &steinerTree, int &maxCompId)
Traverses over all full components and finds the one with the highest win-objective.
std::unique_ptr< steiner_tree::SaveStatic< T > > m_save
The save data structure.
const EdgeWeightedGraph< T > & m_G
The original edge-weighted graph.
NodeArray< bool > m_isNewTerminal
Incidence vector for nonterminal nodes marked as terminals for improvement.
Main(const EdgeWeightedGraph< T > &G, const List< node > &terminals, const NodeArray< bool > &isTerminal, int restricted)
long m_componentsGenerated
Number of generated components.
long m_componentsContracted
Number of contracted components.
long numberOfContractedComponents()
Returns the number of contracted components.
const NodeArray< bool > & m_isTerminal
Incidence vector for terminal nodes.
void findFullComponentsEMV(const EdgeWeightedGraphCopy< T > &tree)
Find full components using algorithm by Erickson et al.
void retrieveComponents(const FCG &fcg, const EdgeWeightedGraphCopy< T > &tree)
Auxiliary function to retrieve components by Dreyfus-Wagner/Erickson et al implementation.
long numberOfComponentLookUps()
Returns the number of components lookups during execution time.
T gain(const TERMINAL_CONTAINER &terminals, const EdgeWeightedGraphCopy< T > &steinerTree)
void generateInitialTerminalSpanningTree(EdgeWeightedGraphCopy< T > &steinerTree, const NodeArray< NodeArray< T > > &distance, const NodeArray< NodeArray< edge > > &pred)
Builds a minimum terminal spanning tree (via a MST call on the complete terminal graph)
long numberOfGeneratedComponents()
Returns the number of generated components.
void findFullComponentsDW(const EdgeWeightedGraphCopy< T > &tree, const NodeArray< NodeArray< T > > &distance, const NodeArray< NodeArray< edge > > &pred)
Find full components using algorithm by Dreyfus-Wagner.
steiner_tree::FullComponentWithLossStore< T > m_fullCompStore
All generated full components.
long m_componentsLookUps
Number of components lookups.
void findFull3Components(const EdgeWeightedGraphCopy< T > &tree, const NodeArray< NodeArray< T > > &distance, const NodeArray< NodeArray< edge > > &pred)
Find full components of size 3.
void multiPass(EdgeWeightedGraphCopy< T > &steinerTree)
Contraction phase of the algorithm.
List< node > m_terminals
List of terminal nodes (will be copied and sorted)
void contractLoss(EdgeWeightedGraphCopy< T > &steinerTree, int compId)
Contracts the loss of a full component and integrates it into the given terminal-spanning tree.
void setup(EdgeWeightedGraphCopy< T > &tree)
Setup (build initial terminal-spanning tree, its save data structure, and find all components)
T getApproximation(EdgeWeightedGraphCopy< T > *&finalSteinerTree) const
int m_restricted
Parameter for the number of terminals in a full component.
This class implements the loss-contracting (1.55+epsilon)-approximation algorithm for the Steiner tre...
long numberOfComponentLookUps()
Returns the number of components lookups during execution time.
virtual T computeSteinerTree(const EdgeWeightedGraph< T > &G, const List< node > &terminals, const NodeArray< bool > &isTerminal, EdgeWeightedGraphCopy< T > *&finalSteinerTree) override
Builds a minimum Steiner tree given a weighted graph and a list of terminals.
long numberOfContractedComponents()
Returns the number of contracted components.
long numberOfGeneratedComponents()
Returns the number of generated components.
void setMaxComponentSize(int k)
Sets the maximal number of terminals in a full component.
std::unique_ptr< Main > m_alg
Dynamic arrays indexed with nodes.
Definition NodeArray.h:125
Class for the representation of nodes.
Definition Graph_d.h:177
node succ() const
Returns the successor in the list of all nodes.
Definition Graph_d.h:229
Enumerator for k-subsets of a given type.
Full 3-component generation using Voronoi regions.
void call(const EdgeWeightedGraph< T > &G, const List< node > &terminals, const NodeArray< bool > &isTerminal, const NodeArray< NodeArray< T > > &distance, const NodeArray< NodeArray< edge > > &pred, std::function< void(node, node, node, node, T)> generateFunction) const
Generate full components and call generateFunction for each full component.
static void computeDistanceMatrix(NodeArray< NodeArray< T > > &distance, NodeArray< NodeArray< edge > > &pred, const EdgeWeightedGraph< T > &graph, const List< node > &terminals, const NodeArray< bool > &isTerminal, int restricted)
Computes distance and predecessor matrix.
A generator for restricted full components (for Steiner tree approximations) based on the Dreyfus-Wag...
A generator for restricted full components (for Steiner tree approximations) based on the Dreyfus-Wag...
A data structure to store full components with additional "loss" functionality.
This class behaves basically the same as SaveDynamic except that the update of the weighted graph is ...
Definition SaveStatic.h:48
T makeMinimumSpanningTree(Graph &G, const EdgeArray< T > &weight)
Reduce a graph to its minimum spanning tree (MST) using Kruskal's algorithm.
bool isTree(const Graph &G)
Returns true iff G is a tree, i.e. contains no undirected cycle and is connected.
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition basic.h:41
int r[]
static MultilevelBuilder * getDoubleFactoredZeroAdjustedMerger()
T obtainFinalSteinerTree(const EdgeWeightedGraph< T > &G, const NodeArray< bool > &isTerminal, const NodeArray< bool > &isOriginalTerminal, EdgeWeightedGraphCopy< T > *&finalSteinerTree)
T constructTerminalSpanningTreeUsingVoronoiRegions(EdgeWeightedGraphCopy< T > &terminalSpanningTree, const EdgeWeightedGraph< T > &graph, const List< node > &terminals)
The namespace for all OGDF objects.
@ tree
for every hyperedge e a minimal subcubic tree connecting all hypernodes incident with e together is a...
static bool shouldUseErickson(int n, int m)
Returns true iff the rule of thumb predicts to use the algorithm by Erickson et al instead of the Dre...