Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

Loading...
Searching...
No Matches
MinSteinerTreeZelikovsky.h
Go to the documentation of this file.
1
33#pragma once
34
36#include <ogdf/basic/Graph.h>
37#include <ogdf/basic/List.h>
38#include <ogdf/basic/basic.h>
39#include <ogdf/basic/comparer.h>
51
52#include <limits>
53
54namespace ogdf::steiner_tree {
55template<typename T>
56class Full3ComponentGeneratorModule;
57} // namespace ogdf::steiner_tree
58
59namespace ogdf {
60template<typename T>
61class EdgeWeightedGraph;
62
80template<typename T>
82public:
83 template<typename TYPE>
85 template<typename TYPE>
87
89 enum class WinCalculation {
90 absolute,
92 };
93
95 enum class TripleGeneration {
97 voronoi,
99 };
100
102 enum class TripleReduction {
103 on,
104 off
105 };
106
108 enum class SaveCalculation {
121 hybrid
122 };
123
125 enum class Pass {
128 one,
130 multi
131 };
132
143
145
146 virtual T call(const EdgeWeightedGraph<T>& G, const List<node>& terminals,
147 const NodeArray<bool>& isTerminal, EdgeWeightedGraphCopy<T>*& finalSteinerTree) override {
149 m_tripleLookUps = 0;
151 return MinSteinerTreeModule<T>::call(G, terminals, isTerminal, finalSteinerTree);
152 }
153
159 void forceAPSP(bool force = true) { m_ssspDistances = !force; }
160
163
166
169
172
175
178
181
184
186 void pass(Pass p) { m_pass = p; }
187
189 Pass pass() const { return m_pass; }
190
193
196
198 long numberOfTripleLookUps() const { return m_tripleLookUps; }
199
200protected:
209 virtual T computeSteinerTree(const EdgeWeightedGraph<T>& G, const List<node>& terminals,
210 const NodeArray<bool>& isTerminal, EdgeWeightedGraphCopy<T>*& finalSteinerTree) override;
211
216
220 inline void generateTriple(node u, node v, node w, node center, const T& minCost,
221 const Save<T>& save) {
222 const double gain = save.gain(u, v, w);
223 const double win = calcWin(gain, minCost);
224 if (tripleReduction() == TripleReduction::off || win > 0) {
226 OGDF_ASSERT(center);
227 Triple<T> triple(u, v, w, center, minCost, win);
228 m_triples.pushBack(triple);
229 }
230 }
231
237 inline void generateTriples(const Save<T>& save,
240 [this, &save](node u, node v, node w, node center, T minCost) {
241 generateTriple(u, v, w, center, minCost, save);
242 });
243 }
244
260
267 void contractTriple(const Triple<T>& triple, Save<T>& save, NodeArray<bool>& isNewTerminal) {
269 save.update(triple);
270 isNewTerminal[triple.z()] = true;
271 }
272
278 void tripleOnDemand(Save<T>& save, NodeArray<bool>& isNewTerminal);
279
287 bool findBestTripleForCenter(node center, const Save<T>& save, Triple<T>& maxTriple) const {
288 bool updated = false; // return value
289
290 // find s0, nearest terminal to center
291 T best = std::numeric_limits<T>::max();
292 node s0 = nullptr;
293 for (node s : *m_terminals) {
294 T tmp = m_distance[s][center];
295 if (best > tmp) {
296 best = tmp;
297 s0 = s;
298 }
299 }
300 OGDF_ASSERT(s0);
301 OGDF_ASSERT(m_pred[s0][center]);
302
303 // find s1 maximizing save(s0, s1) - d(center, s1)
304 node s1 = nullptr;
305 T save1Val(0);
306 for (node s : *m_terminals) {
307 if (s != s0 && m_pred[s][center] != nullptr) {
308 OGDF_ASSERT(m_distance[s][center] != std::numeric_limits<T>::max());
309 T tmpVal = save.saveWeight(s, s0);
310 T tmp = tmpVal - m_distance[s][center];
311 if (!s1 || best < tmp) {
312 best = tmp;
313 s1 = s;
314 save1Val = tmpVal;
315 }
316 }
317 }
318 if (s1) {
319 OGDF_ASSERT(m_pred[s1][center]);
320 node s2 = nullptr;
321 T save2Val(0);
322 const edge save1 = save.saveEdge(s0, s1);
323 for (node s : *m_terminals) {
324 if (s != s0 && s != s1 && m_pred[s][center] != nullptr) {
325 OGDF_ASSERT(m_distance[s][center] != std::numeric_limits<T>::max());
326 const edge tmp = save.saveEdge(s0, s);
327 save2Val = save.saveWeight(tmp == save1 ? s1 : s0, s);
328 T tmpWin = save1Val + save2Val - m_distance[s0][center] - m_distance[s1][center]
329 - m_distance[s][center];
330 if (!s2 || best < tmpWin) {
331 best = tmpWin;
332 s2 = s;
333 }
334 }
335 }
336
337 if (s2 // it may happen that s2 does not exist
338 && best > maxTriple.win()) { // best win is better than previous best; also positive
339 OGDF_ASSERT(m_pred[s2][center]);
340 maxTriple.s0(s0);
341 maxTriple.s1(s1);
342 maxTriple.s2(s2);
343 maxTriple.z(center);
344 maxTriple.win(best);
345 //maxTriple.cost(save1Val + save2Val - win); not needed
346 updated = true;
347 }
348 }
349 return updated;
350 }
351
357 void multiPass(Save<T>& save, NodeArray<bool>& isNewTerminal);
358
364 void onePass(Save<T>& save, NodeArray<bool>& isNewTerminal);
365
369 double calcWin(double gain, T cost) const {
370 switch (winCalculation()) {
372 return gain / cost - 1.0;
374 default:
375 return gain - cost;
376 }
377 }
378
380 // generate complete graph
381 for (node v : *m_terminals) {
382 steinerTree.newNode(v);
383 }
384 for (node u : steinerTree.nodes) {
385 const NodeArray<T>& dist = m_distance[steinerTree.original(u)];
386 for (node v = u->succ(); v; v = v->succ()) {
387 steinerTree.newEdge(u, v, dist[steinerTree.original(v)]);
388 }
389 }
390 // compute MST
391 makeMinimumSpanningTree(steinerTree, steinerTree.edgeWeights());
392 }
393
394private:
401
408
412};
413
414template<typename T>
416 const List<node>& terminals, const NodeArray<bool>& isTerminal,
417 EdgeWeightedGraphCopy<T>*& finalSteinerTree) {
418 OGDF_ASSERT(tripleGeneration()
419 != TripleGeneration::ondemand // combinations that only work with ondemand:
420 || (winCalculation() == WinCalculation::absolute
421 && saveCalculation() != SaveCalculation::hybrid && pass() != Pass::one));
422
423 m_originalGraph = &G;
424 m_terminals = &terminals;
425 m_isTerminal = &isTerminal;
426
427 // build the complete terminal graph and a distance matrix
428 NodeArray<bool> isNewTerminal(G, false);
429 for (node v : *m_terminals) {
430 isNewTerminal[v] = true;
431 }
432
433 if (terminals.size() >= 3) {
434 computeDistanceMatrix();
435
436 // init terminal-spanning tree and its save-edge data structure
437 EdgeWeightedGraphCopy<T> steinerTree; // the terminal-spanning tree to be modified
438 steinerTree.setOriginalGraph(G);
439 generateInitialTerminalSpanningTree(steinerTree);
440
441 Save<T>* save = nullptr;
442 switch (saveCalculation()) {
443 case SaveCalculation::staticEnum:
444 save = new steiner_tree::SaveEnum<T>(steinerTree);
445 break;
446 case SaveCalculation::staticLCATree:
447 save = new steiner_tree::SaveStatic<T>(steinerTree);
448 break;
449 case SaveCalculation::dynamicLCATree:
450 case SaveCalculation::hybrid:
451 save = new steiner_tree::SaveDynamic<T>(steinerTree);
452 break;
453 }
454 OGDF_ASSERT(save);
455
456 if (tripleGeneration() == TripleGeneration::ondemand) { // ondemand triple generation
457 tripleOnDemand(*save, isNewTerminal);
458 } else { // exhaustive or voronoi
459 // triple generation phase
460 if (saveCalculation() == SaveCalculation::hybrid) {
461 steiner_tree::SaveEnum<T> saveTriple(steinerTree);
462 generateTriples(saveTriple);
463 } else {
464 generateTriples(*save);
465 }
466 // contraction phase
467 if (pass() == Pass::multi) {
468 multiPass(*save, isNewTerminal);
469 } else { // pass() == one
470 onePass(*save, isNewTerminal);
471 }
472 }
473 delete save;
474
475 // cleanup
476 m_triples.clear();
477 }
478
479 // obtain final Steiner Tree using (MST-based) Steiner tree approximation algorithm
480 return steiner_tree::obtainFinalSteinerTree(G, isNewTerminal, isTerminal, finalSteinerTree);
481}
482
483template<typename T>
485 if (m_ssspDistances) {
486 MinSteinerTreeModule<T>::allTerminalShortestPaths(*m_originalGraph, *m_terminals,
487 *m_isTerminal, m_distance, m_pred);
488 } else {
489 MinSteinerTreeModule<T>::allPairShortestPaths(*m_originalGraph, *m_isTerminal, m_distance,
490 m_pred);
491 }
492}
493
494template<typename T>
496 Triple<T> maxTriple;
497 ArrayBuffer<node> nonterminals;
498 MinSteinerTreeModule<T>::getNonterminals(nonterminals, *m_originalGraph, *m_isTerminal);
499 do {
500 maxTriple.win(0);
501 for (node center : nonterminals) {
502 if (findBestTripleForCenter(center, save, maxTriple)) {
503 ++m_triplesGenerated;
504 }
505 }
506
507 if (maxTriple.win() > 0) {
508 contractTriple(maxTriple, save, isNewTerminal);
509 }
510 } while (maxTriple.win() > 0);
511}
512
513template<typename T>
515 m_triples.quicksort(GenericComparer<Triple<T>, double>(
516 [](const Triple<T>& x) -> double { return -x.win(); }));
517
518 for (const Triple<T>& t : m_triples) {
519 ++m_tripleLookUps;
520 if (calcWin(double(save.gain(t.s0(), t.s1(), t.s2())), t.cost()) > 0) {
521 contractTriple(t, save, isNewTerminal);
522 }
523 }
524}
525
526template<typename T>
528 double win = 0;
529 ListIterator<Triple<T>> maxTriple;
530
531 do {
532 win = 0;
534 for (ListIterator<Triple<T>> it = m_triples.begin(); it.valid(); it = nextIt) {
535 nextIt = it.succ();
536 ++m_tripleLookUps;
537 Triple<T>& t = *it;
538 t.win(calcWin(double(save.gain(t.s0(), t.s1(), t.s2())), t.cost()));
539 if (t.win() > win) {
540 win = t.win();
541 maxTriple = it;
542 } else {
543 if (tripleReduction() == TripleReduction::on && t.win() <= 0) {
544 m_triples.del(it);
545 }
546 }
547 }
548
549 if (win > 0) {
550 contractTriple(*maxTriple, save, isNewTerminal);
551 m_triples.del(maxTriple);
552 }
553 } while (win > 0);
554}
555
556}
Declaration and implementation of ArrayBuffer class.
Extends the GraphCopy concept to weighted graphs.
Definition of ogdf::steiner_tree::Full3ComponentGeneratorEnumeration class template.
Definition of ogdf::steiner_tree::Full3ComponentGeneratorVoronoi class template.
Includes declaration of graph class.
Declaration of doubly linked lists and iterators.
Declaration of ogdf::MinSteinerTreeModule.
Interface for various LCA methods.
A weighted tree as auxiliary data structure for contraction based algorithms.
Implementation of the staticTree option for calculating save edges in Zelikovsky's 11/6-approximation...
Implementation of the staticLCATree option for calculating save edges in Zelikovsky's 11/6-approximat...
Definition of a Triple used in contraction-based approximation algorithm for the minimum Steiner tree...
Basic declarations, included by all source files.
An array that keeps track of the number of inserted elements; also usable as an efficient stack.
Definition ArrayBuffer.h:64
Class for the representation of edges.
Definition Graph_d.h:364
edge newEdge(node u, node v, T weight)
void setOriginalGraph(const Graph *wG) override
Re-initializes the copy using G (which might be null), but does not create any nodes or edges.
const EdgeArray< T > & edgeWeights() const
node newNode(node vOrig)
Creates a new node in the graph copy with original node vOrig.
Definition GraphCopy.h:191
const Graph & original() const
Returns a reference to the original graph.
Definition GraphCopy.h:104
internal::GraphObjectContainer< NodeElement > nodes
The container containing all node objects.
Definition Graph_d.h:929
Doubly linked lists (maintaining the length of the list).
Definition List.h:1451
int size() const
Returns the number of elements in the list.
Definition List.h:1488
Encapsulates a pointer to a list element.
Definition List.h:113
ListIteratorBase< E, isConst, isReverse > succ() const
Returns successor iterator.
Definition List.h:174
Serves as an interface for various methods to compute or approximate minimum Steiner trees on undirec...
virtual T call(const EdgeWeightedGraph< T > &G, const List< node > &terminals, const NodeArray< bool > &isTerminal, EdgeWeightedGraphCopy< T > *&finalSteinerTree)
Calls the Steiner tree algorithm for nontrivial cases but handles trivial cases directly.
static void allTerminalShortestPaths(const EdgeWeightedGraph< T > &G, const List< node > &terminals, const NodeArray< bool > &isTerminal, NodeArray< NodeArray< T > > &distance, NodeArray< NodeArray< edge > > &pred, std::function< void(const EdgeWeightedGraph< T > &, node, const NodeArray< bool > &, NodeArray< T > &, NodeArray< edge > &)> ssspFunc=singleSourceShortestPaths)
Runs a given (or the default) single-source-shortest-paths function from all terminals.
static void allPairShortestPaths(const EdgeWeightedGraph< T > &G, const NodeArray< bool > &isTerminal, NodeArray< NodeArray< T > > &distance, NodeArray< NodeArray< edge > > &pred)
The default all-pair-shortest-paths algorithm.
static void getNonterminals(ArrayBuffer< node > &nonterminals, const EdgeWeightedGraph< T > &G, const NodeArray< bool > &isTerminal)
Generates a list (as ArrayBuffer<node>) of all nonterminals.
This class implements the 11/6-approximation algorithm by Zelikovsky for the minimum Steiner tree pro...
bool findBestTripleForCenter(node center, const Save< T > &save, Triple< T > &maxTriple) const
Find the best triple for a given nonterminal center.
WinCalculation winCalculation() const
Returns type of gain calculation currently in use.
double calcWin(double gain, T cost) const
Calculate the win.
SaveCalculation
Different methods for obtaining save edges.
@ staticLCATree
Builds a "weight tree" (save edges are inner nodes, terminals are leaves and searches save edges via ...
@ dynamicLCATree
Same as staticLCATree but each time a triple has been contracted the "weight tree" is updated dynamic...
@ staticEnum
Stores explicitly the save edge for every pair of terminals. Needs O(n^2) space but has fast query ti...
@ hybrid
Uses staticEnum for the triple generation phase (many queries) and dynamicLCATree during the contract...
SaveCalculation saveCalculation() const
Returns type of save calculation currently in use.
TripleReduction tripleReduction() const
Returns type of triple reduction currently in use.
SaveCalculation m_saveCalculation
Chosen option for save calculation.
void forceAPSP(bool force=true)
For the 3-restricted case, it is sufficient to compute an SSSP from every terminal instead of doing a...
long m_triplesContracted
Number of contracted triples.
void tripleOnDemand(Save< T > &save, NodeArray< bool > &isNewTerminal)
Contraction phase for algorithm generating triples on demand.
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.
List< Triple< T > > m_triples
The list of triples during the algorithm.
void tripleGeneration(TripleGeneration tg)
Sets type of triple generation.
void onePass(Save< T > &save, NodeArray< bool > &isNewTerminal)
Contraction phase for the one pass heuristic.
TripleGeneration
Choice of triple generation.
@ ondemand
generate triples "on the fly", only usable with WinCalculation::absolute
TripleGeneration tripleGeneration() const
Returns type of triple generation currently in use.
const NodeArray< bool > * m_isTerminal
Incidence vector for terminal nodes.
const EdgeWeightedGraph< T > * m_originalGraph
The original edge-weighted graph.
Pass pass() const
Returns type of pass currently in use.
void tripleReduction(TripleReduction tr)
Sets type of triple reduction.
void generateTriples(const Save< T > &save, const steiner_tree::Full3ComponentGeneratorModule< T > &fcg)
Generates triples using the given full 3-component generator.
long numberOfGeneratedTriples() const
Returns the number of generated triples.
MinSteinerTreeZelikovsky(WinCalculation wc=WinCalculation::absolute, TripleGeneration tg=TripleGeneration::voronoi, SaveCalculation sc=SaveCalculation::hybrid, TripleReduction tr=TripleReduction::on, Pass pass=Pass::multi)
TripleReduction
Switches immediate triple dropping.
@ on
removes triples as soon as their gain is known to be non positive
void generateInitialTerminalSpanningTree(EdgeWeightedGraphCopy< T > &steinerTree)
NodeArray< NodeArray< T > > m_distance
The distance matrix.
void computeDistanceMatrix()
Computes the distance matrix for the original graph.
TripleReduction m_tripleReduction
Chosen option for triple reduction.
void multiPass(Save< T > &save, NodeArray< bool > &isNewTerminal)
Contraction phase for the original version of the algorithm.
void saveCalculation(SaveCalculation sv)
Sets type of save calculation.
void generateTriples(const Save< T > &save)
Generates triples according to the chosen option.
long m_triplesGenerated
Number of generated triples.
NodeArray< NodeArray< edge > > m_pred
The predecessor matrix.
WinCalculation m_winCalculation
Chosen option for gain calculation.
bool m_ssspDistances
True iff we only compute SSSP from terminals instead of APSP for full component construction.
long m_tripleLookUps
Number of triple lookups.
TripleGeneration m_tripleGeneration
Chosen option for triple generation.
Pass
Enables a heuristic version (for TG exhaustive and voronoi only)
@ multi
normal, greedy version
@ one
heuristic: evaluate all triples, sort them descending by gain, traverse sorted triples once,...
long numberOfContractedTriples() const
Returns the number of contracted triples.
long numberOfTripleLookUps() const
Returns the number of triple lookups during execution time.
const List< node > * m_terminals
List of terminal nodes.
virtual T call(const EdgeWeightedGraph< T > &G, const List< node > &terminals, const NodeArray< bool > &isTerminal, EdgeWeightedGraphCopy< T > *&finalSteinerTree) override
Calls the Steiner tree algorithm for nontrivial cases but handles trivial cases directly.
void generateTriple(node u, node v, node w, node center, const T &minCost, const Save< T > &save)
Add a found triple to the triples list.
void pass(Pass p)
Sets type of pass.
void contractTriple(const Triple< T > &triple, Save< T > &save, NodeArray< bool > &isNewTerminal)
Contracts a triple and updates the save data structure.
void winCalculation(WinCalculation wc)
Sets type of gain calculation.
WinCalculation
Choice of objective function.
Class for the representation of nodes.
Definition Graph_d.h:241
node succ() const
Returns the successor in the list of all nodes.
Definition Graph_d.h:293
RegisteredArray for nodes, edges and adjEntries of a graph.
Definition Graph_d.h:659
Interface for full 3-component generation including auxiliary functions.
virtual 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 =0
Generate full components and call generateFunction for each full component.
Full 3-component generation using Voronoi regions.
Dynamically updatable weighted Tree for determining save edges via LCA computation.
Definition SaveDynamic.h:62
This class computes save edges recursively and stores for every node pair their save edge in a HashAr...
Definition SaveEnum.h:59
This class serves as an interface for different approaches concerning the calculation of save edges.
Definition Save.h:50
virtual T gain(node u, node v, node w) const =0
Returns the gain (sum of the save edges) of a node triple.
virtual void update(const Triple< T > &t)=0
Updates the weighted tree data structure given a contracted triple.
virtual edge saveEdge(node u, node v) const =0
Returns the save edge between two nodes.
virtual T saveWeight(node u, node v) const =0
Returns the weight of the save edge between two nodes.
This class behaves basically the same as SaveDynamic except that the update of the weighted graph is ...
Definition SaveStatic.h:57
This class represents a triple used by various contraction-based minimum Steiner tree approximations.
Definition Triple.h:44
double win() const
Definition Triple.h:60
Algorithms used by at least two functions of Steiner tree code or its internal helpers.
Declarations for Comparer objects.
Declaration of extended graph algorithms.
T makeMinimumSpanningTree(Graph &G, const EdgeArray< T > &weight)
Reduce a graph to its minimum spanning tree (MST) using Kruskal's algorithm.
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition basic.h:52
T obtainFinalSteinerTree(const EdgeWeightedGraph< T > &G, const NodeArray< bool > &isTerminal, const NodeArray< bool > &isOriginalTerminal, EdgeWeightedGraphCopy< T > *&finalSteinerTree)
The namespace for all OGDF objects.
Compare elements based on a single comparable attribute.
Definition comparer.h:402