33 using triplet = std::tuple<ttk::SimplexId, ttk::SimplexId, ttk::SimplexId>;
48 template <
typename scalarType>
50 const scalarType *scalars,
51 scalarType *
const fakeScalars,
53 int *
const outputMonotonyOffsets);
55 template <
typename scalarType>
57 scalarType *fakeScalars,
59 int *outputMonotonyOffsets);
61 template <
typename scalarType,
typename offsetType>
64 std::vector<std::vector<std::pair<polarity, polarity>>>
66 std::vector<polarity> &toProcess,
67 const scalarType *fakeScalars,
68 const offsetType *
const offsets,
69 const int *
const monotonyOffsets)
const;
71 template <
typename scalarType,
typename offsetType>
73 std::vector<polarity> &toPropagateMin,
74 std::vector<polarity> &toPropagateMax,
75 std::vector<std::vector<SimplexId>> &vertexRepresentativesMin,
76 std::vector<std::vector<SimplexId>> &vertexRepresentativesMax,
77 std::vector<std::vector<SimplexId>> &saddleCCMin,
78 std::vector<std::vector<SimplexId>> &saddleCCMax,
79 std::vector<Lock> &vertLockMin,
80 std::vector<Lock> &vertLockMax,
81 std::vector<polarity> &isUpdatedMin,
82 std::vector<polarity> &isUpdatedMax,
83 const scalarType *fakeScalars,
84 const offsetType *
const offsetField,
85 const int *
const monotonyOffsets);
87 template <
typename scalarType,
typename offsetType>
90 std::vector<std::pair<polarity, polarity>> &vlp,
91 const scalarType *fakeScalars,
92 const offsetType *
const offsetField,
93 const int *
const monotonyOffsets)
const;
95 template <
typename ScalarType,
typename OffsetType>
97 const ScalarType *
const scalars,
98 const ScalarType *
const fakeScalars,
99 const OffsetType *
const offsets,
100 const int *
const monotonyOffsets,
101 const bool splitTree)
const;
103 template <
typename scalarType,
typename offsetType>
106 std::vector<std::pair<polarity, polarity>> &vlp,
110 const scalarType *fakeScalars,
111 const offsetType *
const offsets,
112 const int *
const monotonyOffsets)
const;
114 template <
typename ScalarType,
typename offsetType>
116 std::vector<std::vector<std::pair<polarity, polarity>>>
118 std::vector<polarity> &toPropagateMin,
119 std::vector<polarity> &toPropagateMax,
120 std::vector<polarity> &toProcess,
121 std::vector<DynamicTree> &link,
122 std::vector<uint8_t> &vertexLink,
124 std::vector<std::vector<SimplexId>> &saddleCCMin,
125 std::vector<std::vector<SimplexId>> &saddleCCMax,
126 ScalarType *fakeScalars,
127 const offsetType *
const offsets,
128 int *monotonyOffsets);
130 template <
typename scalarType,
typename offsetType>
133 std::vector<Lock> &vertLock,
134 std::vector<polarity> &toPropagate,
135 std::vector<std::vector<SimplexId>> &vertexRepresentatives,
136 std::vector<std::vector<SimplexId>> &saddleCC,
137 std::vector<polarity> &isUpdated,
138 std::vector<SimplexId> &globalExtremum,
139 const bool splitTree,
140 const scalarType *fakeScalars,
141 const offsetType *
const offsetField,
142 const int *
const monotonyOffsets)
const;
144 template <
typename ScalarType,
typename offsetType>
146 std::vector<PersistencePair> &CTDiagram,
147 const ScalarType *
const fakeScalars,
148 const offsetType *
const offsets,
149 const int *
const monotonyOffsets,
150 std::vector<std::vector<SimplexId>> &vertexRepresentativesMin,
151 std::vector<std::vector<SimplexId>> &vertexRepresentativesMax,
152 const std::vector<polarity> &toPropagateMin,
153 const std::vector<polarity> &toPropagateMax)
const;
155 template <
typename scalarType,
typename offsetType>
157 std::vector<SimplexId> &sortedVertices,
159 const scalarType *
const fakeScalars,
160 const offsetType *
const offsetField,
161 const int *
const monotonyOffsets);
163 template <
typename scalarType>
165 scalarType *fakeScalars,
167 int *monotonyOffsets)
const;
173 = std::array<std::vector<std::pair<SimplexId, SimplexId>>,
nLink_>;
177 std::vector<std::vector<std::pair<polarity, polarity>>>
179 std::vector<polarity> &toProcess,
180 std::vector<DynamicTree> &link,
181 std::vector<uint8_t> &vertexLink,
183 std::vector<char> &vertexTypes,
187 std::vector<std::vector<std::pair<polarity, polarity>>>
189 std::vector<polarity> &toPropagateMin,
190 std::vector<polarity> &toPropagateMax,
191 std::vector<polarity> &toProcess,
192 std::vector<DynamicTree> &link,
193 std::vector<uint8_t> &vertexLink,
195 std::vector<std::vector<SimplexId>> &saddleCCMin,
196 std::vector<std::vector<SimplexId>> &saddleCCMax,
199 template <
typename scalarType,
typename offsetType>
201 std::vector<polarity> &toPropagateMin,
202 std::vector<polarity> &toPropagateMax,
203 std::vector<std::vector<SimplexId>> &vertexRepresentativesMin,
204 std::vector<std::vector<SimplexId>> &vertexRepresentativesMax,
205 std::vector<std::vector<SimplexId>> &saddleCCMin,
206 std::vector<std::vector<SimplexId>> &saddleCCMax,
207 std::vector<Lock> &vertLockMin,
208 std::vector<Lock> &vertLockMax,
209 std::vector<polarity> &isUpdatedMin,
210 std::vector<polarity> &isUpdatedMax,
211 const scalarType *fakeScalars,
212 const offsetType *
const offsets,
213 const int *
const monotonyOffsets)
const;
215 template <
typename scalarType,
typename offsetType>
218 std::vector<std::pair<polarity, polarity>> &vlp,
219 const scalarType *fakeScalars,
220 const offsetType *
const offsets,
221 const int *
const monotonyOffsets)
const;
223 template <
typename ScalarType,
typename OffsetType>
225 const ScalarType *
const fakeScalars,
226 const OffsetType *
const offsets,
227 const int *
const monotonyOffsets,
228 const bool splitTree)
const;
230 template <
typename scalarType,
typename offsetType>
232 std::vector<PersistencePair> &pairs,
233 std::vector<std::vector<SimplexId>> &vertexRepresentatives,
234 std::vector<triplet> &triplets,
235 const scalarType *
const fakeScalars,
236 const offsetType *
const offsets,
237 const int *
const monotonyOffsets,
238 const bool splitTree)
const;
240 template <
typename scalarType,
typename offsetType>
244 const std::vector<polarity> &isNew,
245 std::vector<polarity> &toProcess,
246 std::vector<polarity> &toReprocess,
247 std::vector<std::pair<polarity, polarity>> &vlp,
248 scalarType *fakeScalars,
249 const offsetType *
const offsets,
250 int *monotonyOffsets)
const;
252 template <
typename ScalarType,
typename offsetType>
255 std::vector<polarity> &isNew,
256 std::vector<std::vector<std::pair<polarity, polarity>>>
258 std::vector<polarity> &toProcess,
259 std::vector<polarity> &toReprocess,
260 ScalarType *fakeScalars,
261 const offsetType *
const offsets,
262 int *monotonyOffsets)
const;
266 std::vector<Lock> &vertLock,
267 std::vector<polarity> &toPropagate,
268 std::vector<std::vector<SimplexId>> &vertexRepresentatives,
269 std::vector<std::vector<SimplexId>> &saddleCC,
270 std::vector<polarity> &isUpdated,
271 std::vector<SimplexId> &globalExtremum,
273 const bool splitTree)
const;
276 std::vector<PersistencePair> &CTDiagram,
278 std::vector<std::vector<SimplexId>> &vertexRepresentativesMin,
279 std::vector<std::vector<SimplexId>> &vertexRepresentativesMax,
280 const std::vector<polarity> &toPropagateMin,
281 const std::vector<polarity> &toPropagateMax)
const;
283 template <
typename scalarType,
typename offsetType>
286 std::vector<std::vector<std::pair<polarity, polarity>>>
288 const scalarType *scalars,
289 const scalarType *fakeScalars,
290 const offsetType *
const offsets,
291 const int *
const monotonyOffsets,
292 bool verbose =
false);
299template <
typename scalarType>
302 scalarType *fakeScalars,
304 int *outputMonotonyOffsets) {
308 SimplexId *
const vertsOrder = outputOffsets;
314 int *monotonyOffsets = outputMonotonyOffsets;
316#ifdef TTK_ENABLE_KAMIKAZE
317 if(vertexNumber == 0) {
318 this->
printErr(
"No points in triangulation");
326 const size_t maxNeigh = dim == 3 ? 14 : (dim == 2 ? 6 : 0);
328 std::vector<std::vector<SimplexId>> saddleCCMin(vertexNumber),
329 saddleCCMax(vertexNumber);
330 std::vector<std::vector<SimplexId>> vertexRepresentativesMin(vertexNumber),
331 vertexRepresentativesMax(vertexNumber);
333 std::vector<std::vector<std::pair<polarity, polarity>>> vertexLinkPolarity(
336 std::vector<polarity> isNew(vertexNumber, 255);
337 std::vector<polarity> toPropagateMin(vertexNumber, 0),
338 toPropagateMax(vertexNumber, 0);
339 std::vector<polarity> isUpToDateMin(vertexNumber, 0),
340 isUpToDateMax(vertexNumber, 0);
343 std::vector<uint8_t> vertexLink(vertexNumber);
345 std::vector<DynamicTree> link(vertexNumber);
346 std::vector<polarity> toProcess(vertexNumber, 0), toReprocess{};
348 std::vector<SimplexId> offsetsVec(vertexNumber);
349 std::iota(offsetsVec.begin(), offsetsVec.end(), 0);
350 const SimplexId *
const offsets = offsetsVec.data();
354 toReprocess.resize(vertexNumber, 0);
357 std::vector<Lock> vertLockMin(vertexNumber), vertLockMax(vertexNumber);
363 for(
SimplexId i = 0; i < vertexNumber; ++i) {
367 vertexLinkPolarity[i].reserve(maxNeigh);
368 link[i].alloc(maxNeigh);
370 printMsg(
"Pre-allocating data structures", 1,
378 std::vector<SimplexId> boundReps{};
381#ifdef TTK_ENABLE_OPENMP
382#pragma omp parallel for num_threads(threadNumber_)
384 for(
size_t i = 0; i < boundReps.size(); i++) {
385 if(boundReps[i] != -1) {
416 toReprocess, fakeScalars, offsets,
419 std::cout <<
"Found ERROR - aborting" << std::endl;
425 toProcess, link, vertexLink, vertexLinkByBoundaryType,
426 saddleCCMin, saddleCCMax, fakeScalars, offsets,
430 vertexRepresentativesMax, saddleCCMin, saddleCCMax,
431 vertLockMin, vertLockMax, isUpToDateMin, isUpToDateMax,
432 fakeScalars, offsets, monotonyOffsets);
435 CTDiagram_, fakeScalars, offsets, monotonyOffsets, vertexRepresentativesMin,
436 vertexRepresentativesMax, toPropagateMin, toPropagateMax);
445 this->threadNumber_);
450 CTDiagram_, fakeScalars, offsets, monotonyOffsets);
454 std::vector<SimplexId> sortedVertices{};
455 sortVertices(vertexNumber, sortedVertices, vertsOrder, fakeScalars, offsets,
460template <
typename ScalarType,
typename OffsetType>
462 std::vector<PersistencePair> &CTDiagram,
463 const ScalarType *
const fakeScalars,
464 const OffsetType *
const offsets,
465 const int *
const monotonyOffsets,
466 std::vector<std::vector<SimplexId>> &vertexRepresentativesMin,
467 std::vector<std::vector<SimplexId>> &vertexRepresentativesMax,
468 const std::vector<polarity> &toPropagateMin,
469 const std::vector<polarity> &toPropagateMax)
const {
473 std::vector<triplet> tripletsMax{}, tripletsMin{};
474 const SimplexId nbDecVert = multiresTriangulation_.getDecimatedVertexNumber();
476 for(
SimplexId localId = 0; localId < nbDecVert; localId++) {
477 SimplexId globalId = multiresTriangulation_.localToGlobalVertexId(localId);
478 if(toPropagateMin[globalId]) {
479 getTripletsFromSaddles(globalId, tripletsMin, vertexRepresentativesMin);
481 if(toPropagateMax[globalId]) {
482 getTripletsFromSaddles(globalId, tripletsMax, vertexRepresentativesMax);
486 sortTriplets(tripletsMax, fakeScalars, offsets, monotonyOffsets,
true);
487 sortTriplets(tripletsMin, fakeScalars, offsets, monotonyOffsets,
false);
489 const auto tm_sort = timer.getElapsedTime();
491 typename std::remove_reference<
decltype(CTDiagram)>::type CTDiagramMin{},
494#ifdef TTK_ENABLE_OPENMP
495#pragma omp parallel sections num_threads(threadNumber_)
498#ifdef TTK_ENABLE_OPENMP
501 tripletsToPersistencePairs(CTDiagramMin, vertexRepresentativesMax,
502 tripletsMax, fakeScalars, offsets,
503 monotonyOffsets,
true);
504#ifdef TTK_ENABLE_OPENMP
507 tripletsToPersistencePairs(CTDiagramMax, vertexRepresentativesMin,
508 tripletsMin, fakeScalars, offsets,
509 monotonyOffsets,
false);
511 CTDiagram = std::move(CTDiagramMin);
512 CTDiagram.insert(CTDiagram.end(), CTDiagramMax.begin(), CTDiagramMax.end());
514 if(debugLevel_ > 3) {
515 std::cout <<
"PAIRS " << timer.getElapsedTime() - tm_sort << std::endl;
519template <
typename ScalarType,
typename OffsetType>
521 const ScalarType *
const fakeScalars,
522 const OffsetType *
const offsets,
523 const int *
const monotonyOffsets,
524 const bool splitTree)
const {
529 return ((fakeScalars[a] < fakeScalars[b])
530 || (fakeScalars[a] == fakeScalars[b]
531 && ((monotonyOffsets[a] < monotonyOffsets[b])
532 || (monotonyOffsets[a] == monotonyOffsets[b]
533 && offsets[a] < offsets[b]))));
543 return lt(s1, s2) != splitTree;
545 return lt(m1, m2) == splitTree;
548 TTK_PSORT(this->threadNumber_, triplets.begin(), triplets.end(), cmp);
551template <
typename scalarType,
typename offsetType>
553 std::vector<PersistencePair> &pairs,
554 std::vector<std::vector<SimplexId>> &vertexRepresentatives,
555 std::vector<triplet> &triplets,
556 const scalarType *
const fakeScalars,
557 const offsetType *
const offsets,
558 const int *
const monotonyOffsets,
560 const bool splitTree)
const {
578 return ((fakeScalars[a] < fakeScalars[b])
579 || (fakeScalars[a] == fakeScalars[b]
580 && ((monotonyOffsets[a] < monotonyOffsets[b])
581 || (monotonyOffsets[a] == monotonyOffsets[b]
582 && offsets[a] < offsets[b]))));
586 auto r = vertexRepresentatives[v][0];
589 r = vertexRepresentatives[v][0];
594 for(
const auto &t : triplets) {
607 pairs.emplace_back(s, r1, 2);
616 pairs.emplace_back(r1, s, 0);
620 vertexRepresentatives[std::get<1>(t)][0] = r2;
621 vertexRepresentatives[r1][0] = r2;
627 if(debugLevel_ > 3) {
628 std::string prefix = splitTree ?
"[sad-max]" :
"[min-sad]";
629 std::cout << prefix <<
" found all pairs in " << tm.
getElapsedTime()
630 <<
" s." << std::endl;
634template <
typename scalarType,
typename offsetType>
637 std::vector<SimplexId> &sortedVertices,
639 const scalarType *
const fakeScalars,
640 const offsetType *
const offsets,
641 const int *
const monotonyOffsets) {
645 sortedVertices.resize(vertexNumber);
648 std::iota(sortedVertices.begin(), sortedVertices.end(), 0);
651 TTK_PSORT(this->threadNumber_, sortedVertices.begin(), sortedVertices.end(),
653 return ((fakeScalars[a] < fakeScalars[b])
654 || (fakeScalars[a] == fakeScalars[b]
655 && ((monotonyOffsets[a] < monotonyOffsets[b])
656 || (monotonyOffsets[a] == monotonyOffsets[b]
657 && offsets[a] < offsets[b]))));
660#ifdef TTK_ENABLE_OPENMP
661#pragma omp parallel for num_threads(threadNumber_)
663 for(
size_t i = 0; i < sortedVertices.size(); ++i) {
664 vertsOrder[sortedVertices[i]] = i;
672template <
typename scalarType,
typename offsetType>
676 const std::vector<polarity> &isNew,
677 std::vector<polarity> &toProcess,
678 std::vector<polarity> &toReprocess,
679 std::vector<std::pair<polarity, polarity>> &vlp,
680 scalarType *fakeScalars,
681 const offsetType *
const offsets,
682 int *monotonyOffsets)
const {
684 int hasMonotonyChanged = 0;
686 = multiresTriangulation_.getVertexNeighborNumber(vertexId);
687 for(
SimplexId i = 0; i < neighborNumber; i++) {
689 multiresTriangulation_.getVertexNeighbor(vertexId, i, neighborId);
696 const bool lowerDynamic
697 = ((fakeScalars[neighborId] < fakeScalars[vertexId])
698 || (fakeScalars[neighborId] == fakeScalars[vertexId]
699 && ((monotonyOffsets[neighborId] < monotonyOffsets[vertexId])
700 || (monotonyOffsets[neighborId] == monotonyOffsets[vertexId]
701 && offsets[neighborId] < offsets[vertexId]))));
703 const polarity isUpperDynamic = lowerDynamic ? 0 : 255;
705 const polarity isUpperOld = vlp[i].first;
707 if(isUpperDynamic != isUpperOld) {
709 int oldDecimation = pow(2, decimationLevel_ + 1);
710 multiresTriangulation_.getVertexNeighborAtDecimation(
711 vertexId, i, oldNeighbor, oldDecimation);
713 double replacementValueDynamic
714 = (0.5 * (double)fakeScalars[oldNeighbor]
715 + .5 * (
double)fakeScalars[vertexId]);
717 = fabs((
double)fakeScalars[neighborId] - replacementValueDynamic);
722 = multiresTriangulation_.getVertexNeighborNumber(neighborId);
723 for(
SimplexId iii = 0; iii < nnumber; iii++) {
725 multiresTriangulation_.getVertexNeighbor(neighborId, iii, neighborId2);
726 if(!isNew[neighborId2]) {
731 if(deltaDynamic > eps or !isNew[neighborId] or oldNeighNumber > 2) {
732 hasMonotonyChanged = 1;
734 toReprocess[vertexId] = 255;
735 if(isNew[neighborId]) {
736 toProcess[neighborId] = 255;
738 toReprocess[neighborId] = 255;
741 = multiresTriangulation_.getVertexNeighborNumber(neighborId);
742 for(
SimplexId j = 0; j < neighborNumberNew; j++) {
744 multiresTriangulation_.getVertexNeighbor(
745 neighborId, j, neighborIdNew);
746 if(isNew[neighborIdNew])
747 toProcess[neighborIdNew] = 255;
751 fakeScalars[neighborId] = replacementValueDynamic;
754 if(fakeScalars[neighborId] == fakeScalars[oldNeighbor]) {
755 fakeScalars[neighborId] = fakeScalars[vertexId];
765 if(offsets[vertexId] > offsets[neighborId]) {
766 monotonyOffsets[neighborId]
767 = monotonyOffsets[vertexId] + pow(2, decimationLevel_);
768 if(monotonyOffsets[vertexId] == monotonyOffsets[oldNeighbor]
769 and fakeScalars[vertexId] == fakeScalars[oldNeighbor]) {
770 std::cout <<
"THIS IS AN ISSUE" << std::endl;
773 monotonyOffsets[neighborId] = monotonyOffsets[vertexId];
776 if(offsets[vertexId] < offsets[neighborId]) {
777 monotonyOffsets[neighborId]
778 = monotonyOffsets[vertexId] - pow(2, decimationLevel_);
779 if(monotonyOffsets[vertexId] == monotonyOffsets[oldNeighbor]
780 and fakeScalars[vertexId] == fakeScalars[oldNeighbor]) {
781 std::cout <<
"THIS IS AN ISSUE" << std::endl;
784 monotonyOffsets[neighborId] = monotonyOffsets[vertexId];
790 return hasMonotonyChanged;
793template <
typename scalarType,
typename offsetType>
796 std::vector<Lock> &vertLock,
797 std::vector<polarity> &toPropagate,
798 std::vector<std::vector<SimplexId>> &vertexRepresentatives,
799 std::vector<std::vector<SimplexId>> &saddleCC,
800 std::vector<polarity> &isUpdated,
801 std::vector<SimplexId> &globalExtremum,
802 const bool splitTree,
803 const scalarType *fakeScalars,
804 const offsetType *
const offsets,
805 const int *
const monotonyOffsets)
const {
807 auto &toProp = toPropagate[vertexId];
808 auto &reps = vertexRepresentatives[vertexId];
809 auto &updated = isUpdated[vertexId];
822 return ((fakeScalars[v1] > fakeScalars[v2])
823 || (fakeScalars[v1] == fakeScalars[v2]
824 && ((monotonyOffsets[v1] > monotonyOffsets[v2])
825 || (monotonyOffsets[v1] == monotonyOffsets[v2]
826 && offsets[v1] > offsets[v2]))))
830 if(this->threadNumber_ > 1) {
831 vertLock[vertexId].lock();
833 if(saddleCC[vertexId].size()
839 printMsg(
"to saddle " + std::to_string(vertexId) +
" "
840 + std::to_string(saddleCC[vertexId].size()));
847 const auto &CC = saddleCC[vertexId];
849 reps.reserve(CC.size());
850 for(
size_t r = 0; r < CC.size(); r++) {
853 multiresTriangulation_.getVertexNeighbor(vertexId, localId, neighborId);
859 neighborId, vertLock, toPropagate, vertexRepresentatives, saddleCC,
860 isUpdated, globalExtremum, splitTree, fakeScalars, offsets,
862 reps.emplace_back(ret);
865 if(reps.size() > 1) {
867 std::sort(reps.begin(), reps.end(), gt);
868 const auto last = std::unique(reps.begin(), reps.end());
869 reps.erase(last, reps.end());
873 if(this->threadNumber_ > 1) {
874 vertLock[vertexId].unlock();
881 printMsg(
"to non saddle " + std::to_string(vertexId) +
" "
882 + std::to_string(saddleCC[vertexId].size()));
886 = multiresTriangulation_.getVertexNeighborNumber(vertexId);
889 for(
SimplexId i = 0; i < neighborNumber; i++) {
891 multiresTriangulation_.getVertexNeighbor(vertexId, i, neighborId);
892 if(gt(neighborId, maxNeighbor)) {
893 maxNeighbor = neighborId;
896 if(maxNeighbor != vertexId) {
897 ret = propagateFromSaddles(maxNeighbor, vertLock, toPropagate,
898 vertexRepresentatives, saddleCC, isUpdated,
899 globalExtremum, splitTree, fakeScalars,
900 offsets, monotonyOffsets);
903#ifdef TTK_ENABLE_OPENMP
904 const auto tid = omp_get_thread_num();
908 if(gt(vertexId, globalExtremum[tid])) {
913 globalExtremum[tid] = vertexId;
919 if(this->threadNumber_ > 1) {
920 vertLock[vertexId].unlock();
926template <
typename scalarType,
typename offsetType>
928 std::vector<polarity> &toPropagateMin,
929 std::vector<polarity> &toPropagateMax,
930 std::vector<std::vector<SimplexId>> &vertexRepresentativesMin,
931 std::vector<std::vector<SimplexId>> &vertexRepresentativesMax,
932 std::vector<std::vector<SimplexId>> &saddleCCMin,
933 std::vector<std::vector<SimplexId>> &saddleCCMax,
934 std::vector<Lock> &vertLockMin,
935 std::vector<Lock> &vertLockMax,
936 std::vector<polarity> &isUpdatedMin,
937 std::vector<polarity> &isUpdatedMax,
938 const scalarType *fakeScalars,
939 const offsetType *
const offsets,
940 const int *
const monotonyOffsets) {
943 const size_t nDecVerts = multiresTriangulation_.getDecimatedVertexNumber();
945 if(debugLevel_ > 5) {
946 const auto pred = [](
const polarity a) {
return a > 0; };
947 const auto numberOfCandidatesToPropagateMax
948 = std::count_if(toPropagateMax.begin(), toPropagateMax.end(), pred);
949 std::cout <<
" sad-max we have " << numberOfCandidatesToPropagateMax
950 <<
" vertices to propagate from outta " << nDecVerts << std::endl;
951 const auto numberOfCandidatesToPropagateMin
952 = std::count_if(toPropagateMin.begin(), toPropagateMin.end(), pred);
953 std::cout <<
" min-sad we have " << numberOfCandidatesToPropagateMin
954 <<
" vertices to propagate from outta " << nDecVerts << std::endl;
957 std::vector<SimplexId> globalMaxThr(threadNumber_, 0);
958 std::vector<SimplexId> globalMinThr(threadNumber_, 0);
961#ifdef TTK_ENABLE_OPENMP
962#pragma omp parallel for num_threads(threadNumber_)
964 for(
size_t i = 0; i < nDecVerts; i++) {
965 SimplexId v = multiresTriangulation_.localToGlobalVertexId(i);
971#ifdef TTK_ENABLE_OPENMP
972#pragma omp parallel for num_threads(threadNumber_)
974 for(
size_t i = 0; i < nDecVerts; i++) {
975 SimplexId v = multiresTriangulation_.localToGlobalVertexId(i);
976 if(toPropagateMin[v]) {
977 propagateFromSaddles(v, vertLockMin, toPropagateMin,
978 vertexRepresentativesMin, saddleCCMin, isUpdatedMin,
979 globalMinThr,
false, fakeScalars, offsets,
982 if(toPropagateMax[v]) {
983 propagateFromSaddles(v, vertLockMax, toPropagateMax,
984 vertexRepresentativesMax, saddleCCMax, isUpdatedMax,
985 globalMaxThr,
true, fakeScalars, offsets,
991 return ((fakeScalars[a] < fakeScalars[b])
992 || (fakeScalars[a] == fakeScalars[b]
993 && ((monotonyOffsets[a] < monotonyOffsets[b])
994 || (monotonyOffsets[a] == monotonyOffsets[b]
995 && offsets[a] < offsets[b]))));
998 globalMin_ = *std::min_element(globalMinThr.begin(), globalMinThr.end(), lt);
999 globalMax_ = *std::max_element(globalMaxThr.begin(), globalMaxThr.end(), lt);
1001 if(globalMin_ == 0 or globalMax_ == 0) {
1002#ifdef TTK_ENABLE_OPENMP
1003#pragma omp parallel for num_threads(threadNumber_)
1005 for(
size_t i = 0; i < nDecVerts; i++) {
1006 SimplexId v = multiresTriangulation_.localToGlobalVertexId(i);
1008#ifdef TTK_ENABLE_OPENMP
1009 const auto tid = omp_get_thread_num();
1014 if(lt(globalMaxThr[tid], v)) {
1015 globalMaxThr[tid] = v;
1017 if(lt(v, globalMinThr[tid])) {
1018 globalMinThr[tid] = v;
1022 = *std::min_element(globalMinThr.begin(), globalMinThr.end(), lt);
1024 = *std::max_element(globalMaxThr.begin(), globalMaxThr.end(), lt);
1027 if(debugLevel_ > 3) {
1028 printMsg(
"Propagation Update", 1, tm.getElapsedTime(), threadNumber_);
1032template <
typename scalarType,
typename offsetType>
1035 std::vector<std::pair<polarity, polarity>> &vlp,
1036 const scalarType *fakeScalars,
1037 const offsetType *
const offsets,
1038 const int *
const monotonyOffsets)
const {
1041 = multiresTriangulation_.getVertexNeighborNumber(vertexId);
1042 vlp.resize(neighborNumber);
1044 for(
SimplexId i = 0; i < neighborNumber; i++) {
1046 multiresTriangulation_.getVertexNeighbor(vertexId, i, neighborId0);
1050 = ((fakeScalars[neighborId0] < fakeScalars[vertexId])
1051 || (fakeScalars[neighborId0] == fakeScalars[vertexId]
1052 && ((monotonyOffsets[neighborId0] < monotonyOffsets[vertexId])
1053 || (monotonyOffsets[neighborId0] == monotonyOffsets[vertexId]
1054 && offsets[neighborId0] < offsets[vertexId]))));
1057 vlp[i] = std::make_pair(isUpper0, 0);
1061template <
typename scalarType,
typename offsetType>
1063 std::vector<polarity> &isNew,
1065 std::vector<std::vector<std::pair<polarity, polarity>>> &vertexLinkPolarity,
1066 const scalarType *scalars,
1067 const scalarType *fakeScalars,
1068 const offsetType *
const offsets,
1069 const int *
const monotonyOffsets,
1073 std::stringstream mymsg;
1074 std::vector<std::pair<polarity, polarity>> &vlp
1075 = vertexLinkPolarity[vertexId];
1076 mymsg <<
"POLARITY PRINT"
1078 mymsg <<
"vertex " << vertexId <<
" has "
1079 << multiresTriangulation_.getVertexNeighborNumber(vertexId)
1082 mymsg <<
"\tself f:" << fakeScalars[vertexId] <<
" s:" << scalars[vertexId]
1083 <<
" o:" << offsets[vertexId] <<
" m:" << monotonyOffsets[vertexId]
1084 <<
" isnew: " << (int)isNew[vertexId] <<
"\n";
1087 std::cout <<
"\tpolarity not initialized for " << vertexId << std::endl;
1088 std::cout << mymsg.str() << std::endl;
1093 i < multiresTriangulation_.getVertexNeighborNumber(vertexId); i++) {
1095 multiresTriangulation_.getVertexNeighbor(vertexId, i, nId);
1097 std::vector<std::pair<polarity, polarity>> &vlp2 = vertexLinkPolarity[nId];
1102 j < multiresTriangulation_.getVertexNeighborNumber(nId); j++) {
1104 multiresTriangulation_.getVertexNeighbor(nId, j, nId2);
1105 if(nId2 == vertexId) {
1106 rpol = vlp2[j].first;
1113 = ((fakeScalars[nId] < fakeScalars[vertexId])
1114 || (fakeScalars[nId] == fakeScalars[vertexId]
1115 && ((monotonyOffsets[nId] < monotonyOffsets[vertexId])
1116 || (monotonyOffsets[nId] == monotonyOffsets[vertexId]
1117 && offsets[nId] < offsets[vertexId]))));
1119 const polarity isUpper = lower ? 0 : 255;
1121 mymsg <<
" " << i <<
"th: " << nId <<
" f:" << fakeScalars[nId]
1122 <<
" s:" << scalars[nId] <<
" o:" << offsets[nId]
1123 <<
" m:" << monotonyOffsets[nId] <<
" , pol:" << (bool)vlp[i].first
1124 <<
"(" << (
bool)vlp[i].second <<
")"
1125 <<
" rpol:" << (bool)rpol <<
" true pol:" << (
bool)isUpper
1126 <<
" init " << init <<
" isnew: " << (int)isNew[nId] <<
"\n";
1127 if((rpol == isUpper and !vlp2.empty())
1128 or (isUpper != vlp[i].first and !vlp[i].second)) {
1129 mymsg <<
"POLARITY ERROR "
1134 if(error or verbose) {
1135 std::cout << mymsg.str() << std::endl;
1140template <
typename scalarType,
typename offsetType>
1143 std::vector<std::pair<polarity, polarity>> &vlp,
1144 uint8_t &vertexLink,
1147 const scalarType *fakeScalars,
1148 const offsetType *
const offsets,
1149 const int *
const monotonyOffsets)
const {
1152 buildVertexLinkPolarityApproximate(
1153 vertexId, vlp, fakeScalars, offsets, monotonyOffsets);
1156 = multiresTriangulation_.getVertexNeighborNumber(vertexId);
1157 link.
alloc(neighborNumber);
1160 vertexLink = multiresTriangulation_.getVertexBoundaryIndex(vertexId);
1164 const auto &vl = vlbt[vertexLink];
1166 for(
size_t edgeId = 0; edgeId < vl.size(); edgeId++) {
1169 if(vlp[n0].first == vlp[n1].first) {
1176template <
typename scalarType,
typename offsetType>
1178 std::vector<polarity> &isNew,
1179 std::vector<std::vector<std::pair<polarity, polarity>>> &vertexLinkPolarity,
1180 std::vector<polarity> &toProcess,
1181 const scalarType *fakeScalars,
1182 const offsetType *
const offsets,
1183 const int *
const monotonyOffsets)
const {
1186 const size_t nDecVerts = multiresTriangulation_.getDecimatedVertexNumber();
1189#ifdef TTK_ENABLE_OPENMP
1190#pragma omp parallel for num_threads(threadNumber_)
1192 for(
size_t i = 0; i < nDecVerts; i++) {
1193 SimplexId globalId = multiresTriangulation_.localToGlobalVertexId(i);
1194 buildVertexLinkPolarityApproximate(globalId, vertexLinkPolarity[globalId],
1195 fakeScalars, offsets, monotonyOffsets);
1196 toProcess[globalId] = 255;
1197 isNew[globalId] = 0;
1199 printMsg(
"Polarity Init", 1, timer.getElapsedTime(), threadNumber_,
1203template <
typename ScalarType,
typename offsetType>
1206 std::vector<polarity> &isNew,
1207 std::vector<std::vector<std::pair<polarity, polarity>>> &vertexLinkPolarity,
1208 std::vector<polarity> &toProcess,
1209 std::vector<polarity> &toReprocess,
1210 ScalarType *fakeScalars,
1211 const offsetType *
const offsets,
1212 int *monotonyOffsets)
const {
1215 const auto nDecVerts = multiresTriangulation_.getDecimatedVertexNumber();
1217#ifdef TTK_ENABLE_OPENMP
1218#pragma omp parallel for num_threads(threadNumber_)
1220 for(
SimplexId localId = 0; localId < nDecVerts; localId++) {
1221 SimplexId globalId = multiresTriangulation_.localToGlobalVertexId(localId);
1222 if(!isNew[globalId]) {
1223 getMonotonyChangeByOldPointCPApproximate(
1224 globalId, eps, isNew, toProcess, toReprocess,
1225 vertexLinkPolarity[globalId], fakeScalars, offsets, monotonyOffsets);
1230#ifdef TTK_ENABLE_OPENMP
1231#pragma omp parallel for num_threads(threadNumber_)
1233 for(
int i = 0; i < multiresTriangulation_.getDecimatedVertexNumber(); i++) {
1234 SimplexId globalId = multiresTriangulation_.localToGlobalVertexId(i);
1235 if(isNew[globalId]) {
1236 if(decimationLevel_ > stoppingDecimationLevel_) {
1237 buildVertexLinkPolarityApproximate(
1238 globalId, vertexLinkPolarity[globalId], fakeScalars, offsets,
1241 isNew[globalId] = 0;
1244 if(toReprocess[globalId]) {
1245 updateLinkPolarityPonctual(vertexLinkPolarity[globalId]);
1247 toProcess[globalId] = 255;
1248 toReprocess[globalId] = 0;
1255template <
typename ScalarType,
typename offsetType>
1257 std::vector<std::vector<std::pair<polarity, polarity>>> &vertexLinkPolarity,
1258 std::vector<polarity> &toPropagateMin,
1259 std::vector<polarity> &toPropagateMax,
1260 std::vector<polarity> &toProcess,
1261 std::vector<DynamicTree> &link,
1262 std::vector<uint8_t> &vertexLink,
1264 std::vector<std::vector<SimplexId>> &saddleCCMin,
1265 std::vector<std::vector<SimplexId>> &saddleCCMax,
1266 ScalarType *fakeScalars,
1267 const offsetType *
const offsets,
1268 int *monotonyOffsets) {
1272#ifdef TTK_ENABLE_OPENMP
1273#pragma omp parallel for num_threads(threadNumber_)
1275 for(
int i = 0; i < multiresTriangulation_.getDecimatedVertexNumber(); i++) {
1276 SimplexId globalId = multiresTriangulation_.localToGlobalVertexId(i);
1278 if(toProcess[globalId]) {
1280 getCriticalTypeApproximate(globalId, vertexLinkPolarity[globalId],
1281 vertexLink[globalId], link[globalId],
1282 vertexLinkByBoundaryType, fakeScalars, offsets,
1284 getValencesFromLink(globalId, vertexLinkPolarity[globalId],
1285 link[globalId], toPropagateMin, toPropagateMax,
1286 saddleCCMin, saddleCCMax);
1290 if(debugLevel_ > 3) {
1292 "Critical Points Computation", 1, tm.
getElapsedTime(), threadNumber_);
1296template <
typename scalarType>
1298 std::vector<PersistencePair> &diagram,
1299 scalarType *fakeScalars,
1301 int *monotonyOffsets)
const {
1302 auto cmp = [fakeScalars, offsets, monotonyOffsets](
1307 return ((fakeScalars[a] < fakeScalars[b])
1308 || (fakeScalars[a] == fakeScalars[b]
1309 && ((monotonyOffsets[a] < monotonyOffsets[b])
1310 || (monotonyOffsets[a] == monotonyOffsets[b]
1311 && offsets[a] < offsets[b]))));
1314 std::sort(diagram.begin(), diagram.end(), cmp);
1319template <
typename scalarType>
1321 std::vector<PersistencePair> &CTDiagram,
1322 const scalarType *scalars,
1323 scalarType *
const fakeScalars,
1325 int *
const outputMonotonyOffsets) {
1328 std::stringstream ss;
1329 ss <<
"Approximate Persistence Diagram computation with "
1334 ret = executeApproximateTopology(
1335 scalars, fakeScalars, outputOffsets, outputMonotonyOffsets);
1336 CTDiagram = std::move(CTDiagram_);
#define ttkNotUsed(x)
Mark function/method parameters that are not used in the function body at all.
#define TTK_PSORT(NTHREADS,...)
Parallel sort macro.
TTK processing package for progressive Topological Data Analysis.
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 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 scalarType *fakeScalars, const offsetType *const offsets, const int *const monotonyOffsets) const
void buildVertexLinkPolarityApproximate(const SimplexId vertexId, std::vector< std::pair< polarity, polarity > > &vlp, const scalarType *fakeScalars, const offsetType *const offsetField, const int *const monotonyOffsets) const
void buildVertexLinkPolarity(const SimplexId vertexId, std::vector< std::pair< polarity, polarity > > &vlp, const scalarType *fakeScalars, const offsetType *const offsets, const int *const monotonyOffsets) const
void sortTriplets(std::vector< triplet > &triplets, const ScalarType *const fakeScalars, const OffsetType *const offsets, const int *const monotonyOffsets, const bool splitTree) const
int getMonotonyChangeByOldPointCPApproximate(const SimplexId vertexId, double eps, const std::vector< polarity > &isNew, std::vector< polarity > &toProcess, std::vector< polarity > &toReprocess, std::vector< std::pair< polarity, polarity > > &vlp, scalarType *fakeScalars, const offsetType *const offsets, int *monotonyOffsets) const
void computePersistencePairsFromSaddles(std::vector< PersistencePair > &CTDiagram, const ScalarType *const fakeScalars, const offsetType *const offsets, const int *const monotonyOffsets, std::vector< std::vector< SimplexId > > &vertexRepresentativesMin, std::vector< std::vector< SimplexId > > &vertexRepresentativesMax, const std::vector< polarity > &toPropagateMin, const std::vector< polarity > &toPropagateMax) const
void initGlobalPolarity(std::vector< polarity > &isNew, std::vector< std::vector< std::pair< polarity, polarity > > > &vertexLinkPolarity, std::vector< polarity > &toProcess, const scalarType *fakeScalars, const offsetType *const offsets, const int *const monotonyOffsets) const
std::array< std::vector< std::pair< SimplexId, SimplexId > >, nLink_ > VLBoundaryType
void initCriticalPoints(std::vector< polarity > &isNew, std::vector< std::vector< std::pair< polarity, polarity > > > &vertexLinkPolarity, std::vector< polarity > &toProcess, 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 scalarType *const fakeScalars, const offsetType *const offsets, const int *const monotonyOffsets, const bool splitTree) const
void sortTripletsApproximate(std::vector< triplet > &triplets, const ScalarType *const scalars, const ScalarType *const fakeScalars, const OffsetType *const offsets, const int *const monotonyOffsets, const bool splitTree) const
void setDelta(double data)
int executeApproximateTopology(const scalarType *scalars, scalarType *fakeScalars, SimplexId *outputOffsets, int *outputMonotonyOffsets)
int sortPersistenceDiagramApproximate(std::vector< PersistencePair > &diagram, scalarType *fakeScalars, const SimplexId *const offsets, int *monotonyOffsets) const
void sortVertices(const SimplexId vertexNumber, std::vector< SimplexId > &sortedVertices, SimplexId *vertsOrder, const scalarType *const fakeScalars, const offsetType *const offsetField, const int *const monotonyOffsets)
int computeApproximatePD(std::vector< PersistencePair > &CTDiagram, const scalarType *scalars, scalarType *const fakeScalars, SimplexId *const outputOffsets, int *const outputMonotonyOffsets)
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 scalarType *fakeScalars, const offsetType *const offsetField, const int *const monotonyOffsets)
bool printPolarity(std::vector< polarity > &isNew, const SimplexId vertexId, std::vector< std::vector< std::pair< polarity, polarity > > > &vertexLinkPolarity, const scalarType *scalars, const scalarType *fakeScalars, const offsetType *const offsets, const int *const monotonyOffsets, bool verbose=false)
void getCriticalTypeApproximate(const SimplexId &vertexId, std::vector< std::pair< polarity, polarity > > &vlp, uint8_t &vertexLink, DynamicTree &link, VLBoundaryType &vlbt, const scalarType *fakeScalars, const offsetType *const offsets, const int *const monotonyOffsets) const
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 bool splitTree, const scalarType *fakeScalars, const offsetType *const offsetField, const int *const monotonyOffsets) const
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
static const size_t nLink_
void setEpsilon(double data)
void computeCriticalPoints(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, ScalarType *fakeScalars, const offsetType *const offsets, int *monotonyOffsets)
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
int updateGlobalPolarity(double eps, std::vector< polarity > &isNew, std::vector< std::vector< std::pair< polarity, polarity > > > &vertexLinkPolarity, std::vector< polarity > &toProcess, std::vector< polarity > &toReprocess, ScalarType *fakeScalars, const offsetType *const offsets, int *monotonyOffsets) const
void setDebugMsgPrefix(const std::string &prefix)
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
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Implements the Dynamic Tree data-structure (or ST-Tree)
void alloc(const std::size_t nbNodes)
bool insertEdge(DynTreeNode *const n1, DynTreeNode *const n2)
TTK processing package for progressive Topological Data Analysis.
int startingDecimationLevel_
MultiresTriangulation multiresTriangulation_
std::vector< PersistencePair > CTDiagram_
void buildVertexLinkByBoundary(const SimplexId vertexId, VLBoundaryType &vlbt) const
ImplicitTriangulation * triangulation_
int stoppingDecimationLevel_
int getDimensionality() const
int getVertexNumber() const
void setTriangulation(ImplicitTriangulation *triangulation)
void setDecimationLevel(int decimationLevel)
void findBoundaryRepresentatives(std::vector< SimplexId > &boundaryRepresentatives)
const std::string ENDCOLOR
const std::string UNDERLINED
std::tuple< ttk::SimplexId, ttk::SimplexId, ttk::SimplexId > triplet
Persistence pair type (with persistence in double)
int SimplexId
Identifier type for simplices of any dimension.
printMsg(debug::output::GREEN+" "+debug::output::ENDCOLOR+debug::output::GREEN+"▒"+debug::output::ENDCOLOR+debug::output::GREEN+"▒▒▒▒▒▒▒▒▒▒▒▒▒░"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)