TTK
Loading...
Searching...
No Matches
MandatoryCriticalPoints.cpp
Go to the documentation of this file.
2
3using namespace ttk;
4
12
14 inputUpperBoundField_ = nullptr;
15 inputLowerBoundField_ = nullptr;
20 vertexNumber_ = 0;
26 vertexPositions_.clear();
27 vertexSoSoffsets_.clear();
28 upperVertexScalars_.clear();
29 lowerVertexScalars_.clear();
30 upperMinimumList_.clear();
31 lowerMinimumList_.clear();
32 upperMaximumList_.clear();
33 lowerMaximumList_.clear();
40 mergedMaximaId_.clear();
41 mergedMinimaId_.clear();
70}
71
73 const TreeType treeType,
74 Graph &mdtTree,
75 std::vector<int> &mdtTreePointComponentId,
76 std::vector<PointType> &mdtTreePointType,
77 std::vector<double> &mdtTreePointLowInterval,
78 std::vector<double> &mdtTreePointUpInterval,
79 std::vector<int> &mdtTreeEdgeSwitchable,
80 const std::vector<int> &mdtExtremumParentSaddle,
81 const std::vector<int> &mdtSaddleParentSaddle,
82 const std::vector<bool> &isExtremumSimplified,
83 const std::vector<bool> &isSaddleSimplified,
84 const std::vector<std::pair<double, double>> &extremumInterval,
85 const std::vector<std::pair<int, int>> &mandatorySaddleVertices,
86 const int extremaNumber,
87 const int saddleNumber,
88 const PointType extremumType,
89 const PointType saddleType,
90 const PointType otherExtremumType,
91 const double globalOtherExtremumValue) const {
92
93 const std::string treeName
94 = treeType == TreeType::JoinTree ? "join tree" : "split tree";
95
96 /* Preliminaries operations */
97 mdtTree.clear();
98 mdtTreePointComponentId.clear();
99 mdtTreePointComponentId.reserve(extremaNumber + saddleNumber + 1);
100 mdtTreePointType.clear();
101 mdtTreePointType.reserve(extremaNumber + saddleNumber + 1);
102 mdtTreePointLowInterval.clear();
103 mdtTreePointLowInterval.reserve(extremaNumber + saddleNumber + 1);
104 mdtTreePointUpInterval.clear();
105 mdtTreePointUpInterval.reserve(extremaNumber + saddleNumber + 1);
106 mdtTreeEdgeSwitchable.clear();
107
108 /* Graph Object Building */
109 std::vector<int> saddleGraphVertex(saddleNumber, -1);
110 // Create and connect all extrema to their saddle
111 for(int i = 0; i < extremaNumber; i++) {
112 // If simplified, do nothing and go to the next extremum
113 if(isExtremumSimplified[i])
114 continue;
115 // New point in the graph
116 int const extremumGraphPoint = mdtTree.addVertex();
117 mdtTreePointComponentId.push_back(i);
118 mdtTreePointType.push_back(extremumType);
119
120 mdtTreePointLowInterval.push_back(extremumInterval[i].first);
121 mdtTreePointUpInterval.push_back(extremumInterval[i].second);
122 // Look for the saddle and connect if there is one
123 int const parentSaddle = mdtExtremumParentSaddle[i];
124 // If no parent saddle, end the loop
125 if(parentSaddle == -1)
126 break;
127 // Create the saddle (if not already)
128 if(saddleGraphVertex[parentSaddle] == -1) {
129 saddleGraphVertex[parentSaddle] = mdtTree.addVertex();
130 mdtTreePointComponentId.push_back(parentSaddle);
131 mdtTreePointType.push_back(saddleType);
132 int const lowerVertex = mandatorySaddleVertices[parentSaddle].first;
133 int const upperVertex = mandatorySaddleVertices[parentSaddle].second;
134 mdtTreePointLowInterval.push_back(lowerVertexScalars_[lowerVertex]);
135 mdtTreePointUpInterval.push_back(upperVertexScalars_[upperVertex]);
136 }
137 // Connect the extrema and saddle
138 mdtTree.addEdge(saddleGraphVertex[parentSaddle], extremumGraphPoint);
139 // Not switchable (saddle -> extremum)
140 mdtTreeEdgeSwitchable.push_back(0);
141 }
142
143 // If there is no extremum (=> no saddles), do nothing (empty graph)
144 if(mdtTree.getNumberOfVertices() == 0) {
145 this->printWrn("Mandatory " + treeName + " empty.");
146 return 0;
147 }
148
149 // If there is only one extremum (=> no saddles), connect the extremum to the
150 // other global extremum
151 if(mdtTree.getNumberOfVertices() == 1) {
152 mdtTree.addVertex();
153 mdtTreePointComponentId.push_back(-1);
154 mdtTreePointType.push_back(otherExtremumType);
155 mdtTreePointLowInterval.push_back(globalOtherExtremumValue);
156 mdtTreePointUpInterval.push_back(globalOtherExtremumValue);
157 mdtTree.addEdge(1, 0);
158 mdtTreeEdgeSwitchable.push_back(0);
159 this->printWrn("Mandatory " + treeName + " with only one minimum.");
160
161 } else {
162 // Continue to add the remaining saddles
163 // Create and connect all remaining saddles
164 for(int i = 0; i < saddleNumber; i++) {
165
166 // If simplified, do nothing and go to the next saddle
167 if(isSaddleSimplified[i]) {
168 continue;
169 }
170 // Create the graph point if not already
171 if(saddleGraphVertex[i] == -1) {
172 saddleGraphVertex[i] = mdtTree.addVertex();
173 mdtTreePointComponentId.push_back(i);
174 mdtTreePointType.push_back(saddleType);
175 int const lowerVertex = mandatorySaddleVertices[i].first;
176 int const upperVertex = mandatorySaddleVertices[i].second;
177 mdtTreePointLowInterval.push_back(lowerVertexScalars_[lowerVertex]);
178 mdtTreePointUpInterval.push_back(upperVertexScalars_[upperVertex]);
179 }
180 // Look for the saddle above and connect if there is one
181 int const parentSaddle = mdtSaddleParentSaddle[i];
182 // If the parent is different from the saddle itself, create it and
183 // connect
184 if(parentSaddle != i) {
185 // Create the graph point if not already
186 if(saddleGraphVertex[parentSaddle] == -1) {
187 saddleGraphVertex[parentSaddle] = mdtTree.addVertex();
188 mdtTreePointComponentId.push_back(parentSaddle);
189 mdtTreePointType.push_back(saddleType);
190 int const lowerVertex = mandatorySaddleVertices[parentSaddle].first;
191 int const upperVertex = mandatorySaddleVertices[parentSaddle].second;
192 mdtTreePointLowInterval.push_back(lowerVertexScalars_[lowerVertex]);
193 mdtTreePointUpInterval.push_back(upperVertexScalars_[upperVertex]);
194 }
195 // Connect the two saddles
196 mdtTree.addEdge(saddleGraphVertex[parentSaddle], saddleGraphVertex[i]);
197 // Test if switchable : parentSaddle and i
198 mdtTreeEdgeSwitchable.push_back(
199 areSaddlesSwitchables(treeType, parentSaddle, i));
200 } else { // It is the root, create the global extremum to connect with it
201 int const globalOtherExtremumGraphPoint = mdtTree.addVertex();
202 mdtTreePointComponentId.push_back(-1);
203 mdtTreePointType.push_back(otherExtremumType);
204 mdtTreePointLowInterval.push_back(globalOtherExtremumValue);
205 mdtTreePointUpInterval.push_back(globalOtherExtremumValue);
206 mdtTree.addEdge(globalOtherExtremumGraphPoint, saddleGraphVertex[i]);
207 mdtTreeEdgeSwitchable.push_back(0);
208 }
209 }
210 }
211
212 /* Debug Messages */
213 this->printMsg("Building of the mandatory " + treeName + "");
214 this->printMsg({{"#Points", std::to_string(mdtTree.getNumberOfVertices())},
215 {"#Edges", std::to_string(mdtTree.getNumberOfEdges())}});
216
217 this->printMsg("List of mandatory " + treeName + " graph points:",
219 for(int i = 0; i < mdtTree.getNumberOfVertices(); i++) {
220 std::stringstream msg{};
221 msg << " (" << std::setw(3) << std::right << i << ") ";
222 msg << std::setw(12) << std::right;
223 switch(mdtTreePointType[i]) {
225 msg << "Minimum";
226 break;
228 msg << "Maximum";
229 break;
231 msg << "Join Saddle";
232 break;
234 msg << "Split Saddle";
235 break;
236 default:
237 break;
238 }
239 msg << " id = " << std::setw(3) << mdtTreePointComponentId[i];
240 msg << " I = [ " << mdtTreePointLowInterval[i];
241 msg << " ; " << mdtTreePointUpInterval[i];
242 msg << " ]";
243 this->printMsg(msg.str(), debug::Priority::DETAIL);
244 }
245
246 this->printMsg(
247 "List of mandatory " + treeName + " graph edges:", debug::Priority::DETAIL);
248 for(int i = 0; i < mdtTree.getNumberOfEdges(); i++) {
249 std::stringstream msg{};
250 msg << " (" << std::setw(3) << std::right << i << ") ";
251 msg << "Points ";
252 msg << std::setw(3) << std::right
253 << mdtTree.getEdge(i).getVertexIdx().first;
254 msg << " -> ";
255 msg << std::setw(3) << std::left
256 << mdtTree.getEdge(i).getVertexIdx().second;
257 this->printMsg(msg.str(), debug::Priority::DETAIL);
258 }
259
260 return 0;
261}
262
264 const TreeType treeType,
265 const std::vector<std::pair<int, int>> &saddleList,
266 const std::vector<std::vector<int>> &mergedExtrema,
267 const std::vector<std::pair<double, double>> &extremumInterval,
268 SubLevelSetTree &lowerTree,
269 SubLevelSetTree &upperTree,
270 std::vector<std::pair<std::pair<int, int>, double>> &extremaSaddlePair)
271 const {
272
273#ifndef TTK_ENABLE_KAMIKAZE
274 if(lowerTree.isJoinTree() != upperTree.isJoinTree())
275 return -1;
276#endif
277
278 // List of pairs
279 // .first.first = saddle id
280 // .first.second = extremum id
281 // .second = metric d(M,S)
282 extremaSaddlePair.clear();
283 // Build list of pairs
284 for(size_t i = 0; i < mergedExtrema.size(); i++) {
285 for(size_t j = 0; j < mergedExtrema[i].size(); j++) {
286 // Build a pair (Si,Mj)
287 std::pair<std::pair<int, int>, double> constructedPair{
288 {mergedExtrema[i][j], i}, 0.0};
289 // Get the values to compute d(Mj,Si)
290 double lowerValue = 0;
291 double upperValue = 0;
292 if(lowerTree.isJoinTree()) {
293 lowerValue = extremumInterval[constructedPair.first.first].first;
294 // lowerTree->getVertexScalar(extremumList[(*mergedExtrema)[i][j]],
295 // lowerValue);
296 upperTree.getVertexScalar(saddleList[i].second, upperValue);
297 } else {
298 lowerTree.getVertexScalar(saddleList[i].first, lowerValue);
299 // upperTree->getVertexScalar(extremumList[(*mergedExtrema)[i][j]],
300 // upperValue);
301 upperValue = extremumInterval[constructedPair.first.first].second;
302 }
303 // Evaluate d(Si,Mj)
304 constructedPair.second = fabs(upperValue - lowerValue);
305 // Add the pair to the list
306 extremaSaddlePair.push_back(constructedPair);
307 }
308 }
309 // Sort pair by increasing value of d(S,M) (.second)
311 std::sort(extremaSaddlePair.begin(), extremaSaddlePair.end(), pairComparison);
312
313 const std::string treeName = treeType == TreeType::JoinTree
314 ? "minimum - join saddle"
315 : "maximum - split saddle";
316 this->printMsg(
317 "List of mandatory " + treeName + " pairs:", debug::Priority::DETAIL);
318 for(size_t i = 0; i < extremaSaddlePair.size(); i++) {
319 std::stringstream msg;
320 msg << " (" << std::setw(3) << extremaSaddlePair[i].first.first << ";";
321 msg << std::setw(3) << extremaSaddlePair[i].first.second << ")";
322 msg << " -> d = " << extremaSaddlePair[i].second;
323 this->printMsg(msg.str(), debug::Priority::DETAIL);
324 }
325
326 return 0;
327}
328
330 const TreeType &treeType,
331 const Graph &mdtTree,
332 const std::vector<PointType> &mdtTreePointType,
333 const std::vector<double> &mdtTreePointLowInterval,
334 const std::vector<double> &mdtTreePointUpInterval,
335 std::vector<double> &xCoord,
336 std::vector<double> &yCoord) const {
337
338 /* Information */
339 const int numberOfPoints = mdtTree.getNumberOfVertices();
340 const double rangeMin = getGlobalMinimum();
341 const double rangeMax = getGlobalMaximum();
342 const double range = rangeMax - rangeMin;
343
344 // Get the root
345 int rootGraphPointId = -1;
346 if(treeType == TreeType::JoinTree) {
347 for(size_t i = 0; i < mdtTreePointType.size(); i++) {
348 if(mdtTreePointType[i] == PointType::Maximum) {
349 rootGraphPointId = i;
350 break;
351 }
352 }
353 } else {
354 for(size_t i = 0; i < mdtTreePointType.size(); i++) {
355 if(mdtTreePointType[i] == PointType::Minimum) {
356 rootGraphPointId = i;
357 break;
358 }
359 }
360 }
361 if(rootGraphPointId == -1) {
362 return -1;
363 }
364
365 // Root down point
366 int downRootPointId = -1;
367 if(mdtTree.getVertex(rootGraphPointId).getNumberOfEdges() == 1) {
368 int const edgeId = mdtTree.getVertex(rootGraphPointId).getEdgeIdx(0);
369 if(mdtTree.getEdge(edgeId).getVertexIdx().first == rootGraphPointId) {
370 downRootPointId = mdtTree.getEdge(edgeId).getVertexIdx().second;
371 }
372 }
373 if(downRootPointId == -1) {
374 return -2;
375 }
376
377 // Resize of outputs
378 xCoord.resize(numberOfPoints);
379 yCoord.resize(numberOfPoints);
380
381 // Graph Point x intervals
382 std::vector<std::pair<double, double>> xInterval(numberOfPoints);
383 xInterval[rootGraphPointId].first = -0.5 * (double)numberOfPoints;
384 xInterval[rootGraphPointId].second = 0.5 * (double)numberOfPoints;
385 // Order
386 std::vector<std::pair<int, double>> xOrder(numberOfPoints);
387
388 std::queue<int> graphPointQueue;
389 graphPointQueue.push(rootGraphPointId);
390
391 while(!graphPointQueue.empty()) {
392
393 int const graphPoint = graphPointQueue.front();
394 graphPointQueue.pop();
395
396 // Number Of Down Edges
397 int const numberOfEdges = mdtTree.getVertex(graphPoint).getNumberOfEdges();
398 int numberOfDownEdges = 0;
399 for(int i = 0; i < numberOfEdges; i++) {
400 int const edgeId = mdtTree.getVertex(graphPoint).getEdgeIdx(i);
401 if(mdtTree.getEdge(edgeId).getVertexIdx().first == graphPoint) {
402 numberOfDownEdges++;
403 }
404 }
405 // X Order
406 xOrder[graphPoint].first = graphPoint;
407 xOrder[graphPoint].second
408 = (xInterval[graphPoint].second + xInterval[graphPoint].first) * 0.5;
409 // Continue to next point in queue if it's a leaf
410 if(numberOfDownEdges == 0)
411 continue;
412 // Down node count
413 int downPointCount = 0;
414 // Interval splitting for down points
415 for(int i = 0; i < numberOfEdges; i++) {
416 int const edgeId = mdtTree.getVertex(graphPoint).getEdgeIdx(i);
417 int downGraphPoint = -1;
418 if(mdtTree.getEdge(edgeId).getVertexIdx().first == graphPoint) {
419 downGraphPoint = mdtTree.getEdge(edgeId).getVertexIdx().second;
420 }
421 // Next edge if it is not a down edge
422 if(downGraphPoint == -1)
423 continue;
424 // Interval for the down graph
425 xInterval[downGraphPoint].first
426 = xInterval[graphPoint].first
427 + ((xInterval[graphPoint].second - xInterval[graphPoint].first)
428 * (double)downPointCount / (double)numberOfDownEdges);
429 xInterval[downGraphPoint].second
430 = xInterval[graphPoint].first
431 + ((xInterval[graphPoint].second - xInterval[graphPoint].first)
432 * (double)(downPointCount + 1) / (double)numberOfDownEdges);
433 // Count the point and add it to the queue
434 downPointCount++;
435 graphPointQueue.push(downGraphPoint);
436 }
437 }
438
439 /* Y coordinates */
440 for(int i = 0; i < numberOfPoints; i++) {
441 yCoord[i]
442 = ((0.5 * (mdtTreePointLowInterval[i] + mdtTreePointUpInterval[i]))
443 - rangeMin)
444 / range;
445 }
446
447 /* X coordinates */
448 // Sorting
449 pairComparison const xCoordCmp;
450 std::sort(xOrder.begin(), xOrder.end(), xCoordCmp);
451 // X coordinates for all points except root (global extremum)
452 int pointCount = 0;
453 for(int i = 0; i < numberOfPoints; i++) {
454 if(xOrder[i].first != rootGraphPointId) {
455 xCoord[xOrder[i].first]
456 = (double)pointCount * (1.0 / ((int)numberOfPoints - 2.0));
457 pointCount++;
458 }
459 }
460 // X coordinate for the root
461 xCoord[rootGraphPointId] = xCoord[downRootPointId];
462
463 const std::string treeName
464 = treeType == TreeType::JoinTree ? "join tree" : "split tree";
465
466 this->printMsg("Planar layout for mandatory " + treeName + ": root point ("
467 + std::to_string(downRootPointId) + ")",
469
470 for(int i = 0; i < numberOfPoints; i++) {
471 std::stringstream msg;
472 msg << " (" << i << ") :"
473 << " x = " << xCoord[i] << " y = " << yCoord[i];
474 this->printMsg(msg.str(), debug::Priority::DETAIL);
475 }
476
477 return 0;
478}
479
481 const PointType &pointType,
482 const SubLevelSetTree &tree,
483 const int seedVertexId,
484 const std::vector<double> &vertexScalars,
485 std::vector<int> &componentVertexList) const {
486
487 const double value = vertexScalars[seedVertexId];
488
489 // Clear the list
490 componentVertexList.clear();
491 // Get the super arc id of the vertex
492 int const superArcId = getVertexSuperArcId(seedVertexId, &tree);
493 // Get the sub tree root super arc
494 int const rootSuperArcId = getSubTreeRootSuperArcId(&tree, superArcId, value);
495 // Get the list of the sub tree super arc ids
496 std::vector<int> subTreeSuperArcId;
497 getSubTreeSuperArcIds(&tree, rootSuperArcId, subTreeSuperArcId);
498 // Comparison
499 int const sign = (pointType == PointType::Minimum) ? 1 : -1;
500 // Compute each super arc
501 for(int i = 0; i < (int)subTreeSuperArcId.size(); i++) {
502 const SuperArc *superArc = tree.getSuperArc(subTreeSuperArcId[i]);
503 const int numberOfRegularNodes = superArc->getNumberOfRegularNodes();
504 // Root super arc and others treated differently
505 if(subTreeSuperArcId[i] == rootSuperArcId) {
506 // Test the value for each regular node
507 for(int j = 0; j < numberOfRegularNodes; j++) {
508 int const regularNodeId = superArc->getRegularNodeId(j);
509 double const nodeScalar = tree.getNodeScalar(regularNodeId);
510 if(!((sign * nodeScalar) > (sign * value))) {
511 int const vertexId = tree.getNode(regularNodeId)->getVertexId();
512 componentVertexList.push_back(vertexId);
513 }
514 }
515 // Down node
516 int const downNodeId = superArc->getDownNodeId();
517 double const nodeScalar = tree.getNodeScalar(downNodeId);
518 if(!((sign * nodeScalar) > (sign * value))) {
519 int const vertexId = tree.getNode(downNodeId)->getVertexId();
520 componentVertexList.push_back(vertexId);
521 }
522 } else {
523 // Take all regular nodes
524 for(int j = 0; j < numberOfRegularNodes; j++) {
525 int const regularNodeId = superArc->getRegularNodeId(j);
526 int const vertexId = tree.getNode(regularNodeId)->getVertexId();
527 componentVertexList.push_back(vertexId);
528 }
529 // Take down node
530 int const downNodeId = superArc->getDownNodeId();
531 int const vertexId = tree.getNode(downNodeId)->getVertexId();
532 componentVertexList.push_back(vertexId);
533 }
534 }
535 return 0;
536}
537
539 const PointType pointType,
540 SubLevelSetTree &firstTree,
541 SubLevelSetTree &secondTree,
542 std::vector<int> &mandatoryExtremum,
543 std::vector<std::pair<double, double>> &criticalInterval) const {
544
545 Timer t;
546
547#ifndef TTK_ENABLE_KAMIKAZE
548 if(!(firstTree.isJoinTree() != firstTree.isSplitTree()))
549 return -1;
550 if(!(secondTree.isJoinTree() != secondTree.isSplitTree()))
551 return -2;
552 if(!((firstTree.isJoinTree() && secondTree.isJoinTree())
553 || (firstTree.isSplitTree() && secondTree.isSplitTree())))
554 return -3;
555#endif
556
557 // Extremum list in the first tree
558 const std::vector<int> &extremumList = *firstTree.getExtremumList();
559 // Some tmp variables
560 size_t const extremumNumber = extremumList.size();
561 std::vector<int> vertexId(extremumNumber);
562 std::vector<double> vertexValue(extremumNumber);
563 std::vector<int> const superArcId(extremumNumber);
564 // vector<int> rootSuperArcId(extremumNumber);
565 std::vector<int> subTreeSuperArcId; // vector<vector<int> >
566 // subTreeSuperArcId(extremumNumber);
567 // Clear the list of mandatory extrema
568 mandatoryExtremum.clear();
569 criticalInterval.clear();
570 // To mark the super arc in the second tree as already used for a mandatory
571 // critical component
572 std::vector<bool> isSuperArcAlreadyVisited(
573 secondTree.getNumberOfSuperArcs(), false);
574
575 // #ifdef TTK_ENABLE_OPENMP
576 // #pragma omp parallel for num_threads(threadNumber_)
577 // #endif
578 for(size_t i = 0; i < extremumNumber; i++) {
579 // Mandatory until proven otherwise
580 bool isMandatory = true;
581 // Vertex Id (first tree)
582 vertexId[i] = extremumList[i];
583 // Vertex Value (first tree)
584 firstTree.getVertexScalar(vertexId[i], vertexValue[i]);
585 // Super Arc Id (second tree)
586 int const secondTreeSuperArcId
587 = getVertexSuperArcId(vertexId[i], &secondTree);
588 // Root Super Arc Id (second tree) of the sub tree containing the vertex and
589 // rooted at the value of the vertex in the first scalar field
590 int rootSuperArcId = -1;
591 if(!isSuperArcAlreadyVisited[secondTreeSuperArcId]) {
592 rootSuperArcId = getSubTreeRootSuperArcId(
593 &secondTree, secondTreeSuperArcId, vertexValue[i]);
594 } else {
595 isMandatory = false;
596 }
597
598 // Exploration of the sub tree (if not already eliminated)
599 if(isMandatory) {
600 subTreeSuperArcId.clear();
601 std::queue<int> superArcQueue;
602 superArcQueue.push(rootSuperArcId);
603 while(isMandatory && (!superArcQueue.empty())) {
604 int const spaId = superArcQueue.front();
605 superArcQueue.pop();
606 if(isSuperArcAlreadyVisited[spaId]) {
607 isMandatory = false;
608 } else {
609 int const downNodeId = secondTree.getSuperArc(spaId)->getDownNodeId();
610 int const numberOfDownSuperArcs
611 = secondTree.getNode(downNodeId)->getNumberOfDownSuperArcs();
612 if(numberOfDownSuperArcs > 0) {
613 for(int j = 0; j < numberOfDownSuperArcs; j++) {
614 superArcQueue.push(
615 secondTree.getNode(downNodeId)->getDownSuperArcId(j));
616 }
617 }
618 subTreeSuperArcId.push_back(spaId);
619 }
620 }
621 }
622
623 // If it is a mandatory extremum
624 if(isMandatory) {
625 // Add it to the list
626 mandatoryExtremum.push_back(vertexId[i]);
627 // Mark all the super arcs in the sub tree as visited and compute the
628 // critical interval
629 criticalInterval.emplace_back(vertexValue[i], vertexValue[i]);
630 for(int j = 0; j < (int)subTreeSuperArcId.size(); j++) {
631 isSuperArcAlreadyVisited[subTreeSuperArcId[j]] = true;
632 int const downNodeId
633 = secondTree.getSuperArc(subTreeSuperArcId[j])->getDownNodeId();
634 double const downNodeValue = secondTree.getNodeScalar(downNodeId);
635 if(pointType == PointType::Minimum) {
636 if(downNodeValue < criticalInterval.back().first) {
637 criticalInterval.back().first = downNodeValue;
638 }
639 } else {
640 if(downNodeValue > criticalInterval.back().second) {
641 criticalInterval.back().second = downNodeValue;
642 }
643 }
644 }
645 // Mark the super arc from the root of the sub tree to the global root
646 int upNodeId = secondTree.getSuperArc(rootSuperArcId)->getUpNodeId();
647 int spaId = secondTree.getNode(upNodeId)->getUpSuperArcId(0);
648 while((spaId != -1) && !(isSuperArcAlreadyVisited[spaId])) {
649 isSuperArcAlreadyVisited[spaId] = true;
650 upNodeId = secondTree.getSuperArc(spaId)->getUpNodeId();
651 spaId = secondTree.getNode(upNodeId)->getUpSuperArcId(0);
652 }
653 }
654
655 // // List of sub tree super arc ids (second tree)
656 // getSubTreeSuperArcIds(secondTree, rootSuperArcId, subTreeSuperArcId);
657 // // Check each super arc in the sub tree in the second tree
658 // bool isMandatoryCriticalPoint = true;
659 // for(int j=0 ; j<(int)subTreeSuperArcId.size() ; j++){
660 // // If one of the super arc has been visited before, the extremum is not
661 // mandatory if(isSuperArcAlreadyVisited[subTreeSuperArcId[j]]){
662 // isMandatoryCriticalPoint = false;
663 // break;
664 // }
665 // }
666 // // If it is a mandatory extremum
667 // if(isMandatoryCriticalPoint){
668 // // Add it to the list
669 // mandatoryExtremum->push_back(vertexId[i]);
670 // // Mark all the super arcs in the sub tree as visited and compute the
671 // critical interval
672 // criticalInterval->push_back(pair<double,double>(vertexValue[i],vertexValue[i]));
673 // for(int j=0 ; j<(int)subTreeSuperArcId.size() ; j++){
674 // isSuperArcAlreadyVisited[subTreeSuperArcId[j]] = true;
675 // int downNodeId =
676 // secondTree->getSuperArc(subTreeSuperArcId[j])->getDownNodeId();
677 // double downNodeValue = secondTree->getNodeScalar(downNodeId);
678 // if(pointType == PointType::Minimum) {
679 // if(downNodeValue < criticalInterval->back().first) {
680 // criticalInterval->back().first = downNodeValue;
681 // }
682 // } else {
683 // if(downNodeValue > criticalInterval->back().second){
684 // criticalInterval->back().second = downNodeValue;
685 // }
686 // }
687 // }
688 // }
689 }
690
691#ifdef TTK_ENABLE_OPENMP
692#pragma omp critical
693#endif
694 {
695 const std::string pt
696 = pointType == PointType::Minimum ? "minima" : "maxima";
697
698 this->printMsg("Computed " + std::to_string(mandatoryExtremum.size())
699 + " mandatory " + pt,
700 1.0, t.getElapsedTime(), this->threadNumber_);
701 this->printMsg("List of mandatory " + pt, debug::Priority::DETAIL);
702
703 for(size_t i = 0; i < mandatoryExtremum.size(); i++) {
704 std::stringstream msg;
705 msg << " -> " << pt << " (" << std::setw(3) << std::right << i << ") ";
706 msg << " \t"
707 << "Vertex " << std::setw(9) << std::left << mandatoryExtremum[i];
708 msg << " \tInterval [ " << std::setw(12) << std::right
709 << criticalInterval[i].first << " ; " << std::setprecision(9)
710 << std::setw(11) << std::left << criticalInterval[i].second << " ]";
711 this->printMsg(msg.str(), debug::Priority::DETAIL);
712 }
713 }
714
715 return 0;
716}
717
719 const PointType pointType,
720 SubLevelSetTree &lowerTree,
721 SubLevelSetTree &upperTree,
722 const std::vector<int> &mandatoryExtremumVertex,
723 std::vector<std::pair<int, int>> &mandatorySaddleVertex,
724 std::vector<std::vector<int>> &mandatoryMergedExtrema) {
725
726 // Timer
727 Timer t;
728
729 // Object to handle requests for common ancestors
730 LowestCommonAncestor lowerLca;
731 lowerLca.setDebugLevel(debugLevel_);
732 LowestCommonAncestor upperLca;
733 upperLca.setDebugLevel(debugLevel_);
734
735 /*
736 - Add all mandatory extrema in the node list
737 - Find all possible saddles
738 - Find ancestor of each node
739 - Preprocess requests
740 - Compute each pair of extrema
741 */
742
743 const unsigned int extremaNumber = mandatoryExtremumVertex.size();
744
745 std::vector<int> upperSaddleList;
746 std::vector<int> lowerSaddleList;
747
748 std::vector<int> upperTransverse(upperTree.getNumberOfSuperArcs(), -1);
749 std::vector<int> lowerTransverse(lowerTree.getNumberOfSuperArcs(), -1);
750
751 std::vector<std::vector<int>> lowerToUpperLinks;
752 std::vector<std::vector<int>> upperToLowerLinks;
753
754 std::vector<std::vector<int>> mergedExtrema;
755
756 // NOTE-julien
757 // the loop below is not thread-safe.
758 // plus, for all tested examples, it turns out to be even faster in serial.
759 // #pragma omp parallel num_threads(threadNumber_)
760 {
761// Build the list of all saddles joining the extrema
762#ifdef TTK_ENABLE_OPENMP
763#pragma omp for
764#endif
765 for(int i = 0; i < (int)mandatoryExtremumVertex.size(); i++) {
766 // Super arc in upper and lower trees
767 int upperSuperArcId
768 = getVertexSuperArcId(mandatoryExtremumVertex[i], &upperTree);
769 int lowerSuperArcId
770 = getVertexSuperArcId(mandatoryExtremumVertex[i], &lowerTree);
771 bool saddleFound;
772 bool rootReached;
773 bool multipleSaddleFound;
774 // Upper Transverse
775 saddleFound = false;
776 multipleSaddleFound = false;
777 rootReached = false;
778 do {
779#ifdef TTK_ENABLE_OPENMP
780#pragma omp critical(upperTreeTransverse)
781#endif
782 {
783 // Check if it's the first time the super arc is visited
784 if(++upperTransverse[upperSuperArcId]) {
785 // If not, a saddle is found
786 saddleFound = true;
787 // If two or more previous visits, the saddle is already in the list
788 if(upperTransverse[upperSuperArcId] > 1) {
789 multipleSaddleFound = true;
790 }
791 }
792 }
793 if(!saddleFound) {
794 // Get the upper super arc
795 int const upNodeId
796 = upperTree.getSuperArc(upperSuperArcId)->getUpNodeId();
797 upperSuperArcId = upperTree.getNode(upNodeId)->getUpSuperArcId(0);
798 if(upperSuperArcId == -1) {
799 rootReached = true;
800 }
801 } else {
802 if(!multipleSaddleFound) {
803 int const saddleId
804 = upperTree.getSuperArc(upperSuperArcId)->getDownNodeId();
805#ifdef TTK_ENABLE_OPENMP
806#pragma omp critical
807#endif
808 upperSaddleList.push_back(saddleId);
809 }
810 }
811 } while(!(saddleFound || rootReached));
812 // Lower Transverse
813 saddleFound = false;
814 multipleSaddleFound = false;
815 rootReached = false;
816 do {
817#ifdef TTK_ENABLE_OPENMP
818#pragma omp critical(lowerTreeTransverse)
819#endif
820 {
821 // Check if it's the first time the super arc is visited
822 if(++lowerTransverse[lowerSuperArcId]) {
823 // If not, a saddle is found
824 saddleFound = true;
825 // If two or more previous visits, the saddle is already in the list
826 if(lowerTransverse[lowerSuperArcId] > 1) {
827 multipleSaddleFound = true;
828 }
829 }
830 }
831 if(!saddleFound) {
832 // Get the upper super arc
833 int const upNodeId
834 = lowerTree.getSuperArc(lowerSuperArcId)->getUpNodeId();
835 lowerSuperArcId = lowerTree.getNode(upNodeId)->getUpSuperArcId(0);
836 if(lowerSuperArcId == -1) {
837 rootReached = true;
838 }
839 } else {
840 if(!multipleSaddleFound) {
841 int const saddleId
842 = lowerTree.getSuperArc(lowerSuperArcId)->getDownNodeId();
843#ifdef TTK_ENABLE_OPENMP
844#pragma omp critical
845#endif
846 lowerSaddleList.push_back(saddleId);
847 }
848 }
849 } while(!(saddleFound || rootReached));
850 }
851 }
852
853 // NOTE-julien
854 // something is not thread-safe above
855
856#ifdef TTK_ENABLE_OPENMP
857#pragma omp parallel num_threads(threadNumber_)
858#endif
859 {
860 // Reinitialize the transverse arrays to -1
861
862#ifdef TTK_ENABLE_OPENMP
863#pragma omp for
864#endif
865 for(int i = 0; i < (int)upperTransverse.size(); i++) {
866 upperTransverse[i] = -1;
867 }
868
869#ifdef TTK_ENABLE_OPENMP
870#pragma omp for
871#endif
872 for(int i = 0; i < (int)lowerTransverse.size(); i++) {
873 lowerTransverse[i] = -1;
874 }
875
876// Mark the super arcs with the id of the saddle
877#ifdef TTK_ENABLE_OPENMP
878#pragma omp for
879#endif
880 for(int i = 0; i < (int)upperSaddleList.size(); i++) {
881 int const superArcId
882 = upperTree.getNode(upperSaddleList[i])->getUpSuperArcId(0);
883 upperTransverse[superArcId] = i;
884 }
885
886#ifdef TTK_ENABLE_OPENMP
887#pragma omp for
888#endif
889 for(int i = 0; i < (int)lowerSaddleList.size(); i++) {
890 int const superArcId
891 = lowerTree.getNode(lowerSaddleList[i])->getUpSuperArcId(0);
892 lowerTransverse[superArcId] = i;
893 }
894
895// Create the nodes in the LCA object
896#ifdef TTK_ENABLE_OPENMP
897#pragma omp sections
898#endif
899 {
900// Upper lca
901#ifdef TTK_ENABLE_OPENMP
902#pragma omp section
903#endif
904 {
905 upperLca.addNodes(mandatoryExtremumVertex.size()
906 + upperSaddleList.size());
907 }
908// Lower lca
909#ifdef TTK_ENABLE_OPENMP
910#pragma omp section
911#endif
912 {
913 lowerLca.addNodes(mandatoryExtremumVertex.size()
914 + lowerSaddleList.size());
915 }
916 }
917
918// For each extrema, find it's first up saddle
919#ifdef TTK_ENABLE_OPENMP
920#pragma omp for
921#endif
922 for(int i = 0; i < (int)mandatoryExtremumVertex.size(); i++) {
923 int superArcId;
924 int lcaSaddleId;
925 // Upper Tree
926 superArcId = getVertexSuperArcId(mandatoryExtremumVertex[i], &upperTree);
927 while((superArcId != -1) && (upperTransverse[superArcId] == -1)) {
928 int const nodeId = upperTree.getSuperArc(superArcId)->getUpNodeId();
929 superArcId = upperTree.getNode(nodeId)->getUpSuperArcId(0);
930 }
931 if(superArcId != -1) {
932 lcaSaddleId = extremaNumber + upperTransverse[superArcId];
933 // Ancestor
934 upperLca.getNode(i).setAncestor(lcaSaddleId);
935// Successor
936#ifdef TTK_ENABLE_OPENMP
937#pragma omp critical(upperLca)
938#endif
939 upperLca.getNode(lcaSaddleId).addSuccessor(i);
940 }
941
942 // Lower Tree
943 superArcId = getVertexSuperArcId(mandatoryExtremumVertex[i], &lowerTree);
944 while((superArcId != -1) && (lowerTransverse[superArcId] == -1)) {
945 int const nodeId = lowerTree.getSuperArc(superArcId)->getUpNodeId();
946 superArcId = lowerTree.getNode(nodeId)->getUpSuperArcId(0);
947 }
948 if(superArcId != -1) {
949 lcaSaddleId = extremaNumber + lowerTransverse[superArcId];
950 // Ancestor
951 lowerLca.getNode(i).setAncestor(lcaSaddleId);
952// Successor
953#ifdef TTK_ENABLE_OPENMP
954#pragma omp critical(lowerLca)
955#endif
956 lowerLca.getNode(lcaSaddleId).addSuccessor(i);
957 }
958 }
959
960// For each saddle, find it's first up saddle
961#ifdef TTK_ENABLE_OPENMP
962#pragma omp for
963#endif
964 for(int i = 0; i < (int)upperSaddleList.size(); i++) {
965 int superArcId
966 = upperTree.getNode(upperSaddleList[i])->getUpSuperArcId(0);
967 do {
968 int const nodeId = upperTree.getSuperArc(superArcId)->getUpNodeId();
969 superArcId = upperTree.getNode(nodeId)->getUpSuperArcId(0);
970 } while((superArcId != -1) && (upperTransverse[superArcId] == -1));
971 if(superArcId != -1) {
972 int const lcaSuccessorSaddleId = extremaNumber + i;
973 int const lcaAncestorSaddleId
974 = extremaNumber + upperTransverse[superArcId];
975 // Ancestor
976 upperLca.getNode(lcaSuccessorSaddleId).setAncestor(lcaAncestorSaddleId);
977// Successor
978#ifdef TTK_ENABLE_OPENMP
979#pragma omp critical(upperLca)
980#endif
981 upperLca.getNode(lcaAncestorSaddleId)
982 .addSuccessor(lcaSuccessorSaddleId);
983 }
984 }
985
986#ifdef TTK_ENABLE_OPENMP
987#pragma omp for
988#endif
989 for(int i = 0; i < (int)lowerSaddleList.size(); i++) {
990 int superArcId
991 = lowerTree.getNode(lowerSaddleList[i])->getUpSuperArcId(0);
992 do {
993 int const nodeId = lowerTree.getSuperArc(superArcId)->getUpNodeId();
994 superArcId = lowerTree.getNode(nodeId)->getUpSuperArcId(0);
995 } while((superArcId != -1) && (lowerTransverse[superArcId] == -1));
996 if(superArcId != -1) {
997 int const lcaSuccessorSaddleId = extremaNumber + i;
998 int const lcaAncestorSaddleId
999 = extremaNumber + lowerTransverse[superArcId];
1000 // Ancestor
1001 lowerLca.getNode(lcaSuccessorSaddleId).setAncestor(lcaAncestorSaddleId);
1002// Successor
1003#ifdef TTK_ENABLE_OPENMP
1004#pragma omp critical(lowerLca)
1005#endif
1006 lowerLca.getNode(lcaAncestorSaddleId)
1007 .addSuccessor(lcaSuccessorSaddleId);
1008 }
1009 }
1010
1011// Preprocess lowest common ancestors requests
1012#ifdef TTK_ENABLE_OPENMP
1013#pragma omp sections
1014#endif
1015 {
1016#ifdef TTK_ENABLE_OPENMP
1017#pragma omp section
1018#endif
1019 { upperLca.preprocess(); }
1020#ifdef TTK_ENABLE_OPENMP
1021#pragma omp section
1022#endif
1023 { lowerLca.preprocess(); }
1024 }
1025
1026 // Link lists for each thread
1027 std::vector<std::vector<int>> localLowerToUpperLinks;
1028 std::vector<std::vector<int>> localUpperToLowerLinks;
1029 // Merged extrema list for each thread (lower saddles only)
1030 std::vector<std::vector<int>> localMergedExtrema;
1031 // Resize of lists
1032 localLowerToUpperLinks.resize(lowerSaddleList.size());
1033 localUpperToLowerLinks.resize(upperSaddleList.size());
1034 localMergedExtrema.resize(lowerSaddleList.size());
1035 // Number of iterations (triangular loop without diagonal)
1036 unsigned int const kmax = (extremaNumber * (extremaNumber - 1)) / 2;
1037// Loop over pairs of extrema
1038#ifdef TTK_ENABLE_OPENMP
1039#pragma omp for
1040#endif
1041 for(int k = 0; k < (int)kmax; k++) {
1042 unsigned int i = k / extremaNumber;
1043 unsigned int j = k % extremaNumber;
1044 if(j <= i) {
1045 i = extremaNumber - i - 2;
1046 j = extremaNumber - j - 1;
1047 }
1048 int const uppLCA = upperLca.query(i, j) - extremaNumber;
1049 int const lowLCA = lowerLca.query(i, j) - extremaNumber;
1050 localLowerToUpperLinks[lowLCA].push_back(uppLCA);
1051 localUpperToLowerLinks[uppLCA].push_back(lowLCA);
1052 localMergedExtrema[lowLCA].push_back(i);
1053 localMergedExtrema[lowLCA].push_back(j);
1054 }
1055
1056// Cleaning of duplicates and fusion of vectors
1057#ifdef TTK_ENABLE_OPENMP
1058#pragma omp single
1059#endif
1060 {
1061 lowerToUpperLinks.resize(lowerSaddleList.size());
1062 upperToLowerLinks.resize(upperSaddleList.size());
1063 mergedExtrema.resize(lowerSaddleList.size());
1064 }
1065 // Lower -> Upper
1066 for(unsigned int i = 0; i < localLowerToUpperLinks.size(); i++) {
1067 std::vector<int>::iterator newEnd;
1068 newEnd = unique(
1069 localLowerToUpperLinks[i].begin(), localLowerToUpperLinks[i].end());
1070#ifdef TTK_ENABLE_OPENMP
1071#pragma omp critical(lowerToUpperFusion)
1072#endif
1073 {
1074 lowerToUpperLinks[i].insert(
1075 lowerToUpperLinks[i].end(),
1076 make_move_iterator(localLowerToUpperLinks[i].begin()),
1077 make_move_iterator(newEnd));
1078 }
1079 localLowerToUpperLinks[i].clear();
1080 }
1081 localLowerToUpperLinks.clear();
1082 // Upper -> Lower
1083 for(unsigned int i = 0; i < localUpperToLowerLinks.size(); i++) {
1084 std::vector<int>::iterator newEnd;
1085 newEnd = unique(
1086 localUpperToLowerLinks[i].begin(), localUpperToLowerLinks[i].end());
1087#ifdef TTK_ENABLE_OPENMP
1088#pragma omp critical(upperToLowerFusion)
1089#endif
1090 {
1091 upperToLowerLinks[i].insert(
1092 upperToLowerLinks[i].end(),
1093 make_move_iterator(localUpperToLowerLinks[i].begin()),
1094 make_move_iterator(newEnd));
1095 }
1096 localUpperToLowerLinks[i].clear();
1097 }
1098 localUpperToLowerLinks.clear();
1099 // Merged extrema
1100 for(unsigned int i = 0; i < localMergedExtrema.size(); i++) {
1101 std::vector<int>::iterator newEnd;
1102 std::sort(localMergedExtrema[i].begin(), localMergedExtrema[i].end());
1103 newEnd
1104 = unique(localMergedExtrema[i].begin(), localMergedExtrema[i].end());
1105#ifdef TTK_ENABLE_OPENMP
1106#pragma omp critical(mergedExtremaFusion)
1107#endif
1108 {
1109 mergedExtrema[i].insert(
1110 mergedExtrema[i].end(),
1111 make_move_iterator(localMergedExtrema[i].begin()),
1112 make_move_iterator(newEnd));
1113 }
1114 localMergedExtrema[i].clear();
1115 }
1116 localMergedExtrema.clear();
1117 } // End of omp parallel
1118
1119 // NOTE-julien:
1120 // something is not thread-safe above
1121 // the code below is thread-safe
1122
1123 // Breadth-first search to identify connected components
1124 std::vector<bool> isLowerVisited(lowerSaddleList.size(), false);
1125 std::vector<bool> isUpperVisited(upperSaddleList.size(), false);
1126 std::vector<std::vector<int>> lowComponent;
1127 std::vector<std::vector<int>> uppComponent;
1128 for(unsigned int i = 0; i < lowerSaddleList.size(); i++) {
1129 if(!isLowerVisited[i]) {
1130 // New component
1131 lowComponent.emplace_back();
1132 uppComponent.emplace_back();
1133 int const componentId = static_cast<int>(lowComponent.size()) - 1;
1134 lowComponent[componentId].push_back(i);
1135 isLowerVisited[i] = true;
1136 // Lists of neighbors
1137 std::vector<int> nextList;
1138 std::vector<int> currentList;
1139 currentList.push_back(i);
1140 // Pointers
1141 std::vector<bool> *isVisited = &(isUpperVisited);
1142 std::vector<std::vector<int>> *component = &(uppComponent);
1143 std::vector<std::vector<int>> *linkList = &(lowerToUpperLinks);
1144 while(!currentList.empty()) {
1145 // For each entry in the list
1146 for(unsigned int j = 0; j < currentList.size(); j++) {
1147 // For each neighbors
1148 for(unsigned int k = 0; k < (*linkList)[currentList[j]].size(); k++) {
1149 // Get the neighbor id;
1150 int const neighbor = (*linkList)[currentList[j]][k];
1151 // Check if it's already visited
1152 if(!(*isVisited)[neighbor]) {
1153 // If not visited, mark it and add it
1154 (*isVisited)[neighbor] = true;
1155 (*component)[componentId].push_back(neighbor);
1156 nextList.push_back(neighbor);
1157 }
1158 }
1159 }
1160 // Swap pointers and lists
1161 isVisited = (isVisited == &(isUpperVisited)) ? &(isLowerVisited)
1162 : &(isUpperVisited);
1163 component
1164 = (component == &(uppComponent)) ? &(lowComponent) : &(uppComponent);
1165 linkList = (linkList == &(lowerToUpperLinks)) ? &(upperToLowerLinks)
1166 : &(lowerToUpperLinks);
1167 currentList.swap(nextList);
1168 nextList.clear();
1169 }
1170 }
1171 }
1172
1173 // Find pairs of vertices and list of merged extrema
1174 int const numberOfComponents = static_cast<int>(lowComponent.size());
1175 mandatorySaddleVertex.resize(numberOfComponents, std::pair<int, int>(-1, -1));
1176 std::vector<std::vector<int>> mandatoryMergedExtrema_tmp;
1177 mandatoryMergedExtrema_tmp.resize(numberOfComponents, std::vector<int>());
1178
1179 for(int i = 0; i < numberOfComponents; i++) {
1180 int nodeId;
1181 // Find the vertex with minimum value in f-
1182 nodeId = lowerSaddleList[lowComponent[i][0]];
1183 mandatorySaddleVertex[i].first = lowerTree.getNode(nodeId)->getVertexId();
1184 for(unsigned int j = 0; j < lowComponent[i].size(); j++) {
1185 // First saddle
1186 int const nId = lowerSaddleList[lowComponent[i][j]];
1187 double const nodeScalar = lowerTree.getNodeScalar(nId);
1188 double refScalar = 0;
1189 lowerTree.getVertexScalar(mandatorySaddleVertex[i].first, refScalar);
1190 if(nodeScalar < refScalar) {
1191 mandatorySaddleVertex[i].first = lowerTree.getNode(nId)->getVertexId();
1192 }
1193 }
1194
1195 for(unsigned int j = 0; j < lowComponent[i].size(); j++) {
1196 mandatoryMergedExtrema_tmp[i].insert(
1197 mandatoryMergedExtrema_tmp[i].end(),
1198 make_move_iterator(mergedExtrema[lowComponent[i][j]].begin()),
1199 make_move_iterator(mergedExtrema[lowComponent[i][j]].end()));
1200 mergedExtrema[lowComponent[i][j]].clear();
1201 }
1202
1203 // Find the vertex with maximum value in f+
1204 nodeId = upperSaddleList[uppComponent[i][0]];
1205 mandatorySaddleVertex[i].second = upperTree.getNode(nodeId)->getVertexId();
1206 for(unsigned int j = 0; j < uppComponent[i].size(); j++) {
1207 // First saddle
1208 int const nId = upperSaddleList[uppComponent[i][j]];
1209 double const nodeScalar = upperTree.getNodeScalar(nId);
1210 double refScalar = 0;
1211 upperTree.getVertexScalar(mandatorySaddleVertex[i].second, refScalar);
1212 if(nodeScalar > refScalar) {
1213 mandatorySaddleVertex[i].second = upperTree.getNode(nId)->getVertexId();
1214 }
1215 }
1216 }
1217
1218 // Sort the merged extrema list
1219 std::vector<std::pair<int, int>> order;
1220 for(unsigned int i = 0; i < mandatoryMergedExtrema_tmp.size(); i++) {
1221 std::sort(mandatoryMergedExtrema_tmp[i].begin(),
1222 mandatoryMergedExtrema_tmp[i].end());
1223 std::vector<int>::iterator const newEnd
1224 = unique(mandatoryMergedExtrema_tmp[i].begin(),
1225 mandatoryMergedExtrema_tmp[i].end());
1226 mandatoryMergedExtrema_tmp[i].resize(
1227 distance(mandatoryMergedExtrema_tmp[i].begin(), newEnd));
1228 mandatoryMergedExtrema_tmp[i].shrink_to_fit();
1229 order.emplace_back(i, mandatoryMergedExtrema_tmp[i].size());
1230 }
1231 // Sort by number of merged extrema
1232 mandatorySaddleComparison const cmp;
1233 std::sort(order.begin(), order.end(), cmp);
1234 // Reorder for output
1235 mandatoryMergedExtrema.clear();
1236 mandatoryMergedExtrema.resize(mandatoryMergedExtrema_tmp.size());
1237 for(unsigned int i = 0; i < order.size(); i++) {
1238 mandatoryMergedExtrema_tmp[order[i].first].swap(mandatoryMergedExtrema[i]);
1239 }
1240
1241// Getting global max and min
1242#ifdef TTK_ENABLE_OPENMP
1243#pragma omp parallel sections
1244#endif
1245 {
1246#ifdef TTK_ENABLE_OPENMP
1247#pragma omp section
1248#endif
1249 {
1250 if(upperMaximumList_.size()) {
1252 for(size_t i = 0; i < upperMaximumList_.size(); i++) {
1255 }
1256 }
1257 }
1258 }
1259#ifdef TTK_ENABLE_OPENMP
1260#pragma omp section
1261#endif
1262 {
1263 if(lowerMinimumList_.size()) {
1265 for(size_t i = 0; i < lowerMinimumList_.size(); i++) {
1268 }
1269 }
1270 }
1271 }
1272 }
1273
1274 const std::string st
1275 = pointType == PointType::JoinSaddle ? "join saddles" : "split saddles";
1276
1277 this->printMsg("Computed " + std::to_string(mandatorySaddleVertex.size())
1278 + " mandatory " + st,
1279 1.0, t.getElapsedTime(), this->threadNumber_);
1280
1281 this->printMsg("List of " + st + ":", debug::Priority::DETAIL);
1282 for(size_t i = 0; i < mandatorySaddleVertex.size(); i++) {
1283 std::stringstream msg;
1284 msg << " -> " << st << " (";
1285 msg << std::setw(3) << std::right << i << ")";
1286 msg << " Vertices <";
1287 msg << std::setw(9) << std::right << mandatorySaddleVertex[i].first
1288 << " ; ";
1289 msg << std::setw(9) << std::left << mandatorySaddleVertex[i].second << ">";
1290 msg << " Interval [";
1291 double lowerValue = 0;
1292 double upperValue = 0;
1293 lowerTree.getVertexScalar(mandatorySaddleVertex[i].first, lowerValue);
1294 upperTree.getVertexScalar(mandatorySaddleVertex[i].second, upperValue);
1295 msg << std::setw(12) << std::right << lowerValue << " ; ";
1296 msg << std::setw(12) << std::left << upperValue << "]";
1297 this->printMsg(msg.str(), debug::Priority::DETAIL);
1298 }
1299
1300 return 0;
1301}
1302
1304 const SubLevelSetTree *tree,
1305 const int &startingSuperArcId,
1306 const double &targetValue) const {
1307 // Starting to the input super arc id
1308 int superArcId = startingSuperArcId;
1309 // If the super arc exists
1310 if(superArcId != -1) {
1311 // Id of the node at the top of the super arc
1312 int upNodeId = tree->getSuperArc(superArcId)->getUpNodeId();
1313 // Value of the vertex associated with the node
1314 double upNodeValue = tree->getNodeScalar(upNodeId);
1315 // While condition
1316 int const sign = tree->isJoinTree() ? 1 : -1;
1317 // Climb up the tree
1318 while(!((sign * targetValue) < (sign * upNodeValue))) {
1319 int const numberOfUpSuperArcs
1320 = tree->getNode(upNodeId)->getNumberOfUpSuperArcs();
1321 if(numberOfUpSuperArcs > 0) {
1322 superArcId = tree->getNode(upNodeId)->getUpSuperArcId(0);
1323 upNodeId = tree->getSuperArc(superArcId)->getUpNodeId();
1324 upNodeValue = tree->getNodeScalar(upNodeId);
1325 } else {
1326 break;
1327 }
1328 }
1329 return superArcId;
1330 }
1331 return -1;
1332}
1333
1335 const SubLevelSetTree *tree,
1336 const int &vertexId0,
1337 const int &vertexId1) const {
1338 int const numberOfSuperArcs = tree->getNumberOfSuperArcs();
1339 std::vector<bool> isSuperArcVisited(numberOfSuperArcs, false);
1340 int const superArcId0 = getVertexSuperArcId(vertexId0, tree);
1341 int const superArcId1 = getVertexSuperArcId(vertexId1, tree);
1342 int superArcId = superArcId0;
1343 do {
1344 isSuperArcVisited[superArcId] = true;
1345 superArcId = tree->getNode(tree->getSuperArc(superArcId)->getUpNodeId())
1346 ->getUpSuperArcId(0);
1347 } while(superArcId != -1);
1348 superArcId = superArcId1;
1349 while(!isSuperArcVisited[superArcId]) {
1350 superArcId = tree->getNode(tree->getSuperArc(superArcId)->getUpNodeId())
1351 ->getUpSuperArcId(0);
1352 }
1353 return tree->getSuperArc(superArcId)->getDownNodeId();
1354}
1355
1357 const SubLevelSetTree *tree,
1358 const int &rootSuperArcId,
1359 std::vector<int> &subTreeSuperArcId) const {
1360 std::vector<int> listOfSuperArcId;
1361 std::queue<int> superArcIdsToCompute;
1362 superArcIdsToCompute.push(rootSuperArcId);
1363 while(!superArcIdsToCompute.empty()) {
1364 int const superArcId = superArcIdsToCompute.front();
1365 int const downNodeId = tree->getSuperArc(superArcId)->getDownNodeId();
1366 int const numberOfUpSuperArcs
1367 = tree->getNode(downNodeId)->getNumberOfDownSuperArcs();
1368 if(numberOfUpSuperArcs > 0) {
1369 for(int i = 0; i < numberOfUpSuperArcs; i++)
1370 superArcIdsToCompute.push(
1371 tree->getNode(downNodeId)->getDownSuperArcId(i));
1372 }
1373 listOfSuperArcId.push_back(superArcId);
1374 superArcIdsToCompute.pop();
1375 }
1376 listOfSuperArcId.swap(subTreeSuperArcId);
1377}
1378
1380 const double normalizedThreshold,
1381 const TreeType treeType,
1382 const std::vector<std::pair<std::pair<int, int>, double>> &extremaSaddlePair,
1383 const std::vector<std::vector<int>> &mergedExtrema,
1384 const int numberOfExtrema,
1385 std::vector<bool> &extremumSimplified,
1386 std::vector<bool> &saddleSimplified,
1387 std::vector<int> &extremumParentSaddle,
1388 std::vector<int> &saddleParentSaddle) const {
1389
1390 // Simplification threshold value
1391 double simplificationThreshold;
1392 if(normalizedThreshold > 1.0)
1393 simplificationThreshold = (globalMaximumValue_ - globalMinimumValue_);
1394 else if(normalizedThreshold < 0.0)
1395 simplificationThreshold = 0.0;
1396 else
1397 simplificationThreshold
1398 = (globalMaximumValue_ - globalMinimumValue_) * normalizedThreshold;
1399
1400 int extremaSimplifiedNumber = 0;
1401 int saddlesSimplifiedNumber = 0;
1402
1403 // First : simplification of extrema
1404 extremumSimplified.resize(numberOfExtrema);
1405 fill(extremumSimplified.begin(), extremumSimplified.end(), false);
1406 for(size_t i = 0; i < extremaSaddlePair.size(); i++) {
1407 if(extremaSaddlePair[i].second < simplificationThreshold) {
1408 extremumSimplified[extremaSaddlePair[i].first.first] = true;
1409 extremaSimplifiedNumber++;
1410 } else
1411 break;
1412 }
1413
1414 // Second : simplification of saddles
1415 saddleSimplified.resize(mergedExtrema.size());
1416 fill(saddleSimplified.begin(), saddleSimplified.end(), false);
1417 std::vector<int> nonSimplifiedExtremaNumber(mergedExtrema.size(), 0);
1418 extremumParentSaddle.resize(numberOfExtrema);
1419 fill(extremumParentSaddle.begin(), extremumParentSaddle.end(), -1);
1420 saddleParentSaddle.resize(mergedExtrema.size());
1421 fill(saddleParentSaddle.begin(), saddleParentSaddle.end(), -1);
1422 for(size_t i = 0; i < mergedExtrema.size(); i++) {
1423 saddleParentSaddle[i] = i;
1424 for(size_t j = 0; j < mergedExtrema[i].size(); j++) {
1425 if(!extremumSimplified[mergedExtrema[i][j]])
1426 nonSimplifiedExtremaNumber[i]++;
1427 }
1428 if(nonSimplifiedExtremaNumber[i] > 1) {
1429 // Find one non simplified extremum to test
1430 int extremum = 0;
1431 while(extremumSimplified[mergedExtrema[i][extremum]]) {
1432 extremum++;
1433 }
1434 if(!(extremumParentSaddle[mergedExtrema[i][extremum]] == -1)) {
1435 // Find the root
1436 int rootSaddleId = extremumParentSaddle[mergedExtrema[i][extremum]];
1437 int lastSaddleId = -1;
1438 while(rootSaddleId != lastSaddleId) {
1439 lastSaddleId = rootSaddleId;
1440 rootSaddleId = saddleParentSaddle[rootSaddleId];
1441 }
1442 // Compare the number of merged extrema
1443 if(!(nonSimplifiedExtremaNumber[i]
1444 > nonSimplifiedExtremaNumber[rootSaddleId])) {
1445 saddleSimplified[i] = true;
1446 saddlesSimplifiedNumber++;
1447 }
1448 }
1449 } else {
1450 saddleSimplified[i] = true;
1451 saddlesSimplifiedNumber++;
1452 }
1453 if(!saddleSimplified[i]) {
1454 for(size_t j = 0; j < mergedExtrema[i].size(); j++) {
1455 int const extremaId = mergedExtrema[i][j];
1456 if(!extremumSimplified[extremaId]) {
1457 // If the extrema is not already connected, define the parent
1458 if(extremumParentSaddle[extremaId] == -1) {
1459 extremumParentSaddle[extremaId] = i;
1460 } else {
1461 // Find the root
1462 int rootSaddleId = extremumParentSaddle[extremaId];
1463 int lastSaddleId = -1;
1464 while(rootSaddleId != lastSaddleId) {
1465 lastSaddleId = rootSaddleId;
1466 rootSaddleId = saddleParentSaddle[rootSaddleId];
1467 }
1468 // Link the root to the processed saddle
1469 saddleParentSaddle[rootSaddleId] = i;
1470 }
1471 }
1472 }
1473 }
1474 }
1475
1476 const std::string pt = treeType == TreeType::JoinTree ? "minima" : "maxima";
1477
1478 this->printMsg(
1479 "#Simplified " + pt + ": " + std::to_string(extremaSimplifiedNumber)
1480 + " (threshold value = " + std::to_string(simplificationThreshold) + ")");
1481
1482 if(extremaSimplifiedNumber > 0) {
1483 this->printMsg("List of simplified " + pt + ":", debug::Priority::DETAIL);
1484 for(size_t i = 0; i < extremumSimplified.size(); i++) {
1485 if(extremumSimplified[i]) {
1486 std::stringstream msg;
1487 msg << " (" << i << ")";
1488 this->printMsg(msg.str(), debug::Priority::DETAIL);
1489 }
1490 }
1491 }
1492
1493 const std::string st
1494 = treeType == TreeType::JoinTree ? "join saddles" : "split saddles";
1495
1496 this->printMsg(
1497 "#Simplified " + st + ": " + std::to_string(saddlesSimplifiedNumber)
1498 + " (threshold value = " + std::to_string(simplificationThreshold) + ")");
1499
1500 if(saddlesSimplifiedNumber > 0) {
1501 this->printMsg("List of simplified " + st + ":", debug::Priority::DETAIL);
1502 for(size_t i = 0; i < saddleSimplified.size(); i++) {
1503 if(saddleSimplified[i]) {
1504 std::stringstream msg;
1505 msg << " (" << i << ")";
1506 this->printMsg(msg.str(), debug::Priority::DETAIL);
1507 }
1508 }
1509 }
1510
1511 return 0;
1512}
int getUpNodeId() const
Definition ContourTree.h:38
int getDownNodeId() const
Definition ContourTree.h:34
int debugLevel_
Definition Debug.h:379
int printWrn(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:159
void setDebugMsgPrefix(const std::string &prefix)
Definition Debug.h:364
virtual int setDebugLevel(const int &debugLevel)
Definition Debug.cpp:147
const std::pair< int, int > & getVertexIdx() const
int getEdgeIdx(const int &connectedEdge) const
const Edge & getEdge(const int idx) const
int addEdge(const int &start, const int &end)
Add an edge between the vertex start and end, returns it's index.
const Vertex & getVertex(const int idx) const
Get a pointer to the vertex idx.
int addVertex()
Add a vertex, returns it's index.
int getNumberOfVertices() const
int getNumberOfEdges() const
Class to answer the lowest common ancestor requests of pairs of nodes in a tree in constant time afte...
int query(int i, int j) const
Node & getNode(const unsigned int &id)
void addNodes(const unsigned int &number)
std::vector< std::pair< int, int > > mandatorySplitSaddleVertex_
Pair of mandatory vertices for each split saddle component.
std::vector< std::pair< std::pair< int, int >, double > > mdtMaxSplitSaddlePair_
Pairs ( (M,S), d(M,S) ) Of maxima and split saddles.
std::vector< double > mdtJoinTreePointXCoord_
std::vector< std::vector< int > > mandatoryMinimumComponentVertices_
std::vector< double > mdtSplitTreePointLowInterval_
std::vector< double > mdtJoinTreePointLowInterval_
int computePlanarLayout(const TreeType &treeType, const Graph &mdtTree, const std::vector< PointType > &mdtTreePointType, const std::vector< double > &mdtTreePointLowInterval, const std::vector< double > &mdtTreePointUpInterval, std::vector< double > &xCoord, std::vector< double > &yCoord) const
int enumerateMandatorySaddles(const PointType pointType, SubLevelSetTree &lowerTree, SubLevelSetTree &upperTree, const std::vector< int > &mandatoryExtremumVertex, std::vector< std::pair< int, int > > &mandatorySaddleVertex, std::vector< std::vector< int > > &mandatoryMergedExtrema)
TODO : Multiplicity.
std::vector< PointType > mdtJoinTreePointType_
bool areSaddlesSwitchables(const TreeType treeType, const int &firstId, const int &secondId) const
int enumerateMandatoryExtrema(const PointType pointType, SubLevelSetTree &firstTree, SubLevelSetTree &secondTree, std::vector< int > &mandatoryExtremum, std::vector< std::pair< double, double > > &criticalInterval) const
std::vector< std::vector< double > > vertexPositions_
Position (x,y,z) of each vertex.
std::vector< std::vector< int > > mandatoryMaximumComponentVertices_
List of the vertices forming each of the mandatory maximum components.
int buildMandatoryTree(const TreeType treeType, Graph &mdtTree, std::vector< int > &mdtTreePointComponentId, std::vector< PointType > &mdtTreePointType, std::vector< double > &mdtTreePointLowInterval, std::vector< double > &mdtTreePointUpInterval, std::vector< int > &mdtTreeEdgeSwitchable, const std::vector< int > &mdtExtremumParentSaddle, const std::vector< int > &mdtSaddleParentSaddle, const std::vector< bool > &isExtremumSimplified, const std::vector< bool > &isSaddleSimplified, const std::vector< std::pair< double, double > > &extremumInterval, const std::vector< std::pair< int, int > > &mandatorySaddleVertices, const int extremaNumber, const int saddleNumber, const PointType extremumType, const PointType saddleType, const PointType otherExtremumType, const double globalOtherExtremumValue) const
int * outputMandatoryMinimum_
Void pointer to the output mandatory minima components.
int getVertexSuperArcId(const int &vertexId, const SubLevelSetTree *tree) const
std::vector< int > mdtSplitSaddleParentSaddleId_
void getSubTreeSuperArcIds(const SubLevelSetTree *tree, const int &rootSuperArcId, std::vector< int > &subTreeSuperArcId) const
SubLevelSetTree lowerJoinTree_
Join tree of the lower bound scalar field.
std::vector< std::vector< int > > mergedMinimaId_
std::vector< int > upperMinimumList_
List of vertex id of the minima in the upper bound scalar field.
void * inputUpperBoundField_
Void pointer to the input upper bound scalar field.
int * outputMandatoryJoinSaddle_
Void pointer to the output mandatory join saddles components.
std::vector< int > mdtJoinSaddleParentSaddleId_
SubLevelSetTree lowerSplitTree_
Split tree of the lower bound scalar field.
std::vector< PointType > mdtSplitTreePointType_
void * inputLowerBoundField_
Void pointer to the input lower bound scalar field.
std::vector< std::pair< std::pair< int, int >, double > > mdtMinJoinSaddlePair_
Pairs ( (M,S), d(M,S) ) Of minima and join saddles.
int simplify(const double normalizedThreshold, const TreeType treeType, const std::vector< std::pair< std::pair< int, int >, double > > &extremaSaddlePair, const std::vector< std::vector< int > > &mergedExtrema, const int numberOfExtrema, std::vector< bool > &extremumSimplified, std::vector< bool > &saddleSimplified, std::vector< int > &extremumParentSaddle, std::vector< int > &saddleParentSaddle) const
std::vector< int > lowerMaximumList_
List of vertex id of the maxima in the lower bound scalar field.
std::vector< double > upperVertexScalars_
Copy of the input upper scalar field converted in double.
std::vector< double > mdtJoinTreePointUpInterval_
std::vector< int > mdtJoinTreePointComponentId_
std::vector< double > lowerVertexScalars_
Copy of the input lower scalar field converted in double.
std::vector< bool > isMdtSplitSaddleSimplified_
double normalizedThreshold_
Value of the simplification threshold.
SubLevelSetTree upperJoinTree_
Join tree of the upper bound scalar field.
int findCommonAncestorNodeId(const SubLevelSetTree *tree, const int &vertexId0, const int &vertexId1) const
std::vector< int > mdtSplitTreePointComponentId_
std::vector< std::pair< int, int > > mandatoryJoinSaddleVertex_
Pair of mandatory vertices for each join saddle component.
SubLevelSetTree upperSplitTree_
Split tree of the upper bound scalar field.
std::vector< int > vertexSoSoffsets_
Offsets.
std::vector< std::pair< double, double > > mandatoryMaximumInterval_
Critical interval for each maximum component.
int getSubTreeRootSuperArcId(const SubLevelSetTree *tree, const int &startingSuperArcId, const double &targetValue) const
std::vector< double > mdtSplitTreePointXCoord_
int computeExtremumComponent(const PointType &pointType, const SubLevelSetTree &tree, const int seedVertexId, const std::vector< double > &vertexScalars, std::vector< int > &componentVertexList) const
int buildPairs(const TreeType treeType, const std::vector< std::pair< int, int > > &saddleList, const std::vector< std::vector< int > > &mergedExtrema, const std::vector< std::pair< double, double > > &extremumInterval, SubLevelSetTree &lowerTree, SubLevelSetTree &upperTree, std::vector< std::pair< std::pair< int, int >, double > > &extremaSaddlePair) const
TODO : Replace SubLevelSetTrees by scalar fields for vertex value.
std::vector< std::vector< int > > mandatorySplitSaddleComponentVertices_
std::vector< int > lowerMinimumList_
List of vertex id of the minima in the lower bound scalar field.
int * outputMandatorySplitSaddle_
Void pointer to the output mandatory split saddles components.
std::vector< std::vector< int > > mandatoryJoinSaddleComponentVertices_
std::vector< std::vector< int > > mergedMaximaId_
std::vector< std::pair< double, double > > mandatoryMinimumInterval_
Critical interval for each minimum component.
std::vector< double > mdtSplitTreePointYCoord_
std::vector< double > mdtJoinTreePointYCoord_
std::vector< double > mdtSplitTreePointUpInterval_
int * outputMandatoryMaximum_
Void pointer to the output mandatory maxima components.
std::vector< bool > isMdtJoinSaddleSimplified_
std::vector< int > upperMaximumList_
List of vertex id of the maxima in the upper bound scalar field.
std::vector< int > mandatoryMinimumVertex_
Mandatory vertex for each minimum component.
std::vector< int > mandatoryMaximumVertex_
Mandatory vertex for each maximum component.
int getUpSuperArcId(const int &neighborId) const
int getNumberOfDownSuperArcs() const
int getVertexId() const
int getNumberOfUpSuperArcs() const
int getDownSuperArcId(const int &neighborId) const
bool isSplitTree() const
const std::vector< int > * getExtremumList() const
const Node * getNode(const int &nodeId) const
double getNodeScalar(const int &nodeId) const
int getNumberOfSuperArcs() const
bool isJoinTree() const
const SuperArc * getSuperArc(const int &superArcId) const
int getVertexScalar(const int &vertexId, double &scalar)
int getNumberOfRegularNodes() const
Definition ContourTree.h:70
int getRegularNodeId(const int &arcNodeId) const
Definition ContourTree.h:82
double getElapsedTime()
Definition Timer.h:15
std::string to_string(__int128)
Definition ripserpy.cpp:99
The Topology ToolKit.
T end(std::pair< T, T > &p)
Definition ripserpy.cpp:472
T begin(std::pair< T, T > &p)
Definition ripserpy.cpp:468
Comparison between critical point pairs ( (Extremum,Saddle), dist(M,S) )
Comparison between mandatory saddles (Saddle id, Number of merged extrema)
Comparison of the second member of a std::pair<int,double>
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)