TTK
Loading...
Searching...
No Matches
LowestCommonAncestor.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4#include <climits>
5#include <cmath>
6#include <sstream>
7#include <stack>
8#include <string>
9
13
15
16 Timer t;
17
18 // Return value
19 int retval;
20 // Eulerian transverse of the tree
21 retval = eulerianTransverse();
22 if(retval != 0) {
23 return retval;
24 }
25 // Divide the depth array in blocs and do preprocessing
26 retval = computeBlocs();
27 if(retval != 0) {
28 return retval;
29 }
30 // Preprocess the range minimum queries on the blocs
31 blocMinimumValueRMQ_.setVector(blocMinimumValue_);
32 blocMinimumValueRMQ_.setDebugLevel(debugLevel_);
33 retval = blocMinimumValueRMQ_.preprocess(true);
34 if(retval != 0) {
35 return retval;
36 }
37
38 this->printMsg("Preprocessed queries.", 1.0, t.getElapsedTime(), 1,
40
41 return 0;
42}
43
44int ttk::LowestCommonAncestor::RMQuery(const int &i, const int &j) const {
45 // Bloc of i
46 int const blocI = i / blocSize_;
47 // Bloc of j
48 int const blocJ = j / blocSize_;
49 // If i and j are in different blocs
50 if(blocI != blocJ) {
51 // Positions and values of the 3 range minima to compare
52 std::array<int, 3> min_pos, min_value;
53 // Position of the min in the bloc containing the ith case
54 min_pos[0] = blocI * blocSize_
55 + normalizedBlocTable_[blocToNormalizedBloc_[blocI]]
56 [i % blocSize_][blocSize_ - 1];
57 // Position of the min in the blocs between the bloc of i and j
58 min_pos[1] = ((blocJ - blocI) > 1)
59 ? blocMinimumPosition_[blocMinimumValueRMQ_.query(
60 blocI + 1, blocJ - 1)]
61 : INT_MAX;
62 // Position of the min in the bloc containing the jth case
63 min_pos[2]
64 = blocJ * blocSize_
65 + normalizedBlocTable_[blocToNormalizedBloc_[blocJ]][0][j % blocSize_];
66 // Values of the depth to compare
67 min_value[0] = nodeDepth_[min_pos[0]];
68 min_value[1] = (min_pos[1] != INT_MAX) ? nodeDepth_[min_pos[1]] : INT_MAX;
69 min_value[2] = nodeDepth_[min_pos[2]];
70 // Return the minimum of the 3
71 return min_pos[min_pos_3(min_value)];
72 } else {
73 // i and j are in the same bloc
74 return blocI * blocSize_
75 + normalizedBlocTable_[blocToNormalizedBloc_[blocI]][i % blocSize_]
76 [j % blocSize_];
77 }
78}
79
81 // Size and number of blocs
82 int const sizeOfArray = static_cast<int>(nodeDepth_.size());
83 blocSize_ = static_cast<int>(log2(sizeOfArray) / 2.0);
84 int const numberOfBlocs
85 = sizeOfArray / blocSize_ + (sizeOfArray % blocSize_ != 0);
86 // Define the bloc ranges
87 for(int i = 0; i < numberOfBlocs; i++) {
88 std::pair<int, int> range;
89 range.first = i * blocSize_;
90 range.second = (i + 1) * blocSize_;
91 blocPartition_.push_back(range);
92 }
93 if(sizeOfArray % blocSize_ != 0) {
94 std::pair<int, int> range;
95 range.first = (numberOfBlocs - 1) * blocSize_;
96 range.second = sizeOfArray;
97 blocPartition_.push_back(range);
98 }
99 // Find the minimum in each bloc
100 blocMinimumValue_.resize(numberOfBlocs);
101 blocMinimumPosition_.resize(numberOfBlocs);
102 for(int i = 0; i < numberOfBlocs; i++) {
103 blocMinimumValue_[i] = nodeDepth_[blocPartition_[i].first];
104 blocMinimumPosition_[i] = blocPartition_[i].first;
105 for(int j = blocPartition_[i].first + 1; j < blocPartition_[i].second;
106 j++) {
107 if(nodeDepth_[j] < blocMinimumValue_[i]) {
108 blocMinimumValue_[i] = nodeDepth_[j];
109 blocMinimumPosition_[i] = j;
110 }
111 }
112 }
113 // Allocate the query tables
114 int const numberOfTables = (1 << (blocSize_ - 1));
115 normalizedBlocTable_.resize(numberOfTables);
116 for(int i = 0; i < numberOfTables; i++) {
117 normalizedBlocTable_[i].resize(blocSize_);
118 for(int j = 0; j < blocSize_; j++) {
119 normalizedBlocTable_[i][j].resize(blocSize_);
120 }
121 }
122 // Build the query table for each possible normalized bloc
123 for(int i = 0; i < numberOfTables; i++) {
124 // Building of the ith possible bloc
125 std::vector<bool> plusOne(blocSize_ - 1);
126 int quotient = i;
127 int remain;
128 for(int j = 0; j < (blocSize_ - 1); j++) {
129 remain = quotient % 2;
130 quotient /= 2;
131 plusOne[blocSize_ - 2 - j] = static_cast<bool>(remain);
132 }
133 if(blocSize_ < 1) {
134 return -1;
135 }
136 std::vector<int> normalizedBloc(blocSize_);
137 normalizedBloc[0] = 0;
138 for(int j = 0; j < (blocSize_ - 1); j++) {
139 if(plusOne[j]) {
140 normalizedBloc[j + 1] = normalizedBloc[j] + 1;
141 } else {
142 normalizedBloc[j + 1] = normalizedBloc[j] - 1;
143 }
144 }
145 // Give the normalizedBloc to a RangeMinimumQuery object
146 RangeMinimumQuery<int> rmq(normalizedBloc);
147 rmq.setDebugLevel(debugLevel_);
148 rmq.preprocess(true);
149 // Double loop to compute all queries
150 for(int j = 0; j < blocSize_; j++) {
151 normalizedBlocTable_[i][j][j] = j;
152 for(int k = j + 1; k < blocSize_; k++) {
153 normalizedBlocTable_[i][j][k] = rmq.query(j, k);
154 normalizedBlocTable_[i][k][j] = normalizedBlocTable_[i][j][k];
155 }
156 }
157 }
158 // Determine the corresponding normalized bloc for each bloc
159 blocToNormalizedBloc_.resize(numberOfBlocs, -1);
160 for(int i = 0; i < numberOfBlocs; i++) {
161 int level = 0;
162 int tableId = 0;
163 for(int j = blocPartition_[i].first + 1; j < blocPartition_[i].second;
164 j++) {
165 if(nodeDepth_[j] > nodeDepth_[j - 1]) {
166 tableId += (1 << (blocSize_ - 2 - level));
167 }
168 level++;
169 }
170 blocToNormalizedBloc_[i] = tableId;
171 }
172 return 0;
173}
174
176 // Find the root
177 int rootId = -1;
178 for(unsigned int i = 0; i < getNumberOfNodes(); i++) {
179 if(node_[i].getAncestorId() == static_cast<int>(i)) {
180 rootId = i;
181 break;
182 }
183 }
184 if(rootId == -1) {
185 this->printErr("Tree root not found.");
186 return -1;
187 } else {
188 this->printMsg("Rout found: node id = " + std::to_string(rootId),
190 }
191 if(!(node_[rootId].getNumberOfSuccessors() > 0)) {
192 this->printErr("Tree root found with no successor.");
193 return -2;
194 }
195 // Initialize the vectors
196 nodeOrder_.clear();
197 nodeOrder_.reserve(2 * getNumberOfNodes() + 1);
198 nodeDepth_.clear();
199 nodeDepth_.reserve(2 * getNumberOfNodes() + 1);
200 nodeFirstAppearance_.clear();
201 nodeFirstAppearance_.resize(getNumberOfNodes(), -1);
202 // Transverse starting from the root
203 std::stack<int> nodeStack;
204 int depth = 0;
205 int iteration = 0;
206 std::vector<bool> isVisited(getNumberOfNodes(), false);
207 nodeStack.push(rootId);
208 while(!nodeStack.empty()) {
209 int const nodeId = nodeStack.top();
210 nodeStack.pop();
211 nodeOrder_.push_back(nodeId);
212 nodeDepth_.push_back(depth);
213 if(!isVisited[nodeId]) {
214 // Add ancestor
215 if(nodeId != rootId) {
216 nodeStack.push(node_[nodeId].getAncestorId());
217 }
218 // Add successors
219 int const numberOfSuccessors = node_[nodeId].getNumberOfSuccessors();
220 for(int i = 0; i < numberOfSuccessors; i++) {
221 nodeStack.push(node_[nodeId].getSuccessorId(i));
222 }
223 nodeFirstAppearance_[nodeId] = iteration;
224 isVisited[nodeId] = true;
225 }
226 // Next depth
227 if(!nodeStack.empty()) {
228 if(nodeStack.top() == node_[nodeId].getAncestorId()) {
229 depth--;
230 } else {
231 depth++;
232 }
233 }
234 iteration++;
235 }
236 return 0;
237}
void setDebugMsgPrefix(const std::string &prefix)
Definition Debug.h:364
virtual int setDebugLevel(const int &debugLevel)
Definition Debug.cpp:147
int RMQuery(const int &i, const int &j) const
Class to answer range minimum queries in an array in constant time after a linearithmic time preproce...
int preprocess(const bool silent=false)
int query(int i, int j) const
double getElapsedTime()
Definition Timer.h:15
std::string to_string(__int128)
Definition ripserpy.cpp:99
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)