TTK
Loading...
Searching...
No Matches
MergeTreeBase.h
Go to the documentation of this file.
1
11
12#pragma once
13
14#include <AssignmentSolver.h>
15#include <FTMNode.h>
16#include <FTMTree.h>
17#include <FTMTreePPUtils.h>
18#include <FTMTreeUtils.h>
19
20#include "MergeTreeUtils.h"
21
22namespace ttk {
23
24 class MergeTreeBase : virtual public Debug {
25 protected:
28 double epsilonTree1_ = 0;
29 double epsilonTree2_ = 0;
30 double epsilon2Tree1_ = 100;
31 double epsilon2Tree2_ = 100;
32 double epsilon3Tree1_ = 100;
33 double epsilon3Tree2_ = 100;
36 bool useMinMaxPair_ = true;
38
42 bool keepSubtree_ = false;
43 double nonMatchingWeight_ = 1.0;
44
45 bool distanceSquaredRoot_ = true; // squared root
46 bool useFullMerge_ = false;
47
49 bool convertToDiagram_ = false;
50
51 // Double input
52 double mixtureCoefficient_ = 0.5;
53 bool useDoubleInput_ = false;
54
55 // Old
56 bool parallelize_ = true;
57 int nodePerTask_ = 32;
58 bool cleanTree_ = true;
59
60 // Clean correspondence
61 std::vector<std::vector<int>> treesNodeCorr_;
62
63 public:
66 "MergeTreeBase"); // inherited from Debug: prefix will be printed
67 // at the beginning of every msg
68 }
69
70 void setAssignmentSolver(int assignmentSolver) {
71 assignmentSolverID_ = assignmentSolver;
72 }
73
77
78 void setEpsilonTree1(double epsilon) {
79 epsilonTree1_ = epsilon;
80 }
81
82 void setEpsilonTree2(double epsilon) {
83 epsilonTree2_ = epsilon;
84 }
85
86 void setEpsilon2Tree1(double epsilon) {
87 epsilon2Tree1_ = epsilon;
88 }
89
90 void setEpsilon2Tree2(double epsilon) {
91 epsilon2Tree2_ = epsilon;
92 }
93
94 void setEpsilon3Tree1(double epsilon) {
95 epsilon3Tree1_ = epsilon;
96 }
97
98 void setEpsilon3Tree2(double epsilon) {
99 epsilon3Tree2_ = epsilon;
100 }
101
102 void setPersistenceThreshold(double pt) {
104 }
105
106 void setParallelize(bool para) {
107 parallelize_ = para;
108 }
109
110 void setNodePerTask(int npt) {
111 nodePerTask_ = npt;
112 }
113
114 void setBranchDecomposition(bool useBD) {
115 branchDecomposition_ = useBD;
116 }
117
118 void setNormalizedWasserstein(bool normalizedWasserstein) {
119 normalizedWasserstein_ = normalizedWasserstein;
120 }
121
122 void setKeepSubtree(bool keepSubtree) {
123 keepSubtree_ = keepSubtree;
124 }
125
126 void setNonMatchingWeight(double weight) {
127 nonMatchingWeight_ = weight;
128 }
129
130 void setBarycenterMergeTree(bool imt) {
132 }
133
134 void setDistanceSquaredRoot(bool distanceSquaredRoot) {
135 distanceSquaredRoot_ = distanceSquaredRoot;
136 }
137
138 void setUseMinMaxPair(bool useMinMaxPair) {
139 useMinMaxPair_ = useMinMaxPair;
140 }
141
142 void setDeleteMultiPersPairs(bool deleteMultiPersPairsT) {
143 deleteMultiPersPairs_ = deleteMultiPersPairsT;
144 }
145
146 void setCleanTree(bool clean) {
147 cleanTree_ = clean;
148 }
149
150 void setIsPersistenceDiagram(bool isPD) {
152 }
153
154 void setJoinSplitMixtureCoefficient(const double mixtureCoefficient) {
155 mixtureCoefficient_ = mixtureCoefficient;
156 }
157
158 void setUseDoubleInput(const bool useDoubleInput) {
159 useDoubleInput_ = useDoubleInput;
160 }
161
162 std::vector<std::vector<int>> getTreesNodeCorr() {
163 return treesNodeCorr_;
164 }
165
166 // ------------------------------------------------------------------------
167 // Double Input
168 // ------------------------------------------------------------------------
169 double mixDistancesMinMaxPairWeight(bool isFirstInput) {
170 return (
172 ? (isFirstInput ? mixtureCoefficient_ : (1.0 - mixtureCoefficient_))
173 : (isFirstInput ? 1.0 / std::pow(mixDistancesWeight(isFirstInput), 2)
174 : 0.0));
175 }
176
177 double mixDistancesWeight(bool isFirstInput) {
178 return (isFirstInput ? std::min(mixtureCoefficient_ * 2, 1.0)
179 : std::min(-mixtureCoefficient_ * 2 + 2, 1.0));
180 }
181
182 template <class dataType>
183 double mixDistances(dataType distance1, dataType distance2) {
184 return mixDistancesWeight(true) * distance1
185 + mixDistancesWeight(false) * distance2;
186 }
187
188 template <class dataType>
189 void
190 mixDistancesMatrix(std::vector<std::vector<dataType>> &distanceMatrix,
191 std::vector<std::vector<dataType>> &distanceMatrix2) {
192 for(unsigned int i = 0; i < distanceMatrix.size(); ++i)
193 for(unsigned int j = 0; j < distanceMatrix[i].size(); ++j)
194 distanceMatrix[i][j] = mixDistances<dataType>(
195 distanceMatrix[i][j], distanceMatrix2[i][j]);
196 }
197
198 // ------------------------------------------------------------------------
199 // Tree Preprocessing
200 // ------------------------------------------------------------------------
201 // Epsilon 1 processing
202 template <class dataType>
204 double epsilon,
205 std::vector<std::vector<ftm::idNode>> &treeNodeMerged,
206 bool mergeByPersistence = false) {
207 bool fullMerge = (epsilon == 100);
208 fullMerge &= useFullMerge_;
209
210 treeNodeMerged.clear();
211 treeNodeMerged.resize(tree->getNumberOfNodes());
212
213 // need to have the pairing (if merge by persistence)
214 if(mergeByPersistence)
216
217 // Compute epsilon value
218 dataType maxValue = tree->getValue<dataType>(0);
219 dataType minValue = tree->getValue<dataType>(0);
220 for(unsigned int i = 0; i < tree->getNumberOfNodes(); ++i) {
221 if(!tree->isRoot(i) and !tree->isLeaf(i)) {
222 dataType iValue = tree->getValue<dataType>(i);
223 if(mergeByPersistence) {
224 maxValue = (maxValue < iValue) ? iValue : maxValue;
225 minValue = (minValue > iValue) ? iValue : minValue;
226 } else {
227 ftm::idNode const parent = tree->getParentSafe(i);
228 dataType parentValue = tree->getValue<dataType>(parent);
229 dataType tempMax = std::max(iValue, parentValue);
230 dataType tempMin = std::min(iValue, parentValue);
231 if((tempMax - tempMin) > (maxValue - minValue)) {
232 maxValue = tempMax;
233 minValue = tempMin;
234 }
235 }
236 }
237 }
238 double const epsilonOri = epsilon;
239 epsilon = (maxValue - minValue) * epsilon / 100;
240
241 // For Farthest Saddle option
243 epsilon = tree->getMaximumPersistence<dataType>() * epsilonOri / 100;
244 bool isJT = tree->isJoinTree<dataType>();
245 auto isFarthest = [&](ftm::idNode a, ftm::idNode b) {
246 return (isJT
247 and tree->getValue<dataType>(a) > tree->getValue<dataType>(b))
248 or (not isJT
249 and tree->getValue<dataType>(a)
250 < tree->getValue<dataType>(b));
251 };
252 std::vector<ftm::idNode> farthestSaddle(tree->getNumberOfNodes());
253 for(unsigned int i = 0; i < farthestSaddle.size(); ++i)
254 farthestSaddle[i] = i;
255
256 // --- Merge saddle
257 // Create stack
258 std::stack<int> nodeStack;
259 std::queue<ftm::idNode> queue;
260 queue.emplace(tree->getRoot());
261 while(!queue.empty()) {
262 ftm::idNode const node = queue.front();
263 queue.pop();
264 nodeStack.emplace(node);
265 std::vector<ftm::idNode> children;
266 tree->getChildren(node, children);
267 for(auto child : children)
268 queue.emplace(child);
269 }
270 // Iterate through nodes
271 while(!nodeStack.empty()) {
272 ftm::idNode const nodeId = nodeStack.top();
273 nodeStack.pop();
274 if(!tree->isRoot(nodeId) and !tree->isLeaf(nodeId)) {
275 ftm::idNode const parentNodeId = tree->getParentSafe(nodeId);
276 dataType nodeValue = tree->getValue<dataType>(nodeId);
278 nodeValue = tree->getValue<dataType>(farthestSaddle[nodeId]);
279 dataType parentNodeValue = tree->getValue<dataType>(parentNodeId);
280 dataType diffValue = std::max(nodeValue, parentNodeValue)
281 - std::min(nodeValue, parentNodeValue);
282 if(diffValue <= epsilon) {
283 ftm::idNode nodeIdToDelete, nodeIdToKeep;
284 if(mergeByPersistence) {
285 auto birthDeath1 = tree->getBirthDeath<dataType>(nodeId);
286 auto birthDeath2 = tree->getBirthDeath<dataType>(parentNodeId);
287 dataType pers1
288 = std::get<1>(birthDeath1) - std::get<0>(birthDeath1);
289 dataType pers2
290 = std::get<1>(birthDeath2) - std::get<0>(birthDeath2);
291 nodeIdToDelete = (pers1 > pers2) ? parentNodeId : nodeId;
292 nodeIdToKeep = (pers1 > pers2) ? nodeId : parentNodeId;
293 if(nodeIdToDelete == parentNodeId)
294 nodeStack.emplace(nodeId);
295 } else {
296 nodeIdToDelete = nodeId;
297 nodeIdToKeep = parentNodeId;
298 }
299 // Manage nodeMerged vector of vector
300 for(auto node : treeNodeMerged[nodeIdToDelete]) {
301 treeNodeMerged[nodeIdToKeep].push_back(node);
302 if(isFarthest(farthestSaddle[nodeIdToKeep],
303 tree->getNode(node)->getOrigin()))
304 farthestSaddle[nodeIdToKeep] = tree->getNode(node)->getOrigin();
305 }
306 treeNodeMerged[nodeIdToKeep].push_back(
307 tree->getNode(nodeIdToDelete)->getOrigin());
308 if(isFarthest(farthestSaddle[nodeIdToKeep], nodeIdToDelete))
309 farthestSaddle[nodeIdToKeep] = nodeIdToDelete;
310 treeNodeMerged[nodeIdToDelete].clear();
311 // Delete node
312 tree->deleteNode(nodeIdToDelete);
313 }
314 }
315 }
316
317 if(fullMerge) {
318 auto root = tree->getRoot();
319 tree->getNode(root)->setOrigin(root);
320 }
321 }
322
323 // Epsilon 2 and 3 processing
324 template <class dataType>
326 double epsilon2,
327 double epsilon3 = 100) {
328 bool fullMerge = (epsilon2 == 0);
329 fullMerge &= useFullMerge_;
330 epsilon2 /= 100;
331 epsilon3 /= 100;
332 dataType maxPers = tree->getMaximumPersistence<dataType>();
333
334 std::queue<ftm::idNode> queue;
335 queue.emplace(tree->getRoot());
336 while(!queue.empty()) {
337 ftm::idNode const node = queue.front();
338 queue.pop();
339 ftm::idNode const nodeParent = tree->getParentSafe(node);
340 if(!tree->isRoot(node)) {
341 const double nodePers = tree->getNodePersistence<dataType>(node);
342 const double nodeParentPers
343 = tree->getNodePersistence<dataType>(nodeParent);
344 if(nodePers / nodeParentPers > epsilon2
345 and nodePers / maxPers < epsilon3)
346 tree->setParent(node, tree->getParentSafe(nodeParent));
347 }
348 std::vector<ftm::idNode> children;
349 tree->getChildren(node, children);
350 for(auto child : children)
351 queue.emplace(child);
352 }
353
354 if(fullMerge) {
355 auto root = tree->getRoot();
356 if(tree->getNode(root)->getOrigin() != (int)root) {
357 tree->setParent(tree->getNode(root)->getOrigin(), root);
358 tree->getNode(root)->setOrigin(root);
359 }
360 }
361 }
362
364 std::vector<ftm::idNode> &nodes) {
365 std::vector<ftm::idSuperArc> arcs;
366 for(unsigned int i = 0; i < nodes.size(); ++i) {
367 ftm::idNode node = nodes[i];
368 if(!tree->isRoot(node))
369 arcs.emplace_back(tree->getNode(node)->getUpSuperArcId(0));
370 tree->getNode(node)->clearDownSuperArcs();
371 tree->getNode(node)->clearUpSuperArcs();
372 ftm::idNode const nodeOrigin = tree->getNode(node)->getOrigin();
373 if(tree->isNodeOriginDefined(node)
374 and tree->getNode(nodeOrigin)->getOrigin() == (int)node) {
375 if(!tree->isRoot(nodeOrigin))
376 arcs.emplace_back(tree->getNode(nodeOrigin)->getUpSuperArcId(0));
377 tree->getNode(nodeOrigin)->clearDownSuperArcs();
378 tree->getNode(nodeOrigin)->clearUpSuperArcs();
379 }
380 }
381 tree->getNode(tree->getRoot())->removeDownSuperArcs(arcs);
382 }
383
384 template <class dataType>
385 void keepMostImportantPairs(ftm::FTMTree_MT *tree, int n, bool useBD) {
386 std::vector<std::tuple<ftm::idNode, ftm::idNode, dataType>> pairs;
387 tree->getPersistencePairsFromTree(pairs, useBD);
388 n = std::max(n, 2); // keep at least 2 pairs
389 unsigned int const index = std::max((int)(pairs.size() - n), 0);
391 std::vector<ftm::idNode> nodes(index);
392 for(unsigned int i = 0; i < index; ++i)
393 nodes[i] = std::get<0>(pairs[i]);
395 } else {
396 for(unsigned int i = 0; i < index; ++i) {
397 ftm::idNode node = std::get<0>(pairs[i]);
398 ftm::idNode nodeOrigin = std::get<1>(pairs[i]);
399 tree->deleteNode(node);
400 if(tree->getNode(nodeOrigin)->getOrigin() == (int)node)
401 tree->deleteNode(nodeOrigin);
402 }
403 }
404 }
405
406 template <class dataType>
408 double persistenceThresholdT,
409 std::vector<ftm::idNode> &deletedNodes) {
410 ftm::idNode const treeRoot = tree->getRoot();
411 dataType maxPers = tree->getMaximumPersistence<dataType>();
412 dataType threshold = persistenceThresholdT / 100 * maxPers;
413
414 dataType secondMax = tree->getSecondMaximumPersistence<dataType>();
415 bool keepOneZeroPersistencePair = (secondMax == 0 or maxPers == 0);
416 if(threshold >= secondMax)
417 threshold = (1.0 - 1e-6) * secondMax;
418
419 std::vector<ftm::idNode> nodes;
420 for(unsigned int i = 0; i < tree->getNumberOfNodes(); ++i) {
421 if(tree->isRoot(i))
422 continue;
423 dataType nodePers = tree->getNodePersistence<dataType>(i);
424 if(nodePers == 0 and keepOneZeroPersistencePair
425 and tree->getParentSafe(i) == treeRoot) {
426 keepOneZeroPersistencePair = false;
427 continue;
428 }
429 if((nodePers == 0 or nodePers <= threshold
430 or not tree->isNodeOriginDefined(i))) {
432 tree->deleteNode(i);
433 else
434 nodes.emplace_back(i);
435 deletedNodes.push_back(i);
436 ftm::idNode const nodeOrigin = tree->getNode(i)->getOrigin();
437 if(tree->isNodeOriginDefined(i)
438 and tree->getNode(nodeOrigin)->getOrigin() == (int)i) {
440 tree->deleteNode(nodeOrigin);
441 deletedNodes.push_back(nodeOrigin);
442 }
443 }
444 }
445
448 }
449
450 template <class dataType>
452 std::vector<ftm::idNode> &deletedNodes) {
454 tree, persistenceThreshold_, deletedNodes);
455 }
456
457 template <class dataType>
459 double persistenceThresholdT) {
460 std::vector<ftm::idNode> deletedNodes;
462 tree, persistenceThresholdT, deletedNodes);
463 }
464
465 template <class dataType>
467 std::vector<ftm::idNode> deletedNodes;
469 tree, persistenceThreshold_, deletedNodes);
470 }
471
472 template <class dataType>
474 for(unsigned int i = 0; i < tree->getNumberOfNodes(); ++i)
475 if(not tree->isNodeAlone(i) and not tree->isNodeOriginDefined(i)) {
476 std::stringstream ss;
477 std::vector<ftm::idNode> children;
478 tree->getChildren(i, children);
479 ss << i << " has no origin (scalar=" << tree->getValue<dataType>(i)
480 << ", noChildren=" << children.size()
481 << ", parent=" << tree->getParentSafe(i) << ")";
482 printMsg(ss.str());
483 if(!tree->isRoot(i))
484 tree->deleteNode(i);
485 else {
486 std::stringstream ss2;
487 ss2 << "the root has no origin!";
488 printErr(ss2.str());
489 }
490 }
491 }
492
493 template <class dataType>
495 bool deleteInconsistentNodes = true) {
496 if(deleteInconsistentNodes) {
497 // Manage inconsistent critical points
498 // Critical points with same scalar value than parent
500 for(unsigned int i = 0; i < tree->getNumberOfNodes(); ++i)
501 if(!tree->isNodeAlone(i) and !tree->isRoot(i)
502 and tree->getValue<dataType>(tree->getParentSafe(i))
503 == tree->getValue<dataType>(i)) {
504 tree->deleteNode(i);
505 }
506 // Valence 2 nodes
507 for(unsigned int i = 0; i < tree->getNumberOfNodes(); ++i)
508 if(tree->getNode(i)->getNumberOfUpSuperArcs() == 1
509 and tree->getNode(i)->getNumberOfDownSuperArcs() == 1) {
510 /*printMsg("[preprocessTree] " + std::to_string(i)
511 + " has 1 up arc and 1 down arc (will be deleted).");*/
512 tree->deleteNode(i);
513 }
514 }
515
516 // Compute persistence pairs
519 // Verify pairs
521 }
522 }
523
524 template <class dataType>
526 ftm::FTMTree_MT *tree,
527 std::vector<std::vector<ftm::idNode>> &treeNodeMerged) {
528 ftm::FTMTree_MT *treeNew = tree;
529
530 ftm::idNode const root = treeNew->getRoot();
531
532 // Manage when there is only one pair
534 ftm::idNode const rootOrigin = treeNew->getNode(root)->getOrigin();
535 treeNew->getNode(rootOrigin)->setOrigin(rootOrigin);
536 return treeNew;
537 }
538
539 // Manage multi persistence pairing
540 std::vector<std::vector<ftm::idNode>> treeMultiPers;
541 tree->getMultiPersOriginsVectorFromTree(treeMultiPers);
542
543 // General case
544 std::vector<bool> nodeDone(tree->getNumberOfNodes(), false);
545 std::queue<ftm::idNode> queueNodes;
546 queueNodes.emplace(root);
547 while(!queueNodes.empty()) {
548 ftm::idNode const node = queueNodes.front();
549 queueNodes.pop();
550 ftm::idNode const nodeOrigin = treeNew->getNode(node)->getOrigin();
551 if(node == nodeOrigin
552 or treeNew->getNodeLevel(node) > treeNew->getNodeLevel(nodeOrigin))
553 continue;
554
555 // Init vector with all origins
556 std::vector<std::tuple<ftm::idNode, int>> vecOrigins;
557 for(auto nodeMergedOrigin : treeNodeMerged[node]) {
558 vecOrigins.emplace_back(nodeMergedOrigin, 0);
559 for(auto multiPersOrigin :
560 treeMultiPers[tree->getNode(nodeMergedOrigin)->getOrigin()])
561 vecOrigins.emplace_back(multiPersOrigin, 1);
562 }
563 if(not tree->isNodeMerged(node))
564 for(auto multiPersOrigin : treeMultiPers[node])
565 vecOrigins.emplace_back(multiPersOrigin, 1);
566 vecOrigins.emplace_back(nodeOrigin, 2);
567
568 bool splitRoot = (vecOrigins.size() != 1 and treeNew->isRoot(node));
569 splitRoot = false; // disabled
570
571 // Process each origin
572 for(auto stackTuple : vecOrigins) {
573 ftm::idNode const nodeOriginT = std::get<0>(stackTuple);
574 int const nodeOriginTID = std::get<1>(stackTuple);
575 if(nodeDone[nodeOriginT]
576 and nodeDone[tree->getNode(nodeOriginT)->getOrigin()])
577 continue;
578 nodeDone[nodeOriginT] = true;
579 nodeDone[tree->getNode(nodeOriginT)->getOrigin()] = true;
580
581 // Manage new parent
582 ftm::idNode newParent = node;
583 // - if merged node
584 if(nodeOriginTID == 0) {
585 newParent = treeNew->getNode(nodeOriginT)->getOrigin();
586 treeNew->setParent(newParent, treeNew->getParentSafe(node));
587 // - if multi pers node or nodeOrigin and splitRoot
588 } else if(nodeOriginTID == 1 or (nodeOriginTID == 2 and splitRoot)) {
589 newParent = nodeOriginT;
590 }
591
592 // Set nodes in the branch as childrens of the node
593 ftm::idNode parentNodeOrigin = treeNew->getParentSafe(nodeOriginT);
594 while(parentNodeOrigin != node) {
595 ftm::idNode const oldParentNodeOrigin
596 = treeNew->getParentSafe(parentNodeOrigin);
597 treeNew->setParent(parentNodeOrigin, newParent);
598 parentNodeOrigin = oldParentNodeOrigin;
599 }
600
601 if(nodeOriginTID == 1 or (nodeOriginTID == 2 and splitRoot))
602 treeNew->setParent(newParent, treeNew->getParentSafe(node));
603 else // if(nodeOriginTID != 1) // if not a multi pers node
604 // Delete the other node of the pair
605 treeNew->deleteNode(nodeOriginT);
606 if(nodeOriginTID == 2 and splitRoot)
607 tree->getNode(node)->setOrigin(node);
608
609 // Push childrens of the node to the stack to process them
610 std::vector<ftm::idNode> childrenNode;
611 treeNew->getChildren(newParent, childrenNode);
612 for(ftm::idNode const children : childrenNode)
613 if(!treeNew->isLeaf(children))
614 queueNodes.emplace(children);
615 }
616 }
617
618 // Verify inconsistency
619 // verifyBranchDecompositionInconsistency<dataType>(treeNew);
620
621 return treeNew;
622 }
623
624 template <class dataType>
626 ftm::idNode const treeRoot = tree->getRoot();
627 // Full merge case, search for the origin
628 if(tree->getNode(treeRoot)->getOrigin() == (int)treeRoot) {
629 ftm::idNode const nodeIdToDelete
630 = tree->getMergedRootOrigin<dataType>();
631 if(nodeIdToDelete != treeRoot
632 and not tree->isNodeIdInconsistent(nodeIdToDelete)) {
634 tree->getNode(nodeIdToDelete)->setOrigin(nodeIdToDelete);
635 else
636 tree->deleteNode(nodeIdToDelete);
637 }
638 // Classic case
639 } else {
640 ftm::idNode const rootOrigin = tree->getNode(treeRoot)->getOrigin();
642 tree->getNode(rootOrigin)->setOrigin(rootOrigin);
643 else
644 tree->deleteNode(rootOrigin);
645 }
646
647 tree->getNode(treeRoot)->setOrigin(treeRoot);
648 }
649
651 int cptBug = 0;
652 for(unsigned int i = 0; i < tree->getNumberOfNodes(); ++i) {
653 if(not tree->isNodeOriginDefined(i)) {
654 std::stringstream ss;
655 ss << i << " _ " << tree->getNode(i)->getOrigin() << " / "
656 << tree->getNumberOfNodes();
657 printMsg(ss.str());
658 if(tree->isNodeAlone(i))
659 printMsg("alone");
660 cptBug++;
661 }
662 }
663 std::stringstream ss;
664 ss << cptBug;
665 printMsg(ss.str());
666 }
667
668 template <class dataType>
669 void deleteMultiPersPairs(ftm::FTMTree_MT *tree, bool useBD) {
670 auto multiPersOrigins = tree->getMultiPersOrigins<dataType>(useBD);
671 for(auto origin : multiPersOrigins)
672 tree->deleteNode(origin);
673 }
674
675 template <class dataType>
677 double epsilonTree,
678 double epsilon2Tree,
679 double epsilon3Tree,
680 bool branchDecompositionT,
681 bool useMinMaxPairT,
682 bool cleanTreeT,
683 double persistenceThreshold,
684 std::vector<int> &nodeCorr,
685 bool deleteInconsistentNodes = true,
686 bool removeMergedSaddles = false) {
687 Timer t_proc;
688
689 ftm::FTMTree_MT *tree = &(mTree.tree);
690
691 preprocessTree<dataType>(tree, deleteInconsistentNodes);
692
693 // - Delete null persistence pairs and persistence thresholding
694 persistenceThresholding<dataType>(tree, persistenceThreshold);
695
696 // - Merge saddle points according epsilon
697 std::vector<std::vector<ftm::idNode>> treeNodeMerged(
698 tree->getNumberOfNodes());
700 if(epsilonTree != 0) {
701 mergeSaddle<dataType>(tree, epsilonTree, treeNodeMerged);
702 if(removeMergedSaddles) {
703 for(unsigned int j = 0; j < treeNodeMerged.size(); j++) {
704 for(auto k : treeNodeMerged[j]) {
705 auto nodeToDelete = tree->getNode(k)->getOrigin();
706 tree->getNode(k)->setOrigin(j);
707 tree->getNode(nodeToDelete)->setOrigin(-1);
708 }
709 }
710 }
711 }
712 }
713
714 // - Compute branch decomposition
715 // verifyPairsTree(tree);
716 if(branchDecompositionT
718 tree = computeBranchDecomposition<dataType>(tree, treeNodeMerged);
719
720 // - Delete multi pers pairs
722 deleteMultiPersPairs<dataType>(tree, branchDecompositionT);
723
724 // - Remove min max pair
725 // verifyPairsTree(tree);
726 if(not useMinMaxPairT)
728
729 // - Epsilon 2 and 3 processing
730 if(branchDecompositionT and not isPersistenceDiagram_)
731 persistenceMerging<dataType>(tree, epsilon2Tree, epsilon3Tree);
732
733 // - Tree cleaning (remove unused nodes)
734 if(cleanTreeT) {
735 ftm::cleanMergeTree<dataType>(mTree, nodeCorr, branchDecompositionT);
736 tree = &(mTree.tree);
737 reverseNodeCorr(tree, nodeCorr);
738 }
739
740 // - Root number verification
741 if(tree->getNumberOfRoot() != 1)
742 printErr("preprocessingPipeline tree->getNumberOfRoot() != 1");
743
744 // - Time printing
745 // verifyPairsTree(tree);
746 auto t_preproc_time = t_proc.getElapsedTime();
747 std::stringstream ss;
748 ss << "TIME PREPROC. = " << t_preproc_time;
750 }
751
752 template <class dataType>
754 double epsilonTree,
755 double epsilon2Tree,
756 double epsilon3Tree,
757 bool branchDecompositionT,
758 bool useMinMaxPairT,
759 bool cleanTreeT,
760 std::vector<int> &nodeCorr,
761 bool deleteInconsistentNodes = true,
762 bool removeMergedSaddles = false) {
764 mTree, epsilonTree, epsilon2Tree, epsilon3Tree, branchDecompositionT,
765 useMinMaxPairT, cleanTreeT, persistenceThreshold_, nodeCorr,
766 deleteInconsistentNodes, removeMergedSaddles);
767 }
768
769 void reverseNodeCorr(ftm::FTMTree_MT *tree, std::vector<int> &nodeCorr) {
770 std::vector<int> newNodeCorr(tree->getNumberOfNodes());
771 for(unsigned int i = 0; i < nodeCorr.size(); ++i)
772 if(nodeCorr[i] >= 0 && nodeCorr[i] < (int)newNodeCorr.size())
773 newNodeCorr[nodeCorr[i]] = i;
774 nodeCorr = newNodeCorr;
775 }
776
777 template <class dataType>
779 ftm::FTMTree_MT *tree = &(mt.tree);
782 std::vector<std::vector<ftm::idNode>> treeNodeMerged;
783 mergeSaddle<dataType>(tree, 100.0, treeNodeMerged);
784 computeBranchDecomposition<dataType>(tree, treeNodeMerged);
785 }
786
787 template <class dataType>
788 void mtsFlattening(std::vector<ftm::MergeTree<dataType>> &mts) {
789 for(auto &mt : mts)
790 mtFlattening(mt);
791 }
792
793 double getSizeLimitMetric(std::vector<ftm::FTMTree_MT *> &trees) {
794 std::array<double, 3> stats;
795 getTreesStats(trees, stats);
796 auto meanNodes = stats[0];
797 unsigned int const n = trees.size();
798 return meanNodes * n;
799 }
800
801 // ------------------------------------------------------------------------
802 // Tree Postprocessing
803 // ------------------------------------------------------------------------
804 template <class dataType>
807 bool setOrigins = false) {
808 // Get min max pair
809 ftm::FTMTree_MT *tree1 = &(mTree1.tree);
810 ftm::idNode root = tree1->getRoot();
811 dataType newMax = tree1->getValue<dataType>(root);
812 ftm::idNode rootOrigin = tree1->getNode(root)->getOrigin();
813 dataType newMin = tree1->getValue<dataType>(rootOrigin);
814
815 // Update tree
816 ftm::idNode root2 = mTree2.tree.getRoot();
817 std::vector<dataType> newScalarsVector;
818 ftm::getTreeScalars<dataType>(mTree2, newScalarsVector);
819 newScalarsVector[root2] = newMax;
820
821 auto root2Origin = mTree2.tree.getNode(root2)->getOrigin();
822 if(root2Origin == (int)root2)
823 root2Origin = mTree2.tree.template getMergedRootOrigin<dataType>();
824 if(mTree2.tree.isNodeIdInconsistent(root2Origin))
825 newScalarsVector.push_back(newMin);
826 else
827 newScalarsVector[root2Origin] = newMin;
828
829 // Set new scalars
830 ftm::setTreeScalars<dataType>(mTree2, newScalarsVector);
831
832 // Create root origin if not already there
833 ftm::FTMTree_MT *treeNew = &(mTree2.tree);
834 if(mTree2.tree.isNodeIdInconsistent(root2Origin)) {
835 root2Origin = treeNew->getNumberOfNodes();
836 treeNew->makeNode(root2Origin);
837 }
838
839 // Manage new origins
840 if(setOrigins) {
841 treeNew->getNode(root2Origin)->setOrigin(root2);
842 treeNew->getNode(root2)->setOrigin(root2Origin);
843 }
844 }
845
846 template <class dataType>
847 std::tuple<int, dataType> fixMergedRootOrigin(ftm::FTMTree_MT *tree) {
848 if(not tree->isFullMerge())
849 return std::make_tuple(-1, -1);
850
851 // Get node of the min max pair
852 int maxIndex = tree->getMergedRootOrigin<dataType>();
853
854 // Link node of the min max pair with the root
855 ftm::idNode const treeRoot = tree->getRoot();
856 dataType oldOriginValue
857 = tree->getValue<dataType>(tree->getNode(maxIndex)->getOrigin());
858 tree->getNode(maxIndex)->setOrigin(treeRoot);
859
860 return std::make_tuple(maxIndex, oldOriginValue);
861 }
862
863 // TODO fix bug when one multi pers. pairs is moved up with epsilon 2 and 3
864 // but not its brothers
865 template <class dataType>
867 ftm::idNode const treeRoot = tree->getRoot();
868
869 // Get original tree message
870 std::stringstream const oriPrintTree = tree->printTree();
871 std::stringstream const oriPrintPairs
872 = tree->printPairsFromTree<dataType>(true);
873 std::stringstream const oriPrintMultiPers
874 = tree->printMultiPersPairsFromTree<dataType>(true);
875
876 // One pair case
878 ftm::idNode const treeRootOrigin = tree->getNode(treeRoot)->getOrigin();
879 tree->getNode(treeRootOrigin)->setOrigin(treeRoot);
880 return;
881 }
882
883 // Manage full merge and dontuseMinMaxPair_
884 bool const isFM = tree->isFullMerge();
885 if(isFM) {
886 ftm::idNode const mergedRootOrigin
887 = tree->getMergedRootOrigin<dataType>();
888 if(not tree->isNodeIdInconsistent(mergedRootOrigin)
889 and mergedRootOrigin != treeRoot)
890 tree->getNode(treeRoot)->setOrigin(mergedRootOrigin);
891 else {
892 printErr("branchDecompositionToTree mergedRootOrigin inconsistent");
893 }
894 }
895
896 // Some functions
897 bool isJT = tree->isJoinTree<dataType>();
898 auto comp = [&](const std::tuple<ftm::idNode, dataType> &a,
899 const std::tuple<ftm::idNode, dataType> &b) {
900 return isJT ? std::get<1>(a) > std::get<1>(b)
901 : std::get<1>(a) < std::get<1>(b);
902 };
903 auto getIndexNotMultiPers = [&](int index, ftm::FTMTree_MT *treeT,
904 std::vector<ftm::idNode> &children) {
905 while(index >= 0 and treeT->isMultiPersPair(children[index]))
906 --index;
907 return index;
908 };
909
910 // Branch Decomposition To Tree
911 std::vector<std::tuple<ftm::idNode, ftm::idNode>> nodeParent;
912 std::queue<ftm::idNode> queue;
913 queue.emplace(treeRoot);
914 while(!queue.empty()) {
915 ftm::idNode node = queue.front();
916 queue.pop();
917 auto nodeOrigin = tree->getNode(node)->getOrigin();
918 if(tree->isLeaf(node)) {
919 if(tree->isNodeAlone(nodeOrigin)) {
920 if(not isFM)
921 nodeParent.emplace_back(nodeOrigin, node);
922 else
923 nodeParent.emplace_back(node, nodeOrigin);
924 } else if(tree->isMultiPersPair(node)) {
925 nodeParent.emplace_back(node, nodeOrigin);
926 }
927 continue;
928 }
929
930 // Get children and sort them by scalar values
931 std::vector<ftm::idNode> childrenOri;
932 tree->getChildren(node, childrenOri);
933 std::vector<ftm::idNode> children = childrenOri;
934 std::vector<std::tuple<ftm::idNode, dataType>> childrenScalars;
935 for(unsigned int i = 0; i < children.size(); ++i) {
936 if(isFM and (int) children[i] != nodeOrigin)
937 children[i] = tree->getNode(children[i])->getOrigin();
938 childrenScalars.push_back(std::make_tuple(
939 children[i], tree->getValue<dataType>(children[i])));
940 }
941 std::sort(std::begin(childrenScalars), std::end(childrenScalars), comp);
942 children.clear();
943 for(unsigned int i = 0; i < childrenScalars.size(); ++i)
944 children.push_back(std::get<0>(childrenScalars[i]));
945
946 // Get new parent of children
947 for(unsigned int i = 1; i < children.size(); ++i) {
948 if(tree->isMultiPersPair(children[i]))
949 continue;
950 int const index = getIndexNotMultiPers(i - 1, tree, children);
951 if(index >= 0)
952 nodeParent.emplace_back(children[i], children[index]);
953 }
954
955 bool const multiPersPair
956 = tree->getNode(nodeOrigin)->getOrigin() != (int)node;
957 if(not multiPersPair) {
958 if(not isFM) {
959 int const index
960 = getIndexNotMultiPers(children.size() - 1, tree, children);
961 nodeParent.emplace_back(nodeOrigin, children[index]);
962 } else
963 nodeParent.emplace_back(children[0], node);
964 } else {
965 // std::cout << "branchDecompositionToTree multiPersPair" <<
966 // std::endl;
967 nodeParent.emplace_back(children[0], nodeOrigin);
968 int index = getIndexNotMultiPers(children.size() - 1, tree, children);
969 if(index < 0) { // should not be possible
970 printErr("[branchDecompositionToTree] index < 0");
971 index = 0;
972 }
973 nodeParent.emplace_back(node, children[index]);
974 }
975
976 // Push children to the queue
977 for(auto child : childrenOri)
978 queue.emplace(child);
979 }
980
981 // Set new parents for each node
982 for(auto nodeParentT : nodeParent)
983 tree->setParent(std::get<0>(nodeParentT), std::get<1>(nodeParentT));
984
985 // Verify that the tree is correct
986 for(unsigned int i = 0; i < tree->getNumberOfNodes(); ++i)
987 if(tree->getNode(i)->getNumberOfDownSuperArcs() == 1
988 and tree->getNode(i)->getNumberOfUpSuperArcs() == 1) {
989 printMsg(oriPrintPairs.str());
990 printMsg(oriPrintMultiPers.str());
991 printMsg(oriPrintTree.str());
992 printMsg(tree->printTree().str());
993 std::stringstream ss;
994 auto iOrigin = tree->getNode(i)->getOrigin();
995 ss << i << " _ " << iOrigin;
996 if(tree->getNode(iOrigin)->getOrigin() != int(i))
997 ss << " _ " << tree->getNode(iOrigin)->getOrigin() << " _ "
998 << tree->getNode(tree->getNode(iOrigin)->getOrigin())
999 ->getOrigin();
1000 printMsg(ss.str());
1001 printErr("[branchDecompositionToTree] 1 up arc and 1 down arc");
1002 }
1003 }
1004
1005 // For not branch decomposition tree
1006 template <class dataType>
1008 bool isJT = tree->isJoinTree<dataType>();
1009 std::queue<ftm::idNode> queue;
1010 queue.emplace(tree->getRoot());
1011 while(!queue.empty()) {
1012 ftm::idNode const node = queue.front();
1013 queue.pop();
1014 ftm::idNode const nodeOrigin = tree->getNode(node)->getOrigin();
1015 if(!tree->isLeaf(node)) {
1016 std::vector<ftm::idNode> children;
1017 tree->getChildren(node, children);
1018 std::vector<ftm::idNode> lowestNodes;
1019 ftm::idNode branchOrigin = nodeOrigin;
1020 for(auto child : children) {
1021 ftm::idNode lowestNode = tree->getLowestNode<dataType>(child);
1022 lowestNodes.push_back(lowestNode);
1023 ftm::idNode const lowestNodeOrigin
1024 = tree->getNode(lowestNode)->getOrigin();
1025 if(not tree->isNodeAlone(lowestNodeOrigin)
1026 and lowestNodeOrigin != node)
1027 branchOrigin = lowestNode;
1028 }
1029 for(size_t i = 0; i < children.size(); ++i) {
1030 ftm::idNode lowestNodeOrigin
1031 = tree->getNode(lowestNodes[i])->getOrigin();
1032 if(branchOrigin == lowestNodes[i] or lowestNodeOrigin == node)
1033 continue;
1034 dataType lowestNodeOriginVal
1035 = tree->getValue<dataType>(lowestNodeOrigin);
1036 ftm::idNode branchOriginT = branchOrigin;
1037 ftm::idNode const branchRoot
1038 = tree->getNode(branchOrigin)->getOrigin();
1039 while(branchRoot != branchOriginT) {
1040 dataType val
1041 = tree->getValue<dataType>(tree->getParentSafe(branchOriginT));
1042 if((val > lowestNodeOriginVal and isJT)
1043 or (val < lowestNodeOriginVal and not isJT))
1044 break;
1045 branchOriginT = tree->getParentSafe(branchOriginT);
1046 }
1047 tree->setParent(
1048 lowestNodeOrigin, tree->getParentSafe(branchOriginT));
1049 tree->setParent(branchOriginT, lowestNodeOrigin);
1050 tree->setParent(children[i], lowestNodeOrigin);
1051 }
1052 }
1053 std::vector<ftm::idNode> children;
1054 tree->getChildren(node, children);
1055 for(auto child : children)
1056 queue.emplace(child);
1057 }
1058 }
1059
1060 template <class dataType>
1062 // if(not branchDecomposition_ or not useMinMaxPair)
1063 // fixMergedRootOrigin<dataType>(tree);
1064 if(tree->isFullMerge()) {
1065 auto mergedRootOrigin = tree->getMergedRootOrigin<dataType>();
1066 if(not tree->isNodeIdInconsistent(mergedRootOrigin))
1067 tree->getNode(tree->getRoot())->setOrigin(mergedRootOrigin);
1068 else
1069 printErr(
1070 "[postprocessingPipeline] mergedRootOrigin inconsistent id.");
1071 }
1073 if(not isPersistenceDiagram_ and tree->getRealNumberOfNodes() != 0)
1075 } else
1077 }
1078
1079 // ------------------------------------------------------------------------
1080 // Output Matching
1081 // ------------------------------------------------------------------------
1082 template <class dataType>
1084 ftm::FTMTree_MT *tree1,
1085 ftm::FTMTree_MT *tree2,
1086 std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>
1087 &outputMatching) {
1088 std::vector<std::tuple<ftm::idNode, ftm::idNode, double>> toAdd;
1089 for(auto mTuple : outputMatching) {
1090 ftm::idNode const node1 = std::get<0>(mTuple);
1091 ftm::idNode const node2 = std::get<1>(mTuple);
1092 double const cost = std::get<2>(mTuple);
1093 ftm::idNode const node1Origin = tree1->getNode(node1)->getOrigin();
1094 ftm::idNode const node2Origin = tree2->getNode(node2)->getOrigin();
1095
1096 int const node1Level = tree1->getNodeLevel(node1);
1097 int const node1OriginLevel = tree1->getNodeLevel(node1Origin);
1098 int const node2Level = tree2->getNodeLevel(node2);
1099 int const node2OriginLevel = tree2->getNodeLevel(node2Origin);
1100
1101 ftm::idNode const node1Higher
1102 = (node1Level > node1OriginLevel) ? node1 : node1Origin;
1103 ftm::idNode const node1Lower
1104 = (node1Level > node1OriginLevel) ? node1Origin : node1;
1105 ftm::idNode const node2Higher
1106 = (node2Level > node2OriginLevel) ? node2 : node2Origin;
1107 ftm::idNode const node2Lower
1108 = (node2Level > node2OriginLevel) ? node2Origin : node2;
1109
1110 if(((tree1->isRoot(node1Higher) and tree1->isFullMerge())
1111 or (tree2->isRoot(node2Higher) and tree2->isFullMerge())))
1112 continue;
1113
1114 if(!tree1->isNodeAlone(node1Higher)
1115 and !tree2->isNodeAlone(node2Higher))
1116 toAdd.emplace_back(node1Higher, node2Higher, cost);
1117 if(!tree1->isNodeAlone(node1Lower) and !tree2->isNodeAlone(node2Lower))
1118 toAdd.emplace_back(node1Lower, node2Lower, cost);
1119 }
1120 outputMatching.clear();
1121 outputMatching.insert(outputMatching.end(), toAdd.begin(), toAdd.end());
1122 }
1123
1124 template <class dataType>
1126 ftm::FTMTree_MT *tree1,
1127 ftm::FTMTree_MT *tree2,
1128 std::vector<std::tuple<ftm::idNode, ftm::idNode>> &outputMatching) {
1129 std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>
1130 realOutputMatching(outputMatching.size());
1131 for(size_t i = 0; i < outputMatching.size(); ++i) {
1132 const auto &tup{outputMatching[i]};
1133 realOutputMatching[i] = {std::get<0>(tup), std::get<1>(tup), 0.0};
1134 }
1135
1137 tree1, tree2, realOutputMatching);
1138
1139 outputMatching.clear();
1140 for(auto tup : realOutputMatching)
1141 outputMatching.emplace_back(std::get<0>(tup), std::get<1>(tup));
1142 }
1143
1144 template <class dataType>
1146 ftm::FTMTree_MT *tree1,
1147 ftm::FTMTree_MT *tree2,
1148 std::vector<std::tuple<ftm::idNode, ftm::idNode>> &outputMatching,
1149 std::vector<std::tuple<ftm::idNode, ftm::idNode, bool>> &realMatching) {
1150 for(std::tuple<ftm::idNode, ftm::idNode> mTuple : outputMatching) {
1151 ftm::idNode tree1Node = std::get<0>(mTuple);
1152 ftm::idNode tree2Node = std::get<1>(mTuple);
1153 dataType relabelCostVal
1154 = relabelCostOnly<dataType>(tree1, tree1Node, tree2, tree2Node);
1155 dataType deleteInsertCostVal = deleteCost<dataType>(tree1, tree1Node)
1156 + insertCost<dataType>(tree2, tree2Node);
1157 bool isRealMatching = (relabelCostVal <= deleteInsertCostVal);
1158 realMatching.emplace_back(tree1Node, tree2Node, isRealMatching);
1159 }
1160 }
1161
1162 // ------------------------------------------------------------------------
1163 // Edit Costs
1164 // ------------------------------------------------------------------------
1165 template <class dataType>
1167 dataType x1, dataType x2, dataType y1, dataType y2, double power = 2) {
1168 if(power <= 0)
1169 return std::max(
1170 std::abs((double)(x1 - y1)), std::abs((double)(x2 - y2)));
1171 else
1172 return std::pow(std::abs((double)(x1 - y1)), power)
1173 + std::pow(std::abs((double)(x2 - y2)), power);
1174 }
1175
1176 template <class dataType>
1177 dataType deleteCost(const ftm::FTMTree_MT *tree, ftm::idNode nodeId) {
1178 dataType cost = 0;
1179 dataType newMin = 0.0, newMax = 1.0;
1180 // Get birth/death
1181 auto birthDeath
1183 ? getNormalizedBirthDeath<dataType>(tree, nodeId, newMin, newMax)
1184 : tree->getBirthDeath<dataType>(nodeId);
1185 dataType birth = std::get<0>(birthDeath);
1186 dataType death = std::get<1>(birthDeath);
1187 dataType projec = (birth + death) / 2;
1188 // Compute delete cost
1190 birth, death, projec, projec, wassersteinPower_);
1191 // Divide cost by two if not branch decomposition and not merged
1192 /*if(! branchDecomposition_ and ! tree->isNodeMerged(nodeId))
1193 cost /= 2;*/
1194 cost *= nonMatchingWeight_;
1195
1196 return cost;
1197 }
1198
1199 template <class dataType>
1200 dataType insertCost(const ftm::FTMTree_MT *tree, ftm::idNode nodeId) {
1201 return deleteCost<dataType>(tree, nodeId);
1202 }
1203
1204 template <class dataType>
1205 dataType relabelCostOnly(const ftm::FTMTree_MT *tree1,
1206 ftm::idNode nodeId1,
1207 const ftm::FTMTree_MT *tree2,
1208 ftm::idNode nodeId2) {
1209 dataType cost = 0;
1210 dataType newMin = 0.0, newMax = 1.0;
1211 // Get birth/death of the first tree
1212 auto birthDeath1
1214 ? getNormalizedBirthDeath<dataType>(tree1, nodeId1, newMin, newMax)
1215 : tree1->getBirthDeath<dataType>(nodeId1);
1216 dataType birth1 = std::get<0>(birthDeath1);
1217 dataType death1 = std::get<1>(birthDeath1);
1218 // Get birth/death of the second tree
1219 auto birthDeath2
1221 ? getNormalizedBirthDeath<dataType>(tree2, nodeId2, newMin, newMax)
1222 : tree2->getBirthDeath<dataType>(nodeId2);
1223 dataType birth2 = std::get<0>(birthDeath2);
1224 dataType death2 = std::get<1>(birthDeath2);
1225 // Compute relabel cost
1227 birth1, death1, birth2, death2, wassersteinPower_);
1228 // Divide cost by two if not branch decomposition and not merged
1229 /*bool merged = isNodeMerged(tree1, nodeId1) or isNodeMerged(tree2,
1230 nodeId2); if(! branchDecomposition_ and ! merged) cost /= 2;*/
1231
1232 return cost;
1233 }
1234
1235 template <class dataType>
1236 dataType relabelCost(const ftm::FTMTree_MT *tree1,
1237 ftm::idNode nodeId1,
1238 const ftm::FTMTree_MT *tree2,
1239 ftm::idNode nodeId2) {
1240 // Full merge case and only one persistence pair case
1241 if(tree1->getNode(nodeId1)->getOrigin() == (int)nodeId1
1242 or tree2->getNode(nodeId2)->getOrigin() == (int)nodeId2)
1243 return 0;
1244
1245 // Compute relabel cost
1246 dataType cost = relabelCostOnly<dataType>(tree1, nodeId1, tree2, nodeId2);
1247
1248 if(keepSubtree_) {
1249 // Compute deleteInsert cost
1250 dataType deleteInsertCost = deleteCost<dataType>(tree1, nodeId1)
1251 + insertCost<dataType>(tree2, nodeId2);
1252 if(deleteInsertCost < cost)
1253 cost = deleteInsertCost;
1254 }
1255
1256 return cost;
1257 }
1258
1259 // ------------------------------------------------------------------------
1260 // Utils
1261 // ------------------------------------------------------------------------
1262 void getParamNames(std::vector<std::string> &paramNames) {
1263 paramNames = std::vector<std::string>{"epsilon1",
1264 "epsilon2",
1265 "epsilon3",
1266 "persistenceThreshold",
1267 "branchDecomposition",
1268 "normalizedWasserstein",
1269 "keepSubtree",
1270 "isPersistenceDiagram",
1271 "deleteMultiPersPairs",
1272 "epsilon1UseFarthestSaddle",
1273 "mixtureCoefficient"};
1274 }
1275
1276 double getParamValueFromName(std::string &paramName) {
1277 double value = 0.0;
1278 if(paramName == "epsilon1")
1279 value = epsilonTree1_;
1280 else if(paramName == "epsilon2")
1281 value = epsilon2Tree1_;
1282 else if(paramName == "epsilon3")
1283 value = epsilon3Tree1_;
1284 else if(paramName == "persistenceThreshold")
1285 value = persistenceThreshold_;
1286 else if(paramName == "branchDecomposition")
1287 value = branchDecomposition_;
1288 else if(paramName == "normalizedWasserstein")
1289 value = normalizedWasserstein_;
1290 else if(paramName == "keepSubtree")
1291 value = keepSubtree_;
1292 else if(paramName == "isPersistenceDiagram")
1293 value = isPersistenceDiagram_;
1294 else if(paramName == "deleteMultiPersPairs")
1295 value = deleteMultiPersPairs_;
1296 else if(paramName == "epsilon1UseFarthestSaddle")
1298 else if(paramName == "mixtureCoefficient")
1299 value = mixtureCoefficient_;
1300 return value;
1301 }
1302
1303 void setParamValueFromName(std::string &paramName, double value) {
1304 if(paramName == "epsilon1")
1305 epsilonTree1_ = value;
1306 else if(paramName == "epsilon2")
1307 epsilon2Tree1_ = value;
1308 else if(paramName == "epsilon3")
1309 epsilon3Tree1_ = value;
1310 else if(paramName == "persistenceThreshold")
1311 persistenceThreshold_ = value;
1312 else if(paramName == "branchDecomposition")
1313 branchDecomposition_ = value;
1314 else if(paramName == "normalizedWasserstein")
1315 normalizedWasserstein_ = value;
1316 else if(paramName == "keepSubtree")
1317 keepSubtree_ = value;
1318 else if(paramName == "isPersistenceDiagram")
1319 isPersistenceDiagram_ = value;
1320 else if(paramName == "deleteMultiPersPairs")
1321 deleteMultiPersPairs_ = value;
1322 else if(paramName == "epsilon1UseFarthestSaddle")
1324 else if(paramName == "mixtureCoefficient")
1325 mixtureCoefficient_ = value;
1326 }
1327
1328 void getTreesStats(std::vector<ftm::FTMTree_MT *> &trees,
1329 std::array<double, 3> &stats) {
1330 double avgNodes = 0, avgNodesT = 0;
1331 double avgDepth = 0;
1332 for(unsigned int i = 0; i < trees.size(); ++i) {
1333 auto noNodesT = trees[i]->getNumberOfNodes();
1334 auto noNodes = trees[i]->getRealNumberOfNodes();
1335 avgNodes += noNodes;
1336 avgNodesT += noNodesT;
1337 avgDepth += trees[i]->getTreeDepth();
1338 }
1339 avgNodes /= trees.size();
1340 avgNodesT /= trees.size();
1341 avgDepth /= trees.size();
1342
1343 stats = {avgNodes, avgNodesT, avgDepth};
1344 }
1345
1346 void printTreesStats(std::vector<ftm::FTMTree_MT *> &trees) {
1347 std::array<double, 3> stats;
1348 getTreesStats(trees, stats);
1349 int avgNodes = stats[0], avgNodesT = stats[1];
1350 double const avgDepth = stats[2];
1351 std::stringstream ss;
1352 ss << trees.size() << " trees average [node: " << avgNodes << " / "
1353 << avgNodesT << ", depth: " << avgDepth << "]";
1355 }
1356
1357 template <class dataType>
1358 void printTreesStats(std::vector<ftm::MergeTree<dataType>> &trees) {
1359 std::vector<ftm::FTMTree_MT *> treesT;
1360 ftm::mergeTreeToFTMTree<dataType>(trees, treesT);
1361 printTreesStats(treesT);
1362 }
1363
1364 template <class dataType>
1365 void printTableVector(std::vector<std::vector<dataType>> &table) {
1366 std::streamsize const ssize = std::cout.precision();
1367 std::stringstream ss;
1368 ss << " ";
1369 for(unsigned int j = 0; j < table[0].size(); ++j)
1370 ss << j - 1 << " ";
1371 printMsg(ss.str());
1372 ss.str("");
1373 ss.clear();
1374 for(unsigned int i = 0; i < table.size(); ++i) {
1375 ss << std::setw(3) << std::setfill('0') << std::internal << i - 1
1376 << " | ";
1377 for(unsigned int j = 0; j < table[0].size(); ++j) {
1378 ss << std::fixed << std::setprecision(2) << table[i][j] << " ";
1379 }
1380 printMsg(ss.str());
1381 printMsg("");
1382 }
1383 std::cout.precision(ssize);
1385 }
1386
1387 template <class dataType>
1388 void printTable(dataType *table, int nRows, int nCols) {
1389 std::vector<std::vector<dataType>> vec(nRows, std::vector<dataType>());
1390 for(int i = 0; i < nRows; ++i)
1391 for(int j = 0; j < nCols; ++j)
1392 vec[i].push_back(table[i * nCols + j]);
1394 }
1395
1396 void printMatching(std::vector<MatchingType> &matchings) {
1398 for(const auto &mTuple : matchings) {
1399 std::stringstream ss;
1400 ss << std::get<0>(mTuple) << " - " << std::get<1>(mTuple) << " - "
1401 << std::get<2>(mTuple);
1402 printMsg(ss.str());
1403 }
1405 }
1406
1408 std::vector<std::tuple<ftm::idNode, ftm::idNode, double>> &matchings) {
1410 for(auto mTuple : matchings) {
1411 std::stringstream ss;
1412 ss << std::get<0>(mTuple) << " - " << std::get<1>(mTuple);
1413 printMsg(ss.str());
1414 }
1416 }
1417
1419 std::vector<std::tuple<ftm::idNode, ftm::idNode>> &matchings) {
1420 std::vector<std::tuple<ftm::idNode, ftm::idNode, double>> matchingsT(
1421 matchings.size());
1422 for(size_t i = 0; i < matchings.size(); ++i) {
1423 const auto &tup{matchings[i]};
1424 matchingsT[i] = {std::get<0>(tup), std::get<1>(tup), 0.0};
1425 }
1426 printMatching(matchingsT);
1427 }
1428
1429 template <class dataType>
1431 std::vector<std::tuple<SimplexId, SimplexId, dataType>> &treePairs) {
1432 for(auto pair : treePairs) {
1433 std::stringstream const ss;
1434 ss << std::get<0>(pair) << " _ " << std::get<1>(pair) << " _ "
1435 << std::get<2>(pair);
1436 printMsg(ss.str());
1437 }
1439 }
1440
1441 template <class dataType>
1443 std::vector<std::tuple<ftm::idNode, ftm::idNode>> &outputMatching,
1444 ftm::FTMTree_MT *tree1,
1445 ftm::FTMTree_MT *tree2,
1446 bool computeCosts = true) {
1447 dataType cost = 0;
1448 std::vector<bool> tree1Done(tree1->getNumberOfNodes(), false);
1449 std::vector<bool> tree2Done(tree2->getNumberOfNodes(), false);
1450 std::stringstream ss;
1451 for(std::tuple<ftm::idNode, ftm::idNode> matching : outputMatching) {
1452 ftm::idNode node0 = std::get<0>(matching);
1453 ftm::idNode node1 = std::get<1>(matching);
1454 ftm::idNode node0Origin = tree1->getNode(node0)->getOrigin();
1455 ftm::idNode node1Origin = tree2->getNode(node1)->getOrigin();
1456 ss << node0 << " - " << node1 << " _ [ ";
1457 ss << "f(" << node0 << ")=" << tree1->getValue<dataType>(node0)
1458 << " _ ";
1459 ss << "g(" << node1 << ")=" << tree2->getValue<dataType>(node1) << " ]"
1460 << " _ [ ";
1461 ss << "f(" << node0Origin
1462 << ")=" << tree1->getValue<dataType>(node0Origin) << " _ ";
1463 ss << "g(" << node1Origin
1464 << ")=" << tree2->getValue<dataType>(node1Origin) << " ] ";
1465
1466 if(computeCosts) {
1467 dataType tempCost = relabelCost<dataType>(tree1, node0, tree2, node1);
1468 dataType tempCost2
1469 = relabelCostOnly<dataType>(tree1, node0, tree2, node1);
1470 ss << "cost = " << tempCost << " (" << tempCost2 << ")" << std::endl;
1471 cost += tempCost;
1472 } else
1473 ss << std::endl;
1474 tree1Done[node0] = true;
1475 tree2Done[node1] = true;
1476 }
1477
1478 for(unsigned int i = 0; i < tree1->getNumberOfNodes(); ++i)
1479 if(not tree1Done[i] and not tree1->isNodeAlone(i)) {
1480 ftm::idNode nodeOrigin = tree1->getNode(i)->getOrigin();
1481 ss << "T1 " << i << " _ [ f(" << i
1482 << ") = " << tree1->getValue<dataType>(i);
1483 ss << "_ f(" << nodeOrigin
1484 << ") = " << tree1->getValue<dataType>(nodeOrigin);
1485 ss << "]";
1486 if(computeCosts) {
1487 dataType tempCost = deleteCost<dataType>(tree1, i);
1488 ss << " _ cost = " << tempCost << std::endl;
1489 cost += tempCost;
1490 } else
1491 ss << std::endl;
1492 }
1493 for(unsigned int i = 0; i < tree2->getNumberOfNodes(); ++i)
1494 if(not tree2Done[i] and not tree2->isNodeAlone(i)) {
1495 ftm::idNode nodeOrigin = tree2->getNode(i)->getOrigin();
1496 ss << "T2 " << i << " _ [ g(" << i
1497 << ") = " << tree2->getValue<dataType>(i);
1498 ss << "_ g(" << nodeOrigin
1499 << ") = " << tree2->getValue<dataType>(nodeOrigin);
1500 ss << "]";
1501 if(computeCosts) {
1502 dataType tempCost = deleteCost<dataType>(tree2, i);
1503 ss << " _ cost = " << tempCost << std::endl;
1504 cost += tempCost;
1505 } else
1506 ss << std::endl;
1507 }
1508 if(computeCosts)
1509 ss << "total cost = " << cost << " (" << std::sqrt(cost) << ")"
1510 << std::endl;
1511
1512 printMsg(ss.str());
1514 }
1515 }; // MergeTreeBase class
1516
1517} // namespace ttk
void setDebugMsgPrefix(const std::string &prefix)
Definition Debug.h:364
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:149
void printTable(dataType *table, int nRows, int nCols)
void setBranchDecomposition(bool useBD)
void setNormalizedWasserstein(bool normalizedWasserstein)
void setDistanceSquaredRoot(bool distanceSquaredRoot)
void getTreesStats(std::vector< ftm::FTMTree_MT * > &trees, std::array< double, 3 > &stats)
void setParamValueFromName(std::string &paramName, double value)
void setUseDoubleInput(const bool useDoubleInput)
void printTreesStats(std::vector< ftm::MergeTree< dataType > > &trees)
void setEpsilon3Tree1(double epsilon)
void setEpsilonTree1(double epsilon)
void setAssignmentSolver(int assignmentSolver)
void persistenceThresholding(ftm::FTMTree_MT *tree)
dataType computeDistance(dataType x1, dataType x2, dataType y1, dataType y2, double power=2)
dataType deleteCost(const ftm::FTMTree_MT *tree, ftm::idNode nodeId)
void deleteMultiPersPairs(ftm::FTMTree_MT *tree, bool useBD)
void printOutputMatching(std::vector< std::tuple< ftm::idNode, ftm::idNode > > &outputMatching, ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2, bool computeCosts=true)
void mtFlattening(ftm::MergeTree< dataType > &mt)
void mergeSaddle(ftm::FTMTree_MT *tree, double epsilon, std::vector< std::vector< ftm::idNode > > &treeNodeMerged, bool mergeByPersistence=false)
void keepMostImportantPairs(ftm::FTMTree_MT *tree, int n, bool useBD)
double mixDistancesWeight(bool isFirstInput)
void setNodePerTask(int npt)
void convertBranchDecompositionMatching(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2, std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > &outputMatching)
std::vector< std::vector< int > > getTreesNodeCorr()
void getParamNames(std::vector< std::string > &paramNames)
void putBackMergedNodes(ftm::FTMTree_MT *tree)
void dontUseMinMaxPair(ftm::FTMTree_MT *tree)
void setEpsilon2Tree1(double epsilon)
void setEpsilonTree2(double epsilon)
void setBarycenterMergeTree(bool imt)
ftm::FTMTree_MT * computeBranchDecomposition(ftm::FTMTree_MT *tree, std::vector< std::vector< ftm::idNode > > &treeNodeMerged)
void printMatching(std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > &matchings)
dataType relabelCost(const ftm::FTMTree_MT *tree1, ftm::idNode nodeId1, const ftm::FTMTree_MT *tree2, ftm::idNode nodeId2)
void verifyOrigins(ftm::FTMTree_MT *tree)
double mixDistances(dataType distance1, dataType distance2)
void printMatching(std::vector< std::tuple< ftm::idNode, ftm::idNode > > &matchings)
void persistenceThresholding(ftm::FTMTree_MT *tree, std::vector< ftm::idNode > &deletedNodes)
void branchDecompositionToTree(ftm::FTMTree_MT *tree)
void persistenceThresholding(ftm::FTMTree_MT *tree, double persistenceThresholdT)
void deletePersistenceDiagramsPairs(ftm::FTMTree_MT *tree, std::vector< ftm::idNode > &nodes)
double getSizeLimitMetric(std::vector< ftm::FTMTree_MT * > &trees)
void setPersistenceThreshold(double pt)
void preprocessingPipeline(ftm::MergeTree< dataType > &mTree, double epsilonTree, double epsilon2Tree, double epsilon3Tree, bool branchDecompositionT, bool useMinMaxPairT, bool cleanTreeT, double persistenceThreshold, std::vector< int > &nodeCorr, bool deleteInconsistentNodes=true, bool removeMergedSaddles=false)
void printTreesStats(std::vector< ftm::FTMTree_MT * > &trees)
void postprocessingPipeline(ftm::FTMTree_MT *tree)
void printTableVector(std::vector< std::vector< dataType > > &table)
void verifyPairsTree(ftm::FTMTree_MT *tree)
void setNonMatchingWeight(double weight)
void printMatching(std::vector< MatchingType > &matchings)
void printPairs(std::vector< std::tuple< SimplexId, SimplexId, dataType > > &treePairs)
void copyMinMaxPair(ftm::MergeTree< dataType > &mTree1, ftm::MergeTree< dataType > &mTree2, bool setOrigins=false)
std::vector< std::vector< int > > treesNodeCorr_
void preprocessTree(ftm::FTMTree_MT *tree, bool deleteInconsistentNodes=true)
void setCleanTree(bool clean)
void reverseNodeCorr(ftm::FTMTree_MT *tree, std::vector< int > &nodeCorr)
void identifyRealMatching(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2, std::vector< std::tuple< ftm::idNode, ftm::idNode > > &outputMatching, std::vector< std::tuple< ftm::idNode, ftm::idNode, bool > > &realMatching)
void setJoinSplitMixtureCoefficient(const double mixtureCoefficient)
dataType relabelCostOnly(const ftm::FTMTree_MT *tree1, ftm::idNode nodeId1, const ftm::FTMTree_MT *tree2, ftm::idNode nodeId2)
void setEpsilon2Tree2(double epsilon)
void setKeepSubtree(bool keepSubtree)
void persistenceThresholding(ftm::FTMTree_MT *tree, double persistenceThresholdT, std::vector< ftm::idNode > &deletedNodes)
void persistenceMerging(ftm::FTMTree_MT *tree, double epsilon2, double epsilon3=100)
void mtsFlattening(std::vector< ftm::MergeTree< dataType > > &mts)
void setEpsilon1UseFarthestSaddle(bool b)
void setDeleteMultiPersPairs(bool deleteMultiPersPairsT)
void setUseMinMaxPair(bool useMinMaxPair)
void setEpsilon3Tree2(double epsilon)
double mixDistancesMinMaxPairWeight(bool isFirstInput)
void preprocessingPipeline(ftm::MergeTree< dataType > &mTree, double epsilonTree, double epsilon2Tree, double epsilon3Tree, bool branchDecompositionT, bool useMinMaxPairT, bool cleanTreeT, std::vector< int > &nodeCorr, bool deleteInconsistentNodes=true, bool removeMergedSaddles=false)
dataType insertCost(const ftm::FTMTree_MT *tree, ftm::idNode nodeId)
void setParallelize(bool para)
double getParamValueFromName(std::string &paramName)
void setIsPersistenceDiagram(bool isPD)
void convertBranchDecompositionMatching(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2, std::vector< std::tuple< ftm::idNode, ftm::idNode > > &outputMatching)
std::tuple< int, dataType > fixMergedRootOrigin(ftm::FTMTree_MT *tree)
void mixDistancesMatrix(std::vector< std::vector< dataType > > &distanceMatrix, std::vector< std::vector< dataType > > &distanceMatrix2)
double getElapsedTime()
Definition Timer.h:15
std::stringstream printMultiPersPairsFromTree(bool useBD=false, bool printPairs=true, bool doPrint=true) const
void getMultiPersOriginsVectorFromTree(std::vector< std::vector< idNode > > &res) const
Node * getNode(idNode nodeId) const
Definition FTMTree_MT.h:393
std::stringstream printTree(bool doPrint=true) const
const scalarType & getValue(SimplexId nodeId) const
Definition FTMTree_MT.h:339
void getChildren(idNode nodeId, std::vector< idNode > &res) const
idNode getNumberOfNodes() const
Definition FTMTree_MT.h:389
bool isMultiPersPair(idNode nodeId) const
void setParent(idNode nodeId, idNode newParentNodeId)
idNode getRoot() const
int getNodeLevel(idNode nodeId) const
idNode getLowestNode(idNode nodeStart) const
idNode getParentSafe(idNode nodeId) const
std::vector< ftm::idNode > getMultiPersOrigins(bool useBD) const
dataType getMaximumPersistence() const
dataType getSecondMaximumPersistence() const
int getRealNumberOfNodes() const
dataType getNodePersistence(idNode nodeId) const
std::stringstream printPairsFromTree(bool useBD=false, bool printPairs=true, bool doPrint=true) const
bool isNodeOriginDefined(idNode nodeId) const
bool isLeaf(idNode nodeId) const
void deleteNode(idNode nodeId)
bool isRoot(idNode nodeId) const
std::tuple< dataType, dataType > getBirthDeath(idNode nodeId) const
bool isNodeIdInconsistent(idNode nodeId) const
int getNumberOfRoot() const
idNode makeNode(SimplexId vertexId, SimplexId linked=nullVertex)
bool isNodeAlone(idNode nodeId) const
void getPersistencePairsFromTree(std::vector< std::tuple< ftm::idNode, ftm::idNode, dataType > > &pairs, bool useBD) const
bool isNodeMerged(idNode nodeId) const
bool isFullMerge() const
bool isThereOnlyOnePersistencePair() const
idSuperArc getUpSuperArcId(idSuperArc neighborId) const
Definition FTMNode.h:105
idSuperArc clearUpSuperArcs()
Definition FTMNode.h:133
idSuperArc getNumberOfDownSuperArcs() const
Definition FTMNode.h:82
idSuperArc clearDownSuperArcs()
Definition FTMNode.h:127
void setOrigin(SimplexId linked)
Definition FTMNode.h:72
SimplexId getOrigin() const
Definition FTMNode.h:64
idSuperArc getNumberOfUpSuperArcs() const
Definition FTMNode.h:86
void removeDownSuperArcs(std::vector< idSuperArc > &idSa)
Definition FTMNode.h:157
void setTreeScalars(MergeTree< dataType > &mergeTree, std::vector< dataType > &scalarsVector)
MergeTree< dataType > cleanMergeTree(ftm::FTMTree_MT *tree, std::vector< int > &nodeCorr, bool useBD=true)
void getTreeScalars(const ftm::FTMTree_MT *tree, std::vector< dataType > &scalarsVector)
void mergeTreeToFTMTree(std::vector< MergeTree< dataType > > &trees, std::vector< ftm::FTMTree_MT * > &treesT)
unsigned int idNode
Node index in vect_nodes_.
std::vector< std::tuple< SimplexId, SimplexId, dataType > > computePersistencePairs(FTMTree_MT *tree)
TTK base package defining the standard types.
std::tuple< dataType, dataType > getNormalizedBirthDeath(const ftm::FTMTree_MT *tree, ftm::idNode nodeId, dataType newMin=0.0, dataType newMax=1.0)
ftm::FTMTree_MT tree
Definition FTMTree_MT.h:906
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/| (_) |"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)