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) {
415 toProcess, toReprocess, fakeScalars,
416 offsets, monotonyOffsets);
418 std::cout <<
"Found ERROR - aborting" << std::endl;
424 toProcess, link, vertexLink, vertexLinkByBoundaryType,
425 saddleCCMin, saddleCCMax, fakeScalars, offsets,
429 vertexRepresentativesMax, saddleCCMin, saddleCCMax,
430 vertLockMin, vertLockMax, isUpToDateMin, isUpToDateMax,
431 fakeScalars, offsets, monotonyOffsets);
434 CTDiagram_, fakeScalars, offsets, monotonyOffsets, vertexRepresentativesMin,
435 vertexRepresentativesMax, toPropagateMin, toPropagateMax);
444 this->threadNumber_);
449 CTDiagram_, fakeScalars, offsets, monotonyOffsets);
453 std::vector<SimplexId> sortedVertices{};
454 sortVertices(vertexNumber, sortedVertices, vertsOrder, fakeScalars, offsets,
459template <
typename ScalarType,
typename OffsetType>
461 std::vector<PersistencePair> &CTDiagram,
462 const ScalarType *
const fakeScalars,
463 const OffsetType *
const offsets,
464 const int *
const monotonyOffsets,
465 std::vector<std::vector<SimplexId>> &vertexRepresentativesMin,
466 std::vector<std::vector<SimplexId>> &vertexRepresentativesMax,
467 const std::vector<polarity> &toPropagateMin,
468 const std::vector<polarity> &toPropagateMax)
const {
472 std::vector<triplet> tripletsMax{}, tripletsMin{};
473 const SimplexId nbDecVert = multiresTriangulation_.getDecimatedVertexNumber();
475 for(
SimplexId localId = 0; localId < nbDecVert; localId++) {
477 = 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 const 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) {
643 sortedVertices.resize(vertexNumber);
646 std::iota(sortedVertices.begin(), sortedVertices.end(), 0);
649 TTK_PSORT(this->threadNumber_, sortedVertices.begin(), sortedVertices.end(),
651 return ((fakeScalars[a] < fakeScalars[b])
652 || (fakeScalars[a] == fakeScalars[b]
653 && ((monotonyOffsets[a] < monotonyOffsets[b])
654 || (monotonyOffsets[a] == monotonyOffsets[b]
655 && offsets[a] < offsets[b]))));
658#ifdef TTK_ENABLE_OPENMP
659#pragma omp parallel for num_threads(threadNumber_)
661 for(
size_t i = 0; i < sortedVertices.size(); ++i) {
662 vertsOrder[sortedVertices[i]] = i;
666template <
typename scalarType,
typename offsetType>
670 const std::vector<polarity> &isNew,
671 std::vector<polarity> &toProcess,
672 std::vector<polarity> &toReprocess,
673 std::vector<std::pair<polarity, polarity>> &vlp,
674 scalarType *fakeScalars,
675 const offsetType *
const offsets,
676 int *monotonyOffsets)
const {
678 int hasMonotonyChanged = 0;
680 = multiresTriangulation_.getVertexNeighborNumber(vertexId);
681 for(
SimplexId i = 0; i < neighborNumber; i++) {
683 multiresTriangulation_.getVertexNeighbor(vertexId, i, neighborId);
690 const bool lowerDynamic
691 = ((fakeScalars[neighborId] < fakeScalars[vertexId])
692 || (fakeScalars[neighborId] == fakeScalars[vertexId]
693 && ((monotonyOffsets[neighborId] < monotonyOffsets[vertexId])
694 || (monotonyOffsets[neighborId] == monotonyOffsets[vertexId]
695 && offsets[neighborId] < offsets[vertexId]))));
697 const polarity isUpperDynamic = lowerDynamic ? 0 : 255;
699 const polarity isUpperOld = vlp[i].first;
701 if(isUpperDynamic != isUpperOld) {
703 const int oldDecimation = pow(2, decimationLevel_ + 1);
704 multiresTriangulation_.getVertexNeighborAtDecimation(
705 vertexId, i, oldNeighbor, oldDecimation);
707 double const replacementValueDynamic
708 = (0.5 * (double)fakeScalars[oldNeighbor]
709 + .5 * (
double)fakeScalars[vertexId]);
710 double const deltaDynamic
711 = fabs((
double)fakeScalars[neighborId] - replacementValueDynamic);
716 = multiresTriangulation_.getVertexNeighborNumber(neighborId);
717 for(
SimplexId iii = 0; iii < nnumber; iii++) {
719 multiresTriangulation_.getVertexNeighbor(neighborId, iii, neighborId2);
720 if(!isNew[neighborId2]) {
725 if(deltaDynamic > eps or !isNew[neighborId] or oldNeighNumber > 2) {
726 hasMonotonyChanged = 1;
728 toReprocess[vertexId] = 255;
729 if(isNew[neighborId]) {
730 toProcess[neighborId] = 255;
732 toReprocess[neighborId] = 255;
735 = multiresTriangulation_.getVertexNeighborNumber(neighborId);
736 for(
SimplexId j = 0; j < neighborNumberNew; j++) {
738 multiresTriangulation_.getVertexNeighbor(
739 neighborId, j, neighborIdNew);
740 if(isNew[neighborIdNew])
741 toProcess[neighborIdNew] = 255;
745 fakeScalars[neighborId] = replacementValueDynamic;
748 if(fakeScalars[neighborId] == fakeScalars[oldNeighbor]) {
749 fakeScalars[neighborId] = fakeScalars[vertexId];
759 if(offsets[vertexId] > offsets[neighborId]) {
760 monotonyOffsets[neighborId]
761 = monotonyOffsets[vertexId] + pow(2, decimationLevel_);
762 if(monotonyOffsets[vertexId] == monotonyOffsets[oldNeighbor]
763 and fakeScalars[vertexId] == fakeScalars[oldNeighbor]) {
764 std::cout <<
"THIS IS AN ISSUE" << std::endl;
767 monotonyOffsets[neighborId] = monotonyOffsets[vertexId];
770 if(offsets[vertexId] < offsets[neighborId]) {
771 monotonyOffsets[neighborId]
772 = monotonyOffsets[vertexId] - pow(2, decimationLevel_);
773 if(monotonyOffsets[vertexId] == monotonyOffsets[oldNeighbor]
774 and fakeScalars[vertexId] == fakeScalars[oldNeighbor]) {
775 std::cout <<
"THIS IS AN ISSUE" << std::endl;
778 monotonyOffsets[neighborId] = monotonyOffsets[vertexId];
784 return hasMonotonyChanged;
787template <
typename scalarType,
typename offsetType>
790 std::vector<Lock> &vertLock,
791 std::vector<polarity> &toPropagate,
792 std::vector<std::vector<SimplexId>> &vertexRepresentatives,
793 std::vector<std::vector<SimplexId>> &saddleCC,
794 std::vector<polarity> &isUpdated,
795 std::vector<SimplexId> &globalExtremum,
796 const bool splitTree,
797 const scalarType *fakeScalars,
798 const offsetType *
const offsets,
799 const int *
const monotonyOffsets)
const {
801 auto &toProp = toPropagate[vertexId];
802 auto &reps = vertexRepresentatives[vertexId];
803 auto &updated = isUpdated[vertexId];
816 return ((fakeScalars[v1] > fakeScalars[v2])
817 || (fakeScalars[v1] == fakeScalars[v2]
818 && ((monotonyOffsets[v1] > monotonyOffsets[v2])
819 || (monotonyOffsets[v1] == monotonyOffsets[v2]
820 && offsets[v1] > offsets[v2]))))
824 if(this->threadNumber_ > 1) {
825 vertLock[vertexId].lock();
827 if(saddleCC[vertexId].size()
833 printMsg(
"to saddle " + std::to_string(vertexId) +
" "
834 + std::to_string(saddleCC[vertexId].size()));
841 const auto &CC = saddleCC[vertexId];
843 reps.reserve(CC.size());
844 for(
size_t r = 0; r < CC.size(); r++) {
847 multiresTriangulation_.getVertexNeighbor(vertexId, localId, neighborId);
852 SimplexId const ret = propagateFromSaddles(
853 neighborId, vertLock, toPropagate, vertexRepresentatives, saddleCC,
854 isUpdated, globalExtremum, splitTree, fakeScalars, offsets,
856 reps.emplace_back(ret);
859 if(reps.size() > 1) {
861 std::sort(reps.begin(), reps.end(), gt);
862 const auto last = std::unique(reps.begin(), reps.end());
863 reps.erase(last, reps.end());
867 if(this->threadNumber_ > 1) {
868 vertLock[vertexId].unlock();
875 printMsg(
"to non saddle " + std::to_string(vertexId) +
" "
876 + std::to_string(saddleCC[vertexId].size()));
880 = multiresTriangulation_.getVertexNeighborNumber(vertexId);
883 for(
SimplexId i = 0; i < neighborNumber; i++) {
885 multiresTriangulation_.getVertexNeighbor(vertexId, i, neighborId);
886 if(gt(neighborId, maxNeighbor)) {
887 maxNeighbor = neighborId;
890 if(maxNeighbor != vertexId) {
891 ret = propagateFromSaddles(maxNeighbor, vertLock, toPropagate,
892 vertexRepresentatives, saddleCC, isUpdated,
893 globalExtremum, splitTree, fakeScalars,
894 offsets, monotonyOffsets);
897#ifdef TTK_ENABLE_OPENMP
898 const auto tid = omp_get_thread_num();
902 if(gt(vertexId, globalExtremum[tid])) {
907 globalExtremum[tid] = vertexId;
913 if(this->threadNumber_ > 1) {
914 vertLock[vertexId].unlock();
920template <
typename scalarType,
typename offsetType>
922 std::vector<polarity> &toPropagateMin,
923 std::vector<polarity> &toPropagateMax,
924 std::vector<std::vector<SimplexId>> &vertexRepresentativesMin,
925 std::vector<std::vector<SimplexId>> &vertexRepresentativesMax,
926 std::vector<std::vector<SimplexId>> &saddleCCMin,
927 std::vector<std::vector<SimplexId>> &saddleCCMax,
928 std::vector<Lock> &vertLockMin,
929 std::vector<Lock> &vertLockMax,
930 std::vector<polarity> &isUpdatedMin,
931 std::vector<polarity> &isUpdatedMax,
932 const scalarType *fakeScalars,
933 const offsetType *
const offsets,
934 const int *
const monotonyOffsets) {
937 const size_t nDecVerts = multiresTriangulation_.getDecimatedVertexNumber();
939 if(debugLevel_ > 5) {
940 const auto pred = [](
const polarity a) {
return a > 0; };
941 const auto numberOfCandidatesToPropagateMax
942 = std::count_if(toPropagateMax.begin(), toPropagateMax.end(), pred);
943 std::cout <<
" sad-max we have " << numberOfCandidatesToPropagateMax
944 <<
" vertices to propagate from outta " << nDecVerts << std::endl;
945 const auto numberOfCandidatesToPropagateMin
946 = std::count_if(toPropagateMin.begin(), toPropagateMin.end(), pred);
947 std::cout <<
" min-sad we have " << numberOfCandidatesToPropagateMin
948 <<
" vertices to propagate from outta " << nDecVerts << std::endl;
951 std::vector<SimplexId> globalMaxThr(threadNumber_, 0);
952 std::vector<SimplexId> globalMinThr(threadNumber_, 0);
955#ifdef TTK_ENABLE_OPENMP
956#pragma omp parallel for num_threads(threadNumber_)
958 for(
size_t i = 0; i < nDecVerts; i++) {
959 const SimplexId v = multiresTriangulation_.localToGlobalVertexId(i);
965#ifdef TTK_ENABLE_OPENMP
966#pragma omp parallel for num_threads(threadNumber_)
968 for(
size_t i = 0; i < nDecVerts; i++) {
969 SimplexId const v = multiresTriangulation_.localToGlobalVertexId(i);
970 if(toPropagateMin[v]) {
971 propagateFromSaddles(v, vertLockMin, toPropagateMin,
972 vertexRepresentativesMin, saddleCCMin, isUpdatedMin,
973 globalMinThr,
false, fakeScalars, offsets,
976 if(toPropagateMax[v]) {
977 propagateFromSaddles(v, vertLockMax, toPropagateMax,
978 vertexRepresentativesMax, saddleCCMax, isUpdatedMax,
979 globalMaxThr,
true, fakeScalars, offsets,
985 return ((fakeScalars[a] < fakeScalars[b])
986 || (fakeScalars[a] == fakeScalars[b]
987 && ((monotonyOffsets[a] < monotonyOffsets[b])
988 || (monotonyOffsets[a] == monotonyOffsets[b]
989 && offsets[a] < offsets[b]))));
992 globalMin_ = *std::min_element(globalMinThr.begin(), globalMinThr.end(), lt);
993 globalMax_ = *std::max_element(globalMaxThr.begin(), globalMaxThr.end(), lt);
995 if(globalMin_ == 0 or globalMax_ == 0) {
996#ifdef TTK_ENABLE_OPENMP
997#pragma omp parallel for num_threads(threadNumber_)
999 for(
size_t i = 0; i < nDecVerts; i++) {
1000 SimplexId const v = multiresTriangulation_.localToGlobalVertexId(i);
1002#ifdef TTK_ENABLE_OPENMP
1003 const auto tid = omp_get_thread_num();
1008 if(lt(globalMaxThr[tid], v)) {
1009 globalMaxThr[tid] = v;
1011 if(lt(v, globalMinThr[tid])) {
1012 globalMinThr[tid] = v;
1016 = *std::min_element(globalMinThr.begin(), globalMinThr.end(), lt);
1018 = *std::max_element(globalMaxThr.begin(), globalMaxThr.end(), lt);
1021 if(debugLevel_ > 3) {
1022 printMsg(
"Propagation Update", 1, tm.getElapsedTime(), threadNumber_);
1026template <
typename scalarType,
typename offsetType>
1029 std::vector<std::pair<polarity, polarity>> &vlp,
1030 const scalarType *fakeScalars,
1031 const offsetType *
const offsets,
1032 const int *
const monotonyOffsets)
const {
1035 = multiresTriangulation_.getVertexNeighborNumber(vertexId);
1036 vlp.resize(neighborNumber);
1038 for(
SimplexId i = 0; i < neighborNumber; i++) {
1040 multiresTriangulation_.getVertexNeighbor(vertexId, i, neighborId0);
1044 = ((fakeScalars[neighborId0] < fakeScalars[vertexId])
1045 || (fakeScalars[neighborId0] == fakeScalars[vertexId]
1046 && ((monotonyOffsets[neighborId0] < monotonyOffsets[vertexId])
1047 || (monotonyOffsets[neighborId0] == monotonyOffsets[vertexId]
1048 && offsets[neighborId0] < offsets[vertexId]))));
1051 vlp[i] = std::make_pair(isUpper0, 0);
1055template <
typename scalarType,
typename offsetType>
1057 std::vector<polarity> &isNew,
1059 std::vector<std::vector<std::pair<polarity, polarity>>> &vertexLinkPolarity,
1060 const scalarType *scalars,
1061 const scalarType *fakeScalars,
1062 const offsetType *
const offsets,
1063 const int *
const monotonyOffsets,
1067 std::stringstream mymsg;
1068 std::vector<std::pair<polarity, polarity>> &vlp
1069 = vertexLinkPolarity[vertexId];
1070 mymsg <<
"POLARITY PRINT"
1072 mymsg <<
"vertex " << vertexId <<
" has "
1073 << multiresTriangulation_.getVertexNeighborNumber(vertexId)
1076 mymsg <<
"\tself f:" << fakeScalars[vertexId] <<
" s:" << scalars[vertexId]
1077 <<
" o:" << offsets[vertexId] <<
" m:" << monotonyOffsets[vertexId]
1078 <<
" isnew: " << (int)isNew[vertexId] <<
"\n";
1081 std::cout <<
"\tpolarity not initialized for " << vertexId << std::endl;
1082 std::cout << mymsg.str() << std::endl;
1087 i < multiresTriangulation_.getVertexNeighborNumber(vertexId); i++) {
1089 multiresTriangulation_.getVertexNeighbor(vertexId, i, nId);
1091 std::vector<std::pair<polarity, polarity>> &vlp2 = vertexLinkPolarity[nId];
1096 j < multiresTriangulation_.getVertexNeighborNumber(nId); j++) {
1098 multiresTriangulation_.getVertexNeighbor(nId, j, nId2);
1099 if(nId2 == vertexId) {
1100 rpol = vlp2[j].first;
1107 = ((fakeScalars[nId] < fakeScalars[vertexId])
1108 || (fakeScalars[nId] == fakeScalars[vertexId]
1109 && ((monotonyOffsets[nId] < monotonyOffsets[vertexId])
1110 || (monotonyOffsets[nId] == monotonyOffsets[vertexId]
1111 && offsets[nId] < offsets[vertexId]))));
1113 const polarity isUpper = lower ? 0 : 255;
1115 mymsg <<
" " << i <<
"th: " << nId <<
" f:" << fakeScalars[nId]
1116 <<
" s:" << scalars[nId] <<
" o:" << offsets[nId]
1117 <<
" m:" << monotonyOffsets[nId] <<
" , pol:" << (bool)vlp[i].first
1118 <<
"(" << (
bool)vlp[i].second <<
")"
1119 <<
" rpol:" << (bool)rpol <<
" true pol:" << (
bool)isUpper
1120 <<
" init " << init <<
" isnew: " << (int)isNew[nId] <<
"\n";
1121 if((rpol == isUpper and !vlp2.empty())
1122 or (isUpper != vlp[i].first and !vlp[i].second)) {
1123 mymsg <<
"POLARITY ERROR "
1128 if(error or verbose) {
1129 std::cout << mymsg.str() << std::endl;
1134template <
typename scalarType,
typename offsetType>
1137 std::vector<std::pair<polarity, polarity>> &vlp,
1138 uint8_t &vertexLink,
1141 const scalarType *fakeScalars,
1142 const offsetType *
const offsets,
1143 const int *
const monotonyOffsets)
const {
1146 buildVertexLinkPolarityApproximate(
1147 vertexId, vlp, fakeScalars, offsets, monotonyOffsets);
1150 = multiresTriangulation_.getVertexNeighborNumber(vertexId);
1151 link.
alloc(neighborNumber);
1154 vertexLink = multiresTriangulation_.getVertexBoundaryIndex(vertexId);
1158 const auto &vl = vlbt[vertexLink];
1160 for(
size_t edgeId = 0; edgeId < vl.size(); edgeId++) {
1163 if(vlp[n0].first == vlp[n1].first) {
1170template <
typename scalarType,
typename offsetType>
1172 std::vector<polarity> &isNew,
1173 std::vector<std::vector<std::pair<polarity, polarity>>> &vertexLinkPolarity,
1174 std::vector<polarity> &toProcess,
1175 const scalarType *fakeScalars,
1176 const offsetType *
const offsets,
1177 const int *
const monotonyOffsets)
const {
1180 const size_t nDecVerts = multiresTriangulation_.getDecimatedVertexNumber();
1183#ifdef TTK_ENABLE_OPENMP
1184#pragma omp parallel for num_threads(threadNumber_)
1186 for(
size_t i = 0; i < nDecVerts; i++) {
1187 SimplexId const globalId = multiresTriangulation_.localToGlobalVertexId(i);
1188 buildVertexLinkPolarityApproximate(globalId, vertexLinkPolarity[globalId],
1189 fakeScalars, offsets, monotonyOffsets);
1190 toProcess[globalId] = 255;
1191 isNew[globalId] = 0;
1193 printMsg(
"Polarity Init", 1, timer.getElapsedTime(), threadNumber_,
1197template <
typename ScalarType,
typename offsetType>
1200 std::vector<polarity> &isNew,
1201 std::vector<std::vector<std::pair<polarity, polarity>>> &vertexLinkPolarity,
1202 std::vector<polarity> &toProcess,
1203 std::vector<polarity> &toReprocess,
1204 ScalarType *fakeScalars,
1205 const offsetType *
const offsets,
1206 int *monotonyOffsets)
const {
1208 const auto nDecVerts = multiresTriangulation_.getDecimatedVertexNumber();
1210#ifdef TTK_ENABLE_OPENMP
1211#pragma omp parallel for num_threads(threadNumber_)
1213 for(
SimplexId localId = 0; localId < nDecVerts; localId++) {
1215 = multiresTriangulation_.localToGlobalVertexId(localId);
1216 if(!isNew[globalId]) {
1217 getMonotonyChangeByOldPointCPApproximate(
1218 globalId, eps, isNew, toProcess, toReprocess,
1219 vertexLinkPolarity[globalId], fakeScalars, offsets, monotonyOffsets);
1224#ifdef TTK_ENABLE_OPENMP
1225#pragma omp parallel for num_threads(threadNumber_)
1227 for(
int i = 0; i < multiresTriangulation_.getDecimatedVertexNumber(); i++) {
1228 SimplexId const globalId = multiresTriangulation_.localToGlobalVertexId(i);
1229 if(isNew[globalId]) {
1230 if(decimationLevel_ > stoppingDecimationLevel_) {
1231 buildVertexLinkPolarityApproximate(
1232 globalId, vertexLinkPolarity[globalId], fakeScalars, offsets,
1235 isNew[globalId] = 0;
1238 if(toReprocess[globalId]) {
1239 updateLinkPolarityPonctual(vertexLinkPolarity[globalId]);
1241 toProcess[globalId] = 255;
1242 toReprocess[globalId] = 0;
1249template <
typename ScalarType,
typename offsetType>
1251 std::vector<std::vector<std::pair<polarity, polarity>>> &vertexLinkPolarity,
1252 std::vector<polarity> &toPropagateMin,
1253 std::vector<polarity> &toPropagateMax,
1254 std::vector<polarity> &toProcess,
1255 std::vector<DynamicTree> &link,
1256 std::vector<uint8_t> &vertexLink,
1258 std::vector<std::vector<SimplexId>> &saddleCCMin,
1259 std::vector<std::vector<SimplexId>> &saddleCCMax,
1260 ScalarType *fakeScalars,
1261 const offsetType *
const offsets,
1262 int *monotonyOffsets) {
1266#ifdef TTK_ENABLE_OPENMP
1267#pragma omp parallel for num_threads(threadNumber_)
1269 for(
int i = 0; i < multiresTriangulation_.getDecimatedVertexNumber(); i++) {
1270 SimplexId const globalId = multiresTriangulation_.localToGlobalVertexId(i);
1272 if(toProcess[globalId]) {
1274 getCriticalTypeApproximate(globalId, vertexLinkPolarity[globalId],
1275 vertexLink[globalId], link[globalId],
1276 vertexLinkByBoundaryType, fakeScalars, offsets,
1278 getValencesFromLink(globalId, vertexLinkPolarity[globalId],
1279 link[globalId], toPropagateMin, toPropagateMax,
1280 saddleCCMin, saddleCCMax);
1284 if(debugLevel_ > 3) {
1286 "Critical Points Computation", 1, tm.
getElapsedTime(), threadNumber_);
1290template <
typename scalarType>
1292 std::vector<PersistencePair> &diagram,
1293 scalarType *fakeScalars,
1295 int *monotonyOffsets)
const {
1296 auto cmp = [fakeScalars, offsets, monotonyOffsets](
1301 return ((fakeScalars[a] < fakeScalars[b])
1302 || (fakeScalars[a] == fakeScalars[b]
1303 && ((monotonyOffsets[a] < monotonyOffsets[b])
1304 || (monotonyOffsets[a] == monotonyOffsets[b]
1305 && offsets[a] < offsets[b]))));
1308 std::sort(diagram.begin(), diagram.end(), cmp);
1313template <
typename scalarType>
1315 std::vector<PersistencePair> &CTDiagram,
1316 const scalarType *scalars,
1317 scalarType *
const fakeScalars,
1319 int *
const outputMonotonyOffsets) {
1322 std::stringstream ss;
1323 ss <<
"Approximate Persistence Diagram computation with "
1328 ret = executeApproximateTopology(
1329 scalars, fakeScalars, outputOffsets, outputMonotonyOffsets);
1330 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 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::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)