Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

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...