TTK
Loading...
Searching...
No Matches
MergeTreeBarycenter.h
Go to the documentation of this file.
1
15
21
22#pragma once
23
24#include <random>
25
26// ttk common includes
27#include <Debug.h>
28#include <Triangulation.h>
29
30#include "MergeTreeBase.h"
31#include "MergeTreeDistance.h"
32#include "PathMappingDistance.h"
33
34#include <fstream>
35#include <iostream>
36
37namespace ttk {
38
43 class MergeTreeBarycenter : virtual public Debug, public MergeTreeBase {
44
45 protected:
46 double tol_ = 0.0;
47 bool addNodes_ = true;
48 bool deterministic_ = true;
51 bool isCalled_ = false;
54 double alpha_ = 0.5;
57
58 double allDistanceTime_ = 0;
59
61
62 bool preprocess_ = true;
63 bool postprocess_ = true;
64
65 int pathMetric_ = 0;
66 int baseModule_ = 0;
68 bool useFixedInit_ = false;
69 // bool useEarlyOut_ = true;
71 int iterationLimit_ = 100;
72
73 // Output
74 std::vector<double> finalDistances_;
75
76 public:
79 "MergeTreeBarycenter"); // inherited from Debug: prefix will be printed
80 // at the beginning of every msg
81#ifdef TTK_ENABLE_OPENMP4
82 omp_set_max_active_levels(100);
83#endif
84 }
85 ~MergeTreeBarycenter() override = default;
86
87 void setTol(double tolT) {
88 tol_ = tolT;
89 }
90
91 void setAddNodes(bool addNodesT) {
92 addNodes_ = addNodesT;
93 }
94
95 void setDeterministic(bool deterministicT) {
96 deterministic_ = deterministicT;
97 }
98
99 void setBarycenterInitIndex(int barycenterInitIndex) {
100 barycenterInitIndex_ = barycenterInitIndex;
101 }
102
103 void setBarycenterMaxIter(int barycenterMaxIter) {
104 barycenterMaxIter_ = barycenterMaxIter;
105 }
106
107 void setProgressiveBarycenter(bool progressive) {
108 progressiveBarycenter_ = progressive;
109 }
110
111 void setProgressiveSpeedDivisor(double progSpeed) {
112 progressiveSpeedDivisor_ = progSpeed;
113 }
114
115 void setIsCalled(bool ic) {
116 isCalled_ = ic;
117 }
118
120 return allDistanceTime_;
121 }
122
125 }
126
127 void setAlpha(double alpha) {
128 alpha_ = alpha;
129 }
130
131 void setBarycenterMaximumNumberOfPairs(unsigned int maxi) {
133 }
134
135 void setBarycenterSizeLimitPercent(double percent) {
137 }
138
139 void setPreprocess(bool preproc) {
140 preprocess_ = preproc;
141 }
142
143 void setPostprocess(bool postproc) {
144 postprocess_ = postproc;
145 }
146
147 std::vector<double> getFinalDistances() {
148 return finalDistances_;
149 }
150
151 void setBaseModule(int m) {
152 baseModule_ = m;
153 }
154
155 void setPathMetric(int m) {
156 pathMetric_ = m;
157 }
158
159 void setUseMedianBarycenter(bool useMedian) {
160 useMedianBarycenter_ = useMedian;
161 }
162
163 void setUseFixedInit(bool useFixedInit) {
164 useFixedInit_ = useFixedInit;
165 }
166
167 // void setUseEarlyOut(bool useEarlyOut) {
168 // useEarlyOut_ = useEarlyOut;
169 // }
170
171 void setFixedInitNumber(int fixedInitNumber) {
172 fixedInitNumber_ = fixedInitNumber;
173 }
174
175 void setIterationLimit(int l) {
176 iterationLimit_ = l;
177 }
178
182 // ------------------------------------------------------------------------
183 // Initialization
184 // ------------------------------------------------------------------------
185 template <class dataType>
186 void getDistanceMatrix(std::vector<ftm::FTMTree_MT *> &trees,
187 std::vector<ftm::FTMTree_MT *> &trees2,
188 std::vector<std::vector<double>> &distanceMatrix,
189 bool useDoubleInput = false,
190 bool isFirstInput = true) {
191 distanceMatrix.clear();
192 distanceMatrix.resize(trees.size(), std::vector<double>(trees.size(), 0));
193#ifdef TTK_ENABLE_OPENMP4
194#pragma omp parallel for schedule(dynamic) \
195 num_threads(this->threadNumber_) if(parallelize_)
196#endif
197 for(unsigned int i = 0; i < trees.size(); ++i)
198 for(unsigned int j = i + 1; j < trees.size(); ++j) {
199 std::vector<std::tuple<ftm::idNode, ftm::idNode, double>> matching;
200 std::vector<std::pair<std::pair<ftm::idNode, ftm::idNode>,
201 std::pair<ftm::idNode, ftm::idNode>>>
202 matching_path;
203 dataType distance;
204 computeOneDistance<dataType>(trees[i], trees2[j], matching,
205 matching_path, distance, useDoubleInput,
206 isFirstInput);
207 distanceMatrix[i][j] = distance;
208 distanceMatrix[j][i] = distance;
209 }
210 }
211
212 template <class dataType>
213 void getDistanceMatrix(std::vector<ftm::FTMTree_MT *> &trees,
214 std::vector<std::vector<double>> &distanceMatrix,
215 bool useDoubleInput = false,
216 bool isFirstInput = true) {
218 trees, trees, distanceMatrix, useDoubleInput, isFirstInput);
219 }
220
221 template <class dataType>
223 std::vector<ftm::FTMTree_MT *> &trees,
224 unsigned int barycenterMaximumNumberOfPairs,
225 double sizeLimitPercent,
226 std::vector<ftm::MergeTree<dataType>> &mTreesLimited) {
227 mTreesLimited.resize(trees.size());
228#ifdef TTK_ENABLE_OPENMP4
229#pragma omp parallel for schedule(dynamic) \
230 num_threads(this->threadNumber_) if(parallelize_)
231#endif
232 for(unsigned int i = 0; i < trees.size(); ++i) {
233 mTreesLimited[i] = ftm::copyMergeTree<dataType>(trees[i]);
234 limitSizeBarycenter(mTreesLimited[i], trees,
235 barycenterMaximumNumberOfPairs, sizeLimitPercent);
236 ftm::cleanMergeTree<dataType>(mTreesLimited[i]);
237 }
238 }
239
240 template <class dataType>
242 std::vector<ftm::FTMTree_MT *> &trees,
243 std::vector<std::vector<double>> &distanceMatrix,
244 unsigned int barycenterMaximumNumberOfPairs,
245 double sizeLimitPercent,
246 bool useDoubleInput = false,
247 bool isFirstInput = true) {
248 std::vector<ftm::MergeTree<dataType>> mTreesLimited;
250 trees, barycenterMaximumNumberOfPairs, sizeLimitPercent, mTreesLimited);
251 std::vector<ftm::FTMTree_MT *> treesLimited;
252 ftm::mergeTreeToFTMTree<dataType>(mTreesLimited, treesLimited);
254 trees, treesLimited, distanceMatrix, useDoubleInput, isFirstInput);
255 }
256
257 template <class dataType>
259 std::vector<ftm::FTMTree_MT *> &trees,
260 std::vector<std::vector<double>> &distanceMatrix,
261 unsigned int barycenterMaximumNumberOfPairs,
262 double sizeLimitPercent,
263 bool useDoubleInput = false,
264 bool isFirstInput = true) {
265 if(barycenterMaximumNumberOfPairs <= 0 and sizeLimitPercent <= 0.0)
267 trees, distanceMatrix, useDoubleInput, isFirstInput);
268 else
270 trees, distanceMatrix, barycenterMaximumNumberOfPairs,
271 sizeLimitPercent, useDoubleInput, isFirstInput);
272 }
273
274 template <class dataType>
275 int getBestInitTreeIndex(std::vector<ftm::FTMTree_MT *> &trees,
276 std::vector<ftm::FTMTree_MT *> &trees2,
277 unsigned int barycenterMaximumNumberOfPairs,
278 double sizeLimitPercent,
279 bool distMinimizer = true) {
280 if(barycenterInitIndex_ != -1)
282 std::vector<std::vector<double>> distanceMatrix, distanceMatrix2;
283 bool const useDoubleInput = (trees2.size() != 0);
284 getParametrizedDistanceMatrix<dataType>(trees, distanceMatrix,
285 barycenterMaximumNumberOfPairs,
286 sizeLimitPercent, useDoubleInput);
287 if(trees2.size() != 0)
289 trees2, distanceMatrix2, barycenterMaximumNumberOfPairs,
290 sizeLimitPercent, useDoubleInput, false);
291
292 int bestIndex = -1;
293 dataType bestValue
294 = distMinimizer ? std::numeric_limits<dataType>::max() : 0;
295 std::vector<int> sizes(trees.size());
296 for(unsigned int i = 0; i < trees.size(); ++i) {
297 dataType value = 0;
298 for(unsigned int j = 0; j < distanceMatrix[i].size(); ++j)
299 value += (not useDoubleInput ? distanceMatrix[i][j]
300 : mixDistances(distanceMatrix[i][j],
301 distanceMatrix2[i][j]));
302 if((distMinimizer and value < bestValue)
303 or (not distMinimizer and value > bestValue)) {
304 bestIndex = i;
305 bestValue = value;
306 }
307 sizes[i] = -value;
308 sizes[i] *= (distMinimizer) ? 1 : -1;
309 }
310 if(not deterministic_) {
311 std::random_device rd;
312 std::default_random_engine generator(rd());
313 std::discrete_distribution<int> distribution(
314 sizes.begin(), sizes.end());
315 bestIndex = distribution(generator);
316 }
317 return bestIndex;
318 }
319
320 template <class dataType>
321 int getBestInitTreeIndex(std::vector<ftm::FTMTree_MT *> &trees,
322 std::vector<ftm::FTMTree_MT *> &trees2,
323 double sizeLimitPercent,
324 bool distMinimizer = true) {
325 return getBestInitTreeIndex<dataType>(trees, trees2,
327 sizeLimitPercent, distMinimizer);
328 }
329
330 template <class dataType>
331 int getBestInitTreeIndex(std::vector<ftm::FTMTree_MT *> &trees,
332 bool distMinimizer = true) {
333 std::vector<ftm::FTMTree_MT *> trees2;
335 trees, trees2, barycenterMaximumNumberOfPairs_,
336 barycenterSizeLimitPercent_, distMinimizer);
337 }
338
339 template <class dataType>
340 void initBarycenterTree(std::vector<ftm::FTMTree_MT *> &trees,
341 ftm::MergeTree<dataType> &baryTree,
342 bool distMinimizer = true) {
343 int bestIndex;
344 if(useFixedInit_) {
345 if(fixedInitNumber_ >= 0 && fixedInitNumber_ < (int)trees.size())
346 bestIndex = fixedInitNumber_;
347 else
348 bestIndex = 0;
349 } else
350 bestIndex = getBestInitTreeIndex<dataType>(trees, distMinimizer);
351 // bestIndex = 10;
352 // baryTree = ftm::copyMergeTree<dataType>(trees[bestIndex], true);
353 baryTree
354 = ftm::copyMergeTree<dataType>(trees[bestIndex], baseModule_ != 2);
355 // ftm::FTMTree_MT* bt = &(baryTree.tree);
356 limitSizeBarycenter(baryTree, trees);
357 }
358
359 // ------------------------------------------------------------------------
360 // Update
361 // ------------------------------------------------------------------------
375 template <class dataType>
377 ftm::idNode nodeId1,
378 ftm::FTMTree_MT *tree,
379 ftm::idNode nodeId2,
380 std::vector<dataType> &newScalarsVector,
381 std::vector<std::tuple<ftm::idNode, ftm::idNode, int>> &nodesToProcess,
382 ftm::idNode nodeCpt,
383 int i) {
384 // Get nodes and scalars to add
385 std::queue<std::tuple<ftm::idNode, ftm::idNode>> queue;
386 queue.emplace(nodeId2, nodeId1);
387 nodesToProcess.emplace_back(nodeId2, nodeId1, i);
388 while(!queue.empty()) {
389 auto &queueTuple = queue.front();
390 queue.pop();
391 ftm::idNode const node = std::get<0>(queueTuple);
392 // Get scalars
393 newScalarsVector.push_back(
394 tree->getValue<dataType>(tree->getNode(node)->getOrigin()));
395 newScalarsVector.push_back(tree->getValue<dataType>(node));
396 // Process children
397 std::vector<ftm::idNode> children;
398 tree->getChildren(node, children);
399 for(auto child : children) {
400 queue.emplace(child, nodeCpt + 1);
401 nodesToProcess.emplace_back(child, nodeCpt + 1, i);
402 }
403 nodeCpt += 2; // we will add two nodes (birth and death)
404 }
405
406 return nodeCpt;
407 }
408
409 template <class dataType>
412 int noTrees,
413 std::vector<std::tuple<ftm::idNode, ftm::idNode, int>> &nodesToProcess,
414 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode>>>
415 &nodesProcessed) {
416 ftm::FTMTree_MT *tree1 = &(mTree1.tree);
417
418 // Add nodes
419 nodesProcessed.clear();
420 nodesProcessed.resize(noTrees);
421 for(auto &processTuple : nodesToProcess) {
422 ftm::idNode const parent = std::get<1>(processTuple);
423 ftm::idNode const nodeTree1 = tree1->getNumberOfNodes();
424 int const index = std::get<2>(processTuple);
425 nodesProcessed[index].emplace_back(
426 nodeTree1 + 1, std::get<0>(processTuple));
427 // Make node and its origin
428 tree1->makeNode(nodeTree1);
429 tree1->makeNode(nodeTree1 + 1);
430 tree1->setParent(nodeTree1 + 1, parent);
431 tree1->getNode(nodeTree1)->setOrigin(nodeTree1 + 1);
432 tree1->getNode(nodeTree1 + 1)->setOrigin(nodeTree1);
433 }
434 }
435
436 template <class dataType>
439 int noTrees,
440 std::vector<std::tuple<ftm::idNode, ftm::idNode, int>> &nodesToProcess,
441 std::vector<dataType> &newScalarsVector,
442 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode>>>
443 &nodesProcessed) {
444 ftm::FTMTree_MT *tree1 = &(mTree1.tree);
445
446 // Create new tree
448 = ftm::createEmptyMergeTree<dataType>(newScalarsVector.size());
449 ftm::setTreeScalars<dataType>(mTreeNew, newScalarsVector);
450 ftm::FTMTree_MT *treeNew = &(mTreeNew.tree);
451
452 // Copy the old tree structure
453 treeNew->copyMergeTreeStructure(tree1);
454
455 // Add nodes in the other trees
456 addNodes<dataType>(mTreeNew, noTrees, nodesToProcess, nodesProcessed);
457
458 // Copy new tree
459 mTree1 = mTreeNew;
460 }
461
462 template <class dataType>
464 std::vector<ftm::FTMTree_MT *> &trees,
465 ftm::MergeTree<dataType> &baryMergeTree,
466 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>>
467 &matchings) {
468 ftm::FTMTree_MT *baryTree = &(baryMergeTree.tree);
469 ftm::idNode const baryTreeRoot = baryTree->getRoot();
470
471 // Init matching matrix
472 // m[i][j] contains the node in the barycenter matched to the jth node of
473 // the ith tree
474 std::vector<std::vector<ftm::idNode>> matrixMatchings(trees.size());
475 std::vector<bool> baryMatched(baryTree->getNumberOfNodes(), false);
476 for(unsigned int i = 0; i < matchings.size(); ++i) {
477 auto &matching = matchings[i];
478 matrixMatchings[i].resize(trees[i]->getNumberOfNodes(),
479 std::numeric_limits<ftm::idNode>::max());
480 for(auto &match : matching) {
481 matrixMatchings[i][std::get<1>(match)] = std::get<0>(match);
482 baryMatched[std::get<0>(match)] = true;
483 }
484 }
485
486 // Iterate through trees to get the nodes to add in the barycenter
487 std::vector<std::vector<ftm::idNode>> nodesToAdd(trees.size());
488#ifdef TTK_ENABLE_OPENMP4
489#pragma omp parallel for schedule(dynamic) \
490 num_threads(this->threadNumber_) if(parallelize_)
491#endif
492 for(unsigned int i = 0; i < trees.size(); ++i) {
493 ftm::idNode const root = trees[i]->getRoot();
494 std::queue<ftm::idNode> queue;
495 queue.emplace(root);
496 while(!queue.empty()) {
497 ftm::idNode const node = queue.front();
498 queue.pop();
499 bool processChildren = true;
500 // if node in trees[i] is not matched
501 if(matrixMatchings[i][node]
502 == std::numeric_limits<ftm::idNode>::max()) {
503 if(not keepSubtree_) {
504 processChildren = false;
505 nodesToAdd[i].push_back(node);
506 } else {
507 // not todo manage if keepSubtree=true (not important since it is
508 // not a valid merge tree)
509 printErr(
510 "barycenter with keepSubtree_=true is not implemented yet");
511 }
512 }
513 if(processChildren) {
514 std::vector<ftm::idNode> children;
515 trees[i]->getChildren(node, children);
516 for(auto child : children)
517 if(not(trees[i]->isThereOnlyOnePersistencePair()
518 and trees[i]->isLeaf(child)))
519 queue.emplace(child);
520 }
521 }
522 }
523
524 bool foundRootNotMatched = false;
525 for(unsigned int i = 0; i < trees.size(); ++i)
526 foundRootNotMatched |= baryTree->isNodeIdInconsistent(
527 matrixMatchings[i][trees[i]->getRoot()]);
528 if(foundRootNotMatched)
529 printWrn("[updateBarycenterTreeStructure] an input tree has its root "
530 "not matched.");
531
532 // Delete nodes that are not matched in the barycenter
533 for(unsigned int i = 0; i < baryTree->getNumberOfNodes(); ++i)
534 if(not baryMatched[i])
535 baryTree->deleteNode(i);
536
537 if(not keepSubtree_) {
538 // Add scalars and nodes not present in the barycenter
539 ftm::idNode nodeCpt = baryTree->getNumberOfNodes();
540 std::vector<std::tuple<ftm::idNode, ftm::idNode, int>> nodesToProcess;
541 std::vector<dataType> newScalarsVector;
542 ftm::getTreeScalars<dataType>(baryMergeTree, newScalarsVector);
543 for(unsigned int i = 0; i < nodesToAdd.size(); ++i) {
544 for(auto node : nodesToAdd[i]) {
545 ftm::idNode parent
546 = matrixMatchings[i][trees[i]->getParentSafe(node)];
547 if(matchings[i].size() == 0)
548 parent = baryTreeRoot;
549
550 if((baryTree->isNodeIdInconsistent(parent)
551 or baryTree->isNodeAlone(parent))
552 and matchings[i].size() != 0) {
553 std::stringstream ss;
554 ss << trees[i]->getParentSafe(node) << " _ " << node;
555 printMsg(ss.str());
556 printMsg(trees[i]->printTree().str());
557 printMsg(trees[i]->printPairsFromTree<dataType>(true).str());
558 printMatching(matchings[i]);
559 std::stringstream ss2;
560 ss2 << "parent " << parent;
561 printMsg(ss2.str());
562 }
563 /*if(isRoot(trees[i], node))
564 parent = baryTree->getRoot();*/
565 std::vector<dataType> addedScalars;
567 parent, trees[i], node, addedScalars, nodesToProcess, nodeCpt, i);
568 newScalarsVector.insert(
569 newScalarsVector.end(), addedScalars.begin(), addedScalars.end());
570 }
571 }
572 if(addNodes_) {
573 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode>>>
574 nodesProcessed;
575 updateNodesAndScalars<dataType>(baryMergeTree, trees.size(),
576 nodesToProcess, newScalarsVector,
577 nodesProcessed);
578 for(unsigned int i = 0; i < matchings.size(); ++i) {
579 std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>
580 nodesProcessedT;
581 for(auto &tup : nodesProcessed[i])
582 nodesProcessedT.emplace_back(
583 std::get<0>(tup), std::get<1>(tup), -1);
584 matchings[i].insert(matchings[i].end(), nodesProcessedT.begin(),
585 nodesProcessedT.end());
586 }
587 }
588 } else {
589 // not todo manage if keepSubtree=true (not important since it is not a
590 // valid merge tree)
591 printErr("barycenter with keepSubtree_=true is not implemented yet");
592 }
593 }
594
595 template <class dataType>
596 std::tuple<dataType, dataType>
598 std::tuple<dataType, dataType> birthDeath;
599 // Normalized Wasserstein
601 birthDeath = getNormalizedBirthDeath<dataType>(tree1, nodeId1);
602 // Classical Wasserstein
603 else
604 birthDeath = tree1->getBirthDeath<dataType>(nodeId1);
605 return birthDeath;
606 }
607
608 template <class dataType>
609 std::tuple<dataType, dataType>
611 ftm::idNode nodeId,
612 std::vector<dataType> &newScalarsVector,
613 std::vector<ftm::FTMTree_MT *> &trees,
614 std::vector<ftm::idNode> &nodes,
615 std::vector<double> &alphas) {
616 dataType newBirth = 0, newDeath = 0;
617
618 // Compute projection
619 dataType tempBirth = 0, tempDeath = 0;
620 double alphaSum = 0;
621 for(unsigned int i = 0; i < trees.size(); ++i)
622 if(nodes[i] != std::numeric_limits<ftm::idNode>::max())
623 alphaSum += alphas[i];
624 for(unsigned int i = 0; i < trees.size(); ++i) {
625 // if node is matched in trees[i]
626 if(nodes[i] != std::numeric_limits<ftm::idNode>::max()) {
627 auto iBirthDeath
628 = getParametrizedBirthDeath<dataType>(trees[i], nodes[i]);
629 dataType tTempBirth = 0, tTempDeath = 0;
630 tTempBirth += std::get<0>(iBirthDeath);
631 tTempDeath += std::get<1>(iBirthDeath);
632 tempBirth += tTempBirth * alphas[i] / alphaSum;
633 tempDeath += tTempDeath * alphas[i] / alphaSum;
634 }
635 }
636 dataType const projec = (tempBirth + tempDeath) / 2;
637
638 // Compute newBirth and newDeath
639 for(unsigned int i = 0; i < trees.size(); ++i) {
640 dataType iBirth = projec, iDeath = projec;
641 // if node is matched in trees[i]
642 if(nodes[i] != std::numeric_limits<ftm::idNode>::max()) {
643 auto iBirthDeath
644 = getParametrizedBirthDeath<dataType>(trees[i], nodes[i]);
645 iBirth = std::get<0>(iBirthDeath);
646 iDeath = std::get<1>(iBirthDeath);
647 }
648 newBirth += alphas[i] * iBirth;
649 newDeath += alphas[i] * iDeath;
650 }
652 ftm::FTMTree_MT *baryTree = &(baryMergeTree.tree);
653 dataType mu_max = getMinMaxLocalFromVector<dataType>(
654 baryTree, nodeId, newScalarsVector, false);
655 dataType mu_min = getMinMaxLocalFromVector<dataType>(
656 baryTree, nodeId, newScalarsVector);
657 // Forbid compiler optimization to have same results on different
658 // computers
659 volatile dataType tempBirthT = newBirth * (mu_max - mu_min);
660 volatile dataType tempDeathT = newDeath * (mu_max - mu_min);
661 newBirth = tempBirthT + mu_min;
662 newDeath = tempDeathT + mu_min;
663 }
664
665 return std::make_tuple(newBirth, newDeath);
666 }
667
668 template <class dataType>
669 std::tuple<dataType, dataType>
671 ftm::idNode nodeId,
672 double alpha,
673 ftm::MergeTree<dataType> &baryMergeTree,
674 ftm::idNode nodeB,
675 std::vector<dataType> &newScalarsVector) {
676 auto birthDeath = getParametrizedBirthDeath<dataType>(tree, nodeId);
677 dataType newBirth = std::get<0>(birthDeath);
678 dataType newDeath = std::get<1>(birthDeath);
679 dataType const projec = (newBirth + newDeath) / 2;
680
681 newBirth = alpha * newBirth + (1 - alpha) * projec;
682 newDeath = alpha * newDeath + (1 - alpha) * projec;
683
685 ftm::FTMTree_MT *baryTree = &(baryMergeTree.tree);
686 dataType mu_max = getMinMaxLocalFromVector<dataType>(
687 baryTree, nodeB, newScalarsVector, false);
688 dataType mu_min = getMinMaxLocalFromVector<dataType>(
689 baryTree, nodeB, newScalarsVector);
690 // Forbid compiler optimization to have same results on different
691 // computers
692 volatile dataType tempBirthT = newBirth * (mu_max - mu_min);
693 volatile dataType tempDeathT = newDeath * (mu_max - mu_min);
694 newBirth = tempBirthT + mu_min;
695 newDeath = tempDeathT + mu_min;
696 }
697
698 return std::make_tuple(newBirth, newDeath);
699 }
700
701 template <class dataType>
703 std::vector<ftm::FTMTree_MT *> &trees,
704 ftm::MergeTree<dataType> &baryMergeTree,
705 std::vector<double> &alphas,
706 unsigned int indexAddedNodes,
707 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>>
708 &matchings) {
709 ftm::FTMTree_MT *baryTree = &(baryMergeTree.tree);
710 bool const isJT = baryTree->isJoinTree<dataType>();
711
712 // Init matching matrix
713 // m[i][j] contains the node in trees[j] matched to the node i in the
714 // barycenter
715 std::vector<std::vector<ftm::idNode>> baryMatching(
716 indexAddedNodes,
717 std::vector<ftm::idNode>(
718 trees.size(), std::numeric_limits<ftm::idNode>::max()));
719 std::vector<std::tuple<int, ftm::idNode>> nodesAddedTree(
720 baryTree->getNumberOfNodes(), std::make_tuple(-1, -1));
721 for(unsigned int i = 0; i < matchings.size(); ++i) {
722 auto &matching = matchings[i];
723 for(auto &match : matching) {
724 if(std::get<0>(match) >= indexAddedNodes)
725 // get the tree of this added node
726 nodesAddedTree[std::get<0>(match)]
727 = std::make_tuple(i, std::get<1>(match));
728 else
729 baryMatching[std::get<0>(match)][i] = std::get<1>(match);
730 }
731 }
732
733 // Interpolate scalars
734 std::vector<dataType> newScalarsVector(baryTree->getNumberOfNodes());
735 ftm::idNode const root = baryTree->getRoot();
736 std::queue<ftm::idNode> queue;
737 queue.emplace(root);
738 while(!queue.empty()) {
739 ftm::idNode const node = queue.front();
740 queue.pop();
741 std::tuple<dataType, dataType> newBirthDeath;
742 if(node < indexAddedNodes) {
743 newBirthDeath
744 = interpolation<dataType>(baryMergeTree, node, newScalarsVector,
745 trees, baryMatching[node], alphas);
746 } else {
747 int const i = std::get<0>(nodesAddedTree[node]);
748 ftm::idNode const nodeT = std::get<1>(nodesAddedTree[node]);
749 newBirthDeath = interpolationAdded<dataType>(
750 trees[i], nodeT, alphas[i], baryMergeTree, node, newScalarsVector);
751 }
752 dataType nodeScalar
753 = (isJT ? std::get<1>(newBirthDeath) : std::get<0>(newBirthDeath));
754 dataType nodeOriginScalar
755 = (isJT ? std::get<0>(newBirthDeath) : std::get<1>(newBirthDeath));
756 newScalarsVector[node] = nodeScalar;
757 newScalarsVector[baryTree->getNode(node)->getOrigin()]
758 = nodeOriginScalar;
759 std::vector<ftm::idNode> children;
760 baryTree->getChildren(node, children);
761 for(auto child : children)
762 queue.emplace(child);
763 }
764
765 if(baryMergeTree.tree.isFullMerge()) {
766 auto mergedRootOrigin = baryTree->getMergedRootOrigin<dataType>();
767 dataType mergedRootOriginScalar = 0.0;
768 for(unsigned int i = 0; i < trees.size(); ++i)
769 mergedRootOriginScalar += trees[i]->getValue<dataType>(
770 trees[i]->getMergedRootOrigin<dataType>());
771 mergedRootOriginScalar /= trees.size();
772 newScalarsVector[mergedRootOrigin] = mergedRootOriginScalar;
773 }
774
775 setTreeScalars(baryMergeTree, newScalarsVector);
776 std::vector<ftm::idNode> deletedNodesT;
778 &(baryMergeTree.tree), 0, deletedNodesT);
779 limitSizeBarycenter(baryMergeTree, trees);
780 ftm::cleanMergeTree<dataType>(baryMergeTree);
781 }
782
783 template <class dataType>
785 std::vector<ftm::FTMTree_MT *> &trees,
786 ftm::MergeTree<dataType> &baryMergeTree,
787 std::vector<double> &alphas,
788 std::vector<std::vector<std::pair<std::pair<ftm::idNode, ftm::idNode>,
789 std::pair<ftm::idNode, ftm::idNode>>>>
790 &matchings) {
791 ftm::FTMTree_MT *baryTree = &(baryMergeTree.tree);
792 double alphaSum = 0;
793 for(unsigned int i = 0; i < trees.size(); ++i)
794 alphaSum += alphas[i];
795 bool joinTrees = trees[0]->isJoinTree<dataType>();
796 int oldSize = baryTree->getNumberOfNodes();
797
798 // compute matched and unmatched nodes for all trees and barycenter
799 std::vector<bool> baryNodesMatched(baryTree->getNumberOfNodes(), false);
800 std::vector<std::vector<bool>> treeNodesMatched(trees.size());
801 for(unsigned int i = 0; i < trees.size(); i++) {
802 if(alphas[i] == 0)
803 continue;
804 treeNodesMatched[i].resize(trees[i]->getNumberOfNodes(), false);
805 for(auto match : matchings[i]) {
806 baryNodesMatched[match.first.first] = true;
807 baryNodesMatched[match.first.second] = true;
808 treeNodesMatched[i][match.second.first] = true;
809 treeNodesMatched[i][match.second.second] = true;
810 }
811 }
812 // compute size of new barycenter tree
813 int newSize = oldSize;
814 for(unsigned int i = 0; i < treeNodesMatched.size(); i++) {
815 if(alphas[i] == 0 || useMedianBarycenter_)
816 continue;
817 for(unsigned int j = 0; j < treeNodesMatched[i].size(); j++) {
818 if(!treeNodesMatched[i][j])
819 newSize++;
820 }
821 }
822
823 // Create new barycenter tree
824 ftm::MergeTree<dataType> baryMergeTreeNew
826 // newScalars.resize(newSize);
827 // ftm::setTreeScalars<dataType>(baryMergeTreeNew, newScalars);
828 ftm::FTMTree_MT *baryTreeNew = &(baryMergeTreeNew.tree);
829
830 // Copy the old tree structure
831 baryTreeNew->copyMergeTreeStructure(baryTree);
832
833 // delete not-matched nodes in barycenter
834 for(ftm::idNode i = 0; i < baryTree->getNumberOfNodes(); i++) {
835 if(not baryNodesMatched[i]) {
836 baryTreeNew->getNode(i)->setOrigin(-1);
837 baryTreeNew->deleteNode(i);
838 }
839 }
840
841 // relabel paths
842 std::vector<std::vector<dataType>> parentEdgeLengths(
843 baryTree->getNumberOfNodes());
844 for(unsigned int i = 0; i < trees.size(); i++) {
845 if(alphas[i] == 0)
846 continue;
847 auto tree = trees[i];
848 for(auto match : matchings[i]) {
849 dataType bv1 = baryTree->getValue<dataType>(match.first.first);
850 dataType bv2 = baryTree->getValue<dataType>(match.first.second);
851 dataType tv1 = tree->getValue<dataType>(match.second.first);
852 dataType tv2 = tree->getValue<dataType>(match.second.second);
853 dataType pathRangeB = bv1 > bv2 ? bv1 - bv2 : bv2 - bv1;
854 dataType pathRangeT = tv1 > tv2 ? tv1 - tv2 : tv2 - tv1;
855 ftm::idNode currB = baryTreeNew->getParentSafe(match.first.first);
856 ftm::idNode lastB = match.first.first;
857 while(lastB != match.first.second) {
858 dataType currValueB = baryTree->getValue<dataType>(currB);
859 dataType lastValueB = baryTree->getValue<dataType>(lastB);
860 dataType relativeValueB = lastValueB > currValueB
861 ? lastValueB - currValueB
862 : currValueB - lastValueB;
863 relativeValueB = relativeValueB / pathRangeB;
865 parentEdgeLengths[lastB].emplace_back(relativeValueB
866 * pathRangeT);
867 else
868 parentEdgeLengths[lastB].emplace_back(relativeValueB * pathRangeT
869 * alphas[i]);
870 // continue iteration
871 lastB = currB;
872 currB = baryTreeNew->getParentSafe(currB);
873 }
874 }
875 }
876 std::queue<ftm::idNode> q;
877 q.push(baryTreeNew->getRoot());
878 // std::vector<dataType> newScalars(baryTree->getNumberOfNodes(),0);
879 std::vector<dataType> newScalars(newSize, 0);
880 newScalars[baryTreeNew->getRoot()]
881 = baryTree->getValue<dataType>(baryTree->getRoot());
882 while(!q.empty()) {
883 auto curr = q.front();
884 q.pop();
885 std::vector<ftm::idNode> children;
886 baryTreeNew->getChildren(curr, children);
887 for(auto child : children) {
888 q.emplace(child);
890 auto m = parentEdgeLengths[child].begin()
891 + parentEdgeLengths[child].size() / 2;
892 std::nth_element(parentEdgeLengths[child].begin(), m,
893 parentEdgeLengths[child].end());
894 auto medianEdgeLength
895 = parentEdgeLengths[child][parentEdgeLengths[child].size() / 2];
896 newScalars[child]
897 = newScalars[curr]
898 + (joinTrees ? -medianEdgeLength : medianEdgeLength);
899 } else {
900 dataType avgEdgeLength = 0;
901 for(auto l : parentEdgeLengths[child]) {
902 avgEdgeLength += l;
903 }
904 // avgEdgeLength =
905 // avgEdgeLength/static_cast<dataType>(trees.size());
906 avgEdgeLength = avgEdgeLength / alphaSum;
907 newScalars[child]
908 = newScalars[curr] + (joinTrees ? -avgEdgeLength : avgEdgeLength);
909 }
910 }
911 }
912 setTreeScalars(baryMergeTreeNew, newScalars);
913
914 // insert new nodes
915 int currSize = oldSize;
916 for(unsigned int i = 0; i < trees.size(); i++) {
917 if(alphas[i] == 0 || useMedianBarycenter_)
918 continue;
919 auto tree = trees[i];
920 std::vector<int> newIndices(tree->getNumberOfNodes(), -1);
921 for(auto match : matchings[i]) {
922 dataType bv1 = baryTreeNew->getValue<dataType>(match.first.first);
923 dataType bv2 = baryTreeNew->getValue<dataType>(match.first.second);
924 dataType tv1 = tree->getValue<dataType>(match.second.first);
925 dataType tv2 = tree->getValue<dataType>(match.second.second);
926 dataType pathRangeB = bv1 > bv2 ? bv1 - bv2 : bv2 - bv1;
927 dataType pathRangeT = tv1 > tv2 ? tv1 - tv2 : tv2 - tv1;
928 ftm::idNode currB = baryTreeNew->getParentSafe(match.first.first);
929 ftm::idNode currT = tree->getParentSafe(match.second.first);
930 ftm::idNode lastB = match.first.first;
931 ftm::idNode lastT = match.second.first;
932 ftm::idNode lastNode = lastB;
933 while(currB != match.first.second || currT != match.second.second) {
934 dataType currValueB = baryTreeNew->getValue<dataType>(currB);
935 dataType currValueT = tree->getValue<dataType>(currT);
936 dataType relativeValueB
937 = bv1 > bv2 ? bv1 - currValueB : currValueB - bv1;
938 dataType relativeValueT
939 = tv1 > tv2 ? tv1 - currValueT : currValueT - tv1;
940 relativeValueB = relativeValueB / pathRangeB;
941 relativeValueT = relativeValueT / pathRangeT;
942 // if next node in barycenter, ignore
943 if(relativeValueB < relativeValueT) {
944 // continue iteration
945 lastB = currB;
946 currB = baryTreeNew->getParentSafe(currB);
947 lastNode = lastB;
948 }
949 // if next node in tree, add nodes
950 else if(relativeValueB > relativeValueT) {
951 q = std::queue<ftm::idNode>();
952 std::vector<ftm::idNode> currChildren;
953 tree->getChildren(currT, currChildren);
954 newIndices[currT] = currSize; // newScalars.size();
955 currSize++;
956 ftm::idNode nI = newIndices[currT];
957 // newScalars.emplace_back(tree->getValue<dataType>(currT));
958 // newScalars.emplace_back(bv1 + (joinTrees ? relativeValueT *
959 // pathRangeB : - relativeValueT * pathRangeB));
960 newScalars[nI] = bv1
961 + (joinTrees ? relativeValueT * pathRangeB
962 : -relativeValueT * pathRangeB);
963 baryTreeNew->makeNode(nI);
964 baryTreeNew->setParent(nI, currB);
965 baryTreeNew->deleteParent(lastNode);
966 baryTreeNew->setParent(lastNode, nI);
967 baryTreeNew->getNode(nI)->setOrigin(-1);
968 std::vector<int> nodesWithoutLink;
969 // baryTreeNew->getNode(nI)->setOrigin(newIndices[tree->getNode(currT)->getOrigin()]);
970 lastNode = newIndices[currT];
971 for(auto child : currChildren) {
972 if(child == lastT)
973 continue;
974 q.emplace(child);
975 newIndices[child] = currSize; // newScalars.size();
976 currSize++;
977 nI = newIndices[child];
978 // newScalars.emplace_back(tree->getValue<dataType>(child));
979 dataType edgeLength
980 = (joinTrees ? tree->getValue<dataType>(currT)
981 - tree->getValue<dataType>(child)
982 : tree->getValue<dataType>(child)
983 - tree->getValue<dataType>(currT));
984 // newScalars.emplace_back(newScalars[newIndices[currT]] +
985 // (joinTrees ? - edgeLength * (alphas[i]/alphaSum) : edgeLength
986 // * (alphas[i]/alphaSum)));
987 newScalars[nI]
988 = newScalars[newIndices[currT]]
989 + (joinTrees ? -edgeLength * (alphas[i] / alphaSum)
990 : edgeLength * (alphas[i] / alphaSum));
991 baryTreeNew->makeNode(nI);
992 baryTreeNew->setParent(nI, newIndices[currT]);
993 baryTreeNew->getNode(nI)->setOrigin(-1);
994 if(tree->getNumberOfChildren(child) == 0
995 && newIndices[tree->getNode(child)->getOrigin()] >= 0) {
996 ftm::idNode ln
997 = newIndices[tree->getNode(child)->getOrigin()];
998 baryTreeNew->getNode(nI)->setOrigin(ln);
999 baryTreeNew->getNode(ln)->setOrigin(nI);
1000 } else {
1001 nodesWithoutLink.push_back(nI);
1002 }
1003 }
1004 while(!q.empty()) {
1005 auto currNode = q.front();
1006 q.pop();
1007 currChildren.clear();
1008 tree->getChildren(currNode, currChildren);
1009 for(auto child : currChildren) {
1010 q.emplace(child);
1011 newIndices[child] = currSize; // newScalars.size();
1012 currSize++;
1013 nI = newIndices[child];
1014 // newScalars.emplace_back(tree->getValue<dataType>(child));
1015 dataType edgeLength
1016 = (joinTrees ? tree->getValue<dataType>(currNode)
1017 - tree->getValue<dataType>(child)
1018 : tree->getValue<dataType>(child)
1019 - tree->getValue<dataType>(currNode));
1020 // newScalars.emplace_back(newScalars[newIndices[currNode]] +
1021 // (joinTrees ? - edgeLength * (alphas[i]/alphaSum) :
1022 // edgeLength * (alphas[i]/alphaSum)));
1023 newScalars[nI]
1024 = newScalars[newIndices[currNode]]
1025 + (joinTrees ? -edgeLength * (alphas[i] / alphaSum)
1026 : edgeLength * (alphas[i] / alphaSum));
1027 baryTreeNew->makeNode(nI);
1028 baryTreeNew->getNode(nI)->setOrigin(-1);
1029 baryTreeNew->setParent(nI, newIndices[currNode]);
1030 if(tree->getNumberOfChildren(child) == 0
1031 && newIndices[tree->getNode(child)->getOrigin()] >= 0) {
1032 ftm::idNode ln
1033 = newIndices[tree->getNode(child)->getOrigin()];
1034 baryTreeNew->getNode(nI)->setOrigin(ln);
1035 baryTreeNew->getNode(ln)->setOrigin(nI);
1036 } else {
1037 nodesWithoutLink.push_back(nI);
1038 }
1039 }
1040 }
1041 // std::cout <<
1042 // baryTreeNew->getNode(newIndices[currT])->getOrigin() << " " <<
1043 // nodesWithoutLink.size() << std::endl;
1044 if(baryTreeNew->getNode(newIndices[currT])->getOrigin() < 0) {
1045 baryTreeNew->getNode(newIndices[currT])
1046 ->setOrigin(nodesWithoutLink[0]);
1047 }
1048 for(ftm::idNode n : nodesWithoutLink) {
1049 baryTreeNew->getNode(n)->setOrigin(newIndices[currT]);
1050 }
1051 // continue iteration
1052 lastT = currT;
1053 currT = tree->getParentSafe(currT);
1054 } else {
1055 // this should not happen
1056 printErr("Impossible Matching behaviour.");
1057 lastB = currB;
1058 lastT = currT;
1059 currB = baryTreeNew->getParentSafe(currB);
1060 currT = tree->getParentSafe(currT);
1061 }
1062 }
1063 }
1064 setTreeScalars(baryMergeTreeNew, newScalars);
1065 }
1066
1067 ftm::cleanMergeTree<dataType>(baryMergeTreeNew, true);
1068 baryMergeTree = baryMergeTreeNew;
1069 }
1070
1071 template <class dataType>
1073 std::vector<ftm::FTMTree_MT *> &trees,
1074 ftm::MergeTree<dataType> &baryMergeTree,
1075 std::vector<double> &alphas,
1076 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>>
1077 &matchings) {
1078 int const indexAddedNodes = baryMergeTree.tree.getNumberOfNodes();
1079 updateBarycenterTreeStructure<dataType>(trees, baryMergeTree, matchings);
1081 trees, baryMergeTree, alphas, indexAddedNodes, matchings);
1082 }
1083
1084 // ------------------------------------------------------------------------
1085 // Assignment
1086 // ------------------------------------------------------------------------
1087
1088 template <class dataType>
1090 ftm::FTMTree_MT *tree,
1091 ftm::FTMTree_MT *baryTree,
1092 std::vector<std::tuple<ftm::idNode, ftm::idNode, double>> &matching,
1093 std::vector<std::pair<std::pair<ftm::idNode, ftm::idNode>,
1094 std::pair<ftm::idNode, ftm::idNode>>>
1095 &matching_path,
1096 dataType &distance,
1097 bool useDoubleInput = false,
1098 bool isFirstInput = true) {
1099 // Timer t_distance;
1100 if(baseModule_ == 2) {
1101 PathMappingDistance pathDistance;
1102 pathDistance.setDebugLevel(std::min(debugLevel_, 2));
1103 pathDistance.setPreprocess(false);
1105 pathDistance.setThreadNumber(this->threadNumber_);
1106 pathDistance.setDistanceSquaredRoot(false); // squared root
1107 pathDistance.setComputeMapping(true);
1108 distance = pathDistance.computeDistance<dataType>(
1109 baryTree, tree, &matching, &matching_path);
1110 } else {
1111 MergeTreeDistance mergeTreeDistance;
1112 mergeTreeDistance.setDebugLevel(std::min(debugLevel_, 2));
1113 mergeTreeDistance.setPreprocess(false);
1114 mergeTreeDistance.setPostprocess(false);
1115 mergeTreeDistance.setBranchDecomposition(true);
1117 mergeTreeDistance.setKeepSubtree(keepSubtree_);
1118 mergeTreeDistance.setAssignmentSolver(assignmentSolverID_);
1119 mergeTreeDistance.setIsCalled(true);
1120 mergeTreeDistance.setThreadNumber(this->threadNumber_);
1121 mergeTreeDistance.setDistanceSquaredRoot(true); // squared root
1122 mergeTreeDistance.setNodePerTask(nodePerTask_);
1123 if(useDoubleInput) {
1124 double const weight = mixDistancesMinMaxPairWeight(isFirstInput);
1125 mergeTreeDistance.setMinMaxPairWeight(weight);
1126 }
1127 /*if(progressiveBarycenter_){
1128 mergeTreeDistance.setAuctionNoRounds(1);
1129 mergeTreeDistance.setAuctionEpsilonDiviser(NoIteration-1);
1130 }*/
1131 distance = mergeTreeDistance.computeDistance<dataType>(
1132 baryTree, tree, matching);
1133 }
1134 std::stringstream ss, ss2;
1135 ss << "distance tree : " << distance;
1137 ss2 << "distance²tree : " << distance * distance;
1139
1140 // auto t_distance_time = t_distance.getElapsedTime();
1141 // allDistanceTime_ += t_distance_time;
1142 }
1143
1144 template <class dataType>
1146 ftm::FTMTree_MT *tree,
1147 ftm::MergeTree<dataType> &baryMergeTree,
1148 std::vector<std::tuple<ftm::idNode, ftm::idNode, double>> &matching,
1149 std::vector<std::pair<std::pair<ftm::idNode, ftm::idNode>,
1150 std::pair<ftm::idNode, ftm::idNode>>>
1151 &matching_path,
1152 dataType &distance,
1153 bool useDoubleInput = false,
1154 bool isFirstInput = true) {
1155 computeOneDistance<dataType>(tree, &(baryMergeTree.tree), matching,
1156 matching_path, distance, useDoubleInput,
1157 isFirstInput);
1158 }
1159
1160 template <class dataType>
1162 ftm::MergeTree<dataType> &baryMergeTree,
1163 ftm::MergeTree<dataType> &baryMergeTree2,
1164 std::vector<std::tuple<ftm::idNode, ftm::idNode, double>> &matching,
1165 std::vector<std::pair<std::pair<ftm::idNode, ftm::idNode>,
1166 std::pair<ftm::idNode, ftm::idNode>>>
1167 &matching_path,
1168 dataType &distance,
1169 bool useDoubleInput = false,
1170 bool isFirstInput = true) {
1171 computeOneDistance<dataType>(&(baryMergeTree.tree), baryMergeTree2,
1172 matching, matching_path, distance,
1173 useDoubleInput, isFirstInput);
1174 }
1175
1176 template <class dataType>
1178 ftm::FTMTree_MT *tree,
1179 ftm::FTMTree_MT *baryTree,
1180 std::vector<std::tuple<ftm::idNode, ftm::idNode, double>> &matching,
1181 dataType &distance,
1182 bool useDoubleInput = false,
1183 bool isFirstInput = true) {
1184 std::vector<std::pair<std::pair<ftm::idNode, ftm::idNode>,
1185 std::pair<ftm::idNode, ftm::idNode>>>
1186 matching_path;
1187 computeOneDistance<dataType>(tree, baryTree, matching, matching_path,
1188 distance, useDoubleInput, isFirstInput);
1189 }
1190
1191 template <class dataType>
1193 ftm::FTMTree_MT *tree,
1194 ftm::MergeTree<dataType> &baryMergeTree,
1195 std::vector<std::tuple<ftm::idNode, ftm::idNode, double>> &matching,
1196 dataType &distance,
1197 bool useDoubleInput = false,
1198 bool isFirstInput = true) {
1199 std::vector<std::pair<std::pair<ftm::idNode, ftm::idNode>,
1200 std::pair<ftm::idNode, ftm::idNode>>>
1201 matching_path;
1202 computeOneDistance<dataType>(tree, &(baryMergeTree.tree), matching,
1203 matching_path, distance, useDoubleInput,
1204 isFirstInput);
1205 }
1206
1207 template <class dataType>
1209 ftm::MergeTree<dataType> &baryMergeTree,
1210 ftm::MergeTree<dataType> &baryMergeTree2,
1211 std::vector<std::tuple<ftm::idNode, ftm::idNode, double>> &matching,
1212 dataType &distance,
1213 bool useDoubleInput = false,
1214 bool isFirstInput = true) {
1215 std::vector<std::pair<std::pair<ftm::idNode, ftm::idNode>,
1216 std::pair<ftm::idNode, ftm::idNode>>>
1217 matching_path;
1218 computeOneDistance<dataType>(&(baryMergeTree.tree), baryMergeTree2,
1219 matching, matching_path, distance,
1220 useDoubleInput, isFirstInput);
1221 }
1222
1223 template <class dataType>
1225 std::vector<ftm::FTMTree_MT *> &trees,
1226 ftm::MergeTree<dataType> &baryMergeTree,
1227 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>>
1228 &matchings,
1229 std::vector<std::vector<std::pair<std::pair<ftm::idNode, ftm::idNode>,
1230 std::pair<ftm::idNode, ftm::idNode>>>>
1231 &matchings_path,
1232 std::vector<dataType> &distances,
1233 bool useDoubleInput = false,
1234 bool isFirstInput = true) {
1235 if(not isCalled_)
1236 assignmentPara(trees, baryMergeTree, matchings, matchings_path,
1237 distances, useDoubleInput, isFirstInput);
1238 else
1239 assignmentTask(trees, baryMergeTree, matchings, matchings_path,
1240 distances, useDoubleInput, isFirstInput);
1241 }
1242
1243 template <class dataType>
1245 std::vector<ftm::FTMTree_MT *> &trees,
1246 ftm::MergeTree<dataType> &baryMergeTree,
1247 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>>
1248 &matchings,
1249 std::vector<std::vector<std::pair<std::pair<ftm::idNode, ftm::idNode>,
1250 std::pair<ftm::idNode, ftm::idNode>>>>
1251 &matchings_path,
1252 std::vector<dataType> &distances,
1253 bool useDoubleInput = false,
1254 bool isFirstInput = true) {
1255#ifdef TTK_ENABLE_OPENMP4
1256#pragma omp parallel num_threads(this->threadNumber_) \
1257 shared(baryMergeTree) if(parallelize_)
1258 {
1259#pragma omp single nowait
1260#endif
1261 assignmentTask(trees, baryMergeTree, matchings, matchings_path,
1262 distances, useDoubleInput, isFirstInput);
1263#ifdef TTK_ENABLE_OPENMP4
1264 } // pragma omp parallel
1265#endif
1266 }
1267
1268 template <class dataType>
1270 std::vector<ftm::FTMTree_MT *> &trees,
1271 ftm::MergeTree<dataType> &baryMergeTree,
1272 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>>
1273 &matchings,
1274 std::vector<std::vector<std::pair<std::pair<ftm::idNode, ftm::idNode>,
1275 std::pair<ftm::idNode, ftm::idNode>>>>
1276 &matchings_path,
1277 std::vector<dataType> &distances,
1278 bool useDoubleInput = false,
1279 bool isFirstInput = true) {
1280 for(unsigned int i = 0; i < trees.size(); ++i)
1281#ifdef TTK_ENABLE_OPENMP4
1282#pragma omp task firstprivate(i) UNTIED() \
1283 shared(baryMergeTree, matchings, matchings_path, distances)
1284#endif
1285 computeOneDistance<dataType>(trees[i], baryMergeTree, matchings[i],
1286 matchings_path[i], distances[i],
1287 useDoubleInput, isFirstInput);
1288#ifdef TTK_ENABLE_OPENMP4
1289#pragma omp taskwait
1290#endif
1291 }
1292
1293 // ------------------------------------------------------------------------
1294 // Progressivity
1295 // ------------------------------------------------------------------------
1296 template <class dataType>
1297 unsigned int
1298 persistenceScaling(std::vector<ftm::FTMTree_MT *> &trees,
1299 std::vector<ftm::MergeTree<dataType>> &mergeTrees,
1300 std::vector<ftm::FTMTree_MT *> &oriTrees,
1301 int iterationNumber,
1302 std::vector<std::vector<ftm::idNode>> &deletedNodes) {
1303 deletedNodes.clear();
1304 deletedNodes.resize(oriTrees.size());
1305 unsigned int noTreesUnscaled = 0;
1306
1307 // Scale trees
1308 for(unsigned int i = 0; i < oriTrees.size(); ++i) {
1309 double persistenceThreshold = 50.0;
1310 if(iterationNumber != -1) {
1311 // Get number of pairs in scaled merge tree
1312 int const noPairs = mergeTrees[i].tree.getRealNumberOfNodes();
1313
1314 // Get pairs in original merge tree
1315 std::vector<std::tuple<ftm::idNode, ftm::idNode, dataType>> pairs;
1316 oriTrees[i]->getPersistencePairsFromTree<dataType>(
1317 pairs, branchDecomposition_);
1318
1319 // Compute new persistence threshold
1320 double const multiplier
1321 = (progressiveSpeedDivisor_ < 1e-6
1322 ? 1.
1323 : iterationNumber / progressiveSpeedDivisor_);
1324 int const decrement = multiplier * pairs.size() / 10;
1325 int thresholdIndex = pairs.size() - noPairs - std::max(decrement, 2);
1326 thresholdIndex = std::max(thresholdIndex, 0);
1327 const double persistence = std::get<2>(pairs[thresholdIndex]);
1328 persistenceThreshold
1329 = persistence / std::get<2>(pairs.back()) * 100.0;
1330 if(thresholdIndex == 0) {
1331 persistenceThreshold = 0.;
1332 ++noTreesUnscaled;
1333 }
1334 }
1335 if(persistenceThreshold != 0.) {
1337 = ftm::copyMergeTree<dataType>(oriTrees[i]);
1339 &(mt.tree), persistenceThreshold, deletedNodes[i]);
1340 if(mergeTrees.size() == 0)
1341 mergeTrees.resize(oriTrees.size());
1342 mergeTrees[i] = mt;
1343 trees[i] = &(mt.tree);
1344 } else {
1345 trees[i] = oriTrees[i];
1346 }
1347 }
1348
1349 printTreesStats(trees);
1350
1351 return noTreesUnscaled;
1352 }
1353
1354 template <class dataType>
1356 std::vector<ftm::FTMTree_MT *> &oriTrees,
1357 std::vector<std::vector<ftm::idNode>> &deletedNodes,
1358 std::vector<dataType> &distances) {
1359 for(unsigned int i = 0; i < oriTrees.size(); ++i)
1360 for(auto node : deletedNodes[i])
1361 distances[i] += deleteCost<dataType>(oriTrees[i], node);
1362 }
1363
1364 // ------------------------------------------------------------------------
1365 // Main Functions
1366 // ------------------------------------------------------------------------
1367 template <class dataType>
1369 std::vector<ftm::FTMTree_MT *> &trees,
1370 ftm::MergeTree<dataType> &baryMergeTree,
1371 std::vector<double> &alphas,
1372 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>>
1373 &finalMatchings,
1374 std::vector<std::vector<std::pair<std::pair<ftm::idNode, ftm::idNode>,
1375 std::pair<ftm::idNode, ftm::idNode>>>>
1376 &finalMatchings_path,
1377 bool finalAsgnDoubleInput = false,
1378 bool finalAsgnFirstInput = true) {
1379 Timer t_bary;
1380
1381 ftm::FTMTree_MT *baryTree = &(baryMergeTree.tree);
1382
1383 // Persistence scaling
1384 std::vector<ftm::FTMTree_MT *> oriTrees;
1385 std::vector<ftm::MergeTree<dataType>> scaledMergeTrees;
1386 std::vector<std::vector<ftm::idNode>> deletedNodes;
1388 oriTrees.insert(oriTrees.end(), trees.begin(), trees.end());
1390 trees, scaledMergeTrees, oriTrees, -1, deletedNodes);
1391 std::vector<ftm::idNode> deletedNodesT;
1392 persistenceThresholding<dataType>(baryTree, 50, deletedNodesT);
1393 }
1394 bool treesUnscaled = false;
1395
1396 // Print bary stats
1397 printBaryStats(baryTree);
1398
1399 // Run
1400 bool converged = false;
1401 dataType frechetEnergy = -1;
1402 dataType minFrechet = std::numeric_limits<dataType>::max();
1403 int cptBlocked = 0;
1404 int NoIteration = 0;
1405 std::stringstream energySequence;
1406 int minBarySize = std::numeric_limits<int>::max();
1407 int maxBarySize = 0;
1408 while(not converged
1409 && (iterationLimit_ < 0 || NoIteration < iterationLimit_)) {
1410 ++NoIteration;
1411 if(barycenterMaxIter_ != -1 and NoIteration > barycenterMaxIter_)
1412 break;
1413
1415 std::stringstream ss;
1416 ss << "Iteration " << NoIteration;
1417 printMsg(ss.str());
1418
1419 // --- Assignment
1420 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>>
1421 matchings(trees.size());
1422 std::vector<std::vector<std::pair<std::pair<ftm::idNode, ftm::idNode>,
1423 std::pair<ftm::idNode, ftm::idNode>>>>
1424 matchings_path(trees.size());
1425 std::vector<dataType> distances(trees.size(), -1);
1426 Timer t_assignment;
1428 trees, baryMergeTree, matchings, matchings_path, distances);
1429 Timer t_addDeletedNodes;
1432 oriTrees, deletedNodes, distances);
1433 addDeletedNodesTime_ += t_addDeletedNodes.getElapsedTime();
1434 auto t_assignment_time
1435 = t_assignment.getElapsedTime() - t_addDeletedNodes.getElapsedTime();
1436 printMsg("Assignment", 1, t_assignment_time, this->threadNumber_,
1438
1439 // --- Update
1440 Timer t_update;
1441 if(baseModule_ == 2) {
1443 trees, baryMergeTree, alphas, matchings_path);
1444 } else {
1446 trees, baryMergeTree, alphas, matchings);
1447 }
1448 auto t_update_time = t_update.getElapsedTime();
1449 baryTree = &(baryMergeTree.tree);
1450 printMsg("Update", 1, t_update_time, this->threadNumber_,
1452
1453 // --- Check convergence
1454 dataType currentFrechetEnergy = 0;
1455 dataType currentFrechetEnergy2 = 0;
1456 for(unsigned int i = 0; i < trees.size(); ++i) {
1457 currentFrechetEnergy2 += alphas[i] * distances[i];
1458 currentFrechetEnergy += alphas[i] * distances[i] * distances[i];
1459 }
1460 auto frechetDiff
1461 = std::abs((double)(frechetEnergy - currentFrechetEnergy));
1462 converged = (frechetDiff <= tol_);
1463 converged = converged and (not progressiveBarycenter_ or treesUnscaled);
1464 frechetEnergy = currentFrechetEnergy;
1465 tol_ = frechetEnergy / 125.0;
1466 energySequence << currentFrechetEnergy << std::endl;
1467
1468 std::stringstream ss4, ss5;
1469 auto barycenterTime = t_bary.getElapsedTime() - addDeletedNodesTime_;
1470 printMsg("Total", 1, barycenterTime, this->threadNumber_,
1473 ss4 << "Frechet energy : " << frechetEnergy;
1474 ss5 << "Frechet energy non-squared: " << currentFrechetEnergy2;
1475 printMsg(ss4.str());
1476 printMsg(ss5.str());
1477
1478 if((int)baryTree->getNumberOfNodes() > maxBarySize)
1479 maxBarySize = baryTree->getNumberOfNodes();
1480 if((int)baryTree->getNumberOfNodes() < minBarySize)
1481 minBarySize = baryTree->getNumberOfNodes();
1482
1483 minFrechet = std::min(minFrechet, frechetEnergy);
1484 if(not converged and (not progressiveBarycenter_ or treesUnscaled)) {
1485 cptBlocked = (minFrechet < frechetEnergy) ? cptBlocked + 1 : 0;
1486 converged = (cptBlocked >= 10);
1487 }
1488 // if(!useEarlyOut_) converged = false;
1489
1490 // --- Persistence scaling
1492 unsigned int const noTreesUnscaled = persistenceScaling<dataType>(
1493 trees, scaledMergeTrees, oriTrees, NoIteration, deletedNodes);
1494 treesUnscaled = (noTreesUnscaled == oriTrees.size());
1495 }
1496 }
1497
1498 // std::ofstream energyFile;
1499 // energyFile.open("/home/wetzels/ttk/energy.txt");
1500 // energyFile << energySequence.str();
1501 // energyFile.close();
1502
1503 // Final processing
1505 printMsg("Final assignment");
1506
1507 std::vector<dataType> distances(trees.size(), -1);
1508 if(baseModule_ == 2) {
1510 trees, baryMergeTree, finalMatchings, finalMatchings_path, distances);
1511 } else {
1512 assignment<dataType>(trees, baryMergeTree, finalMatchings,
1513 finalMatchings_path, distances,
1514 finalAsgnDoubleInput, finalAsgnFirstInput);
1515 }
1516 for(auto dist : distances)
1517 finalDistances_.push_back(dist);
1518 dataType currentFrechetEnergy = 0;
1519 dataType currentFrechetEnergy2 = 0;
1520 for(unsigned int i = 0; i < trees.size(); ++i) {
1521 currentFrechetEnergy2 += alphas[i] * distances[i];
1522 currentFrechetEnergy += alphas[i] * distances[i] * distances[i];
1523 }
1524
1525 auto barycenterTime = t_bary.getElapsedTime() - addDeletedNodesTime_;
1526 std::stringstream ss, ss2;
1527 ss << "Frechet energy : " << currentFrechetEnergy;
1528 ss2 << "Frechet energy non-squared: " << currentFrechetEnergy2;
1529 printMsg(ss.str());
1530 printMsg(ss2.str());
1531 printMsg("Total", 1, barycenterTime, this->threadNumber_,
1533 // std::cout << "Bary Distance Time = " << allDistanceTime_ << std::endl;
1534
1535 std::stringstream ssIt;
1536 ssIt << "Number of iterations: " << NoIteration;
1538 std::stringstream ssMin;
1539 ssMin << "Min barycenter bize: " << minBarySize;
1541 std::stringstream ssMax;
1542 ssMax << "Max barycenter bize: " << maxBarySize;
1544
1545 if(trees.size() == 2 and not isCalled_ && baseModule_ != 2)
1547 trees, baryMergeTree, finalMatchings, distances);
1548
1549 // Persistence (un)scaling
1551 scaledMergeTrees.clear();
1552 trees.clear();
1553 trees.insert(trees.end(), oriTrees.begin(), oriTrees.end());
1554 }
1555 }
1556
1557 template <class dataType>
1559 std::vector<ftm::MergeTree<dataType>> &trees,
1560 std::vector<double> &alphas,
1561 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>>
1562 &finalMatchings,
1563 std::vector<std::vector<std::pair<std::pair<ftm::idNode, ftm::idNode>,
1564 std::pair<ftm::idNode, ftm::idNode>>>>
1565 &finalMatchings_path,
1566 ftm::MergeTree<dataType> &baryMergeTree,
1567 bool finalAsgnDoubleInput = false,
1568 bool finalAsgnFirstInput = true) {
1569 // --- Preprocessing
1570 if(preprocess_) {
1571 treesNodeCorr_.resize(trees.size());
1572 for(unsigned int i = 0; i < trees.size(); ++i) {
1576 true, baseModule_ == 2);
1577 }
1578 printTreesStats(trees);
1579 }
1580
1581 // --- Init barycenter
1582 std::vector<ftm::FTMTree_MT *> treesT;
1583 ftm::mergeTreeToFTMTree<dataType>(trees, treesT);
1584 initBarycenterTree<dataType>(treesT, baryMergeTree);
1585
1586 // --- Execute
1587 computeBarycenter<dataType>(treesT, baryMergeTree, alphas, finalMatchings,
1588 finalMatchings_path, finalAsgnDoubleInput,
1589 finalAsgnFirstInput);
1590
1591 if(baseModule_ == 2) {
1592 ftm::FTMTree_MT *baryTree = &(baryMergeTree.tree);
1593 for(ftm::idNode node = 0; node < baryTree->getNumberOfNodes(); node++) {
1594 baryTree->getNode(node)->setOrigin(-1);
1595 }
1596 preprocessTree<dataType>(baryTree, false);
1597 }
1598
1599 // --- Postprocessing
1600 if(postprocess_) {
1601 std::vector<int> const allRealNodes(trees.size());
1602 for(unsigned int i = 0; i < trees.size(); ++i) {
1604 }
1605
1606 // fixMergedRootOriginBarycenter<dataType>(baryMergeTree);
1607 postprocessingPipeline<dataType>(&(baryMergeTree.tree));
1608 for(unsigned int i = 0; i < trees.size(); ++i) {
1610 &(baryMergeTree.tree), treesT[i], finalMatchings[i]);
1611 }
1612 }
1613 }
1614
1615 template <class dataType>
1617 std::vector<ftm::MergeTree<dataType>> &trees,
1618 std::vector<double> &alphas,
1619 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>>
1620 &finalMatchings,
1621 ftm::MergeTree<dataType> &baryMergeTree,
1622 bool finalAsgnDoubleInput = false,
1623 bool finalAsgnFirstInput = true) {
1624
1625 std::vector<std::vector<std::pair<std::pair<ftm::idNode, ftm::idNode>,
1626 std::pair<ftm::idNode, ftm::idNode>>>>
1627 finalMatchings_path;
1628 execute<dataType>(trees, alphas, finalMatchings, finalMatchings_path,
1629 baryMergeTree, finalAsgnDoubleInput,
1630 finalAsgnFirstInput);
1631 }
1632
1633 template <class dataType>
1635 std::vector<ftm::MergeTree<dataType>> &trees,
1636 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>>
1637 &finalMatchings,
1638 std::vector<std::vector<std::pair<std::pair<ftm::idNode, ftm::idNode>,
1639 std::pair<ftm::idNode, ftm::idNode>>>>
1640 &finalMatchings_path,
1641 ftm::MergeTree<dataType> &baryMergeTree,
1642 bool finalAsgnDoubleInput = false,
1643 bool finalAsgnFirstInput = true) {
1644 std::vector<double> alphas;
1645 if(trees.size() != 2) {
1646 for(unsigned int i = 0; i < trees.size(); ++i)
1647 alphas.push_back(1.0 / trees.size());
1648 } else {
1649 alphas.push_back(alpha_);
1650 alphas.push_back(1 - alpha_);
1651 }
1652
1653 execute<dataType>(trees, alphas, finalMatchings, finalMatchings_path,
1654 baryMergeTree, finalAsgnDoubleInput,
1655 finalAsgnFirstInput);
1656 }
1657
1658 template <class dataType>
1660 std::vector<ftm::MergeTree<dataType>> &trees,
1661 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>>
1662 &finalMatchings,
1663 ftm::MergeTree<dataType> &baryMergeTree,
1664 bool finalAsgnDoubleInput = false,
1665 bool finalAsgnFirstInput = true) {
1666 std::vector<double> alphas;
1667 if(trees.size() != 2) {
1668 for(unsigned int i = 0; i < trees.size(); ++i)
1669 alphas.push_back(1.0 / trees.size());
1670 } else {
1671 alphas.push_back(alpha_);
1672 alphas.push_back(1 - alpha_);
1673 }
1674
1675 std::vector<std::vector<std::pair<std::pair<ftm::idNode, ftm::idNode>,
1676 std::pair<ftm::idNode, ftm::idNode>>>>
1677 finalMatchings_path;
1678
1679 execute<dataType>(trees, alphas, finalMatchings, finalMatchings_path,
1680 baryMergeTree, finalAsgnDoubleInput,
1681 finalAsgnFirstInput);
1682 }
1683
1684 // ------------------------------------------------------------------------
1685 // Preprocessing
1686 // ------------------------------------------------------------------------
1687 template <class dataType>
1689 std::vector<ftm::FTMTree_MT *> &trees,
1690 unsigned int barycenterMaximumNumberOfPairs,
1691 double percent,
1692 bool useBD = true) {
1693 auto metric = getSizeLimitMetric(trees);
1694 unsigned int percentMaxPairs = metric * percent / 100.0;
1695
1696 unsigned int newNoNodes;
1697 if(barycenterMaximumNumberOfPairs > 0 and percent > 0)
1698 newNoNodes = std::min(barycenterMaximumNumberOfPairs, percentMaxPairs);
1699 else if(barycenterMaximumNumberOfPairs > 0)
1700 newNoNodes = barycenterMaximumNumberOfPairs;
1701 else if(percent > 0)
1702 newNoNodes = percentMaxPairs;
1703 else
1704 return;
1705 keepMostImportantPairs<dataType>(&(bary.tree), newNoNodes, useBD);
1706 }
1707
1708 template <class dataType>
1710 std::vector<ftm::FTMTree_MT *> &trees,
1711 double percent,
1712 bool useBD = true) {
1714 bary, trees, barycenterMaximumNumberOfPairs_, percent, useBD);
1715 }
1716
1717 template <class dataType>
1719 std::vector<ftm::FTMTree_MT *> &trees,
1720 bool useBD = true) {
1723 }
1724
1725 // ------------------------------------------------------------------------
1726 // Postprocessing
1727 // ------------------------------------------------------------------------
1728 template <class dataType>
1730 if(not barycenter.tree.isFullMerge())
1731 return;
1732
1733 ftm::FTMTree_MT *tree = &(barycenter.tree);
1734 auto &tup = fixMergedRootOrigin<dataType>(tree);
1735 int maxIndex = std::get<0>(tup);
1736 dataType oldOriginValue = std::get<1>(tup);
1737
1738 // Verify that scalars are consistent
1739 ftm::idNode const treeRoot = tree->getRoot();
1740 std::vector<dataType> newScalarsVector;
1741 ftm::getTreeScalars<dataType>(tree, newScalarsVector);
1742 bool isJT = tree->isJoinTree<dataType>();
1743 if((isJT and tree->getValue<dataType>(maxIndex) > oldOriginValue)
1744 or (not isJT
1745 and tree->getValue<dataType>(maxIndex) < oldOriginValue)) {
1746 newScalarsVector[treeRoot] = newScalarsVector[maxIndex];
1747 newScalarsVector[maxIndex] = oldOriginValue;
1748 } else
1749 newScalarsVector[treeRoot] = oldOriginValue;
1750 setTreeScalars(barycenter, newScalarsVector);
1751 }
1752
1753 // ------------------------------------------------------------------------
1754 // Utils
1755 // ------------------------------------------------------------------------
1757 const debug::Priority &priority
1759 auto noNodesT = baryTree->getNumberOfNodes();
1760 auto noNodes = baryTree->getRealNumberOfNodes();
1761 std::stringstream ss;
1762 ss << "Barycenter number of nodes : " << noNodes << " / " << noNodesT;
1763 printMsg(ss.str(), priority);
1764 }
1765
1766 // ------------------------------------------------------------------------
1767 // Testing
1768 // ------------------------------------------------------------------------
1769 template <class dataType>
1771 std::vector<ftm::FTMTree_MT *> &trees,
1772 ftm::MergeTree<dataType> &baryMergeTree,
1773 std::vector<std::vector<std::tuple<ftm::idNode, ftm::idNode, double>>>
1774 &finalMatchings,
1775 std::vector<dataType> distances) {
1776 std::vector<std::tuple<ftm::idNode, ftm::idNode, double>> matching;
1777 std::vector<std::pair<std::pair<ftm::idNode, ftm::idNode>,
1778 std::pair<ftm::idNode, ftm::idNode>>>
1779 matching_path;
1780 dataType distance;
1781 computeOneDistance(trees[0], trees[1], matching, matching_path, distance);
1782 if(distance != (distances[0] + distances[1])) {
1783 std::stringstream ss, ss2, ss3, ss4;
1784 ss << "distance T1 T2 : " << distance;
1785 printMsg(ss.str());
1786 ss2 << "distance T1 T' T2 : " << distances[0] + distances[1];
1787 printMsg(ss2.str());
1788 ss3 << "distance T1 T' : " << distances[0];
1789 printMsg(ss3.str());
1790 ss4 << "distance T' T2 : " << distances[1];
1791 printMsg(ss4.str());
1792 }
1793 return;
1794
1795 auto baryTree = &(baryMergeTree.tree);
1796 std::vector<std::vector<ftm::idNode>> baryMatched(
1797 baryTree->getNumberOfNodes(),
1798 std::vector<ftm::idNode>(
1799 trees.size(), std::numeric_limits<ftm::idNode>::max()));
1800 for(unsigned int i = 0; i < finalMatchings.size(); ++i)
1801 for(auto &match : finalMatchings[i])
1802 baryMatched[std::get<0>(match)][i] = std::get<1>(match);
1803
1804 std::queue<ftm::idNode> queue;
1805 queue.emplace(baryTree->getRoot());
1806 while(!queue.empty()) {
1807 auto node = queue.front();
1808 queue.pop();
1809 std::vector<dataType> costs(trees.size());
1810 for(unsigned int i = 0; i < trees.size(); ++i)
1811 if(baryMatched[node][i] != std::numeric_limits<ftm::idNode>::max())
1812 costs[i] = relabelCost<dataType>(
1813 baryTree, node, trees[i], baryMatched[node][i]);
1814 else
1815 costs[i] = deleteCost<dataType>(baryTree, node);
1816 dataType cost = 0;
1817 if(baryMatched[node][0] != std::numeric_limits<ftm::idNode>::max()
1818 and baryMatched[node][1] != std::numeric_limits<ftm::idNode>::max())
1819 cost = relabelCost<dataType>(
1820 trees[0], baryMatched[node][0], trees[1], baryMatched[node][1]);
1821 else if(baryMatched[node][0] == std::numeric_limits<ftm::idNode>::max())
1822 cost = deleteCost<dataType>(trees[1], baryMatched[node][1]);
1823 else if(baryMatched[node][1] == std::numeric_limits<ftm::idNode>::max())
1824 cost = deleteCost<dataType>(trees[0], baryMatched[node][0]);
1825 else
1826 printErr("problem");
1827 costs[0] = std::sqrt(costs[0]);
1828 costs[1] = std::sqrt(costs[1]);
1829 cost = std::sqrt(cost);
1830 if(std::abs((double)(costs[0] - costs[1])) > 1e-7) {
1832 std::stringstream ss, ss2, ss3, ss4;
1833 ss << "cost T' T0 : " << costs[0];
1834 printMsg(ss.str());
1835 ss2 << "cost T' T1 : " << costs[1];
1836 printMsg(ss2.str());
1837 ss3 << "cost T0 T1 : " << cost;
1838 printMsg(ss2.str());
1839 ss4 << "cost T0 T' T1 : " << costs[0] + costs[1];
1840 printMsg(ss4.str());
1841 if(std::abs((double)((costs[0] + costs[1]) - cost)) > 1e-7) {
1842 std::stringstream ss5;
1843 ss5 << "diff : "
1844 << std::abs((double)((costs[0] + costs[1]) - cost));
1845 printMsg(ss5.str());
1846 }
1847 std::stringstream ss6;
1848 ss6 << "diff2 : " << std::abs((double)(costs[0] - costs[1]));
1849 printMsg(ss.str());
1850 // baryTree->printNode2<dataType>(node);
1851 // baryTree->printNode2<dataType>(baryTree->getParentSafe(node));
1852 for(unsigned int i = 0; i < 2; ++i)
1853 if(baryMatched[node][i]
1854 != std::numeric_limits<ftm::idNode>::max()) {
1855 printMsg(
1856 trees[i]->printNode2<dataType>(baryMatched[node][i]).str());
1857 printMsg(trees[i]
1858 ->printNode2<dataType>(
1859 trees[i]->getParentSafe(baryMatched[node][i]))
1860 .str());
1861 }
1862 }
1863 std::vector<ftm::idNode> children;
1864 baryTree->getChildren(node, children);
1865 for(auto child : children)
1866 queue.emplace(child);
1867 }
1868 }
1869
1870 }; // MergeTreeBarycenter class
1871
1872} // namespace ttk
#define UNTIED()
TTK processing package that efficiently computes the contour tree of scalar data and more (data segme...
virtual int setThreadNumber(const int threadNumber)
Definition BaseClass.h:80
int debugLevel_
Definition Debug.h:379
int printWrn(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:159
void setDebugMsgPrefix(const std::string &prefix)
Definition Debug.h:364
virtual int setDebugLevel(const int &debugLevel)
Definition Debug.cpp:147
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:149
int getBestInitTreeIndex(std::vector< ftm::FTMTree_MT * > &trees, std::vector< ftm::FTMTree_MT * > &trees2, unsigned int barycenterMaximumNumberOfPairs, double sizeLimitPercent, bool distMinimizer=true)
void limitSizeBarycenter(ftm::MergeTree< dataType > &bary, std::vector< ftm::FTMTree_MT * > &trees, unsigned int barycenterMaximumNumberOfPairs, double percent, bool useBD=true)
std::tuple< dataType, dataType > getParametrizedBirthDeath(ftm::FTMTree_MT *tree1, ftm::idNode nodeId1)
void getParametrizedDistanceMatrix(std::vector< ftm::FTMTree_MT * > &trees, std::vector< std::vector< double > > &distanceMatrix, unsigned int barycenterMaximumNumberOfPairs, double sizeLimitPercent, bool useDoubleInput=false, bool isFirstInput=true)
void setUseMedianBarycenter(bool useMedian)
void verifyBarycenterTwoTrees(std::vector< ftm::FTMTree_MT * > &trees, ftm::MergeTree< dataType > &baryMergeTree, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &finalMatchings, std::vector< dataType > distances)
void computeOneDistance(ftm::FTMTree_MT *tree, ftm::FTMTree_MT *baryTree, std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > &matching, dataType &distance, bool useDoubleInput=false, bool isFirstInput=true)
void updateNodesAndScalars(ftm::MergeTree< dataType > &mTree1, int noTrees, std::vector< std::tuple< ftm::idNode, ftm::idNode, int > > &nodesToProcess, std::vector< dataType > &newScalarsVector, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode > > > &nodesProcessed)
unsigned int persistenceScaling(std::vector< ftm::FTMTree_MT * > &trees, std::vector< ftm::MergeTree< dataType > > &mergeTrees, std::vector< ftm::FTMTree_MT * > &oriTrees, int iterationNumber, std::vector< std::vector< ftm::idNode > > &deletedNodes)
void fixMergedRootOriginBarycenter(ftm::MergeTree< dataType > &barycenter)
void setAddNodes(bool addNodesT)
void setBarycenterMaxIter(int barycenterMaxIter)
void setPreprocess(bool preproc)
void computeOneDistance(ftm::MergeTree< dataType > &baryMergeTree, ftm::MergeTree< dataType > &baryMergeTree2, std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > &matching, dataType &distance, bool useDoubleInput=false, bool isFirstInput=true)
void getDistanceMatrix(std::vector< ftm::FTMTree_MT * > &trees, std::vector< ftm::FTMTree_MT * > &trees2, std::vector< std::vector< double > > &distanceMatrix, bool useDoubleInput=false, bool isFirstInput=true)
void computeOneDistance(ftm::MergeTree< dataType > &baryMergeTree, ftm::MergeTree< dataType > &baryMergeTree2, std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > &matching, std::vector< std::pair< std::pair< ftm::idNode, ftm::idNode >, std::pair< ftm::idNode, ftm::idNode > > > &matching_path, dataType &distance, bool useDoubleInput=false, bool isFirstInput=true)
void limitSizeBarycenter(ftm::MergeTree< dataType > &bary, std::vector< ftm::FTMTree_MT * > &trees, double percent, bool useBD=true)
std::tuple< dataType, dataType > interpolation(ftm::MergeTree< dataType > &baryMergeTree, ftm::idNode nodeId, std::vector< dataType > &newScalarsVector, std::vector< ftm::FTMTree_MT * > &trees, std::vector< ftm::idNode > &nodes, std::vector< double > &alphas)
int getBestInitTreeIndex(std::vector< ftm::FTMTree_MT * > &trees, bool distMinimizer=true)
void setPostprocess(bool postproc)
std::tuple< dataType, dataType > interpolationAdded(ftm::FTMTree_MT *tree, ftm::idNode nodeId, double alpha, ftm::MergeTree< dataType > &baryMergeTree, ftm::idNode nodeB, std::vector< dataType > &newScalarsVector)
unsigned int barycenterMaximumNumberOfPairs_
void execute(std::vector< ftm::MergeTree< dataType > > &trees, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &finalMatchings, std::vector< std::vector< std::pair< std::pair< ftm::idNode, ftm::idNode >, std::pair< ftm::idNode, ftm::idNode > > > > &finalMatchings_path, ftm::MergeTree< dataType > &baryMergeTree, bool finalAsgnDoubleInput=false, bool finalAsgnFirstInput=true)
void setBarycenterInitIndex(int barycenterInitIndex)
void assignmentPara(std::vector< ftm::FTMTree_MT * > &trees, ftm::MergeTree< dataType > &baryMergeTree, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &matchings, std::vector< std::vector< std::pair< std::pair< ftm::idNode, ftm::idNode >, std::pair< ftm::idNode, ftm::idNode > > > > &matchings_path, std::vector< dataType > &distances, bool useDoubleInput=false, bool isFirstInput=true)
ftm::idNode getNodesAndScalarsToAdd(ftm::idNode nodeId1, ftm::FTMTree_MT *tree, ftm::idNode nodeId2, std::vector< dataType > &newScalarsVector, std::vector< std::tuple< ftm::idNode, ftm::idNode, int > > &nodesToProcess, ftm::idNode nodeCpt, int i)
Get information about the nodes to add in the barycenter.
void setDeterministic(bool deterministicT)
void assignmentTask(std::vector< ftm::FTMTree_MT * > &trees, ftm::MergeTree< dataType > &baryMergeTree, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &matchings, std::vector< std::vector< std::pair< std::pair< ftm::idNode, ftm::idNode >, std::pair< ftm::idNode, ftm::idNode > > > > &matchings_path, std::vector< dataType > &distances, bool useDoubleInput=false, bool isFirstInput=true)
~MergeTreeBarycenter() override=default
void updateBarycenterTreeScalars(std::vector< ftm::FTMTree_MT * > &trees, ftm::MergeTree< dataType > &baryMergeTree, std::vector< double > &alphas, unsigned int indexAddedNodes, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &matchings)
void addNodes(ftm::MergeTree< dataType > &mTree1, int noTrees, std::vector< std::tuple< ftm::idNode, ftm::idNode, int > > &nodesToProcess, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode > > > &nodesProcessed)
void initBarycenterTree(std::vector< ftm::FTMTree_MT * > &trees, ftm::MergeTree< dataType > &baryTree, bool distMinimizer=true)
void computeBarycenter(std::vector< ftm::FTMTree_MT * > &trees, ftm::MergeTree< dataType > &baryMergeTree, std::vector< double > &alphas, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &finalMatchings, std::vector< std::vector< std::pair< std::pair< ftm::idNode, ftm::idNode >, std::pair< ftm::idNode, ftm::idNode > > > > &finalMatchings_path, bool finalAsgnDoubleInput=false, bool finalAsgnFirstInput=true)
void computeOneDistance(ftm::FTMTree_MT *tree, ftm::FTMTree_MT *baryTree, std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > &matching, std::vector< std::pair< std::pair< ftm::idNode, ftm::idNode >, std::pair< ftm::idNode, ftm::idNode > > > &matching_path, dataType &distance, bool useDoubleInput=false, bool isFirstInput=true)
void computeOneDistance(ftm::FTMTree_MT *tree, ftm::MergeTree< dataType > &baryMergeTree, std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > &matching, std::vector< std::pair< std::pair< ftm::idNode, ftm::idNode >, std::pair< ftm::idNode, ftm::idNode > > > &matching_path, dataType &distance, bool useDoubleInput=false, bool isFirstInput=true)
void execute(std::vector< ftm::MergeTree< dataType > > &trees, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &finalMatchings, ftm::MergeTree< dataType > &baryMergeTree, bool finalAsgnDoubleInput=false, bool finalAsgnFirstInput=true)
void setProgressiveSpeedDivisor(double progSpeed)
void addScaledDeletedNodesCost(std::vector< ftm::FTMTree_MT * > &oriTrees, std::vector< std::vector< ftm::idNode > > &deletedNodes, std::vector< dataType > &distances)
void updateBarycenterTreeStructure(std::vector< ftm::FTMTree_MT * > &trees, ftm::MergeTree< dataType > &baryMergeTree, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &matchings)
void setUseFixedInit(bool useFixedInit)
std::vector< double > finalDistances_
void execute(std::vector< ftm::MergeTree< dataType > > &trees, std::vector< double > &alphas, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &finalMatchings, std::vector< std::vector< std::pair< std::pair< ftm::idNode, ftm::idNode >, std::pair< ftm::idNode, ftm::idNode > > > > &finalMatchings_path, ftm::MergeTree< dataType > &baryMergeTree, bool finalAsgnDoubleInput=false, bool finalAsgnFirstInput=true)
void getSizeLimitedTrees(std::vector< ftm::FTMTree_MT * > &trees, unsigned int barycenterMaximumNumberOfPairs, double sizeLimitPercent, std::vector< ftm::MergeTree< dataType > > &mTreesLimited)
void printBaryStats(ftm::FTMTree_MT *baryTree, const debug::Priority &priority=debug::Priority::INFO)
void setProgressiveBarycenter(bool progressive)
void updateBarycenterTree_path(std::vector< ftm::FTMTree_MT * > &trees, ftm::MergeTree< dataType > &baryMergeTree, std::vector< double > &alphas, std::vector< std::vector< std::pair< std::pair< ftm::idNode, ftm::idNode >, std::pair< ftm::idNode, ftm::idNode > > > > &matchings)
void limitSizeBarycenter(ftm::MergeTree< dataType > &bary, std::vector< ftm::FTMTree_MT * > &trees, bool useBD=true)
void setBarycenterMaximumNumberOfPairs(unsigned int maxi)
void computeOneDistance(ftm::FTMTree_MT *tree, ftm::MergeTree< dataType > &baryMergeTree, std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > &matching, dataType &distance, bool useDoubleInput=false, bool isFirstInput=true)
void setBarycenterSizeLimitPercent(double percent)
void getSizeLimitedDistanceMatrix(std::vector< ftm::FTMTree_MT * > &trees, std::vector< std::vector< double > > &distanceMatrix, unsigned int barycenterMaximumNumberOfPairs, double sizeLimitPercent, bool useDoubleInput=false, bool isFirstInput=true)
void updateBarycenterTree(std::vector< ftm::FTMTree_MT * > &trees, ftm::MergeTree< dataType > &baryMergeTree, std::vector< double > &alphas, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &matchings)
std::vector< double > getFinalDistances()
void setFixedInitNumber(int fixedInitNumber)
void getDistanceMatrix(std::vector< ftm::FTMTree_MT * > &trees, std::vector< std::vector< double > > &distanceMatrix, bool useDoubleInput=false, bool isFirstInput=true)
int getBestInitTreeIndex(std::vector< ftm::FTMTree_MT * > &trees, std::vector< ftm::FTMTree_MT * > &trees2, double sizeLimitPercent, bool distMinimizer=true)
void execute(std::vector< ftm::MergeTree< dataType > > &trees, std::vector< double > &alphas, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &finalMatchings, ftm::MergeTree< dataType > &baryMergeTree, bool finalAsgnDoubleInput=false, bool finalAsgnFirstInput=true)
void assignment(std::vector< ftm::FTMTree_MT * > &trees, ftm::MergeTree< dataType > &baryMergeTree, std::vector< std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > > &matchings, std::vector< std::vector< std::pair< std::pair< ftm::idNode, ftm::idNode >, std::pair< ftm::idNode, ftm::idNode > > > > &matchings_path, std::vector< dataType > &distances, bool useDoubleInput=false, bool isFirstInput=true)
void setBranchDecomposition(bool useBD)
void setNormalizedWasserstein(bool normalizedWasserstein)
void setDistanceSquaredRoot(bool distanceSquaredRoot)
void setAssignmentSolver(int assignmentSolver)
dataType deleteCost(const ftm::FTMTree_MT *tree, ftm::idNode nodeId)
void keepMostImportantPairs(ftm::FTMTree_MT *tree, int n, bool useBD)
void setNodePerTask(int npt)
void convertBranchDecompositionMatching(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2, std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > &outputMatching)
dataType relabelCost(const ftm::FTMTree_MT *tree1, ftm::idNode nodeId1, const ftm::FTMTree_MT *tree2, ftm::idNode nodeId2)
double mixDistances(dataType distance1, dataType distance2)
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, 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 printMatching(std::vector< MatchingType > &matchings)
std::vector< std::vector< int > > treesNodeCorr_
void preprocessTree(ftm::FTMTree_MT *tree, bool deleteInconsistentNodes=true)
void setKeepSubtree(bool keepSubtree)
void persistenceThresholding(ftm::FTMTree_MT *tree, double persistenceThresholdT, std::vector< ftm::idNode > &deletedNodes)
double mixDistancesMinMaxPairWeight(bool isFirstInput)
std::tuple< int, dataType > fixMergedRootOrigin(ftm::FTMTree_MT *tree)
void setPreprocess(bool preproc)
void setPostprocess(bool postproc)
void setMinMaxPairWeight(double weight)
dataType computeDistance(const ftm::FTMTree_MT *tree1, const ftm::FTMTree_MT *tree2, std::vector< std::tuple< ftm::idNode, ftm::idNode, double > > &outputMatching)
void setAssignmentSolver(int assignmentSolver)
dataType computeDistance(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2, std::vector< std::pair< std::pair< ftm::idNode, ftm::idNode >, std::pair< ftm::idNode, ftm::idNode > > > *outputMatching)
double getElapsedTime()
Definition Timer.h:15
Node * getNode(idNode nodeId) const
Definition FTMTree_MT.h:393
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
void setParent(idNode nodeId, idNode newParentNodeId)
void copyMergeTreeStructure(const FTMTree_MT *tree)
idNode getRoot() const
idNode getParentSafe(idNode nodeId) const
int getRealNumberOfNodes() const
void deleteNode(idNode nodeId)
std::tuple< dataType, dataType > getBirthDeath(idNode nodeId) const
bool isNodeIdInconsistent(idNode nodeId) const
idNode makeNode(SimplexId vertexId, SimplexId linked=nullVertex)
bool isNodeAlone(idNode nodeId) const
void deleteParent(idNode nodeId)
bool isFullMerge() const
void setOrigin(SimplexId linked)
Definition FTMNode.h:72
SimplexId getOrigin() const
Definition FTMNode.h:64
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)
MergeTree< dataType > copyMergeTree(const ftm::FTMTree_MT *tree, bool doSplitMultiPersPairs=false)
void mergeTreeToFTMTree(std::vector< MergeTree< dataType > > &trees, std::vector< ftm::FTMTree_MT * > &treesT)
MergeTree< dataType > createEmptyMergeTree(int scalarSize)
unsigned int idNode
Node index in vect_nodes_.
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)
dataType getMinMaxLocalFromVector(ftm::FTMTree_MT *tree, ftm::idNode nodeId, std::vector< dataType > &scalarsVector, bool getMin=true)
T end(std::pair< T, T > &p)
Definition ripser.cpp:503
T begin(std::pair< T, T > &p)
Definition ripser.cpp:499
ftm::FTMTree_MT tree
Definition FTMTree_MT.h:906
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/| (_) |"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)