TTK
Loading...
Searching...
No Matches
FTMTree_MT_Template.h
Go to the documentation of this file.
1
15
16#pragma once
17
18#include <functional>
19
20#include "FTMTree_MT.h"
21
22#ifdef TTK_ENABLE_OMP_PRIORITY
23#define OPTIONAL_PRIORITY(value) priority(value)
24#else
25#define OPTIONAL_PRIORITY(value)
26#endif
27
28// ----
29// Init
30// ----
31
32namespace ttk {
33 namespace ftm {
34
35 template <class triangulationType>
36 void FTMTree_MT::build(const triangulationType *mesh, const bool ct) {
37 std::string treeString;
38 // Comparator init (template)
39 initComp();
40 switch(mt_data_.treeType) {
41 case TreeType::Join:
42 treeString = "JT";
43 break;
44 case TreeType::Split:
45 treeString = "ST";
46 break;
47 default:
48 treeString = "CT";
49 break;
50 }
51
52 // Build Merge treeString using tasks
53 Timer precomputeTime;
54 int const alreadyDone = leafSearch(mesh);
55 printTime(precomputeTime, "leafSearch " + treeString, 3 + alreadyDone);
56
57 Timer buildTime;
58 leafGrowth(mesh);
59 printTime(buildTime, "leafGrowth " + treeString, 3);
60
61 Timer bbTime;
62 trunk(mesh, ct);
63 printTime(bbTime, "trunk " + treeString, 3);
64
65 if(this->getNumberOfNodes() != this->getNumberOfSuperArcs() + 1) {
66 this->printErr(treeString + " not a tree!");
67 }
68
69 // Segmentation
70 if(ct && params_->segm) {
71 Timer segmTime;
73 printTime(segmTime, "segment " + treeString, 3);
74 }
75 }
76
77 // ------------------------------------------------------------------------
78
79 template <class triangulationType>
80 int FTMTree_MT::leafSearch(const triangulationType *mesh) {
81 int ret = 0;
82 // if not already computed by CT
83 if(getNumberOfNodes() == 0) {
84 const auto nbScalars = scalars_->size;
85 const auto chunkSize = getChunkSize();
86 const auto chunkNb = getChunkCount();
87
88 // Extrema extract and launch tasks
89 for(SimplexId chunkId = 0; chunkId < chunkNb; ++chunkId) {
90#ifdef TTK_ENABLE_OPENMP4
91#pragma omp task firstprivate(chunkId) OPTIONAL_PRIORITY(isPrior())
92#endif
93 {
94 const SimplexId lowerBound = chunkId * chunkSize;
95 const SimplexId upperBound
96 = std::min(nbScalars, (chunkId + 1) * chunkSize);
97 for(SimplexId v = lowerBound; v < upperBound; ++v) {
98 const auto &neighNumb = mesh->getVertexNeighborNumber(v);
99 valence val = 0;
100
101 for(valence n = 0; n < neighNumb; ++n) {
102 SimplexId neigh{-1};
103 mesh->getVertexNeighbor(v, n, neigh);
104 comp_.vertLower(neigh, v) && ++val;
105 }
106
107 mt_data_.valences[v] = val;
108
109 if(!val) {
110 makeNode(v);
111 }
112 }
113 }
114 }
115
116#ifdef TTK_ENABLE_OPENMP4
117#pragma omp taskwait
118#endif
119 } else {
120 ret = 1;
121 }
122
123 // fill leaves
124 const auto &nbLeaves = mt_data_.nodes->size();
125 mt_data_.leaves.resize(nbLeaves);
126 std::iota(mt_data_.leaves.begin(), mt_data_.leaves.end(), 0);
127
128 if(debugLevel_ >= 4) {
129 this->printMsg("found " + std::to_string(nbLeaves) + " leaves");
130 }
131
132 // Reserve Arcs
133 mt_data_.superArcs->reserve(nbLeaves * 2 + 1);
134#ifdef TTK_ENABLE_FTM_TREE_STATS_TIME
135 createVector<ActiveTask>(mt_data_.activeTasksStats);
136 mt_data_.activeTasksStats.resize(nbLeaves * 2 + 1);
137#endif
138
139 return ret;
140 }
141
142 // ------------------------------------------------------------------------
143
144 template <class triangulationType>
145 void FTMTree_MT::leafGrowth(const triangulationType *mesh) {
146 _launchGlobalTime.reStart();
147
148 const auto &nbLeaves = mt_data_.leaves.size();
149
150 // memory allocation here
151 initVectStates(nbLeaves + 2);
152
153 // elevation: backbone only
154 if(nbLeaves == 1) {
155 const SimplexId v = (*mt_data_.nodes)[0].getVertexId();
156 mt_data_.openedNodes[v] = 1;
157 mt_data_.storage.emplace_back(v);
158 mt_data_.ufs[v] = &mt_data_.storage[0];
159 return;
160 }
161
162 mt_data_.activeTasks = nbLeaves;
163 mt_data_.storage.resize(nbLeaves);
164
165 auto comp = [this](const idNode a, const idNode b) {
166#ifdef HIGHER
167 return this->comp_.vertHigher(
168 this->getNode(a)->getVertexId(), this->getNode(b)->getVertexId());
169#else
170 return this->comp_.vertLower(
171 this->getNode(a)->getVertexId(), this->getNode(b)->getVertexId());
172#endif
173 };
174 sort(mt_data_.leaves.begin(), mt_data_.leaves.end(), comp);
175
176 for(idNode n = 0; n < nbLeaves; ++n) {
177 const idNode l = mt_data_.leaves[n];
178 SimplexId const v = getNode(l)->getVertexId();
179 // for each node: get vert, create uf and launch
180 mt_data_.storage[n] = AtomicUF{v};
181 mt_data_.ufs[v] = &mt_data_.storage[n];
182
183#ifdef TTK_ENABLE_OPENMP4
184#pragma omp task UNTIED() OPTIONAL_PRIORITY(isPrior())
185#endif
186 arcGrowth(mesh, v, n);
187 }
188
189#ifdef TTK_ENABLE_OPENMP4
190#pragma omp taskwait
191#endif
192 }
193
194 // ------------------------------------------------------------------------
195
196 template <class triangulationType>
197 void FTMTree_MT::arcGrowth(const triangulationType *mesh,
198 const SimplexId startVert,
199 const SimplexId orig) {
200 // current task id / propag
201
202 // local order (ignore non regular verts)
203 SimplexId localOrder = -1;
204 UF startUF = mt_data_.ufs[startVert]->find();
205 // get or recover states
206 CurrentState *currentState;
207 if(startUF->getNbStates()) {
208 currentState = startUF->getFirstState();
209 } else {
210 const std::size_t currentStateId = mt_data_.states->getNext();
211 currentState = &(*mt_data_.states)[currentStateId];
212 currentState->setStartVert(startVert);
213 startUF->addState(currentState);
214 }
215
216 currentState->addNewVertex(startVert);
217
218 // avoid duplicate processing of startVert
219 bool seenFirst = false;
220
221 // ARC OPENING
222 idNode const startNode = getCorrespondingNodeId(startVert);
223 idSuperArc const currentArc = openSuperArc(startNode);
224 startUF->addArcToClose(currentArc);
225#ifdef TTK_ENABLE_FTM_TREE_STATS_TIME
226 (*mt_data_.activeTasksStats)[currentArc].begin
227 = _launchGlobalTime.getElapsedTime();
228 (*mt_data_.activeTasksStats)[currentArc].origin = orig;
229#endif
230
231 // TASK PROPAGATION
232 while(!currentState->empty()) {
233 // Next vertex
234
235 SimplexId const currentVert = currentState->getNextMinVertex();
236
237 // ignore duplicate
238 if(!isCorrespondingNull(currentVert)
239 && !isCorrespondingNode(currentVert)) {
240 continue;
241 } else {
242 // first node can be duplicate, avoid duplicate process
243 if(currentVert == startVert) {
244 if(!seenFirst) {
245 seenFirst = true;
246 } else {
247 continue;
248 }
249 }
250 }
251
252 // local order to avoid sort
253 mt_data_.visitOrder[currentVert] = localOrder++;
254
255 // Saddle & Last detection + propagation
256 bool isSaddle, isLast;
257 std::tie(isSaddle, isLast) = propagate(mesh, *currentState, startUF);
258
259 // regular propagation
260#ifdef TTK_ENABLE_OPENMP4
261#pragma omp atomic write seq_cst
262#endif
263 mt_data_.ufs[currentVert] = startUF;
264
265 // Saddle case
266 if(isSaddle) {
267
268#ifdef TTK_ENABLE_FTM_TREE_STATS_TIME
269 (*mt_data_.activeTasksStats)[currentArc].end
270 = _launchGlobalTime.getElapsedTime();
271#endif
272 // need a node on this vertex
273#ifdef TTK_ENABLE_OPENMP4
274#pragma omp atomic write seq_cst
275#endif
276 mt_data_.openedNodes[currentVert] = 1;
277
278 // If last close all and merge
279 if(isLast) {
280 // finish works here
281 closeAndMergeOnSaddle(mesh, currentVert);
282
283 // last task detection
284 idNode remainingTasks;
285#ifdef TTK_ENABLE_OPENMP4
286#pragma omp atomic read seq_cst
287#endif
288 remainingTasks = mt_data_.activeTasks;
289 if(remainingTasks == 1) {
290 // only backbone remaining
291 return;
292 }
293
294 // made a node on this vertex
295#ifdef TTK_ENABLE_OPENMP4
296#pragma omp atomic write seq_cst
297#endif
298 mt_data_.openedNodes[currentVert] = 0;
299
300 // recursively continue
301#ifdef TTK_ENABLE_OPENMP4
302#pragma omp taskyield
303#endif
304 arcGrowth(mesh, currentVert, orig);
305 } else {
306 // Active tasks / threads
307#ifdef TTK_ENABLE_OPENMP4
308#pragma omp atomic update seq_cst
309#endif
311 }
312
313 // stop at saddle
314 return;
315 }
316
317 if(currentVert != startVert) {
318 updateCorrespondingArc(currentVert, currentArc);
319 }
320 getSuperArc(currentArc)->setLastVisited(currentVert);
321
322 } // end wile propagation
323
324 // close root
325 const SimplexId closeVert = getSuperArc(currentArc)->getLastVisited();
326 bool const existCloseNode = isCorrespondingNode(closeVert);
327 idNode const closeNode = (existCloseNode)
328 ? getCorrespondingNodeId(closeVert)
329 : makeNode(closeVert);
330 closeSuperArc(currentArc, closeNode);
331 getSuperArc(currentArc)->decrNbSeen();
332 idNode const rootPos = mt_data_.roots->getNext();
333 (*mt_data_.roots)[rootPos] = closeNode;
334
335#ifdef TTK_ENABLE_FTM_TREE_STATS_TIME
336 mt_data_.activeTasksStats[currentArc].end
337 = _launchGlobalTime.getElapsedTime();
338#endif
339 }
340
341 // ------------------------------------------------------------------------
342
343 template <class triangulationType>
344 std::tuple<bool, bool> FTMTree_MT::propagate(const triangulationType *mesh,
345 CurrentState &currentState,
346 UF curUF) {
347 bool becameSaddle = false, isLast = false;
348 const auto nbNeigh = mesh->getVertexNeighborNumber(currentState.vertex);
349 valence decr = 0;
350
351 // once for all
352 auto *curUFF = curUF->find();
353
354 // propagation / is saddle
355 for(valence n = 0; n < nbNeigh; ++n) {
356 SimplexId neigh{-1};
357 mesh->getVertexNeighbor(currentState.vertex, n, neigh);
358
359 if(comp_.vertLower(neigh, currentState.vertex)) {
360 UF neighUF = mt_data_.ufs[neigh];
361
362 // is saddle
363 if(!neighUF || neighUF->find() != curUFF) {
364 becameSaddle = true;
365 } else if(neighUF) {
366 ++decr;
367 }
368
369 } else {
370 if(!mt_data_.propagation[neigh]
371 || mt_data_.propagation[neigh]->find() != curUFF) {
372 currentState.addNewVertex(neigh);
373 mt_data_.propagation[neigh] = curUFF;
374 }
375 }
376 }
377
378 // is last
379 valence oldVal;
380 valence &tmp = mt_data_.valences[currentState.vertex];
381#ifdef TTK_ENABLE_OPENMP4
382#pragma omp atomic capture
383#endif
384 {
385 oldVal = tmp;
386 tmp -= decr;
387 }
388 if(oldVal == decr) {
389 isLast = true;
390 }
391
392 return std::make_tuple(becameSaddle, isLast);
393 }
394
395 // ------------------------------------------------------------------------
396
397 template <class triangulationType>
398 SimplexId FTMTree_MT::trunk(const triangulationType *mesh, const bool ct) {
399 Timer bbTimer;
400
401 std::vector<SimplexId> trunkVerts;
402 const auto &nbScalars = scalars_->size;
403
404 // trunkVerts
405 trunkVerts.reserve(std::max(SimplexId{10}, nbScalars / 500));
406 for(SimplexId v = 0; v < nbScalars; ++v) {
407 if(mt_data_.openedNodes[v]) {
408 if(this->isCorrespondingNode(v)) {
409 // parallel leafGrowth can partially build the trunk,
410 // filter out the saddles with an upward arc
411 const auto node{this->getNode(this->getCorrespondingNodeId(v))};
412 if(node->getNumberOfUpSuperArcs() == 0) {
413 trunkVerts.emplace_back(v);
414 }
415 } else {
416 trunkVerts.emplace_back(v);
417 }
418 }
419 }
420 sort(trunkVerts.begin(), trunkVerts.end(), comp_.vertLower);
421 for(const SimplexId v : trunkVerts) {
422 closeOnBackBone(mesh, v);
423 }
424
425 // Arcs
426 const auto &nbNodes = trunkVerts.size();
427 for(idNode n = 1; n < nbNodes; ++n) {
428 idSuperArc const na
429 = makeSuperArc(getCorrespondingNodeId(trunkVerts[n - 1]),
430 getCorrespondingNodeId(trunkVerts[n]));
431 getSuperArc(na)->setLastVisited(trunkVerts[n]);
432 }
433
434 if(!nbNodes) {
435 return 0;
436 }
437 const idSuperArc lastArc
438 = openSuperArc(getCorrespondingNodeId(trunkVerts[nbNodes - 1]));
439
440 // Root (close last arc)
441 // if several CC still the backbone is only in one.
442 // But the root may not be the max node of the whole dataset: TODO
443 const idNode rootNode
444 = makeNode(scalars_->sortedVertices[(isJT()) ? scalars_->size - 1 : 0]);
445 closeSuperArc(lastArc, rootNode);
446 getSuperArc(lastArc)->setLastVisited(getNode(rootNode)->getVertexId());
447
448 printTime(bbTimer, "trunk seq.", 4);
449 bbTimer.reStart();
450
451 // Segmentation
452 SimplexId begin, stop, processed;
453 std::tie(begin, stop) = getBoundsFromVerts(trunkVerts);
454 if(ct) {
455 processed = trunkCTSegmentation(trunkVerts, begin, stop);
456 } else {
457 processed = trunkSegmentation(trunkVerts, begin, stop);
458 }
459 printTime(bbTimer, "trunk para.", 4);
460
461 return processed;
462 }
463
464 // ------------------------------------------------------------------------
465
466 template <class triangulationType>
467 void FTMTree_MT::closeAndMergeOnSaddle(const triangulationType *mesh,
468 SimplexId saddleVert) {
469 idNode const closeNode = makeNode(saddleVert);
470
471 // Union of the UF coming here (merge propagation and closing arcs)
472 const auto &nbNeigh = mesh->getVertexNeighborNumber(saddleVert);
473 for(valence n = 0; n < nbNeigh; ++n) {
474 SimplexId neigh{-1};
475 mesh->getVertexNeighbor(saddleVert, n, neigh);
476
477 if(comp_.vertLower(neigh, saddleVert)) {
478 if(mt_data_.ufs[neigh]->find() != mt_data_.ufs[saddleVert]->find()) {
479 mt_data_.ufs[saddleVert] = AtomicUF::makeUnion(
480 mt_data_.ufs[saddleVert], mt_data_.ufs[neigh]);
481 }
482 }
483 }
484
485 // close arcs on this node
486 closeArcsUF(closeNode, mt_data_.ufs[saddleVert]);
487
488 mt_data_.ufs[saddleVert]->find()->mergeStates();
489 mt_data_.ufs[saddleVert]->find()->setExtrema(saddleVert);
490 }
491
492 // ------------------------------------------------------------------------
493
494 template <class triangulationType>
495 void FTMTree_MT::closeOnBackBone(const triangulationType *mesh,
496 SimplexId saddleVert) {
497 idNode const closeNode = makeNode(saddleVert);
498
499 // Union of the UF coming here (merge propagation and closing arcs)
500 const auto &nbNeigh = mesh->getVertexNeighborNumber(saddleVert);
501 for(valence n = 0; n < nbNeigh; ++n) {
502 SimplexId neigh{-1};
503 mesh->getVertexNeighbor(saddleVert, n, neigh);
504
505 if(comp_.vertLower(neigh, saddleVert)) {
506 if(mt_data_.ufs[neigh]
507 && mt_data_.ufs[neigh]->find()
508 != mt_data_.ufs[saddleVert]->find()) {
509 mt_data_.ufs[saddleVert] = AtomicUF::makeUnion(
510 mt_data_.ufs[saddleVert], mt_data_.ufs[neigh]);
511 }
512 }
513 }
514
515 // close arcs on this node
516 closeArcsUF(closeNode, mt_data_.ufs[saddleVert]);
517 }
518
519 // ------------------------------------------------------------------------
520
521 template <typename scalarType>
523
524 const auto nbVertices = scalars_->size;
525 scalars_->sortedVertices.resize(nbVertices);
526
527#ifdef TTK_ENABLE_OPENMP
528#pragma omp parallel for
529#endif
530 for(SimplexId i = 0; i < nbVertices; i++) {
531 scalars_->sortedVertices[scalars_->offsets[i]] = i;
532 }
533 }
534
535 } // namespace ftm
536} // namespace ttk
537// Process
int debugLevel_
Definition Debug.h:379
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:149
void reStart()
Definition Timer.h:21
void addArcToClose(idSuperArc a)
CurrentState * getFirstState()
Definition FTMAtomicUF.h:58
void addState(CurrentState *s)
size_t getNbStates() const
Definition FTMAtomicUF.h:82
static AtomicUF * makeUnion(AtomicUF *uf0, AtomicUF *uf1)
AtomicUF * find()
Definition FTMAtomicUF.h:38
bool isCorrespondingNode(const SimplexId val) const
Definition FTMTree_MT.h:449
std::shared_ptr< Params > params_
Definition FTMTree_MT.h:86
void closeOnBackBone(const triangulationType *mesh, SimplexId saddleVert)
SuperArc * getSuperArc(idSuperArc i)
Definition FTMTree_MT.h:367
idNode getNumberOfNodes() const
Definition FTMTree_MT.h:389
SimplexId getChunkSize(const SimplexId nbVerts=-1, const SimplexId nbtasks=100) const
Definition FTMTree_MT.h:819
bool isCorrespondingNull(const SimplexId val) const
Definition FTMTree_MT.h:453
void sortInput()
if sortedVertices_ is null, define and fill it
std::tuple< SimplexId, SimplexId > getBoundsFromVerts(const std::vector< SimplexId > &nodes) const
int leafSearch(const triangulationType *mesh)
void closeArcsUF(idNode closeNode, UF uf)
void closeAndMergeOnSaddle(const triangulationType *mesh, SimplexId saddleVert)
virtual SimplexId trunkSegmentation(const std::vector< SimplexId > &pendingNodesVerts, const SimplexId begin, const SimplexId stop)
std::tuple< bool, bool > propagate(const triangulationType *mesh, CurrentState &currentState, UF curUF)
idNode getCorrespondingNodeId(const SimplexId val) const
Definition FTMTree_MT.h:459
idSuperArc getNumberOfSuperArcs() const
Definition FTMTree_MT.h:363
void build(const triangulationType *mesh, const bool ct)
Compute the merge.
int printTime(Timer &t, const std::string &s, const int debugLevel=2) const
SimplexId getChunkCount(const SimplexId nbVerts=-1, const SimplexId nbTasks=100) const
Definition FTMTree_MT.h:832
SimplexId trunkCTSegmentation(const std::vector< SimplexId > &pendingNodesVerts, const SimplexId begin, const SimplexId stop)
idSuperArc openSuperArc(idNode downNodeId)
SimplexId trunk(const triangulationType *mesh, const bool ct)
idNode makeNode(SimplexId vertexId, SimplexId linked=nullVertex)
void buildSegmentation()
use vert2tree to compute the segmentation of the fresh built merge tree.
void leafGrowth(const triangulationType *mesh)
idSuperArc makeSuperArc(idNode downNodeId, idNode upNodeId)
bool isJT() const
Definition FTMTree_MT.h:289
Node * getNode(idNode nodeId)
Definition FTMTree_MT.h:393
void closeSuperArc(idSuperArc superArcId, idNode upNodeId)
std::shared_ptr< Scalars > scalars_
Definition FTMTree_MT.h:87
void initVectStates(const SimplexId nbLeaves)
Definition FTMTree_MT.h:202
void updateCorrespondingArc(const SimplexId vert, const idSuperArc arc)
Definition FTMTree_MT.h:493
void arcGrowth(const triangulationType *mesh, const SimplexId startVert, const SimplexId orig)
SimplexId getVertexId() const
Definition FTMNode.h:54
SimplexId getLastVisited() const
Definition FTMSuperArc.h:86
void setLastVisited(SimplexId vertId)
Definition FTMSuperArc.h:90
std::string to_string(__int128)
Definition ripserpy.cpp:99
long unsigned int idSuperArc
SuperArc index in vect_superArcs_.
SimplexId valence
for vertex up/down valence
unsigned int idNode
Node index in vect_nodes_.
The Topology ToolKit.
int SimplexId
Identifier type for simplices of any dimension.
Definition DataTypes.h:22
T end(std::pair< T, T > &p)
Definition ripserpy.cpp:472
T begin(std::pair< T, T > &p)
Definition ripserpy.cpp:468
void setStartVert(const SimplexId v)
SimplexId getNextMinVertex()
void addNewVertex(const SimplexId v)
std::shared_ptr< FTMAtomicVector< SuperArc > > superArcs
Definition FTMTree_MT.h:46
std::vector< AtomicUF > storage
Definition FTMTree_MT.h:57
std::shared_ptr< FTMAtomicVector< CurrentState > > states
Definition FTMTree_MT.h:60
std::shared_ptr< FTMAtomicVector< Node > > nodes
Definition FTMTree_MT.h:47
std::vector< SimplexId > visitOrder
Definition FTMTree_MT.h:53
std::vector< UF > propagation
Definition FTMTree_MT.h:59
std::vector< UF > ufs
Definition FTMTree_MT.h:58
std::shared_ptr< FTMAtomicVector< idNode > > roots
Definition FTMTree_MT.h:48
std::vector< valence > valences
Definition FTMTree_MT.h:62
std::vector< idNode > leaves
Definition FTMTree_MT.h:49
std::vector< char > openedNodes
Definition FTMTree_MT.h:64
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)