TTK
Loading...
Searching...
No Matches
MandatoryCriticalPoints.cpp
Go to the documentation of this file.
2
3using namespace ttk;
4
6 this->setDebugMsgPrefix("MandatoryCriticalPoints");
11}
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 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 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 lowerVertex = mandatorySaddleVertices[parentSaddle].first;
133 int 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 lowerVertex = mandatorySaddleVertices[i].first;
176 int 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 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 lowerVertex = mandatorySaddleVertices[parentSaddle].first;
191 int 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 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 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 graphPoint = graphPointQueue.front();
394 graphPointQueue.pop();
395
396 // Number Of Down Edges
397 int numberOfEdges = mdtTree.getVertex(graphPoint).getNumberOfEdges();
398 int numberOfDownEdges = 0;
399 for(int i = 0; i < numberOfEdges; i++) {
400 int 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 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 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 superArcId = getVertexSuperArcId(seedVertexId, &tree);
493 // Get the sub tree root super arc
494 int 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 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 regularNodeId = superArc->getRegularNodeId(j);
509 double nodeScalar = tree.getNodeScalar(regularNodeId);
510 if(!((sign * nodeScalar) > (sign * value))) {
511 int vertexId = tree.getNode(regularNodeId)->getVertexId();
512 componentVertexList.push_back(vertexId);
513 }
514 }
515 // Down node
516 int downNodeId = superArc->getDownNodeId();
517 double nodeScalar = tree.getNodeScalar(downNodeId);
518 if(!((sign * nodeScalar) > (sign * value))) {
519 int 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 regularNodeId = superArc->getRegularNodeId(j);
526 int vertexId = tree.getNode(regularNodeId)->getVertexId();
527 componentVertexList.push_back(vertexId);
528 }
529 // Take down node
530 int downNodeId = superArc->getDownNodeId();
531 int 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 extremumNumber = extremumList.size();
561 std::vector<int> vertexId(extremumNumber);
562 std::vector<double> vertexValue(extremumNumber);
563 std::vector<int> 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 secondTreeSuperArcId = getVertexSuperArcId(vertexId[i], &secondTree);
587 // Root Super Arc Id (second tree) of the sub tree containing the vertex and
588 // rooted at the value of the vertex in the first scalar field
589 int rootSuperArcId = -1;
590 if(!isSuperArcAlreadyVisited[secondTreeSuperArcId]) {
591 rootSuperArcId = getSubTreeRootSuperArcId(
592 &secondTree, secondTreeSuperArcId, vertexValue[i]);
593 } else {
594 isMandatory = false;
595 }
596
597 // Exploration of the sub tree (if not already eliminated)
598 if(isMandatory) {
599 subTreeSuperArcId.clear();
600 std::queue<int> superArcQueue;
601 superArcQueue.push(rootSuperArcId);
602 while(isMandatory && (!superArcQueue.empty())) {
603 int spaId = superArcQueue.front();
604 superArcQueue.pop();
605 if(isSuperArcAlreadyVisited[spaId]) {
606 isMandatory = false;
607 } else {
608 int downNodeId = secondTree.getSuperArc(spaId)->getDownNodeId();
609 int numberOfDownSuperArcs
610 = secondTree.getNode(downNodeId)->getNumberOfDownSuperArcs();
611 if(numberOfDownSuperArcs > 0) {
612 for(int j = 0; j < numberOfDownSuperArcs; j++) {
613 superArcQueue.push(
614 secondTree.getNode(downNodeId)->getDownSuperArcId(j));
615 }
616 }
617 subTreeSuperArcId.push_back(spaId);
618 }
619 }
620 }
621
622 // If it is a mandatory extremum
623 if(isMandatory) {
624 // Add it to the list
625 mandatoryExtremum.push_back(vertexId[i]);
626 // Mark all the super arcs in the sub tree as visited and compute the
627 // critical interval
628 criticalInterval.emplace_back(vertexValue[i], vertexValue[i]);
629 for(int j = 0; j < (int)subTreeSuperArcId.size(); j++) {
630 isSuperArcAlreadyVisited[subTreeSuperArcId[j]] = true;
631 int downNodeId
632 = secondTree.getSuperArc(subTreeSuperArcId[j])->getDownNodeId();
633 double downNodeValue = secondTree.getNodeScalar(downNodeId);
634 if(pointType == PointType::Minimum) {
635 if(downNodeValue < criticalInterval.back().first) {
636 criticalInterval.back().first = downNodeValue;
637 }
638 } else {
639 if(downNodeValue > criticalInterval.back().second) {
640 criticalInterval.back().second = downNodeValue;
641 }
642 }
643 }
644 // Mark the super arc from the root of the sub tree to the global root
645 int upNodeId = secondTree.getSuperArc(rootSuperArcId)->getUpNodeId();
646 int spaId = secondTree.getNode(upNodeId)->getUpSuperArcId(0);
647 while((spaId != -1) && !(isSuperArcAlreadyVisited[spaId])) {
648 isSuperArcAlreadyVisited[spaId] = true;
649 upNodeId = secondTree.getSuperArc(spaId)->getUpNodeId();
650 spaId = secondTree.getNode(upNodeId)->getUpSuperArcId(0);
651 }
652 }
653
654 // // List of sub tree super arc ids (second tree)
655 // getSubTreeSuperArcIds(secondTree, rootSuperArcId, subTreeSuperArcId);
656 // // Check each super arc in the sub tree in the second tree
657 // bool isMandatoryCriticalPoint = true;
658 // for(int j=0 ; j<(int)subTreeSuperArcId.size() ; j++){
659 // // If one of the super arc has been visited before, the extremum is not
660 // mandatory if(isSuperArcAlreadyVisited[subTreeSuperArcId[j]]){
661 // isMandatoryCriticalPoint = false;
662 // break;
663 // }
664 // }
665 // // If it is a mandatory extremum
666 // if(isMandatoryCriticalPoint){
667 // // Add it to the list
668 // mandatoryExtremum->push_back(vertexId[i]);
669 // // Mark all the super arcs in the sub tree as visited and compute the
670 // critical interval
671 // criticalInterval->push_back(pair<double,double>(vertexValue[i],vertexValue[i]));
672 // for(int j=0 ; j<(int)subTreeSuperArcId.size() ; j++){
673 // isSuperArcAlreadyVisited[subTreeSuperArcId[j]] = true;
674 // int downNodeId =
675 // secondTree->getSuperArc(subTreeSuperArcId[j])->getDownNodeId();
676 // double downNodeValue = secondTree->getNodeScalar(downNodeId);
677 // if(pointType == PointType::Minimum) {
678 // if(downNodeValue < criticalInterval->back().first) {
679 // criticalInterval->back().first = downNodeValue;
680 // }
681 // } else {
682 // if(downNodeValue > criticalInterval->back().second){
683 // criticalInterval->back().second = downNodeValue;
684 // }
685 // }
686 // }
687 // }
688 }
689
690#ifdef TTK_ENABLE_OPENMP
691#pragma omp critical
692#endif
693 {
694 const std::string pt
695 = pointType == PointType::Minimum ? "minima" : "maxima";
696
697 this->printMsg("Computed " + std::to_string(mandatoryExtremum.size())
698 + " mandatory " + pt,
699 1.0, t.getElapsedTime(), this->threadNumber_);
700 this->printMsg("List of mandatory " + pt, debug::Priority::DETAIL);
701
702 for(size_t i = 0; i < mandatoryExtremum.size(); i++) {
703 std::stringstream msg;
704 msg << " -> " << pt << " (" << std::setw(3) << std::right << i << ") ";
705 msg << " \t"
706 << "Vertex " << std::setw(9) << std::left << mandatoryExtremum[i];
707 msg << " \tInterval [ " << std::setw(12) << std::right
708 << criticalInterval[i].first << " ; " << std::setprecision(9)
709 << std::setw(11) << std::left << criticalInterval[i].second << " ]";
710 this->printMsg(msg.str(), debug::Priority::DETAIL);
711 }
712 }
713
714 return 0;
715}
716
718 const PointType pointType,
719 SubLevelSetTree &lowerTree,
720 SubLevelSetTree &upperTree,
721 const std::vector<int> &mandatoryExtremumVertex,
722 std::vector<std::pair<int, int>> &mandatorySaddleVertex,
723 std::vector<std::vector<int>> &mandatoryMergedExtrema) {
724
725 // Timer
726 Timer t;
727
728 // Object to handle requests for common ancestors
729 LowestCommonAncestor lowerLca;
730 lowerLca.setDebugLevel(debugLevel_);
731 LowestCommonAncestor upperLca;
732 upperLca.setDebugLevel(debugLevel_);
733
734 /*
735 - Add all mandatory extrema in the node list
736 - Find all possible saddles
737 - Find ancestor of each node
738 - Preprocess requests
739 - Compute each pair of extrema
740 */
741
742 const unsigned int extremaNumber = mandatoryExtremumVertex.size();
743
744 std::vector<int> upperSaddleList;
745 std::vector<int> lowerSaddleList;
746
747 std::vector<int> upperTransverse(upperTree.getNumberOfSuperArcs(), -1);
748 std::vector<int> lowerTransverse(lowerTree.getNumberOfSuperArcs(), -1);
749
750 std::vector<std::vector<int>> lowerToUpperLinks;
751 std::vector<std::vector<int>> upperToLowerLinks;
752
753 std::vector<std::vector<int>> mergedExtrema;
754
755 // NOTE-julien
756 // the loop below is not thread-safe.
757 // plus, for all tested examples, it turns out to be even faster in serial.
758 // #pragma omp parallel num_threads(threadNumber_)
759 {
760// Build the list of all saddles joining the extrema
761#ifdef TTK_ENABLE_OPENMP
762#pragma omp for
763#endif
764 for(int i = 0; i < (int)mandatoryExtremumVertex.size(); i++) {
765 // Super arc in upper and lower trees
766 int upperSuperArcId
767 = getVertexSuperArcId(mandatoryExtremumVertex[i], &upperTree);
768 int lowerSuperArcId
769 = getVertexSuperArcId(mandatoryExtremumVertex[i], &lowerTree);
770 bool saddleFound;
771 bool rootReached;
772 bool multipleSaddleFound;
773 // Upper Transverse
774 saddleFound = false;
775 multipleSaddleFound = false;
776 rootReached = false;
777 do {
778#ifdef TTK_ENABLE_OPENMP
779#pragma omp critical(upperTreeTransverse)
780#endif
781 {
782 // Check if it's the first time the super arc is visited
783 if(++upperTransverse[upperSuperArcId]) {
784 // If not, a saddle is found
785 saddleFound = true;
786 // If two or more previous visits, the saddle is already in the list
787 if(upperTransverse[upperSuperArcId] > 1) {
788 multipleSaddleFound = true;
789 }
790 }
791 }
792 if(!saddleFound) {
793 // Get the upper super arc
794 int upNodeId = upperTree.getSuperArc(upperSuperArcId)->getUpNodeId();
795 upperSuperArcId = upperTree.getNode(upNodeId)->getUpSuperArcId(0);
796 if(upperSuperArcId == -1) {
797 rootReached = true;
798 }
799 } else {
800 if(!multipleSaddleFound) {
801 int saddleId
802 = upperTree.getSuperArc(upperSuperArcId)->getDownNodeId();
803#ifdef TTK_ENABLE_OPENMP
804#pragma omp critical
805#endif
806 upperSaddleList.push_back(saddleId);
807 }
808 }
809 } while(!(saddleFound || rootReached));
810 // Lower Transverse
811 saddleFound = false;
812 multipleSaddleFound = false;
813 rootReached = false;
814 do {
815#ifdef TTK_ENABLE_OPENMP
816#pragma omp critical(lowerTreeTransverse)
817#endif
818 {
819 // Check if it's the first time the super arc is visited
820 if(++lowerTransverse[lowerSuperArcId]) {
821 // If not, a saddle is found
822 saddleFound = true;
823 // If two or more previous visits, the saddle is already in the list
824 if(lowerTransverse[lowerSuperArcId] > 1) {
825 multipleSaddleFound = true;
826 }
827 }
828 }
829 if(!saddleFound) {
830 // Get the upper super arc
831 int upNodeId = lowerTree.getSuperArc(lowerSuperArcId)->getUpNodeId();
832 lowerSuperArcId = lowerTree.getNode(upNodeId)->getUpSuperArcId(0);
833 if(lowerSuperArcId == -1) {
834 rootReached = true;
835 }
836 } else {
837 if(!multipleSaddleFound) {
838 int saddleId
839 = lowerTree.getSuperArc(lowerSuperArcId)->getDownNodeId();
840#ifdef TTK_ENABLE_OPENMP
841#pragma omp critical
842#endif
843 lowerSaddleList.push_back(saddleId);
844 }
845 }
846 } while(!(saddleFound || rootReached));
847 }
848 }
849
850 // NOTE-julien
851 // something is not thread-safe above
852
853#ifdef TTK_ENABLE_OPENMP
854#pragma omp parallel num_threads(threadNumber_)
855#endif
856 {
857 // Reinitialize the transverse arrays to -1
858
859#ifdef TTK_ENABLE_OPENMP
860#pragma omp for
861#endif
862 for(int i = 0; i < (int)upperTransverse.size(); i++) {
863 upperTransverse[i] = -1;
864 }
865
866#ifdef TTK_ENABLE_OPENMP
867#pragma omp for
868#endif
869 for(int i = 0; i < (int)lowerTransverse.size(); i++) {
870 lowerTransverse[i] = -1;
871 }
872
873// Mark the super arcs with the id of the saddle
874#ifdef TTK_ENABLE_OPENMP
875#pragma omp for
876#endif
877 for(int i = 0; i < (int)upperSaddleList.size(); i++) {
878 int superArcId
879 = upperTree.getNode(upperSaddleList[i])->getUpSuperArcId(0);
880 upperTransverse[superArcId] = i;
881 }
882
883#ifdef TTK_ENABLE_OPENMP
884#pragma omp for
885#endif
886 for(int i = 0; i < (int)lowerSaddleList.size(); i++) {
887 int superArcId
888 = lowerTree.getNode(lowerSaddleList[i])->getUpSuperArcId(0);
889 lowerTransverse[superArcId] = i;
890 }
891
892// Create the nodes in the LCA object
893#ifdef TTK_ENABLE_OPENMP
894#pragma omp sections
895#endif
896 {
897// Upper lca
898#ifdef TTK_ENABLE_OPENMP
899#pragma omp section
900#endif
901 {
902 upperLca.addNodes(mandatoryExtremumVertex.size()
903 + upperSaddleList.size());
904 }
905// Lower lca
906#ifdef TTK_ENABLE_OPENMP
907#pragma omp section
908#endif
909 {
910 lowerLca.addNodes(mandatoryExtremumVertex.size()
911 + lowerSaddleList.size());
912 }
913 }
914
915// For each extrema, find it's first up saddle
916#ifdef TTK_ENABLE_OPENMP
917#pragma omp for
918#endif
919 for(int i = 0; i < (int)mandatoryExtremumVertex.size(); i++) {
920 int superArcId;
921 int lcaSaddleId;
922 // Upper Tree
923 superArcId = getVertexSuperArcId(mandatoryExtremumVertex[i], &upperTree);
924 while((superArcId != -1) && (upperTransverse[superArcId] == -1)) {
925 int nodeId = upperTree.getSuperArc(superArcId)->getUpNodeId();
926 superArcId = upperTree.getNode(nodeId)->getUpSuperArcId(0);
927 }
928 if(superArcId != -1) {
929 lcaSaddleId = extremaNumber + upperTransverse[superArcId];
930 // Ancestor
931 upperLca.getNode(i).setAncestor(lcaSaddleId);
932// Successor
933#ifdef TTK_ENABLE_OPENMP
934#pragma omp critical(upperLca)
935#endif
936 upperLca.getNode(lcaSaddleId).addSuccessor(i);
937 }
938
939 // Lower Tree
940 superArcId = getVertexSuperArcId(mandatoryExtremumVertex[i], &lowerTree);
941 while((superArcId != -1) && (lowerTransverse[superArcId] == -1)) {
942 int nodeId = lowerTree.getSuperArc(superArcId)->getUpNodeId();
943 superArcId = lowerTree.getNode(nodeId)->getUpSuperArcId(0);
944 }
945 if(superArcId != -1) {
946 lcaSaddleId = extremaNumber + lowerTransverse[superArcId];
947 // Ancestor
948 lowerLca.getNode(i).setAncestor(lcaSaddleId);
949// Successor
950#ifdef TTK_ENABLE_OPENMP
951#pragma omp critical(lowerLca)
952#endif
953 lowerLca.getNode(lcaSaddleId).addSuccessor(i);
954 }
955 }
956
957// For each saddle, find it's first up saddle
958#ifdef TTK_ENABLE_OPENMP
959#pragma omp for
960#endif
961 for(int i = 0; i < (int)upperSaddleList.size(); i++) {
962 int superArcId
963 = upperTree.getNode(upperSaddleList[i])->getUpSuperArcId(0);
964 do {
965 int nodeId = upperTree.getSuperArc(superArcId)->getUpNodeId();
966 superArcId = upperTree.getNode(nodeId)->getUpSuperArcId(0);
967 } while((superArcId != -1) && (upperTransverse[superArcId] == -1));
968 if(superArcId != -1) {
969 int lcaSuccessorSaddleId = extremaNumber + i;
970 int lcaAncestorSaddleId = extremaNumber + upperTransverse[superArcId];
971 // Ancestor
972 upperLca.getNode(lcaSuccessorSaddleId).setAncestor(lcaAncestorSaddleId);
973// Successor
974#ifdef TTK_ENABLE_OPENMP
975#pragma omp critical(upperLca)
976#endif
977 upperLca.getNode(lcaAncestorSaddleId)
978 .addSuccessor(lcaSuccessorSaddleId);
979 }
980 }
981
982#ifdef TTK_ENABLE_OPENMP
983#pragma omp for
984#endif
985 for(int i = 0; i < (int)lowerSaddleList.size(); i++) {
986 int superArcId
987 = lowerTree.getNode(lowerSaddleList[i])->getUpSuperArcId(0);
988 do {
989 int nodeId = lowerTree.getSuperArc(superArcId)->getUpNodeId();
990 superArcId = lowerTree.getNode(nodeId)->getUpSuperArcId(0);
991 } while((superArcId != -1) && (lowerTransverse[superArcId] == -1));
992 if(superArcId != -1) {
993 int lcaSuccessorSaddleId = extremaNumber + i;
994 int lcaAncestorSaddleId = extremaNumber + lowerTransverse[superArcId];
995 // Ancestor
996 lowerLca.getNode(lcaSuccessorSaddleId).setAncestor(lcaAncestorSaddleId);
997// Successor
998#ifdef TTK_ENABLE_OPENMP
999#pragma omp critical(lowerLca)
1000#endif
1001 lowerLca.getNode(lcaAncestorSaddleId)
1002 .addSuccessor(lcaSuccessorSaddleId);
1003 }
1004 }
1005
1006// Preprocess lowest common ancestors requests
1007#ifdef TTK_ENABLE_OPENMP
1008#pragma omp sections
1009#endif
1010 {
1011#ifdef TTK_ENABLE_OPENMP
1012#pragma omp section
1013#endif
1014 { upperLca.preprocess(); }
1015#ifdef TTK_ENABLE_OPENMP
1016#pragma omp section
1017#endif
1018 { lowerLca.preprocess(); }
1019 }
1020
1021 // Link lists for each thread
1022 std::vector<std::vector<int>> localLowerToUpperLinks;
1023 std::vector<std::vector<int>> localUpperToLowerLinks;
1024 // Merged extrema list for each thread (lower saddles only)
1025 std::vector<std::vector<int>> localMergedExtrema;
1026 // Resize of lists
1027 localLowerToUpperLinks.resize(lowerSaddleList.size());
1028 localUpperToLowerLinks.resize(upperSaddleList.size());
1029 localMergedExtrema.resize(lowerSaddleList.size());
1030 // Number of iterations (triangular loop without diagonal)
1031 unsigned int kmax = (extremaNumber * (extremaNumber - 1)) / 2;
1032// Loop over pairs of extrema
1033#ifdef TTK_ENABLE_OPENMP
1034#pragma omp for
1035#endif
1036 for(int k = 0; k < (int)kmax; k++) {
1037 unsigned int i = k / extremaNumber;
1038 unsigned int j = k % extremaNumber;
1039 if(j <= i) {
1040 i = extremaNumber - i - 2;
1041 j = extremaNumber - j - 1;
1042 }
1043 int uppLCA = upperLca.query(i, j) - extremaNumber;
1044 int lowLCA = lowerLca.query(i, j) - extremaNumber;
1045 localLowerToUpperLinks[lowLCA].push_back(uppLCA);
1046 localUpperToLowerLinks[uppLCA].push_back(lowLCA);
1047 localMergedExtrema[lowLCA].push_back(i);
1048 localMergedExtrema[lowLCA].push_back(j);
1049 }
1050
1051// Cleaning of duplicates and fusion of vectors
1052#ifdef TTK_ENABLE_OPENMP
1053#pragma omp single
1054#endif
1055 {
1056 lowerToUpperLinks.resize(lowerSaddleList.size());
1057 upperToLowerLinks.resize(upperSaddleList.size());
1058 mergedExtrema.resize(lowerSaddleList.size());
1059 }
1060 // Lower -> Upper
1061 for(unsigned int i = 0; i < localLowerToUpperLinks.size(); i++) {
1062 std::vector<int>::iterator newEnd;
1063 newEnd = unique(
1064 localLowerToUpperLinks[i].begin(), localLowerToUpperLinks[i].end());
1065#ifdef TTK_ENABLE_OPENMP
1066#pragma omp critical(lowerToUpperFusion)
1067#endif
1068 {
1069 lowerToUpperLinks[i].insert(
1070 lowerToUpperLinks[i].end(),
1071 make_move_iterator(localLowerToUpperLinks[i].begin()),
1072 make_move_iterator(newEnd));
1073 }
1074 localLowerToUpperLinks[i].clear();
1075 }
1076 localLowerToUpperLinks.clear();
1077 // Upper -> Lower
1078 for(unsigned int i = 0; i < localUpperToLowerLinks.size(); i++) {
1079 std::vector<int>::iterator newEnd;
1080 newEnd = unique(
1081 localUpperToLowerLinks[i].begin(), localUpperToLowerLinks[i].end());
1082#ifdef TTK_ENABLE_OPENMP
1083#pragma omp critical(upperToLowerFusion)
1084#endif
1085 {
1086 upperToLowerLinks[i].insert(
1087 upperToLowerLinks[i].end(),
1088 make_move_iterator(localUpperToLowerLinks[i].begin()),
1089 make_move_iterator(newEnd));
1090 }
1091 localUpperToLowerLinks[i].clear();
1092 }
1093 localUpperToLowerLinks.clear();
1094 // Merged extrema
1095 for(unsigned int i = 0; i < localMergedExtrema.size(); i++) {
1096 std::vector<int>::iterator newEnd;
1097 std::sort(localMergedExtrema[i].begin(), localMergedExtrema[i].end());
1098 newEnd
1099 = unique(localMergedExtrema[i].begin(), localMergedExtrema[i].end());
1100#ifdef TTK_ENABLE_OPENMP
1101#pragma omp critical(mergedExtremaFusion)
1102#endif
1103 {
1104 mergedExtrema[i].insert(
1105 mergedExtrema[i].end(),
1106 make_move_iterator(localMergedExtrema[i].begin()),
1107 make_move_iterator(newEnd));
1108 }
1109 localMergedExtrema[i].clear();
1110 }
1111 localMergedExtrema.clear();
1112 } // End of omp parallel
1113
1114 // NOTE-julien:
1115 // something is not thread-safe above
1116 // the code below is thread-safe
1117
1118 // Breadth-first search to identify connected components
1119 std::vector<bool> isLowerVisited(lowerSaddleList.size(), false);
1120 std::vector<bool> isUpperVisited(upperSaddleList.size(), false);
1121 std::vector<std::vector<int>> lowComponent;
1122 std::vector<std::vector<int>> uppComponent;
1123 for(unsigned int i = 0; i < lowerSaddleList.size(); i++) {
1124 if(!isLowerVisited[i]) {
1125 // New component
1126 lowComponent.emplace_back();
1127 uppComponent.emplace_back();
1128 int componentId = static_cast<int>(lowComponent.size()) - 1;
1129 lowComponent[componentId].push_back(i);
1130 isLowerVisited[i] = true;
1131 // Lists of neighbors
1132 std::vector<int> nextList;
1133 std::vector<int> currentList;
1134 currentList.push_back(i);
1135 // Pointers
1136 std::vector<bool> *isVisited = &(isUpperVisited);
1137 std::vector<std::vector<int>> *component = &(uppComponent);
1138 std::vector<std::vector<int>> *linkList = &(lowerToUpperLinks);
1139 while(!currentList.empty()) {
1140 // For each entry in the list
1141 for(unsigned int j = 0; j < currentList.size(); j++) {
1142 // For each neighbors
1143 for(unsigned int k = 0; k < (*linkList)[currentList[j]].size(); k++) {
1144 // Get the neighbor id;
1145 int neighbor = (*linkList)[currentList[j]][k];
1146 // Check if it's already visited
1147 if(!(*isVisited)[neighbor]) {
1148 // If not visited, mark it and add it
1149 (*isVisited)[neighbor] = true;
1150 (*component)[componentId].push_back(neighbor);
1151 nextList.push_back(neighbor);
1152 }
1153 }
1154 }
1155 // Swap pointers and lists
1156 isVisited = (isVisited == &(isUpperVisited)) ? &(isLowerVisited)
1157 : &(isUpperVisited);
1158 component
1159 = (component == &(uppComponent)) ? &(lowComponent) : &(uppComponent);
1160 linkList = (linkList == &(lowerToUpperLinks)) ? &(upperToLowerLinks)
1161 : &(lowerToUpperLinks);
1162 currentList.swap(nextList);
1163 nextList.clear();
1164 }
1165 }
1166 }
1167
1168 // Find pairs of vertices and list of merged extrema
1169 int numberOfComponents = static_cast<int>(lowComponent.size());
1170 mandatorySaddleVertex.resize(numberOfComponents, std::pair<int, int>(-1, -1));
1171 std::vector<std::vector<int>> mandatoryMergedExtrema_tmp;
1172 mandatoryMergedExtrema_tmp.resize(numberOfComponents, std::vector<int>());
1173
1174 for(int i = 0; i < numberOfComponents; i++) {
1175 int nodeId;
1176 // Find the vertex with minimum value in f-
1177 nodeId = lowerSaddleList[lowComponent[i][0]];
1178 mandatorySaddleVertex[i].first = lowerTree.getNode(nodeId)->getVertexId();
1179 for(unsigned int j = 0; j < lowComponent[i].size(); j++) {
1180 // First saddle
1181 int nId = lowerSaddleList[lowComponent[i][j]];
1182 double nodeScalar = lowerTree.getNodeScalar(nId);
1183 double refScalar = 0;
1184 lowerTree.getVertexScalar(mandatorySaddleVertex[i].first, refScalar);
1185 if(nodeScalar < refScalar) {
1186 mandatorySaddleVertex[i].first = lowerTree.getNode(nId)->getVertexId();
1187 }
1188 }
1189
1190 for(unsigned int j = 0; j < lowComponent[i].size(); j++) {
1191 mandatoryMergedExtrema_tmp[i].insert(
1192 mandatoryMergedExtrema_tmp[i].end(),
1193 make_move_iterator(mergedExtrema[lowComponent[i][j]].begin()),
1194 make_move_iterator(mergedExtrema[lowComponent[i][j]].end()));
1195 mergedExtrema[lowComponent[i][j]].clear();
1196 }
1197
1198 // Find the vertex with maximum value in f+
1199 nodeId = upperSaddleList[uppComponent[i][0]];
1200 mandatorySaddleVertex[i].second = upperTree.getNode(nodeId)->getVertexId();
1201 for(unsigned int j = 0; j < uppComponent[i].size(); j++) {
1202 // First saddle
1203 int nId = upperSaddleList[uppComponent[i][j]];
1204 double nodeScalar = upperTree.getNodeScalar(nId);
1205 double refScalar = 0;
1206 upperTree.getVertexScalar(mandatorySaddleVertex[i].second, refScalar);
1207 if(nodeScalar > refScalar) {
1208 mandatorySaddleVertex[i].second = upperTree.getNode(nId)->getVertexId();
1209 }
1210 }
1211 }
1212
1213 // Sort the merged extrema list
1214 std::vector<std::pair<int, int>> order;
1215 for(unsigned int i = 0; i < mandatoryMergedExtrema_tmp.size(); i++) {
1216 std::sort(mandatoryMergedExtrema_tmp[i].begin(),
1217 mandatoryMergedExtrema_tmp[i].end());
1218 std::vector<int>::iterator newEnd
1219 = unique(mandatoryMergedExtrema_tmp[i].begin(),
1220 mandatoryMergedExtrema_tmp[i].end());
1221 mandatoryMergedExtrema_tmp[i].resize(
1222 distance(mandatoryMergedExtrema_tmp[i].begin(), newEnd));
1223 mandatoryMergedExtrema_tmp[i].shrink_to_fit();
1224 order.emplace_back(i, mandatoryMergedExtrema_tmp[i].size());
1225 }
1226 // Sort by number of merged extrema
1228 std::sort(order.begin(), order.end(), cmp);
1229 // Reorder for output
1230 mandatoryMergedExtrema.clear();
1231 mandatoryMergedExtrema.resize(mandatoryMergedExtrema_tmp.size());
1232 for(unsigned int i = 0; i < order.size(); i++) {
1233 mandatoryMergedExtrema_tmp[order[i].first].swap(mandatoryMergedExtrema[i]);
1234 }
1235
1236// Getting global max and min
1237#ifdef TTK_ENABLE_OPENMP
1238#pragma omp parallel sections
1239#endif
1240 {
1241#ifdef TTK_ENABLE_OPENMP
1242#pragma omp section
1243#endif
1244 {
1245 if(upperMaximumList_.size()) {
1247 for(size_t i = 0; i < upperMaximumList_.size(); i++) {
1250 }
1251 }
1252 }
1253 }
1254#ifdef TTK_ENABLE_OPENMP
1255#pragma omp section
1256#endif
1257 {
1258 if(lowerMinimumList_.size()) {
1260 for(size_t i = 0; i < lowerMinimumList_.size(); i++) {
1263 }
1264 }
1265 }
1266 }
1267 }
1268
1269 const std::string st
1270 = pointType == PointType::JoinSaddle ? "join saddles" : "split saddles";
1271
1272 this->printMsg("Computed " + std::to_string(mandatorySaddleVertex.size())
1273 + " mandatory " + st,
1274 1.0, t.getElapsedTime(), this->threadNumber_);
1275
1276 this->printMsg("List of " + st + ":", debug::Priority::DETAIL);
1277 for(size_t i = 0; i < mandatorySaddleVertex.size(); i++) {
1278 std::stringstream msg;
1279 msg << " -> " << st << " (";
1280 msg << std::setw(3) << std::right << i << ")";
1281 msg << " Vertices <";
1282 msg << std::setw(9) << std::right << mandatorySaddleVertex[i].first
1283 << " ; ";
1284 msg << std::setw(9) << std::left << mandatorySaddleVertex[i].second << ">";
1285 msg << " Interval [";
1286 double lowerValue = 0;
1287 double upperValue = 0;
1288 lowerTree.getVertexScalar(mandatorySaddleVertex[i].first, lowerValue);
1289 upperTree.getVertexScalar(mandatorySaddleVertex[i].second, upperValue);
1290 msg << std::setw(12) << std::right << lowerValue << " ; ";
1291 msg << std::setw(12) << std::left << upperValue << "]";
1292 this->printMsg(msg.str(), debug::Priority::DETAIL);
1293 }
1294
1295 return 0;
1296}
1297
1299 const SubLevelSetTree *tree,
1300 const int &startingSuperArcId,
1301 const double &targetValue) const {
1302 // Starting to the input super arc id
1303 int superArcId = startingSuperArcId;
1304 // If the super arc exists
1305 if(superArcId != -1) {
1306 // Id of the node at the top of the super arc
1307 int upNodeId = tree->getSuperArc(superArcId)->getUpNodeId();
1308 // Value of the vertex associated with the node
1309 double upNodeValue = tree->getNodeScalar(upNodeId);
1310 // While condition
1311 int sign = tree->isJoinTree() ? 1 : -1;
1312 // Climb up the tree
1313 while(!((sign * targetValue) < (sign * upNodeValue))) {
1314 int numberOfUpSuperArcs
1315 = tree->getNode(upNodeId)->getNumberOfUpSuperArcs();
1316 if(numberOfUpSuperArcs > 0) {
1317 superArcId = tree->getNode(upNodeId)->getUpSuperArcId(0);
1318 upNodeId = tree->getSuperArc(superArcId)->getUpNodeId();
1319 upNodeValue = tree->getNodeScalar(upNodeId);
1320 } else {
1321 break;
1322 }
1323 }
1324 return superArcId;
1325 }
1326 return -1;
1327}
1328
1330 const SubLevelSetTree *tree,
1331 const int &vertexId0,
1332 const int &vertexId1) const {
1333 int numberOfSuperArcs = tree->getNumberOfSuperArcs();
1334 std::vector<bool> isSuperArcVisited(numberOfSuperArcs, false);
1335 int superArcId0 = getVertexSuperArcId(vertexId0, tree);
1336 int superArcId1 = getVertexSuperArcId(vertexId1, tree);
1337 int superArcId = superArcId0;
1338 do {
1339 isSuperArcVisited[superArcId] = true;
1340 superArcId = tree->getNode(tree->getSuperArc(superArcId)->getUpNodeId())
1341 ->getUpSuperArcId(0);
1342 } while(superArcId != -1);
1343 superArcId = superArcId1;
1344 while(!isSuperArcVisited[superArcId]) {
1345 superArcId = tree->getNode(tree->getSuperArc(superArcId)->getUpNodeId())
1346 ->getUpSuperArcId(0);
1347 }
1348 return tree->getSuperArc(superArcId)->getDownNodeId();
1349}
1350
1352 const SubLevelSetTree *tree,
1353 const int &rootSuperArcId,
1354 std::vector<int> &subTreeSuperArcId) const {
1355 std::vector<int> listOfSuperArcId;
1356 std::queue<int> superArcIdsToCompute;
1357 superArcIdsToCompute.push(rootSuperArcId);
1358 while(!superArcIdsToCompute.empty()) {
1359 int superArcId = superArcIdsToCompute.front();
1360 int downNodeId = tree->getSuperArc(superArcId)->getDownNodeId();
1361 int numberOfUpSuperArcs
1362 = tree->getNode(downNodeId)->getNumberOfDownSuperArcs();
1363 if(numberOfUpSuperArcs > 0) {
1364 for(int i = 0; i < numberOfUpSuperArcs; i++)
1365 superArcIdsToCompute.push(
1366 tree->getNode(downNodeId)->getDownSuperArcId(i));
1367 }
1368 listOfSuperArcId.push_back(superArcId);
1369 superArcIdsToCompute.pop();
1370 }
1371 listOfSuperArcId.swap(subTreeSuperArcId);
1372}
1373
1375 const double normalizedThreshold,
1376 const TreeType treeType,
1377 const std::vector<std::pair<std::pair<int, int>, double>> &extremaSaddlePair,
1378 const std::vector<std::vector<int>> &mergedExtrema,
1379 const int numberOfExtrema,
1380 std::vector<bool> &extremumSimplified,
1381 std::vector<bool> &saddleSimplified,
1382 std::vector<int> &extremumParentSaddle,
1383 std::vector<int> &saddleParentSaddle) const {
1384
1385 // Simplification threshold value
1386 double simplificationThreshold;
1387 if(normalizedThreshold > 1.0)
1388 simplificationThreshold = (globalMaximumValue_ - globalMinimumValue_);
1389 else if(normalizedThreshold < 0.0)
1390 simplificationThreshold = 0.0;
1391 else
1392 simplificationThreshold
1393 = (globalMaximumValue_ - globalMinimumValue_) * normalizedThreshold;
1394
1395 int extremaSimplifiedNumber = 0;
1396 int saddlesSimplifiedNumber = 0;
1397
1398 // First : simplification of extrema
1399 extremumSimplified.resize(numberOfExtrema);
1400 fill(extremumSimplified.begin(), extremumSimplified.end(), false);
1401 for(size_t i = 0; i < extremaSaddlePair.size(); i++) {
1402 if(extremaSaddlePair[i].second < simplificationThreshold) {
1403 extremumSimplified[extremaSaddlePair[i].first.first] = true;
1404 extremaSimplifiedNumber++;
1405 } else
1406 break;
1407 }
1408
1409 // Second : simplification of saddles
1410 saddleSimplified.resize(mergedExtrema.size());
1411 fill(saddleSimplified.begin(), saddleSimplified.end(), false);
1412 std::vector<int> nonSimplifiedExtremaNumber(mergedExtrema.size(), 0);
1413 extremumParentSaddle.resize(numberOfExtrema);
1414 fill(extremumParentSaddle.begin(), extremumParentSaddle.end(), -1);
1415 saddleParentSaddle.resize(mergedExtrema.size());
1416 fill(saddleParentSaddle.begin(), saddleParentSaddle.end(), -1);
1417 for(size_t i = 0; i < mergedExtrema.size(); i++) {
1418 saddleParentSaddle[i] = i;
1419 for(size_t j = 0; j < mergedExtrema[i].size(); j++) {
1420 if(!extremumSimplified[mergedExtrema[i][j]])
1421 nonSimplifiedExtremaNumber[i]++;
1422 }
1423 if(nonSimplifiedExtremaNumber[i] > 1) {
1424 // Find one non simplified extremum to test
1425 int extremum = 0;
1426 while(extremumSimplified[mergedExtrema[i][extremum]]) {
1427 extremum++;
1428 }
1429 if(!(extremumParentSaddle[mergedExtrema[i][extremum]] == -1)) {
1430 // Find the root
1431 int rootSaddleId = extremumParentSaddle[mergedExtrema[i][extremum]];
1432 int lastSaddleId = -1;
1433 while(rootSaddleId != lastSaddleId) {
1434 lastSaddleId = rootSaddleId;
1435 rootSaddleId = saddleParentSaddle[rootSaddleId];
1436 }
1437 // Compare the number of merged extrema
1438 if(!(nonSimplifiedExtremaNumber[i]
1439 > nonSimplifiedExtremaNumber[rootSaddleId])) {
1440 saddleSimplified[i] = true;
1441 saddlesSimplifiedNumber++;
1442 }
1443 }
1444 } else {
1445 saddleSimplified[i] = true;
1446 saddlesSimplifiedNumber++;
1447 }
1448 if(!saddleSimplified[i]) {
1449 for(size_t j = 0; j < mergedExtrema[i].size(); j++) {
1450 int extremaId = mergedExtrema[i][j];
1451 if(!extremumSimplified[extremaId]) {
1452 // If the extrema is not already connected, define the parent
1453 if(extremumParentSaddle[extremaId] == -1) {
1454 extremumParentSaddle[extremaId] = i;
1455 } else {
1456 // Find the root
1457 int rootSaddleId = extremumParentSaddle[extremaId];
1458 int lastSaddleId = -1;
1459 while(rootSaddleId != lastSaddleId) {
1460 lastSaddleId = rootSaddleId;
1461 rootSaddleId = saddleParentSaddle[rootSaddleId];
1462 }
1463 // Link the root to the processed saddle
1464 saddleParentSaddle[rootSaddleId] = i;
1465 }
1466 }
1467 }
1468 }
1469 }
1470
1471 const std::string pt = treeType == TreeType::JoinTree ? "minima" : "maxima";
1472
1473 this->printMsg(
1474 "#Simplified " + pt + ": " + std::to_string(extremaSimplifiedNumber)
1475 + " (threshold value = " + std::to_string(simplificationThreshold) + ")");
1476
1477 if(extremaSimplifiedNumber > 0) {
1478 this->printMsg("List of simplified " + pt + ":", debug::Priority::DETAIL);
1479 for(size_t i = 0; i < extremumSimplified.size(); i++) {
1480 if(extremumSimplified[i]) {
1481 std::stringstream msg;
1482 msg << " (" << i << ")";
1483 this->printMsg(msg.str(), debug::Priority::DETAIL);
1484 }
1485 }
1486 }
1487
1488 const std::string st
1489 = treeType == TreeType::JoinTree ? "join saddles" : "split saddles";
1490
1491 this->printMsg(
1492 "#Simplified " + st + ": " + std::to_string(saddlesSimplifiedNumber)
1493 + " (threshold value = " + std::to_string(simplificationThreshold) + ")");
1494
1495 if(saddlesSimplifiedNumber > 0) {
1496 this->printMsg("List of simplified " + st + ":", debug::Priority::DETAIL);
1497 for(size_t i = 0; i < saddleSimplified.size(); i++) {
1498 if(saddleSimplified[i]) {
1499 std::stringstream msg;
1500 msg << " (" << i << ")";
1501 this->printMsg(msg.str(), debug::Priority::DETAIL);
1502 }
1503 }
1504 }
1505
1506 return 0;
1507}
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
int printMsg(const std::string &msg, const debug::Priority &priority=debug::Priority::INFO, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cout) const
Definition: Debug.h:118
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_
int vertexNumber_
Number of vertices.
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< int > mdtMaximumParentSaddleId_
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< bool > isMdtMinimumSimplified_
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.
std::vector< bool > isMdtMaximumSimplified_
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< int > mdtMinimumParentSaddleId_
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
Definition: ContourTree.h:172
int getNumberOfDownSuperArcs() const
Definition: ContourTree.h:182
int getVertexId() const
Definition: ContourTree.h:194
int getNumberOfUpSuperArcs() const
Definition: ContourTree.h:190
int getDownSuperArcId(const int &neighborId) const
Definition: ContourTree.h:160
bool isSplitTree() const
Definition: ContourTree.h:470
const std::vector< int > * getExtremumList() const
Definition: ContourTree.h:299
const Node * getNode(const int &nodeId) const
Definition: ContourTree.h:305
double getNodeScalar(const int &nodeId) const
Definition: ContourTree.h:357
int getNumberOfSuperArcs() const
Definition: ContourTree.h:369
bool isJoinTree() const
Definition: ContourTree.h:465
const SuperArc * getSuperArc(const int &superArcId) const
Definition: ContourTree.h:398
int getVertexScalar(const int &vertexId, double &scalar)
Definition: ContourTree.h:408
int getNumberOfRegularNodes() const
Definition: ContourTree.h:70
int getRegularNodeId(const int &arcNodeId) const
Definition: ContourTree.h:82
double getElapsedTime()
Definition: Timer.h:15
The Topology ToolKit.
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>