Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

Loading...
Searching...
No Matches
HeavyPathDecomposition.h
Go to the documentation of this file.
1
32#pragma once
33
34#include <ogdf/basic/Graph.h>
36#include <ogdf/basic/List.h>
37#include <ogdf/basic/Math.h>
38#include <ogdf/basic/basic.h>
39
40#include <algorithm>
41#include <vector>
42
43namespace ogdf {
44template<typename T>
45class EdgeWeightedGraphCopy;
46
47namespace steiner_tree {
48
53template<typename T>
55private:
59
60 std::vector<std::vector<node>> chains;
61 std::vector<std::vector<node>> chainsOfTerminals;
68 std::vector<node> fatherOfChain;
69
70 std::vector<std::vector<T>> longestDistToSteinerAncestorOnChain;
71 std::vector<std::vector<T>> longestDistToSteinerAncestorSegTree;
72
77 void buildMaxSegmentTree(std::vector<T>& segmentTree, const int nodeIndex, const int left,
78 const int right, const std::vector<T>& baseArray) const {
79 if (left == right) { // leaf
80 segmentTree[nodeIndex] = baseArray[left];
81 return;
82 }
83
84 int middle = (left + right) >> 1;
85 int leftNodeIndex = nodeIndex + nodeIndex + 1;
86 int rightNodeIndex = leftNodeIndex + 1;
87
88 buildMaxSegmentTree(segmentTree, leftNodeIndex, left, middle, baseArray);
89 buildMaxSegmentTree(segmentTree, rightNodeIndex, middle + 1, right, baseArray);
90
91 segmentTree[nodeIndex] = max(segmentTree[leftNodeIndex], segmentTree[rightNodeIndex]);
92 }
93
98 T getMaxSegmentTree(const std::vector<T>& segmentTree, const int nodeIndex, const int left,
99 const int right, const int queryLeft, const int queryRight) const {
100 if (queryLeft > queryRight || left > queryRight || queryLeft > right) {
101 return 0;
102 }
103
104 if (queryLeft <= left && right <= queryRight) { // included
105 return segmentTree[nodeIndex];
106 }
107
108 int middleIndex = (left + right) >> 1;
109 int leftNodeIndex = nodeIndex + nodeIndex + 1;
110 int rightNodeIndex = leftNodeIndex + 1;
111
112 T maxValue(0);
113 if (queryLeft <= middleIndex) {
114 Math::updateMax(maxValue,
115 getMaxSegmentTree(segmentTree, leftNodeIndex, left, middleIndex, queryLeft,
116 queryRight));
117 }
118 if (queryRight > middleIndex) {
119 Math::updateMax(maxValue,
120 getMaxSegmentTree(segmentTree, rightNodeIndex, middleIndex + 1, right,
121 queryLeft, queryRight));
122 }
123
124 return maxValue;
125 }
126
131 T distanceToAncestor(node v, node ancestor) const {
132 if (ancestor == nullptr) {
133 return distanceToRoot[v];
134 }
135 return distanceToRoot[v] - distanceToRoot[ancestor];
136 }
137
145 for (int i = 0; i < (int)chains.size(); ++i) {
146 longestDistToSteinerAncestorOnChain[i].resize((int)chains[i].size());
147 for (int j = 0; j < (int)chains[i].size(); ++j) {
150 if (j > 0) {
153 }
154 }
155 }
156 }
157
165 for (int i = 0; i < (int)chains.size(); ++i) {
166 longestDistToSteinerAncestorSegTree[i].resize(4 * (int)chains[i].size());
167
168 std::vector<T> distanceToSteinerAncestor_byPosition;
169 distanceToSteinerAncestor_byPosition.resize(chains[i].size());
170 for (int j = 0; j < (int)chains[i].size(); ++j) {
171 distanceToSteinerAncestor_byPosition[j] =
173 }
174
176 (int)chains[i].size() - 1, distanceToSteinerAncestor_byPosition);
177 }
178 }
179
184 void dfsHeavyPathDecomposition(node v, node closestSteinerUpNode) {
185 weightOfSubtree[v] = 1;
186 node heaviestSon = nullptr;
187 closestSteinerAncestor[v] = closestSteinerUpNode;
188
189 for (adjEntry adj : v->adjEntries) {
190 edge e = adj->theEdge();
191 node son = adj->twinNode();
192
193 if (weightOfSubtree[son] != 0) { // the parent
194 continue;
195 }
196
197 nodeLevel[son] = nodeLevel[v] + 1;
198 distanceToRoot[son] = distanceToRoot[v] + tree.weight(e);
199
201
202 fatherOfChain[chainOfNode[son]] = v;
204 if (heaviestSon == nullptr || weightOfSubtree[heaviestSon] < weightOfSubtree[son]) {
205 heaviestSon = son;
206 }
207 }
208
209 if (heaviestSon == nullptr) { // it's leaf => new chain
210 OGDF_ASSERT((v->degree() <= 1));
211
212 std::vector<node> new_chain;
213 chains.push_back(new_chain);
214 chainsOfTerminals.push_back(new_chain);
215
216 fatherOfChain.push_back(nullptr);
217 chainOfNode[v] = (int)chains.size() - 1;
218 } else {
219 chainOfNode[v] = chainOfNode[heaviestSon];
220 }
221
222 chains[chainOfNode[v]].push_back(v);
223 chainsOfTerminals[chainOfNode[v]].push_back(v);
224 positionOnChain[v] = (int)chains[chainOfNode[v]].size() - 1;
225 }
226
232 node binarySearchUpmostTerminal(node v, const std::vector<node>& chainOfTerminals) const {
233 int left = 0, middle, right = (int)chainOfTerminals.size() - 1;
234 while (left <= right) {
235 middle = (left + right) >> 1;
236
237 if (nodeLevel[chainOfTerminals[middle]] >= nodeLevel[v]) {
238 right = middle - 1;
239 } else {
240 left = middle + 1;
241 }
242 }
243
244 if (left == (int)chainOfTerminals.size()) {
245 return nullptr;
246 }
247 return chainOfTerminals[left];
248 }
249
259 void computeBottleneckOnBranch(node x, node ancestor, T& longestPathDistance,
260 T& fromLowestToAncestor) const {
261 node upmostTerminal = x;
262 while (closestSteinerAncestor[chains[chainOfNode[x]][0]] != nullptr
264 >= nodeLevel[ancestor]) {
265 Math::updateMax(longestPathDistance,
267
268 if (!chainsOfTerminals[chainOfNode[x]].empty()
270 upmostTerminal = chainsOfTerminals[chainOfNode[x]][0];
271 }
273 }
274
275 // search the upmost terminal on the current chain that has level >= level[ancestor]
276 node upmostTerminalLastChain =
278 if (nodeLevel[upmostTerminalLastChain] > nodeLevel[x]) {
279 upmostTerminalLastChain = nullptr;
280 }
281 if (upmostTerminalLastChain != nullptr) {
282 upmostTerminal = upmostTerminalLastChain;
283 }
284
285 if (upmostTerminalLastChain != nullptr) {
286 Math::updateMax(longestPathDistance,
288 static_cast<int>(chains[chainOfNode[x]].size()) - 1,
289 positionOnChain[upmostTerminalLastChain] + 1, positionOnChain[x]));
290 }
291
292 fromLowestToAncestor = distanceToAncestor(upmostTerminal, ancestor);
293 }
294
295public:
297 : tree {treeEWGraphCopy}
298 , chainOfNode {tree, -1}
299 , positionOnChain {tree, -1}
300 , weightOfSubtree {tree, 0}
301 , nodeLevel {tree, 0}
302 , distanceToRoot {tree, 0}
303 , closestSteinerAncestor {tree, nullptr} {
304 OGDF_ASSERT(!tree.empty());
305 node root = tree.firstNode();
306
307 dfsHeavyPathDecomposition(root, nullptr);
308 fatherOfChain[chainOfNode[root]] = nullptr;
309
310 // reverse the obtained chains
311 int numberOfChains = static_cast<int>(chains.size());
312 for (int i = 0; i < numberOfChains; ++i) {
313 reverse(chains[i].begin(), chains[i].end());
315 for (node v : chains[i]) {
316 positionOnChain[v] = (int)chains[i].size() - 1 - positionOnChain[v];
317 }
318 }
319
322 }
323
329 while (chainOfNode[x] != chainOfNode[y]) {
330 int xlevelOfFatherOfChain = fatherOfChain[chainOfNode[x]] != nullptr
332 : -1;
333 int ylevelOfFatherOfChain = fatherOfChain[chainOfNode[y]] != nullptr
335 : -1;
336
337 if (xlevelOfFatherOfChain >= ylevelOfFatherOfChain) {
339 } else {
341 }
342 }
343
344 if (nodeLevel[x] <= nodeLevel[y]) {
345 return x;
346 }
347 return y;
348 }
349
355 T xLongestPathDistance = 0, yLongestPathDistance = 0;
356 T xFromLowestToLCA = 0, yFromLowestToLCA = 0;
357 node xyLowestCommonAncestor = lowestCommonAncestor(x, y);
358
359 computeBottleneckOnBranch(x, xyLowestCommonAncestor, xLongestPathDistance, xFromLowestToLCA);
360 computeBottleneckOnBranch(y, xyLowestCommonAncestor, yLongestPathDistance, yFromLowestToLCA);
361
362 T maxValue = max(xLongestPathDistance, yLongestPathDistance);
363 Math::updateMax(maxValue, xFromLowestToLCA + yFromLowestToLCA);
364
365 return maxValue;
366 }
367};
368
369}
370}
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
Class for the representation of edges.
Definition Graph_d.h:364
Doubly linked lists (maintaining the length of the list).
Definition List.h:1451
Class for the representation of nodes.
Definition Graph_d.h:241
int degree() const
Returns the degree of the node (indegree + outdegree).
Definition Graph_d.h:284
internal::GraphObjectContainer< AdjElement > adjEntries
The container containing all entries in the adjacency list of this node.
Definition Graph_d.h:272
RegisteredArray for nodes, edges and adjEntries of a graph.
Definition Graph_d.h:659
An implementation of the heavy path decomposition on trees.
List< node > terminals
list of terminals of the desc tree
NodeArray< int > chainOfNode
the index of a node's chain
NodeArray< int > nodeLevel
the level of a node in the tree
NodeArray< int > positionOnChain
position of a node on his chain
void buildMaxSegmentTree(std::vector< T > &segmentTree, const int nodeIndex, const int left, const int right, const std::vector< T > &baseArray) const
builds a max segment tree on the baseArray
std::vector< node > fatherOfChain
the first node from bottom up that does not belong to the chain
std::vector< std::vector< T > > longestDistToSteinerAncestorOnChain
the max of the interval 0..i for every i on chains
void computeBottleneckOnBranch(node x, node ancestor, T &longestPathDistance, T &fromLowestToAncestor) const
computes for the path from x to ancestor the maximum distance (sum of edges) between any two consecut...
std::vector< std::vector< node > > chains
list of chains of nodes corresponding to the decomposition
T getMaxSegmentTree(const std::vector< T > &segmentTree, const int nodeIndex, const int left, const int right, const int queryLeft, const int queryRight) const
extracts the maximum on the required interval
std::vector< std::vector< node > > chainsOfTerminals
list of chains only of terminals corresponding to the decomposition
NodeArray< T > distanceToRoot
the length of the edge to his father
const EdgeWeightedGraphCopy< T > & tree
constant ref to the tree to be decomposed
NodeArray< node > closestSteinerAncestor
the highest-level Steiner ancestor of the current node
void dfsHeavyPathDecomposition(node v, node closestSteinerUpNode)
performs the heavy path decomposition on the tree belonging to the class updates the fields of the cl...
node lowestCommonAncestor(node x, node y) const
computes the lowest common ancestor of nodes x and y using the hpd
T getBottleneckSteinerDistance(node x, node y) const
computes in the bottleneck distance between terminals x and y
HeavyPathDecomposition(const EdgeWeightedGraphCopy< T > &treeEWGraphCopy)
T distanceToAncestor(node v, node ancestor) const
computes the sum of all edges on the path from v to ancestor v must be in ancestor's subtree
const NodeArray< bool > isTerminal
isTerminal of the desc tree
void computeLongestDistToSteinerAncestorOnChain()
creates for every chain an array with the maximum of every prefix of a fictive array which keeps for ...
std::vector< std::vector< T > > longestDistToSteinerAncestorSegTree
segment tree for segment maxs on every chain
NodeArray< int > weightOfSubtree
weight of the subtree rooted in one node
node binarySearchUpmostTerminal(node v, const std::vector< node > &chainOfTerminals) const
performs a binary search on chainOfTerminals, searches for the closest node to the root on chainOfTer...
void computeLongestDistToSteinerAncestorSegTree()
creates for every chain a segment tree built on a fictive array which keeps for every node the sum of...
Reverse< T > reverse(T &container)
Provides iterators for container to make it easily iterable in reverse.
Definition Reverse.h:74
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition basic.h:52
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)
HypergraphRegistry< HypernodeElement >::iterator end(const HypergraphRegistry< HypernodeElement > &self)