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 Timer t_proc;
687
688 ftm::FTMTree_MT *tree = &(mTree.tree);
689
690 preprocessTree<dataType>(tree, deleteInconsistentNodes);
691
692 // - Delete null persistence pairs and persistence thresholding
693 persistenceThresholding<dataType>(tree, persistenceThreshold);
694
695 // - Merge saddle points according epsilon
696 std::vector<std::vector<ftm::idNode>> treeNodeMerged(
697 tree->getNumberOfNodes());
699 if(epsilonTree != 0)
700 mergeSaddle<dataType>(tree, epsilonTree, treeNodeMerged);
701 }
702
703 // - Compute branch decomposition
704 // verifyPairsTree(tree);
705 if(branchDecompositionT
707 tree = computeBranchDecomposition<dataType>(tree, treeNodeMerged);
708
709 // - Delete multi pers pairs
711 deleteMultiPersPairs<dataType>(tree, branchDecompositionT);
712
713 // - Remove min max pair
714 // verifyPairsTree(tree);
715 if(not useMinMaxPairT)
717
718 // - Epsilon 2 and 3 processing
719 if(branchDecompositionT and not isPersistenceDiagram_)
720 persistenceMerging<dataType>(tree, epsilon2Tree, epsilon3Tree);
721
722 // - Tree cleaning (remove unused nodes)
723 if(cleanTreeT) {
724 ftm::cleanMergeTree<dataType>(mTree, nodeCorr, branchDecompositionT);
725 tree = &(mTree.tree);
726 reverseNodeCorr(tree, nodeCorr);
727 }
728
729 // - Root number verification
730 if(tree->getNumberOfRoot() != 1)
731 printErr("preprocessingPipeline tree->getNumberOfRoot() != 1");
732
733 // - Time printing
734 // verifyPairsTree(tree);
735 auto t_preproc_time = t_proc.getElapsedTime();
736 std::stringstream ss;
737 ss << "TIME PREPROC. = " << t_preproc_time;
739 }
740
741 template <class dataType>
743 double epsilonTree,
744 double epsilon2Tree,
745 double epsilon3Tree,
746 bool branchDecompositionT,
747 bool useMinMaxPairT,
748 bool cleanTreeT,
749 std::vector<int> &nodeCorr,
750 bool deleteInconsistentNodes = true) {
752 mTree, epsilonTree, epsilon2Tree, epsilon3Tree, branchDecompositionT,
753 useMinMaxPairT, cleanTreeT, persistenceThreshold_, nodeCorr,
754 deleteInconsistentNodes);
755 }
756
757 void reverseNodeCorr(ftm::FTMTree_MT *tree, std::vector<int> &nodeCorr) {
758 std::vector<int> newNodeCorr(tree->getNumberOfNodes());
759 for(unsigned int i = 0; i < nodeCorr.size(); ++i)
760 if(nodeCorr[i] >= 0 && nodeCorr[i] < (int)newNodeCorr.size())
761 newNodeCorr[nodeCorr[i]] = i;
762 nodeCorr = newNodeCorr;
763 }
764
765 template <class dataType>
767 ftm::FTMTree_MT *tree = &(mt.tree);
770 std::vector<std::vector<ftm::idNode>> treeNodeMerged;
771 mergeSaddle<dataType>(tree, 100.0, treeNodeMerged);
772 computeBranchDecomposition<dataType>(tree, treeNodeMerged);
773 }
774
775 template <class dataType>
776 void mtsFlattening(std::vector<ftm::MergeTree<dataType>> &mts) {
777 for(auto &mt : mts)
778 mtFlattening(mt);
779 }
780
781 double getSizeLimitMetric(std::vector<ftm::FTMTree_MT *> &trees) {
782 std::array<double, 3> stats;
783 getTreesStats(trees, stats);
784 auto meanNodes = stats[0];
785 unsigned int const n = trees.size();
786 return meanNodes * n;
787 }
788
789 // ------------------------------------------------------------------------
790 // Tree Postprocessing
791 // ------------------------------------------------------------------------
792 template <class dataType>
795 bool setOrigins = false) {
796 // Get min max pair
797 ftm::FTMTree_MT *tree1 = &(mTree1.tree);
798 ftm::idNode root = tree1->getRoot();
799 dataType newMax = tree1->getValue<dataType>(root);
800 ftm::idNode rootOrigin = tree1->getNode(root)->getOrigin();
801 dataType newMin = tree1->getValue<dataType>(rootOrigin);
802
803 // Update tree
804 ftm::idNode root2 = mTree2.tree.getRoot();
805 std::vector<dataType> newScalarsVector;
806 ftm::getTreeScalars<dataType>(mTree2, newScalarsVector);
807 newScalarsVector[root2] = newMax;
808
809 auto root2Origin = mTree2.tree.getNode(root2)->getOrigin();
810 if(root2Origin == (int)root2)
811 root2Origin = mTree2.tree.template getMergedRootOrigin<dataType>();
812 if(mTree2.tree.isNodeIdInconsistent(root2Origin))
813 newScalarsVector.push_back(newMin);
814 else
815 newScalarsVector[root2Origin] = newMin;
816
817 // Set new scalars
818 ftm::setTreeScalars<dataType>(mTree2, newScalarsVector);
819
820 // Create root origin if not already there
821 ftm::FTMTree_MT *treeNew = &(mTree2.tree);
822 if(mTree2.tree.isNodeIdInconsistent(root2Origin)) {
823 root2Origin = treeNew->getNumberOfNodes();
824 treeNew->makeNode(root2Origin);
825 }
826
827 // Manage new origins
828 if(setOrigins) {
829 treeNew->getNode(root2Origin)->setOrigin(root2);
830 treeNew->getNode(root2)->setOrigin(root2Origin);
831 }
832 }
833
834 template <class dataType>
835 std::tuple<int, dataType> fixMergedRootOrigin(ftm::FTMTree_MT *tree) {
836 if(not tree->isFullMerge())
837 return std::make_tuple(-1, -1);
838
839 // Get node of the min max pair
840 int maxIndex = tree->getMergedRootOrigin<dataType>();
841
842 // Link node of the min max pair with the root
843 ftm::idNode const treeRoot = tree->getRoot();
844 dataType oldOriginValue
845 = tree->getValue<dataType>(tree->getNode(maxIndex)->getOrigin());
846 tree->getNode(maxIndex)->setOrigin(treeRoot);
847
848 return std::make_tuple(maxIndex, oldOriginValue);
849 }
850
851 // TODO fix bug when one multi pers. pairs is moved up with epsilon 2 and 3
852 // but not its brothers
853 template <class dataType>
855 ftm::idNode const treeRoot = tree->getRoot();
856
857 // Get original tree message
858 std::stringstream const oriPrintTree = tree->printTree();
859 std::stringstream const oriPrintPairs
860 = tree->printPairsFromTree<dataType>(true);
861 std::stringstream const oriPrintMultiPers
862 = tree->printMultiPersPairsFromTree<dataType>(true);
863
864 // One pair case
866 ftm::idNode const treeRootOrigin = tree->getNode(treeRoot)->getOrigin();
867 tree->getNode(treeRootOrigin)->setOrigin(treeRoot);
868 return;
869 }
870
871 // Manage full merge and dontuseMinMaxPair_
872 bool const isFM = tree->isFullMerge();
873 if(isFM) {
874 ftm::idNode const mergedRootOrigin
875 = tree->getMergedRootOrigin<dataType>();
876 if(not tree->isNodeIdInconsistent(mergedRootOrigin)
877 and mergedRootOrigin != treeRoot)
878 tree->getNode(treeRoot)->setOrigin(mergedRootOrigin);
879 else {
880 printErr("branchDecompositionToTree mergedRootOrigin inconsistent");
881 }
882 }
883
884 // Some functions
885 bool isJT = tree->isJoinTree<dataType>();
886 auto comp = [&](const std::tuple<ftm::idNode, dataType> &a,
887 const std::tuple<ftm::idNode, dataType> &b) {
888 return isJT ? std::get<1>(a) > std::get<1>(b)
889 : std::get<1>(a) < std::get<1>(b);
890 };
891 auto getIndexNotMultiPers = [&](int index, ftm::FTMTree_MT *treeT,
892 std::vector<ftm::idNode> &children) {
893 while(index >= 0 and treeT->isMultiPersPair(children[index]))
894 --index;
895 return index;
896 };
897
898 // Branch Decomposition To Tree
899 std::vector<std::tuple<ftm::idNode, ftm::idNode>> nodeParent;
900 std::queue<ftm::idNode> queue;
901 queue.emplace(treeRoot);
902 while(!queue.empty()) {
903 ftm::idNode node = queue.front();
904 queue.pop();
905 auto nodeOrigin = tree->getNode(node)->getOrigin();
906 if(tree->isLeaf(node)) {
907 if(tree->isNodeAlone(nodeOrigin)) {
908 if(not isFM)
909 nodeParent.emplace_back(nodeOrigin, node);
910 else
911 nodeParent.emplace_back(node, nodeOrigin);
912 } else if(tree->isMultiPersPair(node)) {
913 nodeParent.emplace_back(node, nodeOrigin);
914 }
915 continue;
916 }
917
918 // Get children and sort them by scalar values
919 std::vector<ftm::idNode> childrenOri;
920 tree->getChildren(node, childrenOri);
921 std::vector<ftm::idNode> children = childrenOri;
922 std::vector<std::tuple<ftm::idNode, dataType>> childrenScalars;
923 for(unsigned int i = 0; i < children.size(); ++i) {
924 if(isFM and (int) children[i] != nodeOrigin)
925 children[i] = tree->getNode(children[i])->getOrigin();
926 childrenScalars.push_back(std::make_tuple(
927 children[i], tree->getValue<dataType>(children[i])));
928 }
929 std::sort(std::begin(childrenScalars), std::end(childrenScalars), comp);
930 children.clear();
931 for(unsigned int i = 0; i < childrenScalars.size(); ++i)
932 children.push_back(std::get<0>(childrenScalars[i]));
933
934 // Get new parent of children
935 for(unsigned int i = 1; i < children.size(); ++i) {
936 if(tree->isMultiPersPair(children[i]))
937 continue;
938 int const index = getIndexNotMultiPers(i - 1, tree, children);
939 if(index >= 0)
940 nodeParent.emplace_back(children[i], children[index]);
941 }
942
943 bool const multiPersPair
944 = tree->getNode(nodeOrigin)->getOrigin() != (int)node;
945 if(not multiPersPair) {
946 if(not isFM) {
947 int const index
948 = getIndexNotMultiPers(children.size() - 1, tree, children);
949 nodeParent.emplace_back(nodeOrigin, children[index]);
950 } else
951 nodeParent.emplace_back(children[0], node);
952 } else {
953 // std::cout << "branchDecompositionToTree multiPersPair" <<
954 // std::endl;
955 nodeParent.emplace_back(children[0], nodeOrigin);
956 int index = getIndexNotMultiPers(children.size() - 1, tree, children);
957 if(index < 0) { // should not be possible
958 printErr("[branchDecompositionToTree] index < 0");
959 index = 0;
960 }
961 nodeParent.emplace_back(node, children[index]);
962 }
963
964 // Push children to the queue
965 for(auto child : childrenOri)
966 queue.emplace(child);
967 }
968
969 // Set new parents for each node
970 for(auto nodeParentT : nodeParent)
971 tree->setParent(std::get<0>(nodeParentT), std::get<1>(nodeParentT));
972
973 // Verify that the tree is correct
974 for(unsigned int i = 0; i < tree->getNumberOfNodes(); ++i)
975 if(tree->getNode(i)->getNumberOfDownSuperArcs() == 1
976 and tree->getNode(i)->getNumberOfUpSuperArcs() == 1) {
977 printMsg(oriPrintPairs.str());
978 printMsg(oriPrintMultiPers.str());
979 printMsg(oriPrintTree.str());
980 printMsg(tree->printTree().str());
981 std::stringstream ss;
982 auto iOrigin = tree->getNode(i)->getOrigin();
983 ss << i << " _ " << iOrigin;
984 if(tree->getNode(iOrigin)->getOrigin() != int(i))
985 ss << " _ " << tree->getNode(iOrigin)->getOrigin() << " _ "
986 << tree->getNode(tree->getNode(iOrigin)->getOrigin())
987 ->getOrigin();
988 printMsg(ss.str());
989 printErr("[branchDecompositionToTree] 1 up arc and 1 down arc");
990 }
991 }
992
993 // For not branch decomposition tree
994 template <class dataType>
996 bool isJT = tree->isJoinTree<dataType>();
997 std::queue<ftm::idNode> queue;
998 queue.emplace(tree->getRoot());
999 while(!queue.empty()) {
1000 ftm::idNode const node = queue.front();
1001 queue.pop();
1002 ftm::idNode const nodeOrigin = tree->getNode(node)->getOrigin();
1003 if(!tree->isLeaf(node)) {
1004 std::vector<ftm::idNode> children;
1005 tree->getChildren(node, children);
1006 std::vector<ftm::idNode> lowestNodes;
1007 ftm::idNode branchOrigin = nodeOrigin;
1008 for(auto child : children) {
1009 ftm::idNode lowestNode = tree->getLowestNode<dataType>(child);
1010 lowestNodes.push_back(lowestNode);
1011 ftm::idNode const lowestNodeOrigin
1012 = tree->getNode(lowestNode)->getOrigin();
1013 if(not tree->isNodeAlone(lowestNodeOrigin)
1014 and lowestNodeOrigin != node)
1015 branchOrigin = lowestNode;
1016 }
1017 for(size_t i = 0; i < children.size(); ++i) {
1018 ftm::idNode lowestNodeOrigin
1019 = tree->getNode(lowestNodes[i])->getOrigin();
1020 if(branchOrigin == lowestNodes[i] or lowestNodeOrigin == node)
1021 continue;
1022 dataType lowestNodeOriginVal
1023 = tree->getValue<dataType>(lowestNodeOrigin);
1024 ftm::idNode branchOriginT = branchOrigin;
1025 ftm::idNode const branchRoot
1026 = tree->getNode(branchOrigin)->getOrigin();
1027 while(branchRoot != branchOriginT) {
1028 dataType val
1029 = tree->getValue<dataType>(tree->getParentSafe(branchOriginT));
1030 if((val > lowestNodeOriginVal and isJT)
1031 or (val < lowestNodeOriginVal and not isJT))
1032 break;
1033 branchOriginT = tree->getParentSafe(branchOriginT);
1034 }
1035 tree->setParent(
1036 lowestNodeOrigin, tree->getParentSafe(branchOriginT));
1037 tree->setParent(branchOriginT, lowestNodeOrigin);
1038 tree->setParent(children[i], lowestNodeOrigin);
1039 }
1040 }
1041 std::vector<ftm::idNode> children;
1042 tree->getChildren(node, children);
1043 for(auto child : children)
1044 queue.emplace(child);
1045 }
1046 }
1047
1048 template <class dataType>
1050 // if(not branchDecomposition_ or not useMinMaxPair)
1051 // fixMergedRootOrigin<dataType>(tree);
1052 if(tree->isFullMerge()) {
1053 auto mergedRootOrigin = tree->getMergedRootOrigin<dataType>();
1054 if(not tree->isNodeIdInconsistent(mergedRootOrigin))
1055 tree->getNode(tree->getRoot())->setOrigin(mergedRootOrigin);
1056 else
1057 printErr(
1058 "[postprocessingPipeline] mergedRootOrigin inconsistent id.");
1059 }
1061 if(not isPersistenceDiagram_ and tree->getRealNumberOfNodes() != 0)
1063 } else
1065 }
1066
1067 // ------------------------------------------------------------------------
1068 // Output Matching
1069 // ------------------------------------------------------------------------
1070 template <class dataType>
1072 ftm::FTMTree_MT *tree1,
1073 ftm::FTMTree_MT *tree2,
1074 std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>
1075 &outputMatching) {
1076 std::vector<std::tuple<ftm::idNode, ftm::idNode, double>> toAdd;
1077 for(auto mTuple : outputMatching) {
1078 ftm::idNode const node1 = std::get<0>(mTuple);
1079 ftm::idNode const node2 = std::get<1>(mTuple);
1080 double const cost = std::get<2>(mTuple);
1081 ftm::idNode const node1Origin = tree1->getNode(node1)->getOrigin();
1082 ftm::idNode const node2Origin = tree2->getNode(node2)->getOrigin();
1083
1084 int const node1Level = tree1->getNodeLevel(node1);
1085 int const node1OriginLevel = tree1->getNodeLevel(node1Origin);
1086 int const node2Level = tree2->getNodeLevel(node2);
1087 int const node2OriginLevel = tree2->getNodeLevel(node2Origin);
1088
1089 ftm::idNode const node1Higher
1090 = (node1Level > node1OriginLevel) ? node1 : node1Origin;
1091 ftm::idNode const node1Lower
1092 = (node1Level > node1OriginLevel) ? node1Origin : node1;
1093 ftm::idNode const node2Higher
1094 = (node2Level > node2OriginLevel) ? node2 : node2Origin;
1095 ftm::idNode const node2Lower
1096 = (node2Level > node2OriginLevel) ? node2Origin : node2;
1097
1098 if(((tree1->isRoot(node1Higher) and tree1->isFullMerge())
1099 or (tree2->isRoot(node2Higher) and tree2->isFullMerge())))
1100 continue;
1101
1102 if(!tree1->isNodeAlone(node1Higher)
1103 and !tree2->isNodeAlone(node2Higher))
1104 toAdd.emplace_back(node1Higher, node2Higher, cost);
1105 if(!tree1->isNodeAlone(node1Lower) and !tree2->isNodeAlone(node2Lower))
1106 toAdd.emplace_back(node1Lower, node2Lower, cost);
1107 }
1108 outputMatching.clear();
1109 outputMatching.insert(outputMatching.end(), toAdd.begin(), toAdd.end());
1110 }
1111
1112 template <class dataType>
1114 ftm::FTMTree_MT *tree1,
1115 ftm::FTMTree_MT *tree2,
1116 std::vector<std::tuple<ftm::idNode, ftm::idNode>> &outputMatching) {
1117 std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>
1118 realOutputMatching(outputMatching.size());
1119 for(size_t i = 0; i < outputMatching.size(); ++i) {
1120 const auto &tup{outputMatching[i]};
1121 realOutputMatching[i] = {std::get<0>(tup), std::get<1>(tup), 0.0};
1122 }
1123
1125 tree1, tree2, realOutputMatching);
1126
1127 outputMatching.clear();
1128 for(auto tup : realOutputMatching)
1129 outputMatching.emplace_back(std::get<0>(tup), std::get<1>(tup));
1130 }
1131
1132 template <class dataType>
1134 ftm::FTMTree_MT *tree1,
1135 ftm::FTMTree_MT *tree2,
1136 std::vector<std::tuple<ftm::idNode, ftm::idNode>> &outputMatching,
1137 std::vector<std::tuple<ftm::idNode, ftm::idNode, bool>> &realMatching) {
1138 for(std::tuple<ftm::idNode, ftm::idNode> mTuple : outputMatching) {
1139 ftm::idNode tree1Node = std::get<0>(mTuple);
1140 ftm::idNode tree2Node = std::get<1>(mTuple);
1141 dataType relabelCostVal
1142 = relabelCostOnly<dataType>(tree1, tree1Node, tree2, tree2Node);
1143 dataType deleteInsertCostVal = deleteCost<dataType>(tree1, tree1Node)
1144 + insertCost<dataType>(tree2, tree2Node);
1145 bool isRealMatching = (relabelCostVal <= deleteInsertCostVal);
1146 realMatching.emplace_back(tree1Node, tree2Node, isRealMatching);
1147 }
1148 }
1149
1150 // ------------------------------------------------------------------------
1151 // Edit Costs
1152 // ------------------------------------------------------------------------
1153 template <class dataType>
1155 dataType x1, dataType x2, dataType y1, dataType y2, double power = 2) {
1156 if(power <= 0)
1157 return std::max(
1158 std::abs((double)(x1 - y1)), std::abs((double)(x2 - y2)));
1159 else
1160 return std::pow(std::abs((double)(x1 - y1)), power)
1161 + std::pow(std::abs((double)(x2 - y2)), power);
1162 }
1163
1164 template <class dataType>
1165 dataType deleteCost(const ftm::FTMTree_MT *tree, ftm::idNode nodeId) {
1166 dataType cost = 0;
1167 dataType newMin = 0.0, newMax = 1.0;
1168 // Get birth/death
1169 auto birthDeath
1171 ? getNormalizedBirthDeath<dataType>(tree, nodeId, newMin, newMax)
1172 : tree->getBirthDeath<dataType>(nodeId);
1173 dataType birth = std::get<0>(birthDeath);
1174 dataType death = std::get<1>(birthDeath);
1175 dataType projec = (birth + death) / 2;
1176 // Compute delete cost
1178 birth, death, projec, projec, wassersteinPower_);
1179 // Divide cost by two if not branch decomposition and not merged
1180 /*if(! branchDecomposition_ and ! tree->isNodeMerged(nodeId))
1181 cost /= 2;*/
1182 cost *= nonMatchingWeight_;
1183
1184 return cost;
1185 }
1186
1187 template <class dataType>
1188 dataType insertCost(const ftm::FTMTree_MT *tree, ftm::idNode nodeId) {
1189 return deleteCost<dataType>(tree, nodeId);
1190 }
1191
1192 template <class dataType>
1193 dataType relabelCostOnly(const ftm::FTMTree_MT *tree1,
1194 ftm::idNode nodeId1,
1195 const ftm::FTMTree_MT *tree2,
1196 ftm::idNode nodeId2) {
1197 dataType cost = 0;
1198 dataType newMin = 0.0, newMax = 1.0;
1199 // Get birth/death of the first tree
1200 auto birthDeath1
1202 ? getNormalizedBirthDeath<dataType>(tree1, nodeId1, newMin, newMax)
1203 : tree1->getBirthDeath<dataType>(nodeId1);
1204 dataType birth1 = std::get<0>(birthDeath1);
1205 dataType death1 = std::get<1>(birthDeath1);
1206 // Get birth/death of the second tree
1207 auto birthDeath2
1209 ? getNormalizedBirthDeath<dataType>(tree2, nodeId2, newMin, newMax)
1210 : tree2->getBirthDeath<dataType>(nodeId2);
1211 dataType birth2 = std::get<0>(birthDeath2);
1212 dataType death2 = std::get<1>(birthDeath2);
1213 // Compute relabel cost
1215 birth1, death1, birth2, death2, wassersteinPower_);
1216 // Divide cost by two if not branch decomposition and not merged
1217 /*bool merged = isNodeMerged(tree1, nodeId1) or isNodeMerged(tree2,
1218 nodeId2); if(! branchDecomposition_ and ! merged) cost /= 2;*/
1219
1220 return cost;
1221 }
1222
1223 template <class dataType>
1224 dataType relabelCost(const ftm::FTMTree_MT *tree1,
1225 ftm::idNode nodeId1,
1226 const ftm::FTMTree_MT *tree2,
1227 ftm::idNode nodeId2) {
1228 // Full merge case and only one persistence pair case
1229 if(tree1->getNode(nodeId1)->getOrigin() == (int)nodeId1
1230 or tree2->getNode(nodeId2)->getOrigin() == (int)nodeId2)
1231 return 0;
1232
1233 // Compute relabel cost
1234 dataType cost = relabelCostOnly<dataType>(tree1, nodeId1, tree2, nodeId2);
1235
1236 if(keepSubtree_) {
1237 // Compute deleteInsert cost
1238 dataType deleteInsertCost = deleteCost<dataType>(tree1, nodeId1)
1239 + insertCost<dataType>(tree2, nodeId2);
1240 if(deleteInsertCost < cost)
1241 cost = deleteInsertCost;
1242 }
1243
1244 return cost;
1245 }
1246
1247 // ------------------------------------------------------------------------
1248 // Utils
1249 // ------------------------------------------------------------------------
1250 void getParamNames(std::vector<std::string> &paramNames) {
1251 paramNames = std::vector<std::string>{"epsilon1",
1252 "epsilon2",
1253 "epsilon3",
1254 "persistenceThreshold",
1255 "branchDecomposition",
1256 "normalizedWasserstein",
1257 "keepSubtree",
1258 "isPersistenceDiagram",
1259 "deleteMultiPersPairs",
1260 "epsilon1UseFarthestSaddle",
1261 "mixtureCoefficient"};
1262 }
1263
1264 double getParamValueFromName(std::string &paramName) {
1265 double value = 0.0;
1266 if(paramName == "epsilon1")
1267 value = epsilonTree1_;
1268 else if(paramName == "epsilon2")
1269 value = epsilon2Tree1_;
1270 else if(paramName == "epsilon3")
1271 value = epsilon3Tree1_;
1272 else if(paramName == "persistenceThreshold")
1273 value = persistenceThreshold_;
1274 else if(paramName == "branchDecomposition")
1275 value = branchDecomposition_;
1276 else if(paramName == "normalizedWasserstein")
1277 value = normalizedWasserstein_;
1278 else if(paramName == "keepSubtree")
1279 value = keepSubtree_;
1280 else if(paramName == "isPersistenceDiagram")
1281 value = isPersistenceDiagram_;
1282 else if(paramName == "deleteMultiPersPairs")
1283 value = deleteMultiPersPairs_;
1284 else if(paramName == "epsilon1UseFarthestSaddle")
1286 else if(paramName == "mixtureCoefficient")
1287 value = mixtureCoefficient_;
1288 return value;
1289 }
1290
1291 void setParamValueFromName(std::string &paramName, double value) {
1292 if(paramName == "epsilon1")
1293 epsilonTree1_ = value;
1294 else if(paramName == "epsilon2")
1295 epsilon2Tree1_ = value;
1296 else if(paramName == "epsilon3")
1297 epsilon3Tree1_ = value;
1298 else if(paramName == "persistenceThreshold")
1299 persistenceThreshold_ = value;
1300 else if(paramName == "branchDecomposition")
1301 branchDecomposition_ = value;
1302 else if(paramName == "normalizedWasserstein")
1303 normalizedWasserstein_ = value;
1304 else if(paramName == "keepSubtree")
1305 keepSubtree_ = value;
1306 else if(paramName == "isPersistenceDiagram")
1307 isPersistenceDiagram_ = value;
1308 else if(paramName == "deleteMultiPersPairs")
1309 deleteMultiPersPairs_ = value;
1310 else if(paramName == "epsilon1UseFarthestSaddle")
1312 else if(paramName == "mixtureCoefficient")
1313 mixtureCoefficient_ = value;
1314 }
1315
1316 void getTreesStats(std::vector<ftm::FTMTree_MT *> &trees,
1317 std::array<double, 3> &stats) {
1318 double avgNodes = 0, avgNodesT = 0;
1319 double avgDepth = 0;
1320 for(unsigned int i = 0; i < trees.size(); ++i) {
1321 auto noNodesT = trees[i]->getNumberOfNodes();
1322 auto noNodes = trees[i]->getRealNumberOfNodes();
1323 avgNodes += noNodes;
1324 avgNodesT += noNodesT;
1325 avgDepth += trees[i]->getTreeDepth();
1326 }
1327 avgNodes /= trees.size();
1328 avgNodesT /= trees.size();
1329 avgDepth /= trees.size();
1330
1331 stats = {avgNodes, avgNodesT, avgDepth};
1332 }
1333
1334 void printTreesStats(std::vector<ftm::FTMTree_MT *> &trees) {
1335 std::array<double, 3> stats;
1336 getTreesStats(trees, stats);
1337 int avgNodes = stats[0], avgNodesT = stats[1];
1338 double const avgDepth = stats[2];
1339 std::stringstream ss;
1340 ss << trees.size() << " trees average [node: " << avgNodes << " / "
1341 << avgNodesT << ", depth: " << avgDepth << "]";
1342 printMsg(ss.str());
1343 }
1344
1345 template <class dataType>
1346 void printTreesStats(std::vector<ftm::MergeTree<dataType>> &trees) {
1347 std::vector<ftm::FTMTree_MT *> treesT;
1348 ftm::mergeTreeToFTMTree<dataType>(trees, treesT);
1349 printTreesStats(treesT);
1350 }
1351
1352 template <class dataType>
1353 void printTableVector(std::vector<std::vector<dataType>> &table) {
1354 std::streamsize const ssize = std::cout.precision();
1355 std::stringstream ss;
1356 ss << " ";
1357 for(unsigned int j = 0; j < table[0].size(); ++j)
1358 ss << j - 1 << " ";
1359 printMsg(ss.str());
1360 ss.str("");
1361 ss.clear();
1362 for(unsigned int i = 0; i < table.size(); ++i) {
1363 ss << std::setw(3) << std::setfill('0') << std::internal << i - 1
1364 << " | ";
1365 for(unsigned int j = 0; j < table[0].size(); ++j) {
1366 ss << std::fixed << std::setprecision(2) << table[i][j] << " ";
1367 }
1368 printMsg(ss.str());
1369 printMsg("");
1370 }
1371 std::cout.precision(ssize);
1373 }
1374
1375 template <class dataType>
1376 void printTable(dataType *table, int nRows, int nCols) {
1377 std::vector<std::vector<dataType>> vec(nRows, std::vector<dataType>());
1378 for(int i = 0; i < nRows; ++i)
1379 for(int j = 0; j < nCols; ++j)
1380 vec[i].push_back(table[i * nCols + j]);
1382 }
1383
1384 void printMatching(std::vector<MatchingType> &matchings) {
1386 for(const auto &mTuple : matchings) {
1387 std::stringstream ss;
1388 ss << std::get<0>(mTuple) << " - " << std::get<1>(mTuple) << " - "
1389 << std::get<2>(mTuple);
1390 printMsg(ss.str());
1391 }
1393 }
1394
1396 std::vector<std::tuple<ftm::idNode, ftm::idNode, double>> &matchings) {
1398 for(auto mTuple : matchings) {
1399 std::stringstream ss;
1400 ss << std::get<0>(mTuple) << " - " << std::get<1>(mTuple);
1401 printMsg(ss.str());
1402 }
1404 }
1405
1407 std::vector<std::tuple<ftm::idNode, ftm::idNode>> &matchings) {
1408 std::vector<std::tuple<ftm::idNode, ftm::idNode, double>> matchingsT(
1409 matchings.size());
1410 for(size_t i = 0; i < matchings.size(); ++i) {
1411 const auto &tup{matchings[i]};
1412 matchingsT[i] = {std::get<0>(tup), std::get<1>(tup), 0.0};
1413 }
1414 printMatching(matchingsT);
1415 }
1416
1417 template <class dataType>
1419 std::vector<std::tuple<SimplexId, SimplexId, dataType>> &treePairs) {
1420 for(auto pair : treePairs) {
1421 std::stringstream const ss;
1422 ss << std::get<0>(pair) << " _ " << std::get<1>(pair) << " _ "
1423 << std::get<2>(pair);
1424 printMsg(ss.str());
1425 }
1427 }
1428
1429 template <class dataType>
1431 std::vector<std::tuple<ftm::idNode, ftm::idNode>> &outputMatching,
1432 ftm::FTMTree_MT *tree1,
1433 ftm::FTMTree_MT *tree2,
1434 bool computeCosts = true) {
1435 dataType cost = 0;
1436 std::vector<bool> tree1Done(tree1->getNumberOfNodes(), false);
1437 std::vector<bool> tree2Done(tree2->getNumberOfNodes(), false);
1438 std::stringstream ss;
1439 for(std::tuple<ftm::idNode, ftm::idNode> matching : outputMatching) {
1440 ftm::idNode node0 = std::get<0>(matching);
1441 ftm::idNode node1 = std::get<1>(matching);
1442 ftm::idNode node0Origin = tree1->getNode(node0)->getOrigin();
1443 ftm::idNode node1Origin = tree2->getNode(node1)->getOrigin();
1444 ss << node0 << " - " << node1 << " _ [ ";
1445 ss << "f(" << node0 << ")=" << tree1->getValue<dataType>(node0)
1446 << " _ ";
1447 ss << "g(" << node1 << ")=" << tree2->getValue<dataType>(node1) << " ]"
1448 << " _ [ ";
1449 ss << "f(" << node0Origin
1450 << ")=" << tree1->getValue<dataType>(node0Origin) << " _ ";
1451 ss << "g(" << node1Origin
1452 << ")=" << tree2->getValue<dataType>(node1Origin) << " ] ";
1453
1454 if(computeCosts) {
1455 dataType tempCost = relabelCost<dataType>(tree1, node0, tree2, node1);
1456 dataType tempCost2
1457 = relabelCostOnly<dataType>(tree1, node0, tree2, node1);
1458 ss << "cost = " << tempCost << " (" << tempCost2 << ")" << std::endl;
1459 cost += tempCost;
1460 } else
1461 ss << std::endl;
1462 tree1Done[node0] = true;
1463 tree2Done[node1] = true;
1464 }
1465
1466 for(unsigned int i = 0; i < tree1->getNumberOfNodes(); ++i)
1467 if(not tree1Done[i] and not tree1->isNodeAlone(i)) {
1468 ftm::idNode nodeOrigin = tree1->getNode(i)->getOrigin();
1469 ss << "T1 " << i << " _ [ f(" << i
1470 << ") = " << tree1->getValue<dataType>(i);
1471 ss << "_ f(" << nodeOrigin
1472 << ") = " << tree1->getValue<dataType>(nodeOrigin);
1473 ss << "]";
1474 if(computeCosts) {
1475 dataType tempCost = deleteCost<dataType>(tree1, i);
1476 ss << " _ cost = " << tempCost << std::endl;
1477 cost += tempCost;
1478 } else
1479 ss << std::endl;
1480 }
1481 for(unsigned int i = 0; i < tree2->getNumberOfNodes(); ++i)
1482 if(not tree2Done[i] and not tree2->isNodeAlone(i)) {
1483 ftm::idNode nodeOrigin = tree2->getNode(i)->getOrigin();
1484 ss << "T2 " << i << " _ [ g(" << i
1485 << ") = " << tree2->getValue<dataType>(i);
1486 ss << "_ g(" << nodeOrigin
1487 << ") = " << tree2->getValue<dataType>(nodeOrigin);
1488 ss << "]";
1489 if(computeCosts) {
1490 dataType tempCost = deleteCost<dataType>(tree2, i);
1491 ss << " _ cost = " << tempCost << std::endl;
1492 cost += tempCost;
1493 } else
1494 ss << std::endl;
1495 }
1496 if(computeCosts)
1497 ss << "total cost = " << cost << " (" << std::sqrt(cost) << ")"
1498 << std::endl;
1499
1500 printMsg(ss.str());
1502 }
1503 }; // MergeTreeBase class
1504
1505} // 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 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)
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 preprocessingPipeline(ftm::MergeTree< dataType > &mTree, double epsilonTree, double epsilon2Tree, double epsilon3Tree, bool branchDecompositionT, bool useMinMaxPairT, bool cleanTreeT, std::vector< int > &nodeCorr, bool deleteInconsistentNodes=true)
void setPersistenceThreshold(double pt)
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)
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)