TTK
Loading...
Searching...
No Matches
ProgressiveTopology.cpp
Go to the documentation of this file.
1#include "DataTypes.h"
2#include "MultiresTopology.h"
4
6 std::vector<PersistencePair> &CTDiagram, const SimplexId *offsets) {
7 int ret = -1;
8 printMsg("Progressive Persistence Diagram computation");
9 ret = executeCPProgressive(1, offsets);
10 CTDiagram = std::move(CTDiagram_);
11 CTDiagram_.clear();
12
13 return ret;
14}
15
17 int computePersistenceDiagram, const SimplexId *offsets) {
18
20
21 if(resumeProgressive_) {
22 resumeProgressive(computePersistenceDiagram, offsets);
23 return 0;
24 }
25
26 Timer timer;
27
28 decimationLevel_ = startingDecimationLevel_;
29 multiresTriangulation_.setDecimationLevel(0);
30 const SimplexId vertexNumber = multiresTriangulation_.getVertexNumber();
31
32#ifdef TTK_ENABLE_KAMIKAZE
33 if(vertexNumber == 0) {
34 this->printErr("No points in triangulation");
35 return 1;
36 }
37#endif // TTK_ENABLE_KAMIKAZE
38
39 double tm_allocation = timer.getElapsedTime();
40
41 // clean state (in case previous operation was a resume)
42 clearResumableState();
43
44 const auto dim = multiresTriangulation_.getDimensionality();
45 const size_t maxNeigh = dim == 3 ? 14 : (dim == 2 ? 6 : 0);
46
47 std::vector<std::vector<SimplexId>> saddleCCMin{}, saddleCCMax{};
48 std::vector<std::vector<SimplexId>> vertexRepresentativesMin{},
49 vertexRepresentativesMax{};
50 std::vector<polarity> isUpToDateMin{}, isUpToDateMax{};
51 std::vector<polarity> toPropagateMin{}, toPropagateMax{};
52 std::vector<char> vertexTypes{};
53
54 if(computePersistenceDiagram) {
55 saddleCCMin.resize(vertexNumber);
56 saddleCCMax.resize(vertexNumber);
57 vertexRepresentativesMin.resize(vertexNumber);
58 vertexRepresentativesMax.resize(vertexNumber);
59 toPropagateMin.resize(vertexNumber, 0);
60 toPropagateMax.resize(vertexNumber, 0);
61 isUpToDateMin.resize(vertexNumber, 0);
62 isUpToDateMax.resize(vertexNumber, 0);
63 } else {
64 vertexTypes.resize(vertexNumber, static_cast<char>(CriticalType::Regular));
65 }
66
67 // index in vertexLinkByBoundaryType
68 std::vector<uint8_t> vertexLink(vertexNumber);
69 VLBoundaryType vertexLinkByBoundaryType{};
70 std::vector<DynamicTree> link(vertexNumber);
71 std::vector<polarity> isNew(vertexNumber, 255);
72 std::vector<std::vector<std::pair<polarity, polarity>>> vertexLinkPolarity(
73 vertexNumber);
74 std::vector<polarity> toProcess(vertexNumber, 0), toReprocess{};
75
76 if(this->startingDecimationLevel_ > this->stoppingDecimationLevel_
77 || this->isResumable_) {
78 // only needed for progressive computation
79 toReprocess.resize(vertexNumber, 0);
80 }
81
82 // lock vertex thread access for firstPropagate
83 std::vector<Lock> vertLockMin(vertexNumber), vertLockMax(vertexNumber);
84
85 // pre-allocate memory
86 if(preallocateMemory_) {
87 double const tm_prealloc = timer.getElapsedTime();
88 printMsg("Pre-allocating data structures", 0, 0, threadNumber_,
90 for(SimplexId i = 0; i < vertexNumber; ++i) {
91 vertexLinkPolarity[i].reserve(maxNeigh);
92 link[i].alloc(maxNeigh);
93 }
94 printMsg("Pre-allocating data structures", 1,
95 timer.getElapsedTime() - tm_prealloc, threadNumber_);
96 }
97
98 tm_allocation = timer.getElapsedTime() - tm_allocation;
99 printMsg("Total memory allocation", 1, tm_allocation, threadNumber_);
100
101 // computation of implicit link
102 std::vector<SimplexId> boundReps{};
103 multiresTriangulation_.findBoundaryRepresentatives(boundReps);
104
105#ifdef TTK_ENABLE_OPENMP
106#pragma omp parallel for num_threads(threadNumber_)
107#endif
108 for(size_t i = 0; i < boundReps.size(); i++) {
109 if(boundReps[i] != -1) {
110 buildVertexLinkByBoundary(boundReps[i], vertexLinkByBoundaryType);
111 }
112 }
113
114 printMsg(this->resolutionInfoString(), 0,
115 timer.getElapsedTime() - tm_allocation, this->threadNumber_,
117 multiresTriangulation_.setDecimationLevel(decimationLevel_);
118
119 if(computePersistenceDiagram) {
120 initSaddleSeeds(isNew, vertexLinkPolarity, toPropagateMin, toPropagateMax,
121 toProcess, link, vertexLink, vertexLinkByBoundaryType,
122 saddleCCMin, saddleCCMax, offsets);
123 initPropagation(toPropagateMin, toPropagateMax, vertexRepresentativesMin,
124 vertexRepresentativesMax, saddleCCMin, saddleCCMax,
125 vertLockMin, vertLockMax, isUpToDateMin, isUpToDateMax,
126 offsets);
127
128 // compute pairs in non-progressive mode
129 computePersistencePairsFromSaddles(
130 CTDiagram_, offsets, vertexRepresentativesMin, vertexRepresentativesMax,
131 toPropagateMin, toPropagateMax);
132 } else {
133 initCriticalPoints(isNew, vertexLinkPolarity, toProcess, toReprocess, link,
134 vertexLink, vertexLinkByBoundaryType, vertexTypes,
135 offsets);
136 }
137
138 printMsg(this->resolutionInfoString(), 1,
139 timer.getElapsedTime() - tm_allocation, this->threadNumber_);
140
141 // skip subsequent propagations if time limit is exceeded
142 stopComputationIf(timer.getElapsedTime() - tm_allocation
143 > 0.9 * this->timeLimit_);
144
145 while(decimationLevel_ > stoppingDecimationLevel_) {
146 Timer tmIter{};
147 decimationLevel_--;
148 multiresTriangulation_.setDecimationLevel(decimationLevel_);
149
150 printMsg(this->resolutionInfoString(), 0,
151 timer.getElapsedTime() - tm_allocation, this->threadNumber_,
153
154 if(computePersistenceDiagram) {
155 updateSaddleSeeds(isNew, vertexLinkPolarity, toPropagateMin,
156 toPropagateMax, toProcess, toReprocess, link,
157 vertexLink, vertexLinkByBoundaryType, saddleCCMin,
158 saddleCCMax, isUpToDateMin, isUpToDateMax, offsets);
159 updatePropagation(toPropagateMin, toPropagateMax,
160 vertexRepresentativesMin, vertexRepresentativesMax,
161 saddleCCMin, saddleCCMax, vertLockMin, vertLockMax,
162 isUpToDateMin, isUpToDateMax, offsets);
163 computePersistencePairsFromSaddles(
164 CTDiagram_, offsets, vertexRepresentativesMin, vertexRepresentativesMax,
165 toPropagateMin, toPropagateMax);
166 } else {
167 updateCriticalPoints(isNew, vertexLinkPolarity, toProcess, toReprocess,
168 link, vertexLink, vertexLinkByBoundaryType,
169 vertexTypes, offsets);
170 }
171
172 const auto itDuration = tmIter.getElapsedTime();
173 const auto nextItDuration
174 = predictNextIterationDuration(itDuration, CTDiagram_.size() + 1);
175
176 printMsg(this->resolutionInfoString(), 1,
177 timer.getElapsedTime() - tm_allocation, this->threadNumber_);
178
179 // skip subsequent propagations if time limit is exceeded
180 stopComputationIf(timer.getElapsedTime() + nextItDuration - tm_allocation
181 > this->timeLimit_);
182
183 this->printMsg("current iteration", 1.0, itDuration, 1,
185 this->printMsg("next iteration duration prediction", 1.0, nextItDuration, 1,
187 }
188
189 // ADD GLOBAL MIN-MAX PAIR
190 if(computePersistenceDiagram) {
191 CTDiagram_.emplace_back(this->globalMin_, this->globalMax_, -1);
192 }
193
194 // store state for resuming computation
195 if(this->isResumable_ and decimationLevel_ > 0) {
196 if(computePersistenceDiagram) {
197 this->vertexRepresentativesMax_ = std::move(vertexRepresentativesMax);
198 this->vertexRepresentativesMin_ = std::move(vertexRepresentativesMin);
199 this->saddleCCMin_ = std::move(saddleCCMin);
200 this->saddleCCMax_ = std::move(saddleCCMax);
201 }
202 this->isNew_ = std::move(isNew);
203 this->toProcess_ = std::move(toProcess);
204 this->toReprocess_ = std::move(toReprocess);
205 this->vertexLinkPolarity_ = std::move(vertexLinkPolarity);
206 this->link_ = std::move(link);
207 this->vertexLink_ = std::move(vertexLink);
208 this->vertexLinkByBoundaryType_ = std::move(vertexLinkByBoundaryType);
209 this->resumeProgressive_ = true;
210 }
211
212 // prepare outputs
213 vertexTypes_ = std::move(vertexTypes);
214
215 // finally sort the diagram
216 sortPersistenceDiagram2(CTDiagram_, offsets);
217 // sortPersistenceDiagram(CTDiagram, offsets);
218 this->printMsg(
219 "Total", 1.0, timer.getElapsedTime() - tm_allocation, this->threadNumber_);
220 return 0;
221}
222
223int ttk::ProgressiveTopology::resumeProgressive(int computePersistenceDiagram,
224 const SimplexId *offsets) {
225
226 const auto vertexNumber = multiresTriangulation_.getVertexNumber();
227
228 this->printMsg(
229 "Resuming computation from resolution level "
230 + std::to_string(multiresTriangulation_.DL_to_RL(decimationLevel_))
231 + " to level "
233 multiresTriangulation_.DL_to_RL(stoppingDecimationLevel_)));
234
235 // lock vertex thread access for firstPropagate
236 std::vector<Lock> vertLockMin(vertexNumber), vertLockMax(vertexNumber);
237 // propagation markers
238 std::vector<polarity> toPropagateMin{}, toPropagateMax{};
239 std::vector<polarity> isUpToDateMin{}, isUpToDateMax{};
240
241 if(computePersistenceDiagram) {
242 toPropagateMin.resize(vertexNumber, 0);
243 toPropagateMax.resize(vertexNumber, 0);
244 isUpToDateMin.resize(vertexNumber, 0);
245 isUpToDateMax.resize(vertexNumber, 0);
246 }
247
248 Timer timer;
249
250 while(this->decimationLevel_ > this->stoppingDecimationLevel_) {
251 Timer tmIter{};
252 this->decimationLevel_--;
253 multiresTriangulation_.setDecimationLevel(this->decimationLevel_);
254 printMsg(this->resolutionInfoString(), 0, timer.getElapsedTime(),
255 this->threadNumber_, ttk::debug::LineMode::REPLACE);
256 if(computePersistenceDiagram) {
257 updateSaddleSeeds(isNew_, vertexLinkPolarity_, toPropagateMin,
258 toPropagateMax, toProcess_, toReprocess_, link_,
259 vertexLink_, vertexLinkByBoundaryType_, saddleCCMin_,
260 saddleCCMax_, isUpToDateMin, isUpToDateMax, offsets);
261 updatePropagation(toPropagateMin, toPropagateMax,
262 vertexRepresentativesMin_, vertexRepresentativesMax_,
263 saddleCCMin_, saddleCCMax_, vertLockMin, vertLockMax,
264 isUpToDateMin, isUpToDateMax, offsets);
265 computePersistencePairsFromSaddles(
266 CTDiagram_, offsets, vertexRepresentativesMin_,
267 vertexRepresentativesMax_, toPropagateMin, toPropagateMax);
268 } else {
269 updateCriticalPoints(isNew_, vertexLinkPolarity_, toProcess_,
270 toReprocess_, link_, vertexLink_,
271 vertexLinkByBoundaryType_, vertexTypes_, offsets);
272 }
273
274 const auto itDuration = tmIter.getElapsedTime();
275 const auto nextItDuration
276 = predictNextIterationDuration(itDuration, CTDiagram_.size() + 1);
277
278 printMsg(this->resolutionInfoString(), 1, timer.getElapsedTime(),
279 this->threadNumber_);
280
281 // skip subsequent propagations if time limit is exceeded
282 stopComputationIf(timer.getElapsedTime() + nextItDuration
283 > this->timeLimit_);
284 }
285
286 // ADD GLOBAL MIN-MAX PAIR
287 if(computePersistenceDiagram) {
288 CTDiagram_.emplace_back(this->globalMin_, this->globalMax_, -1);
289 }
290 // finally sort the diagram
291 sortPersistenceDiagram2(CTDiagram_, offsets);
292 // sortPersistenceDiagram(CTDiagram, offsets);
293 this->printMsg("Total", 1.0, timer.getElapsedTime(), this->threadNumber_);
294
295 // clean state (we don't need it anymore)
296 if(this->decimationLevel_ == 0) {
297 clearResumableState();
298 }
299
300 return 0;
301}
302
304 std::vector<PersistencePair> &CTDiagram,
305 const SimplexId *const offsets,
306 std::vector<std::vector<SimplexId>> &vertexRepresentativesMin,
307 std::vector<std::vector<SimplexId>> &vertexRepresentativesMax,
308 const std::vector<polarity> &toPropagateMin,
309 const std::vector<polarity> &toPropagateMax) const {
310
311 Timer timer{};
312 std::vector<triplet> tripletsMax{}, tripletsMin{};
313 const SimplexId nbDecVert = multiresTriangulation_.getDecimatedVertexNumber();
314
315 for(SimplexId localId = 0; localId < nbDecVert; localId++) {
316 SimplexId const globalId
317 = multiresTriangulation_.localToGlobalVertexId(localId);
318 if(toPropagateMin[globalId]) {
319 getTripletsFromSaddles(globalId, tripletsMin, vertexRepresentativesMin);
320 }
321 if(toPropagateMax[globalId]) {
322 getTripletsFromSaddles(globalId, tripletsMax, vertexRepresentativesMax);
323 }
324 }
325
326 this->printMsg("TRIPLETS", 1.0, timer.getElapsedTime(), this->threadNumber_,
328
329 double const tm_pairs = timer.getElapsedTime();
330
331 sortTriplets(tripletsMax, offsets, true);
332 sortTriplets(tripletsMin, offsets, false);
333
334 const auto tm_sort = timer.getElapsedTime();
335 this->printMsg("TRIPLETS SORT", 1.0, tm_sort - tm_pairs, this->threadNumber_,
337
338 typename std::remove_reference<decltype(CTDiagram)>::type CTDiagramMin{},
339 CTDiagramMax{};
340
341#ifdef TTK_ENABLE_OPENMP
342#pragma omp parallel sections num_threads(threadNumber_)
343#endif // TTK_ENABLE_OPENMP
344 {
345#ifdef TTK_ENABLE_OPENMP
346#pragma omp section
347#endif // TTK_ENABLE_OPENMP
348 tripletsToPersistencePairs(
349 CTDiagramMin, vertexRepresentativesMax, tripletsMax, offsets, true);
350#ifdef TTK_ENABLE_OPENMP
351#pragma omp section
352#endif // TTK_ENABLE_OPENMP
353 tripletsToPersistencePairs(
354 CTDiagramMax, vertexRepresentativesMin, tripletsMin, offsets, false);
355 }
356 CTDiagram = std::move(CTDiagramMin);
357 CTDiagram.insert(CTDiagram.end(), CTDiagramMax.begin(), CTDiagramMax.end());
358
359 this->printMsg("PAIRS", 1.0, timer.getElapsedTime() - tm_sort,
360 this->threadNumber_, debug::LineMode::NEW,
362}
363
364void ttk::ProgressiveTopology::sortTriplets(std::vector<triplet> &triplets,
365 const SimplexId *const offsets,
366 const bool splitTree) const {
367 if(triplets.empty())
368 return;
369
370 const auto lt = [=](const SimplexId a, const SimplexId b) -> bool {
371 return offsets[a] < offsets[b];
372 };
373
374 // Sorting step
375 const auto cmp = [=](const triplet &t1, const triplet &t2) {
376 const SimplexId s1 = std::get<0>(t1);
377 const SimplexId s2 = std::get<0>(t2);
378 const SimplexId m1 = std::get<2>(t1);
379 const SimplexId m2 = std::get<2>(t2);
380 if(s1 != s2)
381 return lt(s1, s2) != splitTree;
382 else // s1 == s2
383 return lt(m1, m2) == splitTree;
384 };
385
386 TTK_PSORT(this->threadNumber_, triplets.begin(), triplets.end(), cmp);
387}
388
390 std::vector<PersistencePair> &pairs,
391 std::vector<std::vector<SimplexId>> &vertexRepresentatives,
392 std::vector<triplet> &triplets,
393 const SimplexId *const offsets,
394 const bool splitTree) const {
395
396 Timer tm;
397 if(triplets.empty())
398 return;
399
400 const auto lt = [=](const SimplexId a, const SimplexId b) -> bool {
401 return offsets[a] < offsets[b];
402 };
403
404 const auto getRep = [&](SimplexId v) -> SimplexId {
405 auto r = vertexRepresentatives[v][0];
406 while(r != v) {
407 v = r;
408 r = vertexRepresentatives[v][0];
409 }
410 return r;
411 };
412
413 for(const auto &t : triplets) {
414 SimplexId r1 = getRep(std::get<1>(t));
415 SimplexId r2 = getRep(std::get<2>(t));
416 if(r1 != r2) {
417 SimplexId const s = std::get<0>(t);
418
419 // Add pair
420 if(splitTree) {
421 // r1 = min(r1, r2), r2 = max(r1, r2)
422 if(lt(r2, r1)) {
423 std::swap(r1, r2);
424 }
425 // pair saddle-max: s -> min(r1, r2);
426 pairs.emplace_back(s, r1, 2);
427
428 } else {
429 // r1 = max(r1, r2), r2 = min(r1, r2)
430 if(lt(r1, r2)) {
431 std::swap(r1, r2);
432 }
433 // pair min-saddle: max(r1, r2) -> s;
434 pairs.emplace_back(r1, s, 0);
435 }
436
437 vertexRepresentatives[std::get<1>(t)][0] = r2;
438 vertexRepresentatives[r1][0] = r2;
439 }
440 }
441
442 const std::string ptype = splitTree ? "sad-max" : "min-sad";
443 this->printMsg("found all " + ptype + " pairs", 1.0, tm.getElapsedTime(),
444 this->threadNumber_, debug::LineMode::NEW,
446}
447
449 const SimplexId vertexId,
450 std::vector<std::pair<polarity, polarity>> &vlp,
451 const SimplexId *const offsets) const {
452
453 const SimplexId neighborNumber
454 = multiresTriangulation_.getVertexNeighborNumber(vertexId);
455 vlp.resize(neighborNumber);
456 for(SimplexId i = 0; i < neighborNumber; i++) {
457 SimplexId neighborId0 = -1;
458 multiresTriangulation_.getVertexNeighbor(vertexId, i, neighborId0);
459 const bool lower0 = offsets[neighborId0] < offsets[vertexId];
460 const polarity isUpper0 = static_cast<polarity>(!lower0) * 255;
461 vlp[i] = std::make_pair(isUpper0, 0);
462 }
463}
464
466 const SimplexId &vertexId,
467 std::vector<std::pair<polarity, polarity>> &vlp,
468 uint8_t &vertexLink,
469 DynamicTree &link,
470 VLBoundaryType &vlbt,
471 const SimplexId *const offsets) const {
472
473 if(vlp.empty()) {
474 buildVertexLinkPolarity(vertexId, vlp, offsets);
475 }
476
477 const SimplexId neighborNumber
478 = multiresTriangulation_.getVertexNeighborNumber(vertexId);
479 link.alloc(neighborNumber);
480
481 // associate vertex link boundary
482 vertexLink = multiresTriangulation_.getVertexBoundaryIndex(vertexId);
483
484 // update the link polarity for old points that are processed for
485 // the first time
486 const auto &vl = vlbt[vertexLink];
487 for(size_t edgeId = 0; edgeId < vl.size(); edgeId++) {
488 const SimplexId n0 = vl[edgeId].first;
489 const SimplexId n1 = vl[edgeId].second;
490 if(vlp[n0].first == vlp[n1].first) {
491 // the smallest id (n0) becomes the parent of n1
492 link.insertEdge(n1, n0);
493 }
494 }
495}
496
498 std::vector<polarity> &isNew,
499 std::vector<std::vector<std::pair<polarity, polarity>>> &vertexLinkPolarity,
500 std::vector<polarity> &toProcess,
501 std::vector<polarity> &toReprocess,
502 std::vector<DynamicTree> &link,
503 std::vector<uint8_t> &vertexLink,
504 VLBoundaryType &vertexLinkByBoundaryType,
505 std::vector<char> &vertexTypes,
506 const SimplexId *const offsets) const {
507
508 Timer tm;
509 const auto nDecVerts = multiresTriangulation_.getDecimatedVertexNumber();
510
511 // find breaking edges
512#ifdef TTK_ENABLE_OPENMP
513#pragma omp parallel for num_threads(threadNumber_)
514#endif // TTK_ENABLE_OPENMP
515 for(SimplexId localId = 0; localId < nDecVerts; localId++) {
516 SimplexId const globalId
517 = multiresTriangulation_.localToGlobalVertexId(localId);
518 if(isNew[globalId]) {
519 if(decimationLevel_ > stoppingDecimationLevel_ || isResumable_) {
520 buildVertexLinkPolarity(
521 globalId, vertexLinkPolarity[globalId], offsets);
522 }
523 } else {
524 getMonotonyChangeByOldPointCP(globalId, isNew, toProcess, toReprocess,
525 vertexLinkPolarity[globalId], offsets);
526 }
527 }
528
529 this->printMsg("MONOTONY", 1.0, tm.getElapsedTime(), this->threadNumber_,
531
532 double const t_critical = tm.getElapsedTime();
533 // second Loop process or reprocess
534#ifdef TTK_ENABLE_OPENMP
535#pragma omp parallel for num_threads(threadNumber_)
536#endif
537 for(int i = 0; i < nDecVerts; i++) {
538 SimplexId const globalId = multiresTriangulation_.localToGlobalVertexId(i);
539
540 if(isNew[globalId]) { // new point
541 if(toProcess[globalId]) {
542 initDynamicLink(globalId, vertexLinkPolarity[globalId],
543 vertexLink[globalId], link[globalId],
544 vertexLinkByBoundaryType, offsets);
545 vertexTypes[globalId]
546 = getCriticalTypeFromLink(globalId, vertexLinkPolarity[globalId],
547 link[globalId], toReprocess[globalId]);
548 }
549 isNew[globalId] = false;
550
551 } else { // old point
552 if(toReprocess[globalId]) {
553 if(toProcess[globalId]) { // was already processed : need to reprocess
554 updateDynamicLink(link[globalId], vertexLinkPolarity[globalId],
555 vertexLinkByBoundaryType[vertexLink[globalId]]);
556 } else { // first processing
557 updateLinkPolarity(globalId, vertexLinkPolarity[globalId], offsets);
558 initDynamicLink(globalId, vertexLinkPolarity[globalId],
559 vertexLink[globalId], link[globalId],
560 vertexLinkByBoundaryType, offsets);
561 toProcess[globalId] = 255; // mark as processed
562 }
563 vertexTypes[globalId]
564 = getCriticalTypeFromLink(globalId, vertexLinkPolarity[globalId],
565 link[globalId], toReprocess[globalId]);
566 toReprocess[globalId] = 0;
567 }
568 }
569
570 } // end for openmp
571
572 this->printMsg("CRITICAL POINTS UPDATE", 1.0,
573 tm.getElapsedTime() - t_critical, this->threadNumber_,
575}
576
578 std::vector<polarity> &isNew,
579 std::vector<std::vector<std::pair<polarity, polarity>>> &vertexLinkPolarity,
580 std::vector<polarity> &toPropagateMin,
581 std::vector<polarity> &toPropagateMax,
582 std::vector<polarity> &toProcess,
583 std::vector<polarity> &toReprocess,
584 std::vector<DynamicTree> &link,
585 std::vector<uint8_t> &vertexLink,
586 VLBoundaryType &vertexLinkByBoundaryType,
587 std::vector<std::vector<SimplexId>> &saddleCCMin,
588 std::vector<std::vector<SimplexId>> &saddleCCMax,
589 std::vector<polarity> &isUpdatedMin,
590 std::vector<polarity> &isUpdatedMax,
591 const SimplexId *const offsets) const {
592
593 Timer tm;
594 const auto nDecVerts = multiresTriangulation_.getDecimatedVertexNumber();
595
596 // find breaking edges
597#ifdef TTK_ENABLE_OPENMP
598#pragma omp parallel for num_threads(threadNumber_)
599#endif // TTK_ENABLE_OPENMP
600 for(SimplexId localId = 0; localId < nDecVerts; localId++) {
601 SimplexId const globalId
602 = multiresTriangulation_.localToGlobalVertexId(localId);
603 if(isNew[globalId]) {
604 if(decimationLevel_ > stoppingDecimationLevel_ || isResumable_) {
605 buildVertexLinkPolarity(
606 globalId, vertexLinkPolarity[globalId], offsets);
607 }
608 } else {
609 getMonotonyChangeByOldPointCP(globalId, isNew, toProcess, toReprocess,
610 vertexLinkPolarity[globalId], offsets);
611 }
612 }
613
614 this->printMsg("MONOTONY", 1.0, tm.getElapsedTime(), this->threadNumber_,
616
617 double const t_critical = tm.getElapsedTime();
618 // second Loop process or reprocess
619#ifdef TTK_ENABLE_OPENMP
620#pragma omp parallel for num_threads(threadNumber_)
621#endif
622 for(int i = 0; i < nDecVerts; i++) {
623 SimplexId const globalId = multiresTriangulation_.localToGlobalVertexId(i);
624
625 if(isNew[globalId]) { // new point
626 if(toProcess[globalId]) {
627 initDynamicLink(globalId, vertexLinkPolarity[globalId],
628 vertexLink[globalId], link[globalId],
629 vertexLinkByBoundaryType, offsets);
630 getValencesFromLink(globalId, vertexLinkPolarity[globalId],
631 link[globalId], toPropagateMin, toPropagateMax,
632 saddleCCMin, saddleCCMax);
633 }
634 isNew[globalId] = false;
635
636 } else { // old point
637 if(toReprocess[globalId]) {
638 if(toProcess[globalId]) { // was already processed : need to reprocess
639 updateDynamicLink(link[globalId], vertexLinkPolarity[globalId],
640 vertexLinkByBoundaryType[vertexLink[globalId]]);
641 } else { // first processing
642 updateLinkPolarity(globalId, vertexLinkPolarity[globalId], offsets);
643 initDynamicLink(globalId, vertexLinkPolarity[globalId],
644 vertexLink[globalId], link[globalId],
645 vertexLinkByBoundaryType, offsets);
646 toProcess[globalId] = 255; // mark as processed
647 }
648 getValencesFromLink(globalId, vertexLinkPolarity[globalId],
649 link[globalId], toPropagateMin, toPropagateMax,
650 saddleCCMin, saddleCCMax);
651 toReprocess[globalId] = 0;
652 }
653 }
654
655 // reset updated flag
656 isUpdatedMin[globalId] = 0;
657 isUpdatedMax[globalId] = 0;
658 } // end for openmp
659
660 this->printMsg("CRITICAL POINTS UPDATE", 1.0,
661 tm.getElapsedTime() - t_critical, this->threadNumber_,
663}
664
666 const SimplexId vertexId,
667 const std::vector<polarity> &isNew,
668 std::vector<polarity> &toProcess,
669 std::vector<polarity> &toReprocess,
670 std::vector<std::pair<polarity, polarity>> &vlp,
671 const SimplexId *const offsets) const {
672
673 bool hasMonotonyChanged = false;
674 const SimplexId neighborNumber
675 = multiresTriangulation_.getVertexNeighborNumber(vertexId);
676 for(SimplexId i = 0; i < neighborNumber; i++) {
677 SimplexId neighborId = -1;
678 multiresTriangulation_.getVertexNeighbor(vertexId, i, neighborId);
679
680 // check for monotony changes
681 const bool lower = offsets[neighborId] < offsets[vertexId];
682 const polarity isUpper = lower ? 0 : 255;
683 const polarity isUpperOld = vlp[i].first;
684
685 if(isUpper != isUpperOld) { // change of monotony
686 hasMonotonyChanged = true;
687
688 toReprocess[vertexId] = 255;
689 toProcess[neighborId] = 255;
690 const SimplexId neighborNumberNew
691 = multiresTriangulation_.getVertexNeighborNumber(neighborId);
692 for(SimplexId j = 0; j < neighborNumberNew; j++) {
693 SimplexId neighborIdNew = -1;
694 multiresTriangulation_.getVertexNeighbor(neighborId, j, neighborIdNew);
695 if(isNew[neighborIdNew])
696 toProcess[neighborIdNew] = 255;
697 }
698
699 vlp[i].second = 255;
700 }
701 }
702 return hasMonotonyChanged;
703}
704
706 const SimplexId vertexId,
707 std::vector<Lock> &vertLock,
708 std::vector<polarity> &toPropagate,
709 std::vector<std::vector<SimplexId>> &vertexRepresentatives,
710 std::vector<std::vector<SimplexId>> &saddleCC,
711 std::vector<polarity> &isUpdated,
712 std::vector<SimplexId> &globalExtremum,
713 const SimplexId *const offsets,
714 const bool splitTree) const {
715
716 auto &toProp = toPropagate[vertexId];
717 auto &reps = vertexRepresentatives[vertexId];
718 auto &updated = isUpdated[vertexId];
719
720 const auto gt = [=](const SimplexId a, const SimplexId b) {
721 return (offsets[a] > offsets[b]) == splitTree;
722 };
723
724 if(updated) {
725 return reps[0];
726 }
727
728 if(this->threadNumber_ > 1) {
729 vertLock[vertexId].lock();
730 }
731
732 if(toProp) { // SADDLE POINT
733 const auto &CC = saddleCC[vertexId];
734 reps.clear();
735 reps.reserve(CC.size());
736 for(size_t r = 0; r < CC.size(); r++) {
737 SimplexId neighborId = -1;
738 SimplexId const localId = CC[r];
739 multiresTriangulation_.getVertexNeighbor(vertexId, localId, neighborId);
740 SimplexId const ret = propagateFromSaddles(
741 neighborId, vertLock, toPropagate, vertexRepresentatives, saddleCC,
742 isUpdated, globalExtremum, offsets, splitTree);
743 reps.emplace_back(ret);
744 }
745
746 if(reps.size() > 1) {
747 // sort & remove duplicate elements
748 std::sort(reps.begin(), reps.end(), gt);
749 const auto last = std::unique(reps.begin(), reps.end());
750 reps.erase(last, reps.end());
751 }
752
753 updated = 255;
754 if(this->threadNumber_ > 1) {
755 vertLock[vertexId].unlock();
756 }
757
758 return reps[0];
759
760 } else {
761
762 SimplexId ret = vertexId;
763 SimplexId const neighborNumber
764 = multiresTriangulation_.getVertexNeighborNumber(vertexId);
765 SimplexId maxNeighbor = vertexId;
766 for(SimplexId i = 0; i < neighborNumber; i++) {
767 SimplexId neighborId = -1;
768 multiresTriangulation_.getVertexNeighbor(vertexId, i, neighborId);
769 if(gt(neighborId, maxNeighbor)) {
770 maxNeighbor = neighborId;
771 }
772 }
773 if(maxNeighbor != vertexId) { // not an extremum
774 ret = propagateFromSaddles(maxNeighbor, vertLock, toPropagate,
775 vertexRepresentatives, saddleCC, isUpdated,
776 globalExtremum, offsets, splitTree);
777 } else {
778#ifdef TTK_ENABLE_OPENMP
779 const auto tid = omp_get_thread_num();
780#else
781 const auto tid = 0;
782#endif // TTK_ENABLE_OPENMP
783 if(gt(vertexId, globalExtremum[tid])) {
784 globalExtremum[tid] = vertexId;
785 }
786 }
787 reps.resize(1);
788 reps[0] = ret;
789 updated = 255;
790 if(this->threadNumber_ > 1) {
791 vertLock[vertexId].unlock();
792 }
793 return ret;
794 }
795}
796
798 std::vector<polarity> &isNew,
799 std::vector<std::vector<std::pair<polarity, polarity>>> &vertexLinkPolarity,
800 std::vector<polarity> &toProcess,
801 std::vector<polarity> &toReprocess,
802 std::vector<DynamicTree> &link,
803 std::vector<uint8_t> &vertexLink,
804 VLBoundaryType &vertexLinkByBoundaryType,
805 std::vector<char> &vertexTypes,
806 const SimplexId *const offsets) const {
807
808 Timer timer{};
809 const size_t nDecVerts = multiresTriangulation_.getDecimatedVertexNumber();
810
811 // computes the critical types of all points
812#ifdef TTK_ENABLE_OPENMP
813#pragma omp parallel for num_threads(threadNumber_)
814#endif // TTK_ENABLE_OPENMP
815 for(size_t i = 0; i < nDecVerts; i++) {
816 SimplexId const globalId = multiresTriangulation_.localToGlobalVertexId(i);
817 buildVertexLinkPolarity(globalId, vertexLinkPolarity[globalId], offsets);
818 initDynamicLink(globalId, vertexLinkPolarity[globalId],
819 vertexLink[globalId], link[globalId],
820 vertexLinkByBoundaryType, offsets);
821 vertexTypes[globalId]
822 = getCriticalTypeFromLink(globalId, vertexLinkPolarity[globalId],
823 link[globalId], toReprocess[globalId]);
824 toProcess[globalId] = 255;
825 isNew[globalId] = 0;
826 }
827
828 this->printMsg("initial critical types", 1.0, timer.getElapsedTime(),
829 this->threadNumber_, debug::LineMode::NEW,
831}
832
834 std::vector<polarity> &isNew,
835 std::vector<std::vector<std::pair<polarity, polarity>>> &vertexLinkPolarity,
836 std::vector<polarity> &toPropagateMin,
837 std::vector<polarity> &toPropagateMax,
838 std::vector<polarity> &toProcess,
839 std::vector<DynamicTree> &link,
840 std::vector<uint8_t> &vertexLink,
841 VLBoundaryType &vertexLinkByBoundaryType,
842 std::vector<std::vector<SimplexId>> &saddleCCMin,
843 std::vector<std::vector<SimplexId>> &saddleCCMax,
844 const SimplexId *const offsets) const {
845
846 Timer timer{};
847 const size_t nDecVerts = multiresTriangulation_.getDecimatedVertexNumber();
848
849 // computes the critical types of all points
850#ifdef TTK_ENABLE_OPENMP
851#pragma omp parallel for num_threads(threadNumber_)
852#endif // TTK_ENABLE_OPENMP
853 for(size_t i = 0; i < nDecVerts; i++) {
854 SimplexId const globalId = multiresTriangulation_.localToGlobalVertexId(i);
855 buildVertexLinkPolarity(globalId, vertexLinkPolarity[globalId], offsets);
856 initDynamicLink(globalId, vertexLinkPolarity[globalId],
857 vertexLink[globalId], link[globalId],
858 vertexLinkByBoundaryType, offsets);
859 getValencesFromLink(globalId, vertexLinkPolarity[globalId], link[globalId],
860 toPropagateMin, toPropagateMax, saddleCCMin,
861 saddleCCMax);
862 toProcess[globalId] = 255;
863 isNew[globalId] = 0;
864 }
865
866 this->printMsg("initial critical types", 1.0, timer.getElapsedTime(),
867 this->threadNumber_, debug::LineMode::NEW,
869}
870
872 std::vector<polarity> &toPropagateMin,
873 std::vector<polarity> &toPropagateMax,
874 std::vector<std::vector<SimplexId>> &vertexRepresentativesMin,
875 std::vector<std::vector<SimplexId>> &vertexRepresentativesMax,
876 std::vector<std::vector<SimplexId>> &saddleCCMin,
877 std::vector<std::vector<SimplexId>> &saddleCCMax,
878 std::vector<Lock> &vertLockMin,
879 std::vector<Lock> &vertLockMax,
880 std::vector<polarity> &isUpdatedMin,
881 std::vector<polarity> &isUpdatedMax,
882 const SimplexId *const offsets) const {
883
884 Timer timer{};
885 const size_t nDecVerts = multiresTriangulation_.getDecimatedVertexNumber();
886
887 std::vector<SimplexId> globalMaxThr(threadNumber_, 0);
888 std::vector<SimplexId> globalMinThr(threadNumber_, 0);
889
890#ifdef TTK_ENABLE_OPENMP
891#pragma omp parallel for num_threads(threadNumber_)
892#endif // TTK_ENABLE_OPENMP
893 for(size_t i = 0; i < nDecVerts; i++) {
894 SimplexId const v = multiresTriangulation_.localToGlobalVertexId(i);
895 if(toPropagateMin[v]) {
896 propagateFromSaddles(v, vertLockMin, toPropagateMin,
897 vertexRepresentativesMin, saddleCCMin, isUpdatedMin,
898 globalMinThr, offsets, false);
899 }
900 if(toPropagateMax[v]) {
901 propagateFromSaddles(v, vertLockMax, toPropagateMax,
902 vertexRepresentativesMax, saddleCCMax, isUpdatedMax,
903 globalMaxThr, offsets, true);
904 }
905 }
906
907 const auto lt = [=](const SimplexId a, const SimplexId b) -> bool {
908 return offsets[a] < offsets[b];
909 };
910
911 globalMin_ = *std::min_element(globalMinThr.begin(), globalMinThr.end(), lt);
912 globalMax_ = *std::max_element(globalMaxThr.begin(), globalMaxThr.end(), lt);
913
914 this->printMsg("FIRSTPROPAGATION", 1.0, timer.getElapsedTime(),
915 this->threadNumber_, debug::LineMode::NEW,
917}
918
920 std::vector<polarity> &toPropagateMin,
921 std::vector<polarity> &toPropagateMax,
922 std::vector<std::vector<SimplexId>> &vertexRepresentativesMin,
923 std::vector<std::vector<SimplexId>> &vertexRepresentativesMax,
924 std::vector<std::vector<SimplexId>> &saddleCCMin,
925 std::vector<std::vector<SimplexId>> &saddleCCMax,
926 std::vector<Lock> &vertLockMin,
927 std::vector<Lock> &vertLockMax,
928 std::vector<polarity> &isUpdatedMin,
929 std::vector<polarity> &isUpdatedMax,
930 const SimplexId *const offsets) const {
931
932 Timer tm{};
933 const size_t nDecVerts = multiresTriangulation_.getDecimatedVertexNumber();
934
935 std::vector<SimplexId> globalMaxThr(threadNumber_, 0);
936 std::vector<SimplexId> globalMinThr(threadNumber_, 0);
937
938 // propagate along split tree
939#ifdef TTK_ENABLE_OPENMP
940#pragma omp parallel for num_threads(threadNumber_)
941#endif // TTK_ENABLE_OPENMP
942 for(size_t i = 0; i < nDecVerts; i++) {
943 SimplexId const v = multiresTriangulation_.localToGlobalVertexId(i);
944 if(toPropagateMin[v]) {
945 propagateFromSaddles(v, vertLockMin, toPropagateMin,
946 vertexRepresentativesMin, saddleCCMin, isUpdatedMin,
947 globalMinThr, offsets, false);
948 }
949 if(toPropagateMax[v]) {
950 propagateFromSaddles(v, vertLockMax, toPropagateMax,
951 vertexRepresentativesMax, saddleCCMax, isUpdatedMax,
952 globalMaxThr, offsets, true);
953 }
954 }
955
956 const auto lt = [=](const SimplexId a, const SimplexId b) -> bool {
957 return offsets[a] < offsets[b];
958 };
959
960 globalMin_ = *std::min_element(globalMinThr.begin(), globalMinThr.end(), lt);
961 globalMax_ = *std::max_element(globalMaxThr.begin(), globalMaxThr.end(), lt);
962
963 this->printMsg("PROPAGATION UPDATE", 1.0, tm.getElapsedTime(),
964 this->threadNumber_, debug::LineMode::NEW,
966}
967
969 const SimplexId vertexId,
970 std::vector<std::pair<polarity, polarity>> &vlp,
971 const SimplexId *const offsets) const {
972
973 for(size_t i = 0; i < vlp.size(); i++) {
974 SimplexId neighborId = -1;
975 multiresTriangulation_.getVertexNeighbor(vertexId, i, neighborId);
976 const bool lower = offsets[neighborId] < offsets[vertexId];
977 const polarity isUpper = lower ? 0 : 255;
978 vlp[i] = std::make_pair(isUpper, 0);
979 }
980}
981
983 DynamicTree &link,
984 std::vector<std::pair<polarity, polarity>> &vlp,
985 std::vector<std::pair<SimplexId, SimplexId>> &vl) const {
986
987 std::vector<SimplexId> monotony_changes_list{};
988
989 for(size_t neighborId = 0; neighborId < vlp.size(); neighborId++) {
990 const polarity isBroken = vlp[neighborId].second;
991 if(isBroken != 0) {
992 monotony_changes_list.emplace_back(neighborId);
993 }
994 }
995
996 // loop on the link
997 // for each edge that shares n0
998 // if only one break and different polarity : remove
999 // else if only one break and same polarity : insert
1000 // else : do nothing
1001 std::vector<std::vector<std::pair<SimplexId, SimplexId>>> edgesToInsertLater(
1002 vlp.size());
1003 std::vector<std::vector<std::pair<SimplexId, SimplexId>>> edgesToRemoveLater(
1004 vlp.size());
1005
1006 for(size_t e = 0; e < vl.size(); e++) {
1007 const SimplexId n0 = vl[e].first;
1008 const SimplexId n1 = vl[e].second;
1009 const polarity isBroken0 = vlp[n0].second;
1010 const polarity isBroken1 = vlp[n1].second;
1011
1012 if(isBroken0 != 0 and isBroken1 == 0) {
1013 if(vlp[n0].first != vlp[n1].first) {
1014 edgesToInsertLater[n0].emplace_back(n0, n1);
1015 } else {
1016 edgesToRemoveLater[n0].emplace_back(n0, n1);
1017 }
1018 } else if(isBroken0 == 0 and isBroken1 != 0) {
1019 if(vlp[n0].first != vlp[n1].first) {
1020 edgesToInsertLater[n1].emplace_back(n1, n0);
1021 } else {
1022 edgesToRemoveLater[n1].emplace_back(n1, n0);
1023 }
1024 }
1025 }
1026
1027 // REMOVE EDGES:
1028 for(const auto brokenNode : monotony_changes_list) {
1029 vlp[brokenNode].first = ~vlp[brokenNode].first;
1030 vlp[brokenNode].second = 0;
1031
1032 link.getNode(brokenNode)->evert();
1033 for(const auto &edge : edgesToRemoveLater[brokenNode]) {
1034 link.removeEdge(edge.first, edge.second);
1035 }
1036 }
1037 if(!edgesToRemoveLater.empty()) {
1038 // reconnect link
1039 for(const auto &edge : vl) {
1040 if(vlp[edge.first].first == vlp[edge.second].first) {
1041 link.insertEdge(edge.first, edge.second);
1042 }
1043 }
1044 }
1045
1046 // INSERT EDGES
1047 for(const auto brokenNode : monotony_changes_list) {
1048 for(const auto &edge : edgesToInsertLater[brokenNode]) {
1049 link.insertEdge(edge.first, edge.second);
1050 }
1051 }
1052}
1053
1055 const double currItDuration, const size_t nCurrPairs) const {
1056
1057 // number of vertices at current iteration
1058 const double nCurrVerts = multiresTriangulation_.getDecimatedVertexNumber();
1059 // prediction of duration at iteration n + 1 from iteration n
1060 // (linear regression, R^2 = 0.994)
1061 return -0.21 + 0.77 / (decimationLevel_ + 1) - 4.0 * nCurrPairs / nCurrVerts
1062 + currItDuration
1063 * (3.3 - 2.32 / nCurrPairs + 32.3 * nCurrPairs / nCurrVerts);
1064}
1065
1067 if(b) {
1068 if(this->decimationLevel_ > this->stoppingDecimationLevel_) {
1069 this->printMsg("Computation stopped at resolution level "
1070 + std::to_string(multiresTriangulation_.DL_to_RL(
1071 this->decimationLevel_)));
1072 }
1073 this->stoppingDecimationLevel_ = this->decimationLevel_;
1074 }
1075}
1076
1078 // force de-allocation
1079 vertexRepresentativesMin_ = {};
1080 vertexRepresentativesMax_ = {};
1081 vertexLinkPolarity_ = {};
1082 isNew_ = {};
1083 vertexLink_ = {};
1084 link_ = {};
1085 toProcess_ = {};
1086 toReprocess_ = {};
1087 saddleCCMin_ = {};
1088 saddleCCMax_ = {};
1089 vertexTypes_ = {};
1090}
1091
1093 const SimplexId globalId,
1094 const std::vector<std::pair<polarity, polarity>> &vlp,
1095 DynamicTree &link,
1096 polarity &reprocess) const {
1097
1098 const auto nbCC = link.getNbCC();
1099
1100 bool const isVertexOnBoundary
1101 = multiresTriangulation_.getTriangulation()->isVertexOnBoundary(globalId);
1102
1103 int const dimensionality = multiresTriangulation_.getDimensionality();
1104 SimplexId downValence = 0, upValence = 0;
1105
1106 std::vector<size_t> CCIds;
1107 CCIds.reserve(nbCC);
1108 link.retrieveNbCC(CCIds);
1109 for(size_t i = 0; i < CCIds.size(); i++) {
1110 const SimplexId neighbor = CCIds[i];
1111 const polarity isUpper = vlp[neighbor].first;
1112 if(isUpper) {
1113 upValence++;
1114 } else {
1115 downValence++;
1116 }
1117 }
1118
1119 if(downValence == -1 && upValence == -1) {
1120 return -1;
1121 } else if(downValence == 0 && upValence == 1) {
1122 return static_cast<char>(CriticalType::Local_minimum);
1123 } else if(downValence == 1 && upValence == 0) {
1124 return static_cast<char>(CriticalType::Local_maximum);
1125 } else if(downValence == 1 && upValence == 1) {
1126
1127 // special case of boundary saddles
1128 if(dimensionality == 3 && isVertexOnBoundary) {
1129 reprocess = 255; // need to reprocess at finer resolutions
1130
1131 // find whether the upper and lower links touch the boundary
1132 bool isUpperOnBoundary = false, isLowerOnBoundary = false;
1133 const SimplexId neighborNumber = vlp.size();
1134 SimplexId neighborId = -1;
1135 for(int ineigh = 0; ineigh < neighborNumber; ineigh++) {
1136 multiresTriangulation_.getVertexNeighbor(globalId, ineigh, neighborId);
1137 if(multiresTriangulation_.getTriangulation()->isVertexOnBoundary(
1138 neighborId)) {
1139 if(vlp[ineigh].first) {
1140 isUpperOnBoundary = true;
1141 } else {
1142 isLowerOnBoundary = true;
1143 }
1144 }
1145 }
1146
1147 if((isUpperOnBoundary) && (!isLowerOnBoundary)) {
1148 return (char)(CriticalType::Saddle1);
1149 }
1150 if((!isUpperOnBoundary) && (isLowerOnBoundary)) {
1151 return (char)(CriticalType::Saddle2);
1152 }
1153 }
1154
1155 // regular point
1156 return static_cast<char>(CriticalType::Regular);
1157
1158 } else {
1159 // saddles
1160 if(dimensionality == 2) {
1161 if((downValence == 2 && upValence == 1)
1162 || (downValence == 1 && upValence == 2)
1163 || (downValence == 2 && upValence == 2)) {
1164 // regular saddle
1165 return static_cast<char>(CriticalType::Saddle1);
1166 } else {
1167 // monkey saddle, saddle + extremum
1168 return static_cast<char>(CriticalType::Degenerate);
1169 // NOTE: you may have multi-saddles on the boundary in that
1170 // configuration
1171 // to make this computation 100% correct, one would need to
1172 // disambiguate boundary from interior vertices
1173 }
1174 } else if(dimensionality == 3) {
1175 if(downValence == 2 && upValence == 1) {
1176 return static_cast<char>(CriticalType::Saddle1);
1177 } else if(downValence == 1 && upValence == 2) {
1178 return static_cast<char>(CriticalType::Saddle2);
1179 } else {
1180 // monkey saddle, saddle + extremum
1181 return static_cast<char>(CriticalType::Degenerate);
1182 // NOTE: we may have a similar effect in 3D (TODO)
1183 }
1184 }
1185 }
1186
1187 // -2: regular points
1188 return static_cast<char>(CriticalType::Regular);
1189}
1190
1192 std::vector<PersistencePair> &diagram, const SimplexId *const offsets) const {
1193
1194 auto cmp = [offsets](const PersistencePair &a, const PersistencePair &b) {
1195 return offsets[a.birth] < offsets[b.birth];
1196 };
1197
1198 std::sort(diagram.begin(), diagram.end(), cmp);
1199}
1200
1202 std::vector<std::pair<SimplexId, char>> *criticalPoints,
1203 const SimplexId *offsets) {
1204
1205 printMsg("Progressive Critical Points computation");
1206 int ret = -1;
1207 ret = executeCPProgressive(0, offsets);
1208
1209 SimplexId const vertexNumber = multiresTriangulation_.getVertexNumber();
1210 criticalPoints->clear();
1211 criticalPoints->reserve(vertexNumber);
1212 for(SimplexId i = 0; i < vertexNumber; i++) {
1213 if(vertexTypes_[i] != (char)(CriticalType::Regular)) {
1214 criticalPoints->emplace_back(i, vertexTypes_[i]);
1215 }
1216 }
1217 return ret;
1218}
bool ImplicitTriangulationCRTP< Derived >::TTK_TRIANGULATION_INTERNAL() isVertexOnBoundary(const SimplexId &vertexId) const
#define TTK_PSORT(NTHREADS,...)
Parallel sort macro.
Definition OpenMP.h:46
Implements the Dynamic Tree data-structure (or ST-Tree)
Definition DynamicTree.h:66
void alloc(const std::size_t nbNodes)
Definition DynamicTree.h:73
bool insertEdge(DynTreeNode *const n1, DynTreeNode *const n2)
Definition DynamicTree.h:93
DynTreeNode * getNode(const std::size_t nid)
get the node with the id: nid
Definition DynamicTree.h:78
size_t getNbCC() const
void removeEdge(DynTreeNode *const n)
remove the link btwn n and its parent
void retrieveNbCC(std::vector< size_t > &nbccIds) const
std::vector< PersistencePair > CTDiagram_
void sortTriplets(std::vector< triplet > &triplets, const SimplexId *const offsets, const bool splitTree) const
void updateDynamicLink(DynamicTree &link, std::vector< std::pair< polarity, polarity > > &vlp, std::vector< std::pair< SimplexId, SimplexId > > &vl) const
int executeCPProgressive(int computePersistenceDiagram, const SimplexId *inputOffsets)
ttk::SimplexId propagateFromSaddles(const SimplexId vertexId, std::vector< Lock > &vertLock, std::vector< polarity > &toPropagate, std::vector< std::vector< SimplexId > > &vertexRepresentatives, std::vector< std::vector< SimplexId > > &saddleCC, std::vector< polarity > &isUpdated, std::vector< SimplexId > &globalExtremum, const SimplexId *const offsets, const bool splitTree) const
void initSaddleSeeds(std::vector< polarity > &isNew, std::vector< std::vector< std::pair< polarity, polarity > > > &vertexLinkPolarity, std::vector< polarity > &toPropagateMin, std::vector< polarity > &toPropagateMax, std::vector< polarity > &toProcess, std::vector< DynamicTree > &link, std::vector< uint8_t > &vertexLink, VLBoundaryType &vertexLinkByBoundaryType, std::vector< std::vector< SimplexId > > &saddleCCMin, std::vector< std::vector< SimplexId > > &saddleCCMax, const SimplexId *const offsets) const
void initCriticalPoints(std::vector< polarity > &isNew, std::vector< std::vector< std::pair< polarity, polarity > > > &vertexLinkPolarity, std::vector< polarity > &toProcess, std::vector< polarity > &toReprocess, std::vector< DynamicTree > &link, std::vector< uint8_t > &vertexLink, VLBoundaryType &vertexLinkByBoundaryType, std::vector< char > &vertexTypes, const SimplexId *const offsets) const
void buildVertexLinkPolarity(const SimplexId vertexId, std::vector< std::pair< polarity, polarity > > &vlp, const SimplexId *const offsets) const
void initDynamicLink(const SimplexId &vertexId, std::vector< std::pair< polarity, polarity > > &vlp, uint8_t &vertexLink, DynamicTree &link, VLBoundaryType &vlbt, const SimplexId *const offsets) const
void computePersistencePairsFromSaddles(std::vector< PersistencePair > &CTDiagram, const SimplexId *const offsets, std::vector< std::vector< SimplexId > > &vertexRepresentativesMin, std::vector< std::vector< SimplexId > > &vertexRepresentativesMax, const std::vector< polarity > &toPropagateMin, const std::vector< polarity > &toPropagateMax) const
std::array< std::vector< std::pair< SimplexId, SimplexId > >, nLink_ > VLBoundaryType
char getCriticalTypeFromLink(const SimplexId globalId, const std::vector< std::pair< polarity, polarity > > &vlp, DynamicTree &link, polarity &reprocess) const
void initPropagation(std::vector< polarity > &toPropagateMin, std::vector< polarity > &toPropagateMax, std::vector< std::vector< SimplexId > > &vertexRepresentativesMin, std::vector< std::vector< SimplexId > > &vertexRepresentativesMax, std::vector< std::vector< SimplexId > > &saddleCCMin, std::vector< std::vector< SimplexId > > &saddleCCMax, std::vector< Lock > &vertLockMin, std::vector< Lock > &vertLockMax, std::vector< polarity > &isUpdatedMin, std::vector< polarity > &isUpdatedMax, const SimplexId *const offsets) const
bool getMonotonyChangeByOldPointCP(const SimplexId vertexId, const std::vector< polarity > &isNew, std::vector< polarity > &toProcess, std::vector< polarity > &toReprocess, std::vector< std::pair< polarity, polarity > > &vlp, const SimplexId *const offsets) const
void updatePropagation(std::vector< polarity > &toPropagateMin, std::vector< polarity > &toPropagateMax, std::vector< std::vector< SimplexId > > &vertexRepresentativesMin, std::vector< std::vector< SimplexId > > &vertexRepresentativesMax, std::vector< std::vector< SimplexId > > &saddleCCMin, std::vector< std::vector< SimplexId > > &saddleCCMax, std::vector< Lock > &vertLockMin, std::vector< Lock > &vertLockMax, std::vector< polarity > &isUpdatedMin, std::vector< polarity > &isUpdatedMax, const SimplexId *const offsets) const
int computeProgressivePD(std::vector< PersistencePair > &CTDiagram, const SimplexId *offsets)
void sortPersistenceDiagram2(std::vector< PersistencePair > &diagram, const SimplexId *const offsets) const
int resumeProgressive(int computePersistenceDiagram, const SimplexId *offsets)
void updateSaddleSeeds(std::vector< polarity > &isNew, std::vector< std::vector< std::pair< polarity, polarity > > > &vertexLinkPolarity, std::vector< polarity > &toPropagateMin, std::vector< polarity > &toPropagateMax, std::vector< polarity > &toProcess, std::vector< polarity > &toReprocess, std::vector< DynamicTree > &link, std::vector< uint8_t > &vertexLink, VLBoundaryType &vertexLinkByBoundaryType, std::vector< std::vector< SimplexId > > &saddleCCMin, std::vector< std::vector< SimplexId > > &saddleCCMax, std::vector< polarity > &isUpdatedMin, std::vector< polarity > &isUpdatedMax, const SimplexId *const offsets) const
double predictNextIterationDuration(const double currItDuration, const size_t nCurrPairs) const
void updateLinkPolarity(const SimplexId vertexId, std::vector< std::pair< polarity, polarity > > &vlp, const SimplexId *const offsets) const
void updateCriticalPoints(std::vector< polarity > &isNew, std::vector< std::vector< std::pair< polarity, polarity > > > &vertexLinkPolarity, std::vector< polarity > &toProcess, std::vector< polarity > &toReprocess, std::vector< DynamicTree > &link, std::vector< uint8_t > &vertexLink, VLBoundaryType &vertexLinkByBoundaryType, std::vector< char > &vertexTypes, const SimplexId *const offsets) const
void tripletsToPersistencePairs(std::vector< PersistencePair > &pairs, std::vector< std::vector< SimplexId > > &vertexRepresentatives, std::vector< triplet > &triplets, const SimplexId *const offsets, const bool splitTree) const
int computeProgressiveCP(std::vector< std::pair< SimplexId, char > > *criticalPoints, const SimplexId *offsets)
double getElapsedTime()
Definition Timer.h:15
std::string to_string(__int128)
Definition ripserpy.cpp:99
std::tuple< ttk::SimplexId, ttk::SimplexId, ttk::SimplexId > triplet
Persistence pair type (with persistence in double)
unsigned char polarity
int SimplexId
Identifier type for simplices of any dimension.
Definition DataTypes.h:22
void evert()
Make this node the root of its tree.
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)