From 60e52a8be8d40170bdc07cf911599cf55ccb4f64 Mon Sep 17 00:00:00 2001 From: floWetzels Date: Wed, 2 Nov 2022 13:05:48 +0100 Subject: [PATCH 01/72] Started working on Clustering integration of bdi-ed. Not working yet. --- .../mergeTreeClustering/PathMappingDistance.h | 39 +++++++- .../ttkMergeTreeClustering.cpp | 93 +++++++++++++------ paraview/xmls/MergeTreeClustering.xml | 4 + 3 files changed, 105 insertions(+), 31 deletions(-) diff --git a/core/base/mergeTreeClustering/PathMappingDistance.h b/core/base/mergeTreeClustering/PathMappingDistance.h index cae9a10642..e42cd93661 100644 --- a/core/base/mergeTreeClustering/PathMappingDistance.h +++ b/core/base/mergeTreeClustering/PathMappingDistance.h @@ -84,7 +84,7 @@ namespace ttk { std::vector> &predecessors2, int depth1, int depth2, - dataType *memT, + std::vector &memT, std::vector, std::pair>> &mapping) { @@ -111,6 +111,10 @@ namespace ttk { and tree2->getNumberOfChildren(curr2) == 0) { mapping.emplace_back(std::make_pair( std::make_pair(curr1, parent1), std::make_pair(curr2, parent2))); + tree1->getNode(curr1)->setOrigin(parent1); + tree1->getNode(parent1)->setOrigin(curr1); + tree1->getNode(curr2)->setOrigin(parent2); + tree1->getNode(parent2)->setOrigin(curr2); return; } //--------------------------------------------------------------------------- @@ -178,6 +182,10 @@ namespace ttk { curr1, parent1, curr2, parent2, tree1, tree2)) { mapping.emplace_back(std::make_pair( std::make_pair(curr1, parent1), std::make_pair(curr2, parent2))); + tree1->getNode(curr1)->setOrigin(parent1); + tree1->getNode(parent1)->setOrigin(curr1); + tree1->getNode(curr2)->setOrigin(parent2); + tree1->getNode(parent2)->setOrigin(curr2); traceMapping_path(tree1, tree2, child11, 1, child21, 1, predecessors1, predecessors2, depth1, depth2, memT, mapping); @@ -192,6 +200,10 @@ namespace ttk { curr1, parent1, curr2, parent2, tree1, tree2)) { mapping.emplace_back(std::make_pair( std::make_pair(curr1, parent1), std::make_pair(curr2, parent2))); + tree1->getNode(curr1)->setOrigin(parent1); + tree1->getNode(parent1)->setOrigin(curr1); + tree1->getNode(curr2)->setOrigin(parent2); + tree1->getNode(parent2)->setOrigin(curr2); traceMapping_path(tree1, tree2, child11, 1, child22, 1, predecessors1, predecessors2, depth1, depth2, memT, mapping); @@ -250,6 +262,10 @@ namespace ttk { if(memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4] == d_) { mapping.emplace_back(std::make_pair( std::make_pair(curr1, parent1), std::make_pair(curr2, parent2))); + tree1->getNode(curr1)->setOrigin(parent1); + tree1->getNode(parent1)->setOrigin(curr1); + tree1->getNode(curr2)->setOrigin(parent2); + tree1->getNode(parent2)->setOrigin(curr2); for(auto m : matching) { int n1 = std::get<0>(m) < tree1->getNumberOfChildren(curr1) ? children1[std::get<0>(m)] @@ -332,7 +348,7 @@ namespace ttk { } template - dataType editDistance_path(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2) { + dataType editDistance_path(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2, std::vector> *outputMatching=nullptr) { // initialize memoization tables @@ -357,6 +373,8 @@ namespace ttk { std::vector children; tree1->getChildren(nIdx, children); for(int cIdx : children) { + tree1->getNode(nIdx)->setOrigin(cIdx); + tree1->getNode(cIdx)->setOrigin(nIdx); stack.push(cIdx); predecessors1[cIdx].reserve(predecessors1[nIdx].size() + 1); predecessors1[cIdx].insert(predecessors1[cIdx].end(), @@ -377,6 +395,8 @@ namespace ttk { tree2->getChildren(nIdx, children); for(int cIdx : children) { stack.push(cIdx); + tree2->getNode(nIdx)->setOrigin(cIdx); + tree2->getNode(cIdx)->setOrigin(nIdx); predecessors2[cIdx].reserve(predecessors2[nIdx].size() + 1); predecessors2[cIdx].insert(predecessors2[cIdx].end(), predecessors2[nIdx].begin(), @@ -621,6 +641,21 @@ namespace ttk { dataType res = memT[children1[0] + 1 * dim2 + children2[0] * dim3 + 1 * dim4]; + if(computeMapping_ && outputMatching){ + + std::vector matchedNodes(tree1->getNumberOfNodes(),-1); + std::vector,std::pair>> mapping; + traceMapping_path(tree1,tree2,children1[0],1,children2[0],1,predecessors1,predecessors2,depth1,depth2,memT,mapping); + for(auto m : mapping){ + matchedNodes[m.first.first] = m.second.first; + matchedNodes[m.first.second] = m.second.second; + } + for(ftm::idNode i=0; i=0) outputMatching->emplace_back(std::make_tuple(i,matchedNodes[i], 0.0)); + } + + } + return squared_ ? std::sqrt(res) : res; } }; diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index 81d5ec2e3d..5652c70f73 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include // For port information #include // for new macro @@ -130,9 +132,9 @@ int ttkMergeTreeClustering::RequestData(vtkInformation *ttkNotUsed(request), } // filter out new backends (not yet supported) - if(baseModule != 0) { + if(baseModule != 0 && ComputeBarycenter) { printErr("Invalid Backend chosen. Path Mapping Distance and Branch Mapping " - "Distance not yet supported. Canceling computation."); + "Distance not yet supported for Barycenter computation. Canceling computation."); return 1; } @@ -240,33 +242,66 @@ int ttkMergeTreeClustering::runCompute( // Call base if(not ComputeBarycenter) { - MergeTreeDistance mergeTreeDistance; - mergeTreeDistance.setAssignmentSolver(AssignmentSolver); - mergeTreeDistance.setEpsilonTree1(EpsilonTree1); - mergeTreeDistance.setEpsilonTree2(EpsilonTree2); - mergeTreeDistance.setEpsilon2Tree1(Epsilon2Tree1); - mergeTreeDistance.setEpsilon2Tree2(Epsilon2Tree2); - mergeTreeDistance.setEpsilon3Tree1(Epsilon3Tree1); - mergeTreeDistance.setEpsilon3Tree2(Epsilon3Tree2); - mergeTreeDistance.setProgressiveComputation(ProgressiveComputation); - mergeTreeDistance.setBranchDecomposition(BranchDecomposition); - mergeTreeDistance.setPersistenceThreshold(PersistenceThreshold); - mergeTreeDistance.setNormalizedWasserstein(NormalizedWasserstein); - mergeTreeDistance.setNormalizedWassersteinReg(NormalizedWassersteinReg); - mergeTreeDistance.setRescaledWasserstein(RescaledWasserstein); - mergeTreeDistance.setKeepSubtree(KeepSubtree); - mergeTreeDistance.setUseMinMaxPair(UseMinMaxPair); - mergeTreeDistance.setCleanTree(true); - mergeTreeDistance.setPostprocess(OutputTrees); - mergeTreeDistance.setDeleteMultiPersPairs(DeleteMultiPersPairs); - mergeTreeDistance.setEpsilon1UseFarthestSaddle(Epsilon1UseFarthestSaddle); - mergeTreeDistance.setThreadNumber(this->threadNumber_); - mergeTreeDistance.setDebugLevel(this->debugLevel_); - - distance = mergeTreeDistance.execute( - intermediateMTrees[0], intermediateMTrees[1], outputMatching); - trees1NodeCorrMesh = mergeTreeDistance.getTreesNodeCorr(); - finalDistances = std::vector{distance}; + if(baseModule==0){ + MergeTreeDistance mergeTreeDistance; + mergeTreeDistance.setAssignmentSolver(AssignmentSolver); + mergeTreeDistance.setEpsilonTree1(EpsilonTree1); + mergeTreeDistance.setEpsilonTree2(EpsilonTree2); + mergeTreeDistance.setEpsilon2Tree1(Epsilon2Tree1); + mergeTreeDistance.setEpsilon2Tree2(Epsilon2Tree2); + mergeTreeDistance.setEpsilon3Tree1(Epsilon3Tree1); + mergeTreeDistance.setEpsilon3Tree2(Epsilon3Tree2); + mergeTreeDistance.setProgressiveComputation(ProgressiveComputation); + mergeTreeDistance.setBranchDecomposition(BranchDecomposition); + mergeTreeDistance.setPersistenceThreshold(PersistenceThreshold); + mergeTreeDistance.setNormalizedWasserstein(NormalizedWasserstein); + mergeTreeDistance.setNormalizedWassersteinReg(NormalizedWassersteinReg); + mergeTreeDistance.setRescaledWasserstein(RescaledWasserstein); + mergeTreeDistance.setKeepSubtree(KeepSubtree); + mergeTreeDistance.setUseMinMaxPair(UseMinMaxPair); + mergeTreeDistance.setCleanTree(true); + mergeTreeDistance.setPostprocess(OutputTrees); + mergeTreeDistance.setDeleteMultiPersPairs(DeleteMultiPersPairs); + mergeTreeDistance.setEpsilon1UseFarthestSaddle(Epsilon1UseFarthestSaddle); + mergeTreeDistance.setThreadNumber(this->threadNumber_); + mergeTreeDistance.setDebugLevel(this->debugLevel_); + + distance = mergeTreeDistance.execute( + intermediateMTrees[0], intermediateMTrees[1], outputMatching); + trees1NodeCorrMesh = mergeTreeDistance.getTreesNodeCorr(); + finalDistances = std::vector{distance}; + } + else if(baseModule==1){ + + BranchMappingDistance branchDist; + branchDist.setBaseMetric(branchMetric); + branchDist.setAssignmentSolver(AssignmentSolver); + branchDist.setSquared(false); + distance = branchDist.editDistance_branch(intermediateTrees[0], intermediateTrees[1]); + + std::vector nodeCorr1(intermediateTrees[0]->getNumberOfNodes()); + std::vector nodeCorr2(intermediateTrees[1]->getNumberOfNodes()); + for(ttk::SimplexId i=0; i>{nodeCorr1,nodeCorr2}; + finalDistances = std::vector{distance}; + } + else{ + + PathMappingDistance pathDist; + pathDist.setBaseMetric(pathMetric); + pathDist.setAssignmentSolver(AssignmentSolver); + pathDist.setSquared(false); + pathDist.setComputeMapping(true); + distance = pathDist.editDistance_path(intermediateTrees[0], intermediateTrees[1], &outputMatching); + + std::vector nodeCorr1(intermediateTrees[0]->getNumberOfNodes()); + std::vector nodeCorr2(intermediateTrees[1]->getNumberOfNodes()); + for(ttk::SimplexId i=0; i>{nodeCorr1,nodeCorr2}; + finalDistances = std::vector{distance}; + } } else { if(NumberOfBarycenters == 1) { // and numInputs2==0){ MergeTreeBarycenter mergeTreeBarycenter; diff --git a/paraview/xmls/MergeTreeClustering.xml b/paraview/xmls/MergeTreeClustering.xml index 016b1901de..5a02d4846d 100644 --- a/paraview/xmls/MergeTreeClustering.xml +++ b/paraview/xmls/MergeTreeClustering.xml @@ -123,6 +123,10 @@ Online examples: mode="visibility" property="Backend" value="0" /> + From 5719031a2e8c14b89d24fe66cd2ade78aa043106 Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Wed, 9 Nov 2022 16:22:46 +0100 Subject: [PATCH 02/72] some work on bdi-ed clustering. (experimental state) --- .../BranchMappingDistance.h | 414 +++++++++++++++++- .../mergeTreeClustering/PathMappingDistance.h | 60 ++- .../ttkMergeTreeClustering.cpp | 52 ++- 3 files changed, 495 insertions(+), 31 deletions(-) diff --git a/core/base/mergeTreeClustering/BranchMappingDistance.h b/core/base/mergeTreeClustering/BranchMappingDistance.h index 31ba63011f..fa0bdc4cf5 100644 --- a/core/base/mergeTreeClustering/BranchMappingDistance.h +++ b/core/base/mergeTreeClustering/BranchMappingDistance.h @@ -42,6 +42,8 @@ namespace ttk { int baseMetric_ = 0; int assignmentSolverID_ = 0; bool squared_ = false; + bool computeMapping_ = false; + bool writeOptimalBranchDecomposition_ = false; template inline dataType editCost_Wasserstein1(int n1, @@ -193,9 +195,18 @@ namespace ttk { squared_ = s; } + void setComputeMapping(bool m) { + computeMapping_ = m; + } + + void setWriteBD(bool w) { + writeOptimalBranchDecomposition_ = w; + } + template dataType editDistance_branch(ftm::FTMTree_MT *tree1, - ftm::FTMTree_MT *tree2) { + ftm::FTMTree_MT *tree2, + std::vector> *outputMatching=nullptr) { // initialize memoization tables @@ -550,9 +561,410 @@ namespace ttk { dataType res = memT[children1[0] + 1 * dim2 + children2[0] * dim3 + 1 * dim4]; + + if(computeMapping_ && outputMatching){ + + outputMatching->clear(); + std::vector matchedNodes(tree1->getNumberOfNodes(),-1); + std::vector,std::pair>> mapping; + traceMapping_branch(tree1,tree2,children1[0],1,children2[0],1,predecessors1,predecessors2,depth1,depth2,memT,mapping); + for(auto m : mapping){ + if(writeOptimalBranchDecomposition_ && m.first.first >=0 && m.first.second >=0){ + tree1->getNode(m.first.first)->setOrigin(m.first.second); + tree1->getNode(m.first.second)->setOrigin(m.first.first); + } + if(writeOptimalBranchDecomposition_ && m.second.first >=0 && m.second.second >=0){ + tree2->getNode(m.second.first)->setOrigin(m.second.second); + tree2->getNode(m.second.second)->setOrigin(m.second.first); + } + if(m.first.first == -1) continue; + if(m.first.second == -1) continue; + if(m.second.first == -1) continue; + if(m.second.second == -1) continue; + matchedNodes[m.first.first] = m.second.first; + matchedNodes[m.first.second] = m.second.second; + } + for(ftm::idNode i=0; i=0) outputMatching->emplace_back(std::make_tuple(i,matchedNodes[i], 0.0)); + } + + } return squared_ ? std::sqrt(res) : res; } + + template + void traceMapping_branch( + ftm::FTMTree_MT *tree1, + ftm::FTMTree_MT *tree2, + int curr1, + int l1, + int curr2, + int l2, + std::vector> &predecessors1, + std::vector> &predecessors2, + int depth1, + int depth2, + std::vector &memT, + std::vector, + std::pair>> &mapping) { + + size_t nn1 = tree1->getNumberOfNodes(); + size_t nn2 = tree2->getNumberOfNodes(); + size_t dim1 = 1; + size_t dim2 = (nn1 + 1) * dim1; + size_t dim3 = (depth1 + 1) * dim2; + size_t dim4 = (nn2 + 1) * dim3; + + //=============================================================================== + // If second tree empty, track optimal branch decomposition of first tree + + if(curr2 == nn2){ + std::vector children1; + tree1->getChildren(curr1, children1); + int parent1 = predecessors1[curr1][predecessors1[curr1].size() - l1]; + //----------------------------------------------------------------------- + // If first subtree has only one branch, return deletion cost of this + // branch + if(tree1->getNumberOfChildren(curr1) == 0) { + mapping.emplace_back(std::make_pair( + std::make_pair(curr1, parent1), std::make_pair(-1, -1))); + } + //----------------------------------------------------------------------- + // If first subtree has more than one branch, try all decompositions + else { + for(auto child1_mb : children1) { + dataType c_ + = memT[child1_mb + (l1 + 1) * dim2 + nn2 * dim3 + 0 * dim4]; + for(auto child1 : children1) { + if(child1 == child1_mb) { + continue; + } + c_ += memT[child1 + 1 * dim2 + nn2 * dim3 + 0 * dim4]; + } + if(c_ == memT[curr1 + l1 * dim2 + nn2 * dim3 + 0 * dim4]){ + traceMapping_branch(tree1, tree2, child1_mb, (l1 + 1), nn2, 0, + predecessors1, predecessors2, depth1, depth2, + memT, mapping); + for(auto child1 : children1) { + if(child1 == child1_mb) { + continue; + } + traceMapping_branch(tree1, tree2, child1, 1, nn2, 0, + predecessors1, predecessors2, depth1, depth2, + memT, mapping); + } + } + } + } + return; + } + + //=============================================================================== + // If first tree empty, track optimal branch decomposition of second tree + + if(curr1 == nn1){ + std::vector children2; + tree2->getChildren(curr2, children2); + int parent2 = predecessors2[curr2][predecessors2[curr2].size() - l2]; + //----------------------------------------------------------------------- + // If first subtree has only one branch, return deletion cost of this + // branch + if(tree2->getNumberOfChildren(curr2) == 0) { + mapping.emplace_back(std::make_pair( + std::make_pair(-1, -1), std::make_pair(curr2, parent2))); + } + //----------------------------------------------------------------------- + // If first subtree has more than one branch, try all decompositions + else { + for(auto child2_mb : children2) { + dataType c_ + = memT[nn1 + 0 * dim2 + child2_mb * dim3 + (l2 + 1) * dim4]; + for(auto child2 : children2) { + if(child2 == child2_mb) { + continue; + } + c_ += memT[nn1 + 0 * dim2 + child2 * dim3 + 1 * dim4]; + } + if(c_ == memT[nn1 + 0 * dim2 + curr2 * dim3 + l2 * dim4]){ + traceMapping_branch(tree1, tree2, nn1, 0, child2_mb, (l2+1), + predecessors1, predecessors2, depth1, depth2, + memT, mapping); + for(auto child2 : children2) { + if(child2 == child2_mb) { + continue; + } + traceMapping_branch(tree1, tree2, nn1, 0, child2, 1, + predecessors1, predecessors2, depth1, depth2, + memT, mapping); + } + } + } + } + return; + } + + std::vector children1; + tree1->getChildren(curr1, children1); + std::vector children2; + tree2->getChildren(curr2, children2); + int parent1 = predecessors1[curr1][predecessors1[curr1].size() - l1]; + int parent2 = predecessors2[curr2][predecessors2[curr2].size() - l2]; + + //=============================================================================== + // If both trees not empty, find optimal edit operation + + //--------------------------------------------------------------------------- + // If both trees only have one branch, return edit cost between + // the two branches + if(tree1->getNumberOfChildren(curr1) == 0 + and tree2->getNumberOfChildren(curr2) == 0) { + mapping.emplace_back(std::make_pair( + std::make_pair(curr1, parent1), std::make_pair(curr2, parent2))); + return; + } + //--------------------------------------------------------------------------- + // If first tree only has one branch, try all decompositions of + // second tree + else if(children1.size() == 0) { + for(auto child2_mb : children2) { + dataType d_ = memT[curr1 + l1 * dim2 + child2_mb * dim3 + + (l2 + 1) * dim4]; + for(auto child2 : children2) { + if(child2 == child2_mb) { + continue; + } + d_ += memT[nn1 + 0 * dim2 + child2 * dim3 + 1 * dim4]; + } + if(d_ == memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4]){ + traceMapping_branch(tree1, tree2, curr1, l1, child2_mb, (l2+1), + predecessors1, predecessors2, depth1, depth2, + memT, mapping); + for(auto child2 : children2) { + if(child2 == child2_mb) { + continue; + } + traceMapping_branch(tree1, tree2, nn1, 0, child2, 1, + predecessors1, predecessors2, depth1, depth2, + memT, mapping); + } + return; + } + } + } + //--------------------------------------------------------------------------- + // If second tree only has one branch, try all decompositions of + // first tree + else if(children2.size() == 0) { + for(auto child1_mb : children1) { + dataType d_ = memT[child1_mb + (l1 + 1) * dim2 + curr2 * dim3 + + l2 * dim4]; + for(auto child1 : children1) { + if(child1 == child1_mb) { + continue; + } + d_ += memT[child1 + 1 * dim2 + nn2 * dim3 + 0 * dim4]; + } + if(d_ == memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4]){ + traceMapping_branch(tree1, tree2, child1_mb, (l1 + 1), curr2, l2, + predecessors1, predecessors2, depth1, depth2, + memT, mapping); + for(auto child1 : children1) { + if(child1 == child1_mb) { + continue; + } + traceMapping_branch(tree1, tree2, child1, 1, nn2, 0, + predecessors1, predecessors2, depth1, depth2, + memT, mapping); + } + return; + } + } + } + //--------------------------------------------------------------------------- + // If both trees have more than one branch, try all decompositions + // of both trees + else { + //----------------------------------------------------------------------- + // Try all possible main branches of first tree (child1_mb) and + // all possible main branches of second tree (child2_mb) Then + // try all possible matchings of subtrees + if(children1.size() == 2 && children2.size() == 2) { + int child11 = children1[0]; + int child12 = children1[1]; + int child21 = children2[0]; + int child22 = children2[1]; + if(memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4] == + memT[child11 + (l1 + 1) * dim2 + child21 * dim3 + (l2 + 1) * dim4] + + memT[child12 + 1 * dim2 + child22 * dim3 + 1 * dim4]){ + + traceMapping_branch(tree1, tree2, child11, (l1 + 1), child21, (l2+1), + predecessors1, predecessors2, depth1, depth2, + memT, mapping); + traceMapping_branch(tree1, tree2, child12, 1, child22, 1, + predecessors1, predecessors2, depth1, depth2, + memT, mapping); + + return; + } + if(memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4] == + memT[child12 + (l1 + 1) * dim2 + child22 * dim3 + (l2 + 1) * dim4] + + memT[child11 + 1 * dim2 + child21 * dim3 + 1 * dim4]){ + + traceMapping_branch(tree1, tree2, child12, (l1 + 1), child22, (l2+1), + predecessors1, predecessors2, depth1, depth2, + memT, mapping); + traceMapping_branch(tree1, tree2, child11, 1, child21, 1, + predecessors1, predecessors2, depth1, depth2, + memT, mapping); + + return; + + } + if(memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4] == + memT[child11 + (l1 + 1) * dim2 + child22 * dim3 + (l2 + 1) * dim4] + + memT[child12 + 1 * dim2 + child21 * dim3 + 1 * dim4]){ + + traceMapping_branch(tree1, tree2, child11, (l1 + 1), child22, (l2+1), + predecessors1, predecessors2, depth1, depth2, + memT, mapping); + traceMapping_branch(tree1, tree2, child12, 1, child21, 1, + predecessors1, predecessors2, depth1, depth2, + memT, mapping); + + return; + + } + if(memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4] == + memT[child12 + (l1 + 1) * dim2 + child21 * dim3 + (l2 + 1) * dim4] + + memT[child11 + 1 * dim2 + child22 * dim3 + 1 * dim4]){ + + traceMapping_branch(tree1, tree2, child12, (l1 + 1), child21, (l2+1), + predecessors1, predecessors2, depth1, depth2, + memT, mapping); + traceMapping_branch(tree1, tree2, child11, 1, child22, 1, + predecessors1, predecessors2, depth1, depth2, + memT, mapping); + + return; + + } + } + else { + // ToDo !!! + // for(auto child1_mb : children1) { + // auto topo1_ = children1; + // topo1_.erase( + // std::remove(topo1_.begin(), topo1_.end(), child1_mb), + // topo1_.end()); + // for(auto child2_mb : children2) { + // auto topo2_ = children2; + // topo2_.erase( + // std::remove(topo2_.begin(), topo2_.end(), child2_mb), + // topo2_.end()); + + // auto f = [&](unsigned r, unsigned c) { + // int c1 = r < topo1_.size() ? topo1_[r] : -1; + // int c2 = c < topo2_.size() ? topo2_[c] : -1; + // return memT[c1 + 1 * dim2 + c2 * dim3 + 1 * dim4]; + // }; + // int size = std::max(topo1_.size(), topo2_.size()) + 1; + // auto costMatrix = std::vector>( + // size, std::vector(size, 0)); + // std::vector matching; + // for(int r = 0; r < size; r++) { + // for(int c = 0; c < size; c++) { + // costMatrix[r][c] = f(r, c); + // } + // } + + // AssignmentSolver *assignmentSolver; + // AssignmentExhaustive solverExhaustive; + // AssignmentMunkres solverMunkres; + // AssignmentAuction solverAuction; + // switch(assignmentSolverID_) { + // case 1: + // solverExhaustive = AssignmentExhaustive(); + // assignmentSolver = &solverExhaustive; + // break; + // case 2: + // solverMunkres = AssignmentMunkres(); + // assignmentSolver = &solverMunkres; + // break; + // case 0: + // default: + // solverAuction = AssignmentAuction(); + // assignmentSolver = &solverAuction; + // } + // assignmentSolver->setInput(costMatrix); + // assignmentSolver->setBalanced(true); + // assignmentSolver->run(matching); + // dataType d_ = memT[child1_mb + (l1 + 1) * dim2 + // + child2_mb * dim3 + (l2 + 1) * dim4]; + // for(auto m : matching) + // d_ += std::get<2>(m); + // d = std::min(d, d_); + // } + // } + } + //----------------------------------------------------------------------- + // Try to continue main branch on one child of first tree and + // delete all other subtrees Then match continued branch to + // current branch in second tree + for(auto child1_mb : children1) { + dataType d_ = memT[child1_mb + (l1 + 1) * dim2 + curr2 * dim3 + + l2 * dim4]; + for(auto child1 : children1) { + if(child1 == child1_mb) { + continue; + } + d_ += memT[child1 + 1 * dim2 + nn2 * dim3 + 0 * dim4]; + } + if(memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4] == d_){ + traceMapping_branch(tree1, tree2, child1_mb, (l1 + 1), curr2, l2, + predecessors1, predecessors2, depth1, depth2, + memT, mapping); + for(auto child1 : children1) { + if(child1 == child1_mb) { + continue; + } + traceMapping_branch(tree1, tree2, child1, 1, nn2, 0, + predecessors1, predecessors2, depth1, depth2, + memT, mapping); + } + return; + } + } + //----------------------------------------------------------------------- + // Try to continue main branch on one child of second tree and + // delete all other subtrees Then match continued branch to + // current branch in first tree + for(auto child2_mb : children2) { + dataType d_ = memT[curr1 + l1 * dim2 + child2_mb * dim3 + + (l2 + 1) * dim4]; + for(auto child2 : children2) { + if(child2 == child2_mb) { + continue; + } + d_ += memT[nn1 + 0 * dim2 + child2 * dim3 + 1 * dim4]; + } + if(memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4] == d_){ + traceMapping_branch(tree1, tree2, curr1, l1, child2_mb, (l2+1), + predecessors1, predecessors2, depth1, depth2, + memT, mapping); + for(auto child2 : children2) { + if(child2 == child2_mb) { + continue; + } + traceMapping_branch(tree1, tree2, nn1, 0, child2, 1, + predecessors1, predecessors2, depth1, depth2, + memT, mapping); + } + return; + } + } + } + } }; } // namespace ttk \ No newline at end of file diff --git a/core/base/mergeTreeClustering/PathMappingDistance.h b/core/base/mergeTreeClustering/PathMappingDistance.h index e42cd93661..7d8cf64da8 100644 --- a/core/base/mergeTreeClustering/PathMappingDistance.h +++ b/core/base/mergeTreeClustering/PathMappingDistance.h @@ -111,10 +111,6 @@ namespace ttk { and tree2->getNumberOfChildren(curr2) == 0) { mapping.emplace_back(std::make_pair( std::make_pair(curr1, parent1), std::make_pair(curr2, parent2))); - tree1->getNode(curr1)->setOrigin(parent1); - tree1->getNode(parent1)->setOrigin(curr1); - tree1->getNode(curr2)->setOrigin(parent2); - tree1->getNode(parent2)->setOrigin(curr2); return; } //--------------------------------------------------------------------------- @@ -182,10 +178,6 @@ namespace ttk { curr1, parent1, curr2, parent2, tree1, tree2)) { mapping.emplace_back(std::make_pair( std::make_pair(curr1, parent1), std::make_pair(curr2, parent2))); - tree1->getNode(curr1)->setOrigin(parent1); - tree1->getNode(parent1)->setOrigin(curr1); - tree1->getNode(curr2)->setOrigin(parent2); - tree1->getNode(parent2)->setOrigin(curr2); traceMapping_path(tree1, tree2, child11, 1, child21, 1, predecessors1, predecessors2, depth1, depth2, memT, mapping); @@ -200,10 +192,6 @@ namespace ttk { curr1, parent1, curr2, parent2, tree1, tree2)) { mapping.emplace_back(std::make_pair( std::make_pair(curr1, parent1), std::make_pair(curr2, parent2))); - tree1->getNode(curr1)->setOrigin(parent1); - tree1->getNode(parent1)->setOrigin(curr1); - tree1->getNode(curr2)->setOrigin(parent2); - tree1->getNode(parent2)->setOrigin(curr2); traceMapping_path(tree1, tree2, child11, 1, child22, 1, predecessors1, predecessors2, depth1, depth2, memT, mapping); @@ -262,10 +250,6 @@ namespace ttk { if(memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4] == d_) { mapping.emplace_back(std::make_pair( std::make_pair(curr1, parent1), std::make_pair(curr2, parent2))); - tree1->getNode(curr1)->setOrigin(parent1); - tree1->getNode(parent1)->setOrigin(curr1); - tree1->getNode(curr2)->setOrigin(parent2); - tree1->getNode(parent2)->setOrigin(curr2); for(auto m : matching) { int n1 = std::get<0>(m) < tree1->getNumberOfChildren(curr1) ? children1[std::get<0>(m)] @@ -373,8 +357,6 @@ namespace ttk { std::vector children; tree1->getChildren(nIdx, children); for(int cIdx : children) { - tree1->getNode(nIdx)->setOrigin(cIdx); - tree1->getNode(cIdx)->setOrigin(nIdx); stack.push(cIdx); predecessors1[cIdx].reserve(predecessors1[nIdx].size() + 1); predecessors1[cIdx].insert(predecessors1[cIdx].end(), @@ -395,8 +377,6 @@ namespace ttk { tree2->getChildren(nIdx, children); for(int cIdx : children) { stack.push(cIdx); - tree2->getNode(nIdx)->setOrigin(cIdx); - tree2->getNode(cIdx)->setOrigin(nIdx); predecessors2[cIdx].reserve(predecessors2[nIdx].size() + 1); predecessors2[cIdx].insert(predecessors2[cIdx].end(), predecessors2[nIdx].begin(), @@ -643,6 +623,7 @@ namespace ttk { if(computeMapping_ && outputMatching){ + outputMatching->clear(); std::vector matchedNodes(tree1->getNumberOfNodes(),-1); std::vector,std::pair>> mapping; traceMapping_path(tree1,tree2,children1[0],1,children2[0],1,predecessors1,predecessors2,depth1,depth2,memT,mapping); @@ -658,5 +639,44 @@ namespace ttk { return squared_ ? std::sqrt(res) : res; } + + void computeBranchDecomposition(ftm::FTMTree_MT *tree){ + + auto rootID = tree->getRoot(); + + computeBranchDecomposition(tree,rootID); + + } + + ftm::idNode computeBranchDecomposition(ftm::FTMTree_MT *tree,ftm::idNode rootID){ + + std::vector children; + tree->getChildren(rootID, children); + if(children.empty()) return rootID; + if(children.size() == 1){ + auto me = computeBranchDecomposition(tree, children[0]); + tree->getNode(rootID)->setOrigin(me); + tree->getNode(me)->setOrigin(rootID); + return me; + } + std::vector extrema(children.size()); + ftm::idNode me = computeBranchDecomposition(tree, children[0]); + extrema[0] = me; + for(int i=1; igetValue(e)-tree->getValue(rootID)) > std::abs(tree->getValue(me)-tree->getValue(rootID))){ + if(tree->getValue(e) > tree->getValue(me)){ + me = e; + } + } + for(auto e : extrema){ + if(e==me) continue; + tree->getNode(rootID)->setOrigin(e); + tree->getNode(e)->setOrigin(rootID); + } + return me; + + } }; } // namespace ttk diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index 5652c70f73..720583e156 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -187,17 +187,20 @@ int ttkMergeTreeClustering::runCompute( setDataVisualization(numInputs, numInputs2); std::vector> intermediateMTrees(numInputs), - intermediateMTrees2(numInputs2), barycenters(NumberOfBarycenters); + intermediateMTrees2(numInputs2), barycenters(NumberOfBarycenters), intermediateMTrees3(numInputs); std::vector intermediateTrees(numInputs), - intermediateTrees2(numInputs2); + intermediateTrees2(numInputs2), intermediateTrees3(numInputs); constructTrees( inputTrees, intermediateMTrees, treesNodes, treesArcs, treesSegmentation); constructTrees(inputTrees2, intermediateMTrees2, treesNodes2, treesArcs2, treesSegmentation2); + constructTrees( + inputTrees, intermediateMTrees3, treesNodes, treesArcs, treesSegmentation); mergeTreeToFTMTree(intermediateMTrees, intermediateTrees); mergeTreeToFTMTree(intermediateMTrees2, intermediateTrees2); + mergeTreeToFTMTree(intermediateMTrees3, intermediateTrees3); // ------------------------------------------------------------------------------------ // --- Call base @@ -272,12 +275,13 @@ int ttkMergeTreeClustering::runCompute( finalDistances = std::vector{distance}; } else if(baseModule==1){ - BranchMappingDistance branchDist; branchDist.setBaseMetric(branchMetric); branchDist.setAssignmentSolver(AssignmentSolver); branchDist.setSquared(false); - distance = branchDist.editDistance_branch(intermediateTrees[0], intermediateTrees[1]); + branchDist.setComputeMapping(true); + branchDist.setWriteBD(true); + distance = branchDist.editDistance_branch(intermediateTrees[0], intermediateTrees[1], &outputMatching); std::vector nodeCorr1(intermediateTrees[0]->getNumberOfNodes()); std::vector nodeCorr2(intermediateTrees[1]->getNumberOfNodes()); @@ -287,6 +291,32 @@ int ttkMergeTreeClustering::runCompute( finalDistances = std::vector{distance}; } else{ + MergeTreeDistance mergeTreeDistance; + mergeTreeDistance.setAssignmentSolver(AssignmentSolver); + mergeTreeDistance.setEpsilonTree1(EpsilonTree1); + mergeTreeDistance.setEpsilonTree2(EpsilonTree2); + mergeTreeDistance.setEpsilon2Tree1(Epsilon2Tree1); + mergeTreeDistance.setEpsilon2Tree2(Epsilon2Tree2); + mergeTreeDistance.setEpsilon3Tree1(Epsilon3Tree1); + mergeTreeDistance.setEpsilon3Tree2(Epsilon3Tree2); + mergeTreeDistance.setProgressiveComputation(ProgressiveComputation); + mergeTreeDistance.setBranchDecomposition(BranchDecomposition); + mergeTreeDistance.setPersistenceThreshold(PersistenceThreshold); + mergeTreeDistance.setNormalizedWasserstein(NormalizedWasserstein); + mergeTreeDistance.setNormalizedWassersteinReg(NormalizedWassersteinReg); + mergeTreeDistance.setRescaledWasserstein(RescaledWasserstein); + mergeTreeDistance.setKeepSubtree(KeepSubtree); + mergeTreeDistance.setUseMinMaxPair(UseMinMaxPair); + mergeTreeDistance.setCleanTree(true); + mergeTreeDistance.setPostprocess(OutputTrees); + mergeTreeDistance.setDeleteMultiPersPairs(DeleteMultiPersPairs); + mergeTreeDistance.setEpsilon1UseFarthestSaddle(Epsilon1UseFarthestSaddle); + mergeTreeDistance.setThreadNumber(this->threadNumber_); + mergeTreeDistance.setDebugLevel(this->debugLevel_); + + distance = mergeTreeDistance.execute( + intermediateMTrees[0], intermediateMTrees[1], outputMatching); + trees1NodeCorrMesh = mergeTreeDistance.getTreesNodeCorr(); PathMappingDistance pathDist; pathDist.setBaseMetric(pathMetric); @@ -294,12 +324,14 @@ int ttkMergeTreeClustering::runCompute( pathDist.setSquared(false); pathDist.setComputeMapping(true); distance = pathDist.editDistance_path(intermediateTrees[0], intermediateTrees[1], &outputMatching); - - std::vector nodeCorr1(intermediateTrees[0]->getNumberOfNodes()); - std::vector nodeCorr2(intermediateTrees[1]->getNumberOfNodes()); - for(ttk::SimplexId i=0; i>{nodeCorr1,nodeCorr2}; + //pathDist.computeBranchDecomposition(intermediateTrees[0]); + //pathDist.computeBranchDecomposition(intermediateTrees[1]); + + // std::vector nodeCorr1(intermediateTrees[0]->getNumberOfNodes()); + // std::vector nodeCorr2(intermediateTrees[1]->getNumberOfNodes()); + // for(ttk::SimplexId i=0; i>{nodeCorr1,nodeCorr2}; finalDistances = std::vector{distance}; } } else { From 909049d6da2844a236078947bf22c0a1c6150228 Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Mon, 14 Nov 2022 14:07:53 +0100 Subject: [PATCH 03/72] MergeTreeClustering: Mapping visualizations working for Path Mapping Distance. Branch Mapping Distance still buggy. --- CMake/merge_tree_preprocess.xml | 24 +++ .../BranchMappingDistance.h | 158 +++++++++++------- .../mergeTreeClustering/PathMappingDistance.h | 70 ++++---- .../ttkMergeTreeClustering.cpp | 64 ++++--- 4 files changed, 180 insertions(+), 136 deletions(-) diff --git a/CMake/merge_tree_preprocess.xml b/CMake/merge_tree_preprocess.xml index 1e2b8316bf..03cd0ca086 100644 --- a/CMake/merge_tree_preprocess.xml +++ b/CMake/merge_tree_preprocess.xml @@ -20,6 +20,14 @@ panel_visibility="advanced"> mode="visibility" property="Backend" value="2" /> + + @@ -81,6 +89,14 @@ default_values="5"> mode="visibility" property="Backend" value="2" /> + + @@ -177,6 +193,14 @@ default_values="0"> mode="visibility" property="Backend" value="2" /> + + diff --git a/core/base/mergeTreeClustering/BranchMappingDistance.h b/core/base/mergeTreeClustering/BranchMappingDistance.h index fa0bdc4cf5..d32f326c3e 100644 --- a/core/base/mergeTreeClustering/BranchMappingDistance.h +++ b/core/base/mergeTreeClustering/BranchMappingDistance.h @@ -28,6 +28,7 @@ #include // ttk common includes +#include "MergeTreeBase.h" #include #include #include @@ -36,7 +37,7 @@ namespace ttk { - class BranchMappingDistance : virtual public Debug { + class BranchMappingDistance : virtual public Debug, public MergeTreeBase { private: int baseMetric_ = 0; @@ -45,6 +46,8 @@ namespace ttk { bool computeMapping_ = false; bool writeOptimalBranchDecomposition_ = false; + bool preprocess_ = true; + template inline dataType editCost_Wasserstein1(int n1, int p1, @@ -203,12 +206,32 @@ namespace ttk { writeOptimalBranchDecomposition_ = w; } + void setPreprocess(bool p) { + preprocess_ = p; + } + template dataType editDistance_branch(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2, std::vector> *outputMatching=nullptr) { - // initialize memoization tables + // optional preprocessing + + if(preprocess_){ + std::vector> treeNodeMerged1( tree1->getNumberOfNodes() ); + preprocessTree(tree1, epsilonTree1_, persistenceThreshold_, + treeNodeMerged1, true); + std::vector> treeNodeMerged2( tree2->getNumberOfNodes() ); + preprocessTree(tree2, epsilonTree2_, persistenceThreshold_, + treeNodeMerged2, true); + + if(deleteMultiPersPairs_) + deleteMultiPersPairs(tree1, false); + if(deleteMultiPersPairs_) + deleteMultiPersPairs(tree2, false); + } + + // compute preorder of both trees (necessary for bottom-up dynamic programming) std::vector> predecessors1(tree1->getNumberOfNodes()); std::vector> predecessors2(tree2->getNumberOfNodes()); @@ -259,6 +282,8 @@ namespace ttk { } } + // initialize memoization tables + size_t nn1 = tree1->getNumberOfNodes(); size_t nn2 = tree2->getNumberOfNodes(); size_t dim1 = 1; @@ -565,7 +590,7 @@ namespace ttk { if(computeMapping_ && outputMatching){ outputMatching->clear(); - std::vector matchedNodes(tree1->getNumberOfNodes(),-1); + std::vector matchedNodes(tree1->getNumberOfNodes(),-1); std::vector,std::pair>> mapping; traceMapping_branch(tree1,tree2,children1[0],1,children2[0],1,predecessors1,predecessors2,depth1,depth2,memT,mapping); for(auto m : mapping){ @@ -851,61 +876,78 @@ namespace ttk { } } else { - // ToDo !!! - // for(auto child1_mb : children1) { - // auto topo1_ = children1; - // topo1_.erase( - // std::remove(topo1_.begin(), topo1_.end(), child1_mb), - // topo1_.end()); - // for(auto child2_mb : children2) { - // auto topo2_ = children2; - // topo2_.erase( - // std::remove(topo2_.begin(), topo2_.end(), child2_mb), - // topo2_.end()); - - // auto f = [&](unsigned r, unsigned c) { - // int c1 = r < topo1_.size() ? topo1_[r] : -1; - // int c2 = c < topo2_.size() ? topo2_[c] : -1; - // return memT[c1 + 1 * dim2 + c2 * dim3 + 1 * dim4]; - // }; - // int size = std::max(topo1_.size(), topo2_.size()) + 1; - // auto costMatrix = std::vector>( - // size, std::vector(size, 0)); - // std::vector matching; - // for(int r = 0; r < size; r++) { - // for(int c = 0; c < size; c++) { - // costMatrix[r][c] = f(r, c); - // } - // } - - // AssignmentSolver *assignmentSolver; - // AssignmentExhaustive solverExhaustive; - // AssignmentMunkres solverMunkres; - // AssignmentAuction solverAuction; - // switch(assignmentSolverID_) { - // case 1: - // solverExhaustive = AssignmentExhaustive(); - // assignmentSolver = &solverExhaustive; - // break; - // case 2: - // solverMunkres = AssignmentMunkres(); - // assignmentSolver = &solverMunkres; - // break; - // case 0: - // default: - // solverAuction = AssignmentAuction(); - // assignmentSolver = &solverAuction; - // } - // assignmentSolver->setInput(costMatrix); - // assignmentSolver->setBalanced(true); - // assignmentSolver->run(matching); - // dataType d_ = memT[child1_mb + (l1 + 1) * dim2 - // + child2_mb * dim3 + (l2 + 1) * dim4]; - // for(auto m : matching) - // d_ += std::get<2>(m); - // d = std::min(d, d_); - // } - // } + for(auto child1_mb : children1) { + auto topo1_ = children1; + topo1_.erase( + std::remove(topo1_.begin(), topo1_.end(), child1_mb), + topo1_.end()); + for(auto child2_mb : children2) { + auto topo2_ = children2; + topo2_.erase( + std::remove(topo2_.begin(), topo2_.end(), child2_mb), + topo2_.end()); + + auto f = [&](unsigned r, unsigned c) { + int c1 = r < topo1_.size() ? topo1_[r] : -1; + int c2 = c < topo2_.size() ? topo2_[c] : -1; + return memT[c1 + 1 * dim2 + c2 * dim3 + 1 * dim4]; + }; + int size = std::max(topo1_.size(), topo2_.size()) + 1; + auto costMatrix = std::vector>( + size, std::vector(size, 0)); + std::vector matching; + for(int r = 0; r < size; r++) { + for(int c = 0; c < size; c++) { + costMatrix[r][c] = f(r, c); + } + } + + AssignmentSolver *assignmentSolver; + AssignmentExhaustive solverExhaustive; + AssignmentMunkres solverMunkres; + AssignmentAuction solverAuction; + switch(assignmentSolverID_) { + case 1: + solverExhaustive = AssignmentExhaustive(); + assignmentSolver = &solverExhaustive; + break; + case 2: + solverMunkres = AssignmentMunkres(); + assignmentSolver = &solverMunkres; + break; + case 0: + default: + solverAuction = AssignmentAuction(); + assignmentSolver = &solverAuction; + } + assignmentSolver->setInput(costMatrix); + assignmentSolver->setBalanced(true); + assignmentSolver->run(matching); + dataType d_ = memT[child1_mb + (l1 + 1) * dim2 + + child2_mb * dim3 + (l2 + 1) * dim4]; + for(auto m : matching) + d_ += std::get<2>(m); + + if(d_ == memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4]){ + traceMapping_branch(tree1, tree2, child1_mb, (l1 + 1), child2_mb, (l2 + 1), + predecessors1, predecessors2, depth1, depth2, + memT, mapping); + for(auto m : matching){ + int n1 = std::get<0>(m) < topo1_.size() + ? topo1_[std::get<0>(m)] + : -1; + int n2 = std::get<1>(m) < topo2_.size() + ? topo2_[std::get<1>(m)] + : -1; + if(n1 >= 0 && n2 >= 0) + traceMapping_branch(tree1, tree2, n1, 1, n2, 1, + predecessors1, predecessors2, depth1, depth2, + memT, mapping); + } + return; + } + } + } } //----------------------------------------------------------------------- // Try to continue main branch on one child of first tree and diff --git a/core/base/mergeTreeClustering/PathMappingDistance.h b/core/base/mergeTreeClustering/PathMappingDistance.h index 7d8cf64da8..b1ba74dc20 100644 --- a/core/base/mergeTreeClustering/PathMappingDistance.h +++ b/core/base/mergeTreeClustering/PathMappingDistance.h @@ -28,6 +28,7 @@ #include // ttk common includes +#include "MergeTreeBase.h" #include #include #include @@ -36,7 +37,7 @@ namespace ttk { - class PathMappingDistance : virtual public Debug { + class PathMappingDistance : virtual public Debug, public MergeTreeBase { private: int baseMetric_ = 0; @@ -44,6 +45,8 @@ namespace ttk { bool squared_ = false; bool computeMapping_ = false; + bool preprocess_ = true; + template inline dataType editCost_Persistence(int n1, int p1, @@ -331,10 +334,30 @@ namespace ttk { computeMapping_ = m; } + void setPreprocess(bool p) { + preprocess_ = p; + } + template dataType editDistance_path(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2, std::vector> *outputMatching=nullptr) { - // initialize memoization tables + // optional preprocessing + + if(preprocess_){ + std::vector> treeNodeMerged1( tree1->getNumberOfNodes() ); + preprocessTree(tree1, epsilonTree1_, persistenceThreshold_, + treeNodeMerged1, true); + std::vector> treeNodeMerged2( tree2->getNumberOfNodes() ); + preprocessTree(tree2, epsilonTree2_, persistenceThreshold_, + treeNodeMerged2, true); + + if(deleteMultiPersPairs_) + deleteMultiPersPairs(tree1, false); + if(deleteMultiPersPairs_) + deleteMultiPersPairs(tree2, false); + } + + // compute preorder of both trees (necessary for bottom-up dynamic programming) std::vector> predecessors1(tree1->getNumberOfNodes()); std::vector> predecessors2(tree2->getNumberOfNodes()); @@ -385,6 +408,8 @@ namespace ttk { } } + // initialize memoization tables + size_t nn1 = tree1->getNumberOfNodes(); size_t nn2 = tree2->getNumberOfNodes(); size_t dim1 = 1; @@ -624,7 +649,7 @@ namespace ttk { if(computeMapping_ && outputMatching){ outputMatching->clear(); - std::vector matchedNodes(tree1->getNumberOfNodes(),-1); + std::vector matchedNodes(tree1->getNumberOfNodes(),-1); std::vector,std::pair>> mapping; traceMapping_path(tree1,tree2,children1[0],1,children2[0],1,predecessors1,predecessors2,depth1,depth2,memT,mapping); for(auto m : mapping){ @@ -639,44 +664,5 @@ namespace ttk { return squared_ ? std::sqrt(res) : res; } - - void computeBranchDecomposition(ftm::FTMTree_MT *tree){ - - auto rootID = tree->getRoot(); - - computeBranchDecomposition(tree,rootID); - - } - - ftm::idNode computeBranchDecomposition(ftm::FTMTree_MT *tree,ftm::idNode rootID){ - - std::vector children; - tree->getChildren(rootID, children); - if(children.empty()) return rootID; - if(children.size() == 1){ - auto me = computeBranchDecomposition(tree, children[0]); - tree->getNode(rootID)->setOrigin(me); - tree->getNode(me)->setOrigin(rootID); - return me; - } - std::vector extrema(children.size()); - ftm::idNode me = computeBranchDecomposition(tree, children[0]); - extrema[0] = me; - for(int i=1; igetValue(e)-tree->getValue(rootID)) > std::abs(tree->getValue(me)-tree->getValue(rootID))){ - if(tree->getValue(e) > tree->getValue(me)){ - me = e; - } - } - for(auto e : extrema){ - if(e==me) continue; - tree->getNode(rootID)->setOrigin(e); - tree->getNode(e)->setOrigin(rootID); - } - return me; - - } }; } // namespace ttk diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index 720583e156..3f8af476b3 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -280,7 +280,17 @@ int ttkMergeTreeClustering::runCompute( branchDist.setAssignmentSolver(AssignmentSolver); branchDist.setSquared(false); branchDist.setComputeMapping(true); - branchDist.setWriteBD(true); + branchDist.setWriteBD(false); + + branchDist.setEpsilonTree1(EpsilonTree1); + branchDist.setEpsilonTree2(EpsilonTree2); + branchDist.setPersistenceThreshold(PersistenceThreshold); + //branchDist.setUseMinMaxPair(UseMinMaxPair); + branchDist.setDeleteMultiPersPairs(DeleteMultiPersPairs); + //branchDist.setEpsilon1UseFarthestSaddle(Epsilon1UseFarthestSaddle); + branchDist.setThreadNumber(this->threadNumber_); + branchDist.setDebugLevel(this->debugLevel_); + distance = branchDist.editDistance_branch(intermediateTrees[0], intermediateTrees[1], &outputMatching); std::vector nodeCorr1(intermediateTrees[0]->getNumberOfNodes()); @@ -291,47 +301,29 @@ int ttkMergeTreeClustering::runCompute( finalDistances = std::vector{distance}; } else{ - MergeTreeDistance mergeTreeDistance; - mergeTreeDistance.setAssignmentSolver(AssignmentSolver); - mergeTreeDistance.setEpsilonTree1(EpsilonTree1); - mergeTreeDistance.setEpsilonTree2(EpsilonTree2); - mergeTreeDistance.setEpsilon2Tree1(Epsilon2Tree1); - mergeTreeDistance.setEpsilon2Tree2(Epsilon2Tree2); - mergeTreeDistance.setEpsilon3Tree1(Epsilon3Tree1); - mergeTreeDistance.setEpsilon3Tree2(Epsilon3Tree2); - mergeTreeDistance.setProgressiveComputation(ProgressiveComputation); - mergeTreeDistance.setBranchDecomposition(BranchDecomposition); - mergeTreeDistance.setPersistenceThreshold(PersistenceThreshold); - mergeTreeDistance.setNormalizedWasserstein(NormalizedWasserstein); - mergeTreeDistance.setNormalizedWassersteinReg(NormalizedWassersteinReg); - mergeTreeDistance.setRescaledWasserstein(RescaledWasserstein); - mergeTreeDistance.setKeepSubtree(KeepSubtree); - mergeTreeDistance.setUseMinMaxPair(UseMinMaxPair); - mergeTreeDistance.setCleanTree(true); - mergeTreeDistance.setPostprocess(OutputTrees); - mergeTreeDistance.setDeleteMultiPersPairs(DeleteMultiPersPairs); - mergeTreeDistance.setEpsilon1UseFarthestSaddle(Epsilon1UseFarthestSaddle); - mergeTreeDistance.setThreadNumber(this->threadNumber_); - mergeTreeDistance.setDebugLevel(this->debugLevel_); - - distance = mergeTreeDistance.execute( - intermediateMTrees[0], intermediateMTrees[1], outputMatching); - trees1NodeCorrMesh = mergeTreeDistance.getTreesNodeCorr(); - PathMappingDistance pathDist; pathDist.setBaseMetric(pathMetric); pathDist.setAssignmentSolver(AssignmentSolver); pathDist.setSquared(false); pathDist.setComputeMapping(true); + pathDist.setPreprocess(true); + + pathDist.setEpsilonTree1(EpsilonTree1); + pathDist.setEpsilonTree2(EpsilonTree2); + pathDist.setPersistenceThreshold(PersistenceThreshold); + //pathDist.setUseMinMaxPair(UseMinMaxPair); + pathDist.setDeleteMultiPersPairs(DeleteMultiPersPairs); + //pathDist.setEpsilon1UseFarthestSaddle(Epsilon1UseFarthestSaddle); + pathDist.setThreadNumber(this->threadNumber_); + pathDist.setDebugLevel(this->debugLevel_); + distance = pathDist.editDistance_path(intermediateTrees[0], intermediateTrees[1], &outputMatching); - //pathDist.computeBranchDecomposition(intermediateTrees[0]); - //pathDist.computeBranchDecomposition(intermediateTrees[1]); - - // std::vector nodeCorr1(intermediateTrees[0]->getNumberOfNodes()); - // std::vector nodeCorr2(intermediateTrees[1]->getNumberOfNodes()); - // for(ttk::SimplexId i=0; i>{nodeCorr1,nodeCorr2}; + + std::vector nodeCorr1(intermediateTrees[0]->getNumberOfNodes()); + std::vector nodeCorr2(intermediateTrees[1]->getNumberOfNodes()); + for(ttk::SimplexId i=0; i>{nodeCorr1,nodeCorr2}; finalDistances = std::vector{distance}; } } else { From 2012fdbd03976aa57edfb263c311b0a17a8b4a9e Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Wed, 16 Nov 2022 12:09:36 +0100 Subject: [PATCH 04/72] Some testing code for branch mapping distance. --- .../mergeTreeClustering/BranchMappingDistance.h | 13 ++++++++++++- .../ttkMergeTreeClustering/ttkMergeTreeClustering.h | 2 ++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/core/base/mergeTreeClustering/BranchMappingDistance.h b/core/base/mergeTreeClustering/BranchMappingDistance.h index d32f326c3e..35ce097c1e 100644 --- a/core/base/mergeTreeClustering/BranchMappingDistance.h +++ b/core/base/mergeTreeClustering/BranchMappingDistance.h @@ -217,7 +217,7 @@ namespace ttk { // optional preprocessing - if(preprocess_){ + if(preprocess_ && !writeOptimalBranchDecomposition_){ std::vector> treeNodeMerged1( tree1->getNumberOfNodes() ); preprocessTree(tree1, epsilonTree1_, persistenceThreshold_, treeNodeMerged1, true); @@ -602,6 +602,17 @@ namespace ttk { tree2->getNode(m.second.first)->setOrigin(m.second.second); tree2->getNode(m.second.second)->setOrigin(m.second.first); } + dataType cost = this->baseMetric_ == 0 ? editCost_Wasserstein1( + m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2) + : this->baseMetric_ == 1 ? editCost_Wasserstein2( + m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2) + : this->baseMetric_ == 2 + ? editCost_Persistence( + m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2) + : editCost_Shifting( + m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2); + //std::cout << "(" << m.first.first << " " << m.first.second << ") - (" << m.second.first << " " << m.second.second << ") : " << cost << std::endl; + std::cout << "(" << tree1->getValue(m.first.first) << " " << tree1->getValue(m.first.second) << ") - (" << tree2->getValue(m.second.first) << " " << tree2->getValue(m.second.second) << ") : " << cost << std::endl; if(m.first.first == -1) continue; if(m.first.second == -1) continue; if(m.second.first == -1) continue; diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h index 7f7f8fb116..042def7431 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h @@ -323,11 +323,13 @@ class TTKMERGETREECLUSTERING_EXPORT ttkMergeTreeClustering void SetBranchMetric(int m) { branchMetric = m; Modified(); + resetDataVisualization(); } void SetPathMetric(int m) { pathMetric = m; Modified(); + resetDataVisualization(); } // Output Options From da9aee8f071999c868d9f894f8d111a12ecfc105 Mon Sep 17 00:00:00 2001 From: MatPont Date: Fri, 18 Nov 2022 09:07:36 +0100 Subject: [PATCH 05/72] [MergeTreeVisu] dimension shift for planar layout --- .../ttkMergeTreeVisualization.h | 34 ++++++++++++------- paraview/xmls/MergeTreeClustering.xml | 4 --- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h index 8fd1205c7b..6c15dafa26 100644 --- a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h +++ b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h @@ -903,19 +903,6 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { break; } - // Get dimension shift - printMsg("// Get dimension shift", ttk::debug::Priority::VERBOSE); - double diff_z = PlanarLayout ? 0 : -std::get<4>(allBounds[i]); - // TODO DimensionToShift for Planar Layout - if(not PlanarLayout) - if(DimensionToShift != 0) { // is not X - if(DimensionToShift == 2) // is Z - diff_z = diff_x; - else if(DimensionToShift == 1) // is Y - diff_y = diff_x; - diff_x = -std::get<0>(allBounds[i]); - } - // Planar layout printMsg("// Planar Layout", ttk::debug::Priority::VERBOSE); std::vector layout; @@ -935,6 +922,27 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { } } + // Get dimension shift + printMsg("// Get dimension shift", ttk::debug::Priority::VERBOSE); + double diff_z = PlanarLayout ? 0 : -std::get<4>(allBounds[i]); + if(DimensionToShift != 0) { // is not X + float minX = 0; + if(PlanarLayout) { + minX = layout[0]; + for(unsigned int l = 0; l < layout.size(); ++l) { + if(l % 2 == 0) + minX = std::min(minX, layout[l]); + } + } + if(DimensionToShift == 2) { // is Z + diff_z = diff_x; + diff_x = PlanarLayout ? -minX : -std::get<0>(allBounds[i]); + } else if(not clusteringOutput and DimensionToShift == 1) { // is Y + diff_y = diff_x; + diff_x = PlanarLayout ? -minX : -std::get<0>(allBounds[i]); + } + } + // Internal arrays printMsg("// Internal arrays", ttk::debug::Priority::VERBOSE); int cptNode = 0; diff --git a/paraview/xmls/MergeTreeClustering.xml b/paraview/xmls/MergeTreeClustering.xml index 70eb07fce0..932dbff0ab 100644 --- a/paraview/xmls/MergeTreeClustering.xml +++ b/paraview/xmls/MergeTreeClustering.xml @@ -358,10 +358,6 @@ Online examples: mode="visibility" property="OutputTrees" value="1" /> - From b2275cb69c86de59738b95d741342c3af2f52711 Mon Sep 17 00:00:00 2001 From: MatPont Date: Fri, 18 Nov 2022 09:47:33 +0100 Subject: [PATCH 06/72] [MergeTreeVisu] custom shift and fix planar layout z shift --- .../ttkMergeTreeClustering.cpp | 3 + .../ttkMergeTreeClustering.h | 12 ++++ .../ttkMergeTreeVisualization.h | 29 ++++++++- paraview/xmls/MergeTreeClustering.xml | 61 +++++++++++++++++++ 4 files changed, 102 insertions(+), 3 deletions(-) diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index 8ad69a6e91..4f455fb348 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -516,6 +516,7 @@ int ttkMergeTreeClustering::runOutput( visuMaker.setOutputSegmentation(OutputSegmentation); visuMaker.setDimensionSpacing(DimensionSpacing); visuMaker.setDimensionToShift(DimensionToShift); + visuMaker.setDimensionsShift(XShift, YShift, ZShift); visuMaker.setImportantPairs(ImportantPairs); visuMaker.setMaximumImportantPairs(MaximumImportantPairs); visuMaker.setMinimumImportantPairs(MinimumImportantPairs); @@ -705,6 +706,7 @@ int ttkMergeTreeClustering::runOutput( visuMaker.setOutputSegmentation(OutputSegmentation); visuMaker.setDimensionSpacing(DimensionSpacing); visuMaker.setDimensionToShift(DimensionToShift); + visuMaker.setDimensionsShift(XShift, YShift, ZShift); visuMaker.setImportantPairs(ImportantPairs); visuMaker.setMaximumImportantPairs(MaximumImportantPairs); visuMaker.setMinimumImportantPairs(MinimumImportantPairs); @@ -816,6 +818,7 @@ int ttkMergeTreeClustering::runOutput( visuMakerBary.setOutputSegmentation(false); visuMakerBary.setDimensionSpacing(DimensionSpacing); visuMakerBary.setDimensionToShift(DimensionToShift); + visuMakerBary.setDimensionsShift(XShift, YShift, ZShift); visuMakerBary.setImportantPairs(ImportantPairs); visuMakerBary.setMaximumImportantPairs(MaximumImportantPairs); visuMakerBary.setMinimumImportantPairs(MinimumImportantPairs); diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h index c08789c6ab..2b87a156a8 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h @@ -100,6 +100,9 @@ class TTKMERGETREECLUSTERING_EXPORT ttkMergeTreeClustering bool RescaleTreesIndividually = false; double DimensionSpacing = 1.; int DimensionToShift = 0; + double XShift = 1.0; + double YShift = 0.0; + double ZShift = 0.0; double ImportantPairs = 50.; int MaximumImportantPairs = 0; int MinimumImportantPairs = 0; @@ -363,6 +366,15 @@ class TTKMERGETREECLUSTERING_EXPORT ttkMergeTreeClustering vtkSetMacro(DimensionToShift, int); vtkGetMacro(DimensionToShift, int); + vtkSetMacro(XShift, double); + vtkGetMacro(XShift, double); + + vtkSetMacro(YShift, double); + vtkGetMacro(YShift, double); + + vtkSetMacro(ZShift, double); + vtkGetMacro(ZShift, double); + vtkSetMacro(ImportantPairs, double); vtkGetMacro(ImportantPairs, double); diff --git a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h index 6c15dafa26..0995f5d8cb 100644 --- a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h +++ b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h @@ -35,6 +35,9 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { bool PlanarLayout = false; double DimensionSpacing = 1.; int DimensionToShift = 0; + double XShift = 1.0; + double YShift = 0.0; + double ZShift = 0.0; bool OutputSegmentation = false; int MaximumImportantPairs = 0; int MinimumImportantPairs = 0; @@ -118,6 +121,20 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { void setDimensionToShift(int i) { DimensionToShift = i; } + void setXshift(double shift) { + XShift = shift; + } + void setYshift(double shift) { + YShift = shift; + } + void setZshift(double shift) { + ZShift = shift; + } + void setDimensionsShift(double xShift, double yShift, double zShift) { + setXshift(xShift); + setYshift(yShift); + setZshift(zShift); + } void setOutputSegmentation(bool b) { OutputSegmentation = b; } @@ -934,12 +951,18 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { minX = std::min(minX, layout[l]); } } + double new_diff_x = PlanarLayout ? -minX : -std::get<0>(allBounds[i]); if(DimensionToShift == 2) { // is Z - diff_z = diff_x; - diff_x = PlanarLayout ? -minX : -std::get<0>(allBounds[i]); + diff_z = -diff_x; + diff_x = new_diff_x; } else if(not clusteringOutput and DimensionToShift == 1) { // is Y diff_y = diff_x; - diff_x = PlanarLayout ? -minX : -std::get<0>(allBounds[i]); + diff_x = new_diff_x; + } else if(DimensionToShift == 3) { // Custom + if(not clusteringOutput) + diff_y = YShift * diff_x + (1 - YShift) * diff_y; + diff_z = ZShift * -diff_x + (1 - ZShift) * diff_z; + diff_x = XShift * diff_x + (1 - XShift) * new_diff_x; } } diff --git a/paraview/xmls/MergeTreeClustering.xml b/paraview/xmls/MergeTreeClustering.xml index 932dbff0ab..810c29b1cb 100644 --- a/paraview/xmls/MergeTreeClustering.xml +++ b/paraview/xmls/MergeTreeClustering.xml @@ -363,11 +363,69 @@ Online examples: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 3384a3928f0ed7a6cb8a840e5d71b72280840679 Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Fri, 18 Nov 2022 11:52:45 +0100 Subject: [PATCH 07/72] Some debugging/testing output in Branch Mapping Distance --- .../BranchMappingDistance.h | 45 ++++++++++++++++--- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/core/base/mergeTreeClustering/BranchMappingDistance.h b/core/base/mergeTreeClustering/BranchMappingDistance.h index 5845935f52..164eb8df4e 100644 --- a/core/base/mergeTreeClustering/BranchMappingDistance.h +++ b/core/base/mergeTreeClustering/BranchMappingDistance.h @@ -602,15 +602,22 @@ namespace ttk { outputMatching->clear(); std::vector matchedNodes(tree1->getNumberOfNodes(),-1); std::vector,std::pair>> mapping; + std::vector linkedNodes1(tree1->getNumberOfNodes(),-1); + std::vector linkedNodes2(tree2->getNumberOfNodes(),-1); traceMapping_branch(tree1,tree2,children1[0],1,children2[0],1,predecessors1,predecessors2,depth1,depth2,memT,mapping); + dataType cost_mapping = 0; for(auto m : mapping){ if(writeOptimalBranchDecomposition_ && m.first.first >=0 && m.first.second >=0){ tree1->getNode(m.first.first)->setOrigin(m.first.second); tree1->getNode(m.first.second)->setOrigin(m.first.first); + linkedNodes1[m.first.first] = m.first.second; + linkedNodes1[m.first.second] = m.first.first; } if(writeOptimalBranchDecomposition_ && m.second.first >=0 && m.second.second >=0){ tree2->getNode(m.second.first)->setOrigin(m.second.second); tree2->getNode(m.second.second)->setOrigin(m.second.first); + linkedNodes2[m.second.first] = m.second.second; + linkedNodes2[m.second.second] = m.second.first; } dataType cost = this->baseMetric_ == 0 ? editCost_Wasserstein1( m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2) @@ -621,8 +628,9 @@ namespace ttk { m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2) : editCost_Shifting( m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2); - //std::cout << "(" << m.first.first << " " << m.first.second << ") - (" << m.second.first << " " << m.second.second << ") : " << cost << std::endl; - std::cout << "(" << tree1->getValue(m.first.first) << " " << tree1->getValue(m.first.second) << ") - (" << tree2->getValue(m.second.first) << " " << tree2->getValue(m.second.second) << ") : " << cost << std::endl; + cost_mapping += cost; + std::cout << "(" << m.first.first << " " << m.first.second << ") - (" << m.second.first << " " << m.second.second << ") : " << cost << std::endl; + //std::cout << "(" << tree1->getValue(m.first.first) << " " << tree1->getValue(m.first.second) << ") - (" << tree2->getValue(m.second.first) << " " << tree2->getValue(m.second.second) << ") : " << cost << std::endl; if(m.first.first == -1) continue; if(m.first.second == -1) continue; if(m.second.first == -1) continue; @@ -630,10 +638,20 @@ namespace ttk { matchedNodes[m.first.first] = m.second.first; matchedNodes[m.first.second] = m.second.second; } + std::cout << "Pairs Tree 1:\n"; + for(int i=0; i=0) outputMatching->emplace_back(std::make_tuple(i,matchedNodes[i], 0.0)); } + std::cout << res << " " << cost_mapping << std::endl; + } return squared_ ? std::sqrt(res) : res; @@ -675,6 +693,7 @@ namespace ttk { if(tree1->getNumberOfChildren(curr1) == 0) { mapping.emplace_back(std::make_pair( std::make_pair(curr1, parent1), std::make_pair(-1, -1))); + return; } //----------------------------------------------------------------------- // If first subtree has more than one branch, try all decompositions @@ -700,10 +719,11 @@ namespace ttk { predecessors1, predecessors2, depth1, depth2, memT, mapping); } + return; } } + this->printErr("Mapping traceback not correct."); } - return; } //=============================================================================== @@ -719,6 +739,7 @@ namespace ttk { if(tree2->getNumberOfChildren(curr2) == 0) { mapping.emplace_back(std::make_pair( std::make_pair(-1, -1), std::make_pair(curr2, parent2))); + return; } //----------------------------------------------------------------------- // If first subtree has more than one branch, try all decompositions @@ -744,10 +765,11 @@ namespace ttk { predecessors1, predecessors2, depth1, depth2, memT, mapping); } + return; } } + this->printErr("Mapping traceback not correct."); } - return; } std::vector children1; @@ -898,12 +920,14 @@ namespace ttk { } else { for(auto child1_mb : children1) { - auto topo1_ = children1; + std::vector topo1_; + tree1->getChildren(curr1, topo1_); topo1_.erase( std::remove(topo1_.begin(), topo1_.end(), child1_mb), topo1_.end()); for(auto child2_mb : children2) { - auto topo2_ = children2; + std::vector topo2_; + tree1->getChildren(curr2, topo2_); topo2_.erase( std::remove(topo2_.begin(), topo2_.end(), child2_mb), topo2_.end()); @@ -964,6 +988,14 @@ namespace ttk { traceMapping_branch(tree1, tree2, n1, 1, n2, 1, predecessors1, predecessors2, depth1, depth2, memT, mapping); + else if(n1 >= 0) + traceMapping_branch(tree1, tree2, n1, 1, nn2, 0, + predecessors1, predecessors2, depth1, depth2, + memT, mapping); + else if(n2 >= 0) + traceMapping_branch(tree1, tree2, nn1, 0, n2, 1, + predecessors1, predecessors2, depth1, depth2, + memT, mapping); } return; } @@ -1026,6 +1058,7 @@ namespace ttk { return; } } + this->printErr("Mapping traceback not correct"); } } }; From 1362fc2049b0031674e30930f77666cb2236b7a3 Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Mon, 21 Nov 2022 16:56:13 +0100 Subject: [PATCH 08/72] Branch Mapping Distance fixed. --- .../BranchMappingDistance.h | 32 +++++++++------- .../mergeTreeClustering/PathMappingDistance.h | 37 +++++++++++++++++-- .../ttkMergeTreeClustering.cpp | 13 ++++--- 3 files changed, 58 insertions(+), 24 deletions(-) diff --git a/core/base/mergeTreeClustering/BranchMappingDistance.h b/core/base/mergeTreeClustering/BranchMappingDistance.h index 164eb8df4e..f189464735 100644 --- a/core/base/mergeTreeClustering/BranchMappingDistance.h +++ b/core/base/mergeTreeClustering/BranchMappingDistance.h @@ -498,12 +498,14 @@ namespace ttk { + memT[child11 + 1 * dim2 + child22 * dim3 + 1 * dim4]); } else { for(auto child1_mb : children1) { - auto topo1_ = children1; + std::vector topo1_; + tree1->getChildren(curr1, topo1_); topo1_.erase( std::remove(topo1_.begin(), topo1_.end(), child1_mb), topo1_.end()); for(auto child2_mb : children2) { - auto topo2_ = children2; + std::vector topo2_; + tree2->getChildren(curr2, topo2_); topo2_.erase( std::remove(topo2_.begin(), topo2_.end(), child2_mb), topo2_.end()); @@ -628,9 +630,11 @@ namespace ttk { m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2) : editCost_Shifting( m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2); - cost_mapping += cost; - std::cout << "(" << m.first.first << " " << m.first.second << ") - (" << m.second.first << " " << m.second.second << ") : " << cost << std::endl; - //std::cout << "(" << tree1->getValue(m.first.first) << " " << tree1->getValue(m.first.second) << ") - (" << tree2->getValue(m.second.first) << " " << tree2->getValue(m.second.second) << ") : " << cost << std::endl; + dataType cost_ = editCost_Wasserstein1( + m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2); + cost_mapping += cost_; + std::cout << "(" << m.first.first << " " << m.first.second << ") - (" << m.second.first << " " << m.second.second << ") : " << cost << " " << cost_;// << std::endl; + std::cout << "; (" << tree1->getValue(m.first.first) << " " << tree1->getValue(m.first.second) << ") - (" << tree2->getValue(m.second.first) << " " << tree2->getValue(m.second.second) << ")" << std::endl; if(m.first.first == -1) continue; if(m.first.second == -1) continue; if(m.second.first == -1) continue; @@ -638,14 +642,14 @@ namespace ttk { matchedNodes[m.first.first] = m.second.first; matchedNodes[m.first.second] = m.second.second; } - std::cout << "Pairs Tree 1:\n"; - for(int i=0; i=0) outputMatching->emplace_back(std::make_tuple(i,matchedNodes[i], 0.0)); } @@ -927,7 +931,7 @@ namespace ttk { topo1_.end()); for(auto child2_mb : children2) { std::vector topo2_; - tree1->getChildren(curr2, topo2_); + tree2->getChildren(curr2, topo2_); topo2_.erase( std::remove(topo2_.begin(), topo2_.end(), child2_mb), topo2_.end()); diff --git a/core/base/mergeTreeClustering/PathMappingDistance.h b/core/base/mergeTreeClustering/PathMappingDistance.h index 43e4120e8e..6e4020a264 100644 --- a/core/base/mergeTreeClustering/PathMappingDistance.h +++ b/core/base/mergeTreeClustering/PathMappingDistance.h @@ -352,13 +352,42 @@ namespace ttk { persistenceThresholding(tree2, persistenceThreshold_); // - Merge saddle points according epsilon - std::vector> treeNodeMerged1( tree1->getNumberOfNodes() ); - std::vector> treeNodeMerged2( tree2->getNumberOfNodes() ); if(not isPersistenceDiagram_) { - if(epsilonTree1_ != 0) + treesNodeCorr_.resize(2); + if(epsilonTree1_ != 0){ + std::vector> treeNodeMerged1( tree1->getNumberOfNodes() ); mergeSaddle(tree1, epsilonTree1_, treeNodeMerged1); - if(epsilonTree2_ != 0) + for(int i=0; igetNode(j)->getOrigin(); + tree1->getNode(j)->setOrigin(i); + tree1->getNode(nodeToDelete)->setOrigin(-1); + } + } + ftm::cleanMergeTree(tree1, treesNodeCorr_[0], true); + } + else{ + std::vector nodeCorr1(tree1->getNumberOfNodes()); + for(ttk::SimplexId i=0; i> treeNodeMerged2( tree2->getNumberOfNodes() ); mergeSaddle(tree2, epsilonTree2_, treeNodeMerged2); + for(int i=0; igetNode(j)->getOrigin(); + tree2->getNode(j)->setOrigin(i); + tree2->getNode(nodeToDelete)->setOrigin(-1); + } + } + ftm::cleanMergeTree(tree2, treesNodeCorr_[1], true); + } + else{ + std::vector nodeCorr2(tree2->getNumberOfNodes()); + for(ttk::SimplexId i=0; idebugLevel_); distance = pathDist.editDistance_path(intermediateTrees[0], intermediateTrees[1], &outputMatching); + trees1NodeCorrMesh = pathDist.getTreesNodeCorr(); - std::vector nodeCorr1(intermediateTrees[0]->getNumberOfNodes()); - std::vector nodeCorr2(intermediateTrees[1]->getNumberOfNodes()); - for(ttk::SimplexId i=0; i>{nodeCorr1,nodeCorr2}; + // std::vector nodeCorr1(intermediateTrees[0]->getNumberOfNodes()); + // std::vector nodeCorr2(intermediateTrees[1]->getNumberOfNodes()); + // for(ttk::SimplexId i=0; i>{nodeCorr1,nodeCorr2}; finalDistances = std::vector{distance}; } } else { From 29be19899eb24cb22a9dae08e33764971ccc6a89 Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Thu, 24 Nov 2022 12:03:07 +0100 Subject: [PATCH 09/72] Some work on barycenters with path mapping distance. --- .../BranchMappingDistance.h | 16 +- .../mergeTreeClustering/MergeTreeBarycenter.h | 238 ++++++++++++++++-- .../mergeTreeClustering/PathMappingDistance.h | 36 ++- .../ttkMergeTreeClustering.cpp | 45 ++-- paraview/xmls/MergeTreeClustering.xml | 32 ++- 5 files changed, 290 insertions(+), 77 deletions(-) diff --git a/core/base/mergeTreeClustering/BranchMappingDistance.h b/core/base/mergeTreeClustering/BranchMappingDistance.h index f189464735..d65fd36382 100644 --- a/core/base/mergeTreeClustering/BranchMappingDistance.h +++ b/core/base/mergeTreeClustering/BranchMappingDistance.h @@ -677,12 +677,12 @@ namespace ttk { std::vector, std::pair>> &mapping) { - size_t nn1 = tree1->getNumberOfNodes(); - size_t nn2 = tree2->getNumberOfNodes(); - size_t dim1 = 1; - size_t dim2 = (nn1 + 1) * dim1; - size_t dim3 = (depth1 + 1) * dim2; - size_t dim4 = (nn2 + 1) * dim3; + int nn1 = tree1->getNumberOfNodes(); + int nn2 = tree2->getNumberOfNodes(); + int dim1 = 1; + int dim2 = (nn1 + 1) * dim1; + int dim3 = (depth1 + 1) * dim2; + int dim4 = (nn2 + 1) * dim3; //=============================================================================== // If second tree empty, track optimal branch decomposition of first tree @@ -982,10 +982,10 @@ namespace ttk { predecessors1, predecessors2, depth1, depth2, memT, mapping); for(auto m : matching){ - int n1 = std::get<0>(m) < topo1_.size() + int n1 = std::get<0>(m) < static_cast(topo1_.size()) ? topo1_[std::get<0>(m)] : -1; - int n2 = std::get<1>(m) < topo2_.size() + int n2 = std::get<1>(m) < static_cast(topo2_.size()) ? topo2_[std::get<1>(m)] : -1; if(n1 >= 0 && n2 >= 0) diff --git a/core/base/mergeTreeClustering/MergeTreeBarycenter.h b/core/base/mergeTreeClustering/MergeTreeBarycenter.h index 2b3bc9191b..030da2062e 100644 --- a/core/base/mergeTreeClustering/MergeTreeBarycenter.h +++ b/core/base/mergeTreeClustering/MergeTreeBarycenter.h @@ -22,6 +22,7 @@ #include "MergeTreeBase.h" #include "MergeTreeDistance.h" +#include "PathMappingDistance.h" namespace ttk { @@ -48,6 +49,9 @@ namespace ttk { bool preprocess_ = true; bool postprocess_ = true; + + int pathMetric_ = 0; + int baseModule_ = 0; // Output std::vector finalDistances_; @@ -119,6 +123,14 @@ namespace ttk { return finalDistances_; } + void setBaseModule(int m) { + baseModule_ = m; + } + + void setPathMetric(int m) { + pathMetric_ = m; + } + /** * Implementation of the algorithm. */ @@ -802,6 +814,124 @@ namespace ttk { ftm::cleanMergeTree(baryMergeTree); } + template + void updateBarycenterTree_path( + std::vector &trees, + ftm::MergeTree &baryMergeTree, + std::vector &alphas, + std::vector,std::pair>>> + &matchings) { + ftm::FTMTree_MT* baryTree = &(baryMergeTree.tree); + + // delete not-matched nodes in barycenter + std::vector baryNodesMatched(baryTree->getNumberOfNodes(),false); + for(unsigned int i=0; igetNumberOfNodes(); i++){ + if(not baryNodesMatched[i]){ + baryTree->getNode(i)->setOrigin(-1); + baryTree->deleteNode(i); + } + } + + // relabel paths + std::vector> parentEdgeLengths(baryTree->getNumberOfNodes()); + for(unsigned int i=0; igetValue(match.first.first); + dataType bv2 = baryTree->getValue(match.first.second); + dataType tv1 = tree->getValue(match.second.first); + dataType tv2 = tree->getValue(match.second.second); + dataType pathRangeB = bv1 > bv2 ? bv1 - bv2 : bv2 - bv1; + dataType pathRangeT = tv1 > tv2 ? tv1 - tv2 : tv2 - tv1; + ftm::idNode currB = baryTree->getValue(match.first.first); + ftm::idNode lastB = match.first.first; + while(lastB != match.first.second){ + dataType currValueB = baryTree->getValue(currB); + dataType lastValueB = baryTree->getValue(lastB); + dataType relativeValueB = lastValueB > currValueB ? lastValueB - currValueB : currValueB - lastValueB; + relativeValueB = relativeValueB/pathRangeB; + parentEdgeLengths[lastB].emplace_back(relativeValueB * pathRangeT); + // continue iteration + lastB = currB; + currB = baryTree->getParentSafe(currB); + } + } + } + std::queue q; + q.push(baryTree->getRoot()); + std::vector newScalars(baryTree->getNumberOfNodes(),0); + newScalars[baryTree->getRoot()] = baryTree->getValue(baryTree->getRoot()); + while(!q.empty()){ + auto curr = q.front(); + q.pop(); + std::vector children; + baryTree->getChildren(curr,children); + for(auto child : children){ + q.emplace(child); + dataType avgEdgeLength = 0; + for(auto l : parentEdgeLengths[child]){ + avgEdgeLength += l; + } + avgEdgeLength = avgEdgeLength/static_cast(trees.size()); + newScalars[child] = newScalars[curr] + avgEdgeLength; + } + } + setTreeScalars(baryMergeTree, newScalars); + + // insert new nodes (ToDo!!) + // for(unsigned int i=0; igetValue(match.first.first); + // dataType bv2 = baryTree->getValue(match.first.second); + // dataType tv1 = tree->getValue(match.second.first); + // dataType tv2 = tree->getValue(match.second.second); + // dataType pathRangeB = bv1 > bv2 ? bv1 - bv2 : bv2 - bv1; + // dataType pathRangeT = tv1 > tv2 ? tv1 - tv2 : tv2 - tv1; + // ftm::idNode currB = baryTree->getValue(match.first.first); + // ftm::idNode currT = tree->getValue(match.second.first); + // ftm::idNode lastB = match.first.first; + // ftm::idNode lastT = match.second.first; + // while(currB != match.first.second && currT != match.second.second){ + // dataType currValueB = baryTree->getValue(currB); + // dataType currValueT = tree->getValue(currT); + // dataType relativeValueB = bv1 > bv2 ? bv1 - currValueB : currValueB - bv1; + // dataType relativeValueT = tv1 > tv2 ? tv1 - currValueT : currValueT - tv1; + // relativeValueB = relativeValueB/pathRangeB; + // relativeValueT = relativeValueT/pathRangeT; + // // if next node in tree, ignore + // if(relativeValueB < relativeValueT){ + // // continue iteration + // lastB = currB; + // currB = baryTree->getParentSafe(currB); + // } + // // if next node in tree, ignore + // else if(relativeValueB > relativeValueT){ + // // continue iteration + // lastT = currT; + // currT = tree->getParentSafe(currT); + // } + // else{ + // // this should not happen + // printErr("Impossible Matching behaviour.") + // lastB = currB; + // lastT = currT; + // currB = baryTree->getParentSafe(currB); + // currT = tree->getParentSafe(currT); + // } + // } + // } + // } + + ftm::cleanMergeTree(baryMergeTree); + } + template void updateBarycenterTree( std::vector &trees, @@ -818,6 +948,24 @@ namespace ttk { // ------------------------------------------------------------------------ // Assignment // ------------------------------------------------------------------------ + template + void computeOneDistance_pathMapping( + ftm::FTMTree_MT *tree, + ftm::FTMTree_MT *baryTree, + std::vector,std::pair>> &matching, + dataType &distance) { + // Timer t_distance; + PathMappingDistance pathDistance; + pathDistance.setDebugLevel(std::min(debugLevel_, 2)); + pathDistance.setPreprocess(false); + pathDistance.setAssignmentSolver(assignmentSolverID_); + pathDistance.setThreadNumber(this->threadNumber_); + pathDistance.setDistanceSquared(false); // squared root + pathDistance.setComputeMapping(true); + distance + = pathDistance.editDistance_path(baryTree, tree, &matching); + } + template void computeOneDistance( ftm::FTMTree_MT *tree, @@ -827,31 +975,44 @@ namespace ttk { bool useDoubleInput = false, bool isFirstInput = true) { // Timer t_distance; - MergeTreeDistance mergeTreeDistance; - mergeTreeDistance.setDebugLevel(std::min(debugLevel_, 2)); - mergeTreeDistance.setProgressiveComputation(false); - mergeTreeDistance.setPreprocess(false); - mergeTreeDistance.setPostprocess(false); - mergeTreeDistance.setBranchDecomposition(true); - mergeTreeDistance.setNormalizedWasserstein(normalizedWasserstein_); - mergeTreeDistance.setNormalizedWassersteinReg(normalizedWassersteinReg_); - mergeTreeDistance.setRescaledWasserstein(rescaledWasserstein_); - mergeTreeDistance.setKeepSubtree(keepSubtree_); - mergeTreeDistance.setAssignmentSolver(assignmentSolverID_); - mergeTreeDistance.setIsCalled(true); - mergeTreeDistance.setThreadNumber(this->threadNumber_); - mergeTreeDistance.setDistanceSquared(true); // squared root - mergeTreeDistance.setNodePerTask(nodePerTask_); - if(useDoubleInput) { - double weight = mixDistancesMinMaxPairWeight(isFirstInput); - mergeTreeDistance.setMinMaxPairWeight(weight); + if(baseModule_ == 2){ + PathMappingDistance pathDistance; + pathDistance.setDebugLevel(std::min(debugLevel_, 2)); + pathDistance.setPreprocess(false); + pathDistance.setAssignmentSolver(assignmentSolverID_); + pathDistance.setThreadNumber(this->threadNumber_); + pathDistance.setDistanceSquared(false); // squared root + pathDistance.setComputeMapping(false); + distance + = pathDistance.editDistance_path(baryTree, tree); + } + else{ + MergeTreeDistance mergeTreeDistance; + mergeTreeDistance.setDebugLevel(std::min(debugLevel_, 2)); + mergeTreeDistance.setProgressiveComputation(false); + mergeTreeDistance.setPreprocess(false); + mergeTreeDistance.setPostprocess(false); + mergeTreeDistance.setBranchDecomposition(true); + mergeTreeDistance.setNormalizedWasserstein(normalizedWasserstein_); + mergeTreeDistance.setNormalizedWassersteinReg(normalizedWassersteinReg_); + mergeTreeDistance.setRescaledWasserstein(rescaledWasserstein_); + mergeTreeDistance.setKeepSubtree(keepSubtree_); + mergeTreeDistance.setAssignmentSolver(assignmentSolverID_); + mergeTreeDistance.setIsCalled(true); + mergeTreeDistance.setThreadNumber(this->threadNumber_); + mergeTreeDistance.setDistanceSquared(true); // squared root + mergeTreeDistance.setNodePerTask(nodePerTask_); + if(useDoubleInput) { + double weight = mixDistancesMinMaxPairWeight(isFirstInput); + mergeTreeDistance.setMinMaxPairWeight(weight); + } + /*if(progressiveBarycenter_){ + mergeTreeDistance.setAuctionNoRounds(1); + mergeTreeDistance.setAuctionEpsilonDiviser(NoIteration-1); + }*/ + distance + = mergeTreeDistance.computeDistance(baryTree, tree, matching); } - /*if(progressiveBarycenter_){ - mergeTreeDistance.setAuctionNoRounds(1); - mergeTreeDistance.setAuctionEpsilonDiviser(NoIteration-1); - }*/ - distance - = mergeTreeDistance.computeDistance(baryTree, tree, matching); std::stringstream ss, ss2; ss << "distance tree : " << distance; printMsg(ss.str(), debug::Priority::VERBOSE); @@ -887,6 +1048,19 @@ namespace ttk { isFirstInput); } + template + void assignment_path( + std::vector &trees, + ftm::MergeTree &baryMergeTree, + std::vector,std::pair>>> + &matchings, + std::vector &distances) { + for(unsigned int i = 0; i < trees.size(); ++i){ + computeOneDistance_pathMapping(trees[i], &(baryMergeTree.tree), matchings[i], + distances[i]); + } + } + template void assignment( std::vector &trees, @@ -1067,9 +1241,16 @@ namespace ttk { // --- Assignment std::vector>> matchings(trees.size()); + std::vector,std::pair>>> + matchings_path(trees.size()); std::vector distances(trees.size(), -1); Timer t_assignment; - assignment(trees, baryMergeTree, matchings, distances); + if(baseModule_ == 2){ + assignment_path(trees, baryMergeTree, matchings_path, distances); + } + else{ + assignment(trees, baryMergeTree, matchings, distances); + } Timer t_addDeletedNodes; if(progressiveBarycenter_) addScaledDeletedNodesCost( @@ -1082,7 +1263,12 @@ namespace ttk { // --- Update Timer t_update; - updateBarycenterTree(trees, baryMergeTree, alphas, matchings); + if(baseModule_ == 2){ + updateBarycenterTree_path(trees, baryMergeTree, alphas, matchings_path); + } + else{ + updateBarycenterTree(trees, baryMergeTree, alphas, matchings); + } auto t_update_time = t_update.getElapsedTime(); baryTree = &(baryMergeTree.tree); printMsg("Update", 1, t_update_time, this->threadNumber_, diff --git a/core/base/mergeTreeClustering/PathMappingDistance.h b/core/base/mergeTreeClustering/PathMappingDistance.h index 6e4020a264..ef2725ab5d 100644 --- a/core/base/mergeTreeClustering/PathMappingDistance.h +++ b/core/base/mergeTreeClustering/PathMappingDistance.h @@ -339,7 +339,7 @@ namespace ttk { } template - dataType editDistance_path(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2, std::vector> *outputMatching=nullptr) { + dataType editDistance_path(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2, std::vector,std::pair>> *outputMatching) { // optional preprocessing @@ -357,7 +357,7 @@ namespace ttk { if(epsilonTree1_ != 0){ std::vector> treeNodeMerged1( tree1->getNumberOfNodes() ); mergeSaddle(tree1, epsilonTree1_, treeNodeMerged1); - for(int i=0; igetNode(j)->getOrigin(); tree1->getNode(j)->setOrigin(i); @@ -368,13 +368,13 @@ namespace ttk { } else{ std::vector nodeCorr1(tree1->getNumberOfNodes()); - for(ttk::SimplexId i=0; i> treeNodeMerged2( tree2->getNumberOfNodes() ); mergeSaddle(tree2, epsilonTree2_, treeNodeMerged2); - for(int i=0; igetNode(j)->getOrigin(); tree2->getNode(j)->setOrigin(i); @@ -385,7 +385,7 @@ namespace ttk { } else{ std::vector nodeCorr2(tree2->getNumberOfNodes()); - for(ttk::SimplexId i=0; iclear(); - std::vector matchedNodes(tree1->getNumberOfNodes(),-1); - std::vector,std::pair>> mapping; - traceMapping_path(tree1,tree2,children1[0],1,children2[0],1,predecessors1,predecessors2,depth1,depth2,memT,mapping); + traceMapping_path(tree1,tree2,children1[0],1,children2[0],1,predecessors1,predecessors2,depth1,depth2,memT,*outputMatching); + } + + return squared_ ? std::sqrt(res) : res; + } + + template + dataType editDistance_path(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2, std::vector> *outputMatching){ + + std::vector matchedNodes(tree1->getNumberOfNodes(),-1); + std::vector,std::pair>> mapping; + dataType res = editDistance_path(tree1,tree2,&mapping); + if(computeMapping_ && outputMatching){ + outputMatching->clear(); for(auto m : mapping){ matchedNodes[m.first.first] = m.second.first; matchedNodes[m.first.second] = m.second.second; @@ -698,10 +709,15 @@ namespace ttk { for(ftm::idNode i=0; i=0) outputMatching->emplace_back(std::make_tuple(i,matchedNodes[i], 0.0)); } - } - return squared_ ? std::sqrt(res) : res; + return res; + + } + + template + dataType editDistance_path(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2){ + return editDistance_path(tree1,tree2,(std::vector,std::pair>>*) nullptr); } }; } // namespace ttk diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index da4da7b7ec..b2cd8c1023 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -132,9 +132,8 @@ int ttkMergeTreeClustering::RequestData(vtkInformation *ttkNotUsed(request), } // filter out new backends (not yet supported) - if(baseModule != 0 && ComputeBarycenter) { - printErr("Invalid Backend chosen. Path Mapping Distance and Branch Mapping " - "Distance not yet supported for Barycenter computation. Canceling computation."); + if(baseModule == 1 && ComputeBarycenter) { + printErr("Invalid Backend chosen. Branch Mapping Distance not yet supported for Barycenter computation. Canceling computation."); return 1; } @@ -308,8 +307,8 @@ int ttkMergeTreeClustering::runCompute( std::vector nodeCorr1(intermediateTrees[0]->getNumberOfNodes()); std::vector nodeCorr2(intermediateTrees[1]->getNumberOfNodes()); - for(ttk::SimplexId i=0; i>{nodeCorr1,nodeCorr2}; finalDistances = std::vector{distance}; } @@ -351,23 +350,29 @@ int ttkMergeTreeClustering::runCompute( mergeTreeBarycenter.setEpsilon2Tree2(Epsilon2Tree2); mergeTreeBarycenter.setEpsilon3Tree1(Epsilon3Tree1); mergeTreeBarycenter.setEpsilon3Tree2(Epsilon3Tree2); - mergeTreeBarycenter.setBranchDecomposition(BranchDecomposition); - mergeTreeBarycenter.setPersistenceThreshold(PersistenceThreshold); - mergeTreeBarycenter.setNormalizedWasserstein(NormalizedWasserstein); - mergeTreeBarycenter.setKeepSubtree(KeepSubtree); - mergeTreeBarycenter.setUseMinMaxPair(UseMinMaxPair); - mergeTreeBarycenter.setAddNodes(AddNodes); - mergeTreeBarycenter.setDeterministic(Deterministic); - mergeTreeBarycenter.setBarycenterSizeLimitPercent( - BarycenterSizeLimitPercent); - mergeTreeBarycenter.setAlpha(Alpha); - mergeTreeBarycenter.setPostprocess(OutputTrees); - mergeTreeBarycenter.setDeleteMultiPersPairs(DeleteMultiPersPairs); - mergeTreeBarycenter.setEpsilon1UseFarthestSaddle( - Epsilon1UseFarthestSaddle); - mergeTreeBarycenter.setIsPersistenceDiagram(IsPersistenceDiagram); mergeTreeBarycenter.setThreadNumber(this->threadNumber_); mergeTreeBarycenter.setDebugLevel(this->debugLevel_); + mergeTreeBarycenter.setBaseModule(this->baseModule); + mergeTreeBarycenter.setIsPersistenceDiagram(IsPersistenceDiagram); + mergeTreeBarycenter.setAlpha(Alpha); + mergeTreeBarycenter.setDeterministic(Deterministic); + if(baseModule==2){ + mergeTreeBarycenter.setPathMetric(this->pathMetric); + } + else{ + mergeTreeBarycenter.setBranchDecomposition(BranchDecomposition); + mergeTreeBarycenter.setPersistenceThreshold(PersistenceThreshold); + mergeTreeBarycenter.setNormalizedWasserstein(NormalizedWasserstein); + mergeTreeBarycenter.setKeepSubtree(KeepSubtree); + mergeTreeBarycenter.setUseMinMaxPair(UseMinMaxPair); + mergeTreeBarycenter.setAddNodes(AddNodes); + mergeTreeBarycenter.setBarycenterSizeLimitPercent( + BarycenterSizeLimitPercent); + mergeTreeBarycenter.setPostprocess(OutputTrees); + mergeTreeBarycenter.setDeleteMultiPersPairs(DeleteMultiPersPairs); + mergeTreeBarycenter.setEpsilon1UseFarthestSaddle( + Epsilon1UseFarthestSaddle); + } mergeTreeBarycenter.execute( intermediateMTrees, outputMatchingBarycenter[0], barycenters[0]); diff --git a/paraview/xmls/MergeTreeClustering.xml b/paraview/xmls/MergeTreeClustering.xml index 3b2b7f3bc5..4f31e9441b 100644 --- a/paraview/xmls/MergeTreeClustering.xml +++ b/paraview/xmls/MergeTreeClustering.xml @@ -146,28 +146,34 @@ Online examples: - - - - + + + + + + + + value="0" /> - + mode="visibility" + property="Backend" + value="4" /> + Date: Thu, 24 Nov 2022 15:12:03 +0100 Subject: [PATCH 10/72] Some work on barycenters with path mapping distance. --- .../mergeTreeClustering/MergeTreeBarycenter.h | 76 ++++++++++++++++--- .../ttkMergeTreeClustering.cpp | 8 +- 2 files changed, 73 insertions(+), 11 deletions(-) diff --git a/core/base/mergeTreeClustering/MergeTreeBarycenter.h b/core/base/mergeTreeClustering/MergeTreeBarycenter.h index 030da2062e..c0ae6e0f9e 100644 --- a/core/base/mergeTreeClustering/MergeTreeBarycenter.h +++ b/core/base/mergeTreeClustering/MergeTreeBarycenter.h @@ -828,7 +828,7 @@ namespace ttk { for(unsigned int i=0; igetNumberOfNodes(); i++){ @@ -849,7 +849,7 @@ namespace ttk { dataType tv2 = tree->getValue(match.second.second); dataType pathRangeB = bv1 > bv2 ? bv1 - bv2 : bv2 - bv1; dataType pathRangeT = tv1 > tv2 ? tv1 - tv2 : tv2 - tv1; - ftm::idNode currB = baryTree->getValue(match.first.first); + ftm::idNode currB = baryTree->getParentSafe(match.first.first); ftm::idNode lastB = match.first.first; while(lastB != match.first.second){ dataType currValueB = baryTree->getValue(currB); @@ -1312,8 +1312,26 @@ namespace ttk { printMsg("Final assignment"); std::vector distances(trees.size(), -1); - assignment(trees, baryMergeTree, finalMatchings, distances, - finalAsgnDoubleInput, finalAsgnFirstInput); + if(baseModule_ == 2){ + std::vector,std::pair>>> + matchings_path(trees.size()); + assignment_path(trees, baryMergeTree, matchings_path, distances); + for(unsigned int i=0; i matchedNodes(trees[i]->getNumberOfNodes(),-1); + for(auto m : matchings_path[i]){ + matchedNodes[m.first.first] = m.second.first; + matchedNodes[m.first.second] = m.second.second; + } + for(ftm::idNode j=0; j=0) finalMatchings[i].emplace_back(std::make_tuple(j,matchedNodes[j], 0.0)); + } + } + } + else{ + assignment(trees, baryMergeTree, finalMatchings, distances, + finalAsgnDoubleInput, finalAsgnFirstInput); + } for(auto dist : distances) finalDistances_.push_back(dist); dataType currentFrechetEnergy = 0; @@ -1328,7 +1346,7 @@ namespace ttk { debug::LineMode::NEW, debug::Priority::INFO); // std::cout << "Bary Distance Time = " << allDistanceTime_ << std::endl; - if(trees.size() == 2 and not isCalled_) + if(trees.size() == 2 and not isCalled_ && baseModule_!=2) verifyBarycenterTwoTrees( trees, baryMergeTree, finalMatchings, distances); @@ -1352,11 +1370,45 @@ namespace ttk { // --- Preprocessing if(preprocess_) { treesNodeCorr_.resize(trees.size()); - for(unsigned int i = 0; i < trees.size(); ++i) - preprocessingPipeline(trees[i], epsilonTree2_, - epsilon2Tree2_, epsilon3Tree2_, - branchDecomposition_, useMinMaxPair_, - cleanTree_, treesNodeCorr_[i]); + for(unsigned int i = 0; i < trees.size(); ++i){ + if(baseModule_==2){ + ftm::FTMTree_MT *tree = &(trees[i].tree); + preprocessTree(tree, true); + + // - Delete null persistence pairs and persistence thresholding + persistenceThresholding(tree, persistenceThreshold_); + + // - Merge saddle points according epsilon + if(not isPersistenceDiagram_) { + treesNodeCorr_.resize(2); + if(epsilonTree2_ != 0){ + std::vector> treeNodeMerged( tree->getNumberOfNodes() ); + mergeSaddle(tree, epsilonTree2_, treeNodeMerged); + for(unsigned int i=0; igetNode(j)->getOrigin(); + tree->getNode(j)->setOrigin(i); + tree->getNode(nodeToDelete)->setOrigin(-1); + } + } + ftm::cleanMergeTree(trees[i], treesNodeCorr_[i], true); + } + else{ + std::vector nodeCorr(tree->getNumberOfNodes()); + for(unsigned int i=0; i(tree, false); + } + else{ + preprocessingPipeline(trees[i], epsilonTree2_, + epsilon2Tree2_, epsilon3Tree2_, + branchDecomposition_, useMinMaxPair_, + cleanTree_, treesNodeCorr_[i]); + } + } printTreesStats(trees); } @@ -1368,6 +1420,10 @@ namespace ttk { // --- Execute computeBarycenter(treesT, baryMergeTree, alphas, finalMatchings, finalAsgnDoubleInput, finalAsgnFirstInput); + + if(baseModule_==2){ + preprocessTree(&(baryMergeTree.tree),true); + } // --- Postprocessing if(postprocess_) { diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index b2cd8c1023..04b5a0d188 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -356,12 +356,18 @@ int ttkMergeTreeClustering::runCompute( mergeTreeBarycenter.setIsPersistenceDiagram(IsPersistenceDiagram); mergeTreeBarycenter.setAlpha(Alpha); mergeTreeBarycenter.setDeterministic(Deterministic); + mergeTreeBarycenter.setPersistenceThreshold(PersistenceThreshold); if(baseModule==2){ mergeTreeBarycenter.setPathMetric(this->pathMetric); + mergeTreeBarycenter.setBranchDecomposition(false); + mergeTreeBarycenter.setNormalizedWasserstein(false); + mergeTreeBarycenter.setKeepSubtree(false); + mergeTreeBarycenter.setUseMinMaxPair(false); + mergeTreeBarycenter.setAddNodes(false); + mergeTreeBarycenter.setPostprocess(false); } else{ mergeTreeBarycenter.setBranchDecomposition(BranchDecomposition); - mergeTreeBarycenter.setPersistenceThreshold(PersistenceThreshold); mergeTreeBarycenter.setNormalizedWasserstein(NormalizedWasserstein); mergeTreeBarycenter.setKeepSubtree(KeepSubtree); mergeTreeBarycenter.setUseMinMaxPair(UseMinMaxPair); From 63e81ef2f6fa4f3cb8658619bd3232710430a407 Mon Sep 17 00:00:00 2001 From: MatPont Date: Fri, 2 Dec 2022 10:33:28 +0100 Subject: [PATCH 11/72] enable custom bd for branch mapping --- core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index 04b5a0d188..2ee024f92e 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -291,7 +291,8 @@ int ttkMergeTreeClustering::runCompute( branchDist.setAssignmentSolver(AssignmentSolver); branchDist.setSquared(false); branchDist.setComputeMapping(true); - branchDist.setWriteBD(false); + // branchDist.setWriteBD(false); + branchDist.setWriteBD(true); branchDist.setEpsilonTree1(EpsilonTree1); branchDist.setEpsilonTree2(EpsilonTree2); From 4c0c8f92ab573eb0bc06320ef2749a0fcd5c25fe Mon Sep 17 00:00:00 2001 From: MatPont Date: Fri, 2 Dec 2022 10:57:16 +0100 Subject: [PATCH 12/72] [PathMapping] change dummy node matching --- core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp | 5 +++++ core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index 04b5a0d188..cb7f3efef0 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -596,6 +596,7 @@ int ttkMergeTreeClustering::runOutput( visuMaker.setExcludeImportantPairsHigher(ExcludeImportantPairsHigher); visuMaker.setExcludeImportantPairsLower(ExcludeImportantPairsLower); visuMaker.setIsPersistenceDiagram(IsPersistenceDiagram); + visuMaker.setPathMappingLayout(baseModule==2); nodeCorr.clear(); // First tree @@ -700,6 +701,7 @@ int ttkMergeTreeClustering::runOutput( visuMakerMatching.setVtkOutputNode1(vtkOutputNode2); visuMakerMatching.setNodeCorr1(nodeCorr); visuMakerMatching.setDebugLevel(this->debugLevel_); + visuMakerMatching.setPathMappingLayout(baseModule==2); visuMakerMatching.makeMatchingOutput(tree1, tree2); @@ -803,6 +805,7 @@ int ttkMergeTreeClustering::runOutput( visuMaker.setDebugLevel(this->debugLevel_); visuMaker.setIsPersistenceDiagram(IsPersistenceDiagram); visuMaker.setIsPDSadMax(JoinSplitMixtureCoefficient == 0); + visuMaker.setPathMappingLayout(baseModule==2); visuMaker.makeTreesOutput( intermediateTrees, barycentersTree); @@ -920,6 +923,7 @@ int ttkMergeTreeClustering::runOutput( visuMakerBary.setDebugLevel(this->debugLevel_); visuMakerBary.setIsPersistenceDiagram(IsPersistenceDiagram); visuMakerBary.setIsPDSadMax(JoinSplitMixtureCoefficient == 0); + visuMakerBary.setPathMappingLayout(baseModule==2); visuMakerBary.makeTreesOutput( intermediateTrees, barycentersTree); @@ -995,6 +999,7 @@ int ttkMergeTreeClustering::runOutput( visuMakerMatching.setPrintTreeId(i); visuMakerMatching.setPrintClusterId(c); visuMakerMatching.setDebugLevel(this->debugLevel_); + visuMakerMatching.setPathMappingLayout(baseModule==2); visuMakerMatching.makeMatchingOutput( intermediateTrees, barycentersTree); diff --git a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h index 0995f5d8cb..dbe7c8a2f6 100644 --- a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h +++ b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h @@ -44,6 +44,7 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { bool outputTreeNodeIndex = false; bool isPersistenceDiagram = false; bool isPDSadMax = true; + bool pathMappingLayout = false; // Shift mode // -1: None ; 0: Star ; 1: Star Barycenter ; 2: Line ; 3: Double Line @@ -158,6 +159,10 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { void setIsPDSadMax(bool isSadMax) { isPDSadMax = isSadMax; } + + void setPathMappingLayout(bool pathLayout) { + pathMappingLayout = pathLayout; + } // Offset void setISampleOffset(int offset) { @@ -1108,7 +1113,7 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { SimplexId nextPointId = points->InsertNextPoint(point); treeSimplexId[node] = nextPointId; nodeCorr[i][node] = nextPointId; - if(dummyNode) + if(dummyNode and not pathMappingLayout) nodeCorr[i][node] = treeDummySimplexId[node]; if(isPersistenceDiagram) nodeCorr[i][node] = nextPointId; From 14c75feed33977f6667b8c33153767a1b7f5846e Mon Sep 17 00:00:00 2001 From: MatPont Date: Fri, 2 Dec 2022 12:10:44 +0100 Subject: [PATCH 13/72] [PlanarLayout] fix diff and offset for general branch decomposition --- core/base/planarGraphLayout/MergeTreeVisualization.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/core/base/planarGraphLayout/MergeTreeVisualization.h b/core/base/planarGraphLayout/MergeTreeVisualization.h index 0fc6dc1198..a80928c95e 100644 --- a/core/base/planarGraphLayout/MergeTreeVisualization.h +++ b/core/base/planarGraphLayout/MergeTreeVisualization.h @@ -370,8 +370,12 @@ namespace ttk { if(not rescaleTreesIndividually_) { // diff *= getNodePersistence(tree, treeRoot) / // refPersistence; - diff = tree->getNodePersistence(treeRoot); - offset = tree->getBirth(treeRoot); + dataType rootVal = tree->getValue(treeRoot); + dataType lowestNodeVal + = tree->getValue(tree->getLowestNode(treeRoot)); + diff = (rootVal > lowestNodeVal ? rootVal - lowestNodeVal + : lowestNodeVal - rootVal); + offset = std::min(rootVal, lowestNodeVal); } for(int i = 0; i < outNumberOfPoints; i += 2) { From f2aa0f0841963dd1184ee23b80542cb10badfefa Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Fri, 2 Dec 2022 16:32:40 +0100 Subject: [PATCH 14/72] first working version of path mapping barycenter --- .../mergeTreeClustering/MergeTreeBarycenter.h | 265 ++++++++++++++---- .../mergeTreeClustering/PathMappingDistance.h | 11 + 2 files changed, 221 insertions(+), 55 deletions(-) diff --git a/core/base/mergeTreeClustering/MergeTreeBarycenter.h b/core/base/mergeTreeClustering/MergeTreeBarycenter.h index c0ae6e0f9e..66058af5d3 100644 --- a/core/base/mergeTreeClustering/MergeTreeBarycenter.h +++ b/core/base/mergeTreeClustering/MergeTreeBarycenter.h @@ -285,8 +285,15 @@ namespace ttk { void initBarycenterTree(std::vector &trees, ftm::MergeTree &baryTree, bool distMinimizer = true) { - int bestIndex = getBestInitTreeIndex(trees, distMinimizer); - baryTree = ftm::copyMergeTree(trees[bestIndex], true); + //int bestIndex = getBestInitTreeIndex(trees, distMinimizer); + int bestIndex = trees.size()-1; + //baryTree = ftm::copyMergeTree(trees[bestIndex], true); + baryTree = ftm::copyMergeTree(trees[bestIndex], baseModule_!=2); + ftm::FTMTree_MT* bt = &(baryTree.tree); + std::cout << "Bary Root: " << bt->getRoot() << std::endl; + std::cout << "Tree Root: " << trees[bestIndex]->getRoot() << std::endl; + std::cout << "Bary Root Scalar Value: " << bt->getValue(bt->getRoot()) << std::endl; + std::cout << "Tree Root Scalar Value: " << trees[bestIndex]->getValue(trees[bestIndex]->getRoot()) << std::endl; limitSizeBarycenter(baryTree, trees); } @@ -823,16 +830,30 @@ namespace ttk { &matchings) { ftm::FTMTree_MT* baryTree = &(baryMergeTree.tree); - // delete not-matched nodes in barycenter + // compute matched and unmatched nodes for all trees and barycenter std::vector baryNodesMatched(baryTree->getNumberOfNodes(),false); + std::vector> treeNodesMatched(trees.size()); for(unsigned int i=0; igetNumberOfNodes(),false); for(auto match : matchings[i]){ baryNodesMatched[match.first.first] = true; baryNodesMatched[match.first.second] = true; + treeNodesMatched[i][match.second.first] = true; + treeNodesMatched[i][match.second.second] = true; + } + } + // compute size of new barycenter tree + int oldSize = baryTree->getNumberOfNodes(); + int newSize = baryTree->getNumberOfNodes(); + for(unsigned int i=0; igetNumberOfNodes(); i++){ if(not baryNodesMatched[i]){ + std::cout << "Node deleted: " << baryTree->getValue(i) << std::endl; baryTree->getNode(i)->setOrigin(-1); baryTree->deleteNode(i); } @@ -849,6 +870,7 @@ namespace ttk { dataType tv2 = tree->getValue(match.second.second); dataType pathRangeB = bv1 > bv2 ? bv1 - bv2 : bv2 - bv1; dataType pathRangeT = tv1 > tv2 ? tv1 - tv2 : tv2 - tv1; + std::cout << "Path matched: (" << match.first.first << "," << match.first.second << ")-(" << match.second.first << "," << match.second.second << ") ; " << pathRangeB << "-" << pathRangeT << std::endl; ftm::idNode currB = baryTree->getParentSafe(match.first.first); ftm::idNode lastB = match.first.first; while(lastB != match.first.second){ @@ -867,6 +889,7 @@ namespace ttk { q.push(baryTree->getRoot()); std::vector newScalars(baryTree->getNumberOfNodes(),0); newScalars[baryTree->getRoot()] = baryTree->getValue(baryTree->getRoot()); + dataType maxScalar = std::numeric_limits::min(); while(!q.empty()){ auto curr = q.front(); q.pop(); @@ -880,56 +903,189 @@ namespace ttk { } avgEdgeLength = avgEdgeLength/static_cast(trees.size()); newScalars[child] = newScalars[curr] + avgEdgeLength; + std::cout << "Node relabel " << child << ": " << baryTree->getValue(child) << "->" << newScalars[child] << std::endl; + if(newScalars[child] > maxScalar) maxScalar = newScalars[child]; } } setTreeScalars(baryMergeTree, newScalars); - // insert new nodes (ToDo!!) - // for(unsigned int i=0; igetValue(match.first.first); - // dataType bv2 = baryTree->getValue(match.first.second); - // dataType tv1 = tree->getValue(match.second.first); - // dataType tv2 = tree->getValue(match.second.second); - // dataType pathRangeB = bv1 > bv2 ? bv1 - bv2 : bv2 - bv1; - // dataType pathRangeT = tv1 > tv2 ? tv1 - tv2 : tv2 - tv1; - // ftm::idNode currB = baryTree->getValue(match.first.first); - // ftm::idNode currT = tree->getValue(match.second.first); - // ftm::idNode lastB = match.first.first; - // ftm::idNode lastT = match.second.first; - // while(currB != match.first.second && currT != match.second.second){ - // dataType currValueB = baryTree->getValue(currB); - // dataType currValueT = tree->getValue(currT); - // dataType relativeValueB = bv1 > bv2 ? bv1 - currValueB : currValueB - bv1; - // dataType relativeValueT = tv1 > tv2 ? tv1 - currValueT : currValueT - tv1; - // relativeValueB = relativeValueB/pathRangeB; - // relativeValueT = relativeValueT/pathRangeT; - // // if next node in tree, ignore - // if(relativeValueB < relativeValueT){ - // // continue iteration - // lastB = currB; - // currB = baryTree->getParentSafe(currB); - // } - // // if next node in tree, ignore - // else if(relativeValueB > relativeValueT){ - // // continue iteration - // lastT = currT; - // currT = tree->getParentSafe(currT); - // } - // else{ - // // this should not happen - // printErr("Impossible Matching behaviour.") - // lastB = currB; - // lastT = currT; - // currB = baryTree->getParentSafe(currB); - // currT = tree->getParentSafe(currT); - // } - // } - // } - // } + // Create new barycenter tree + ftm::MergeTree baryMergeTreeNew + = ftm::createEmptyMergeTree(newSize); + //newScalars.resize(newSize); + //ftm::setTreeScalars(baryMergeTreeNew, newScalars); + ftm::FTMTree_MT *baryTreeNew = &(baryMergeTreeNew.tree); - ftm::cleanMergeTree(baryMergeTree); + // Copy the old tree structure + baryTreeNew->copyMergeTreeStructure(baryTree); + + // insert new nodes + for(unsigned int i=0; i newIndices(tree->getNumberOfNodes(),-1); + for(auto match : matchings[i]){ + dataType bv1 = baryTree->getValue(match.first.first); + dataType bv2 = baryTree->getValue(match.first.second); + dataType tv1 = tree->getValue(match.second.first); + dataType tv2 = tree->getValue(match.second.second); + dataType pathRangeB = bv1 > bv2 ? bv1 - bv2 : bv2 - bv1; + dataType pathRangeT = tv1 > tv2 ? tv1 - tv2 : tv2 - tv1; + ftm::idNode currB = baryTree->getParentSafe(match.first.first); + ftm::idNode currT = tree->getParentSafe(match.second.first); + ftm::idNode lastB = match.first.first; + ftm::idNode lastT = match.second.first; + ftm::idNode lastNode = lastB; + while(currB != match.first.second || currT != match.second.second){ + dataType currValueB = baryTree->getValue(currB); + dataType currValueT = tree->getValue(currT); + dataType relativeValueB = bv1 > bv2 ? bv1 - currValueB : currValueB - bv1; + dataType relativeValueT = tv1 > tv2 ? tv1 - currValueT : currValueT - tv1; + relativeValueB = relativeValueB/pathRangeB; + relativeValueT = relativeValueT/pathRangeT; + // if next node in barycenter, ignore + if(relativeValueB < relativeValueT){ + // continue iteration + lastB = currB; + currB = baryTree->getParentSafe(currB); + lastNode = lastB; + } + // if next node in tree, add nodes + else if(relativeValueB > relativeValueT){ + std::queue q; + std::vector currChildren; + tree->getChildren(currT,currChildren); + newIndices[currT] = newScalars.size(); + ftm::idNode nI = newIndices[currT]; + newScalars.emplace_back(tree->getValue(currT)); + baryTreeNew->makeNode(nI); + baryTreeNew->setParent(nI, currB); + baryTreeNew->deleteParent(lastNode); + baryTreeNew->setParent(lastNode, nI); + //baryTree->getNode(nI)->setOrigin(newIndices[tree->getNode(currT)->getOrigin()]); + lastNode = newIndices[currT]; + for(auto child : currChildren){ + if(child==lastT) continue; + q.emplace(child); + newIndices[child] = newScalars.size(); + nI = newIndices[child]; + newScalars.emplace_back(tree->getValue(child)); + baryTreeNew->makeNode(nI); + baryTreeNew->setParent(nI, newIndices[currT]); + if(tree->getNumberOfChildren(child) == 0){ + baryTreeNew->getNode(nI)->setOrigin(newIndices[tree->getNode(child)->getOrigin()]); + baryTreeNew->getNode(newIndices[tree->getNode(child)->getOrigin()])->setOrigin(nI); + } + } + while(!q.empty()){ + auto currNode = q.front(); + q.pop(); + currChildren.clear(); + tree->getChildren(currNode,currChildren); + for(auto child : currChildren){ + q.emplace(child); + newIndices[child] = newScalars.size(); + ftm::idNode nI = newIndices[child]; + newScalars.emplace_back(tree->getValue(child)); + baryTree->makeNode(nI); + baryTree->setParent(nI, newIndices[currNode]); + if(tree->getNumberOfChildren(child) == 0){ + baryTreeNew->getNode(nI)->setOrigin(newIndices[tree->getNode(child)->getOrigin()]); + baryTreeNew->getNode(newIndices[tree->getNode(child)->getOrigin()])->setOrigin(nI); + } + } + } + // continue iteration + lastT = currT; + currT = tree->getParentSafe(currT); + } + else{ + // this should not happen + printErr("Impossible Matching behaviour."); + lastB = currB; + lastT = currT; + currB = baryTree->getParentSafe(currB); + currT = tree->getParentSafe(currT); + } + } + } + setTreeScalars(baryMergeTreeNew,newScalars); + // for(auto match : matchings[i]){ + // dataType bv1 = baryTree->getValue(match.first.first); + // dataType bv2 = baryTree->getValue(match.first.second); + // dataType tv1 = tree->getValue(match.second.first); + // dataType tv2 = tree->getValue(match.second.second); + // dataType pathRangeB = bv1 > bv2 ? bv1 - bv2 : bv2 - bv1; + // dataType pathRangeT = tv1 > tv2 ? tv1 - tv2 : tv2 - tv1; + // ftm::idNode currB = baryTree->getParentSafe(match.first.first); + // ftm::idNode currT = tree->getParentSafe(match.second.first); + // ftm::idNode lastB = match.first.first; + // ftm::idNode lastT = match.second.first; + // ftm::idNode lastNode = lastB; + // while(currB != match.first.second || currT != match.second.second){ + // dataType currValueB = baryTree->getValue(currB); + // dataType currValueT = tree->getValue(currT); + // dataType relativeValueB = bv1 > bv2 ? bv1 - currValueB : currValueB - bv1; + // dataType relativeValueT = tv1 > tv2 ? tv1 - currValueT : currValueT - tv1; + // relativeValueB = relativeValueB/pathRangeB; + // relativeValueT = relativeValueT/pathRangeT; + // // if next node in barycenter, ignore + // if(relativeValueB < relativeValueT){ + // // continue iteration + // lastB = currB; + // currB = baryTree->getParentSafe(currB); + // lastNode = lastB; + // } + // // if next node in tree, add nodes + // else if(relativeValueB > relativeValueT){ + // std::queue q; + // std::vector currChildren; + // tree->getChildren(currT,currChildren); + // ftm::idNode nI = newIndices[currT]; + // baryTree->makeNode(nI); + // baryTree->setParent(nI, currB); + // baryTree->deleteParent(lastNode); + // baryTree->setParent(lastNode, nI); + // baryTree->getNode(nI)->setOrigin(newIndices[tree->getNode(currT)->getOrigin()]); + // lastNode = newIndices[currT]; + // for(auto child : currChildren){ + // if(child==lastT) continue; + // q.emplace(child); + // ftm::idNode nI = newIndices[child]; + // baryTree->makeNode(nI); + // baryTree->setParent(nI, newIndices[currT]); + // baryTree->getNode(nI)->setOrigin(newIndices[tree->getNode(child)->getOrigin()]); + // } + // while(!q.empty()){ + // auto currNode = q.front(); + // q.pop(); + // currChildren.clear(); + // tree->getChildren(currNode,currChildren); + // for(auto child : currChildren){ + // q.emplace(child); + // ftm::idNode nI = newIndices[child]; + // baryTree->makeNode(nI); + // baryTree->setParent(nI, newIndices[currNode]); + // baryTree->getNode(nI)->setOrigin(newIndices[tree->getNode(child)->getOrigin()]); + // } + // } + // // continue iteration + // lastT = currT; + // currT = tree->getParentSafe(currT); + // } + // else{ + // // this should not happen + // printErr("Impossible Matching behaviour."); + // lastB = currB; + // lastT = currT; + // currB = baryTree->getParentSafe(currB); + // currT = tree->getParentSafe(currT); + // } + // } + // } + } + + ftm::cleanMergeTree(baryMergeTreeNew); + baryMergeTree = baryMergeTreeNew; } template @@ -1320,11 +1476,11 @@ namespace ttk { finalMatchings[i].clear(); std::vector matchedNodes(trees[i]->getNumberOfNodes(),-1); for(auto m : matchings_path[i]){ - matchedNodes[m.first.first] = m.second.first; - matchedNodes[m.first.second] = m.second.second; + matchedNodes[m.second.first] = m.first.first; + matchedNodes[m.second.second] = m.first.second; } for(ftm::idNode j=0; j=0) finalMatchings[i].emplace_back(std::make_tuple(j,matchedNodes[j], 0.0)); + if(matchedNodes[j]>=0) finalMatchings[i].emplace_back(std::make_tuple(matchedNodes[j],j, 0.0)); } } } @@ -1380,7 +1536,6 @@ namespace ttk { // - Merge saddle points according epsilon if(not isPersistenceDiagram_) { - treesNodeCorr_.resize(2); if(epsilonTree2_ != 0){ std::vector> treeNodeMerged( tree->getNumberOfNodes() ); mergeSaddle(tree, epsilonTree2_, treeNodeMerged); @@ -1421,9 +1576,9 @@ namespace ttk { computeBarycenter(treesT, baryMergeTree, alphas, finalMatchings, finalAsgnDoubleInput, finalAsgnFirstInput); - if(baseModule_==2){ - preprocessTree(&(baryMergeTree.tree),true); - } + // if(baseModule_==2){ + // preprocessTree(&(baryMergeTree.tree),false); + // } // --- Postprocessing if(postprocess_) { diff --git a/core/base/mergeTreeClustering/PathMappingDistance.h b/core/base/mergeTreeClustering/PathMappingDistance.h index ef2725ab5d..60ae48f6cd 100644 --- a/core/base/mergeTreeClustering/PathMappingDistance.h +++ b/core/base/mergeTreeClustering/PathMappingDistance.h @@ -187,6 +187,7 @@ namespace ttk { traceMapping_path(tree1, tree2, child12, 1, child22, 1, predecessors1, predecessors2, depth1, depth2, memT, mapping); + return; } if(memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4] == memT[child11 + 1 * dim2 + child22 * dim3 + 1 * dim4] @@ -689,6 +690,16 @@ namespace ttk { outputMatching->clear(); traceMapping_path(tree1,tree2,children1[0],1,children2[0],1,predecessors1,predecessors2,depth1,depth2,memT,*outputMatching); + + dataType cost_mapping = 0; + for(auto m : *outputMatching){ + dataType cost = editCost_Persistence( + m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2); + cost_mapping += cost; + std::cout << " (" << m.first.first << " " << m.first.second << ") - (" << m.second.first << " " << m.second.second << ") : " << cost << "\n"; + } + std::cout << res << " " << cost_mapping << std::endl; + } return squared_ ? std::sqrt(res) : res; From 01cc9b2d0732a9429acf8b0afbde5d1cc1079e5e Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Fri, 2 Dec 2022 17:15:40 +0100 Subject: [PATCH 15/72] implemented alphas for path mapping clustering and fixed some warnings --- .../mergeTreeClustering/MergeTreeBarycenter.h | 109 ++++-------------- 1 file changed, 22 insertions(+), 87 deletions(-) diff --git a/core/base/mergeTreeClustering/MergeTreeBarycenter.h b/core/base/mergeTreeClustering/MergeTreeBarycenter.h index 66058af5d3..aa053196b1 100644 --- a/core/base/mergeTreeClustering/MergeTreeBarycenter.h +++ b/core/base/mergeTreeClustering/MergeTreeBarycenter.h @@ -285,8 +285,8 @@ namespace ttk { void initBarycenterTree(std::vector &trees, ftm::MergeTree &baryTree, bool distMinimizer = true) { - //int bestIndex = getBestInitTreeIndex(trees, distMinimizer); - int bestIndex = trees.size()-1; + int bestIndex = getBestInitTreeIndex(trees, distMinimizer); + bestIndex = trees.size()-1; //baryTree = ftm::copyMergeTree(trees[bestIndex], true); baryTree = ftm::copyMergeTree(trees[bestIndex], baseModule_!=2); ftm::FTMTree_MT* bt = &(baryTree.tree); @@ -829,6 +829,9 @@ namespace ttk { std::vector,std::pair>>> &matchings) { ftm::FTMTree_MT* baryTree = &(baryMergeTree.tree); + double alphaSum = 0; + for(unsigned int i = 0; i < trees.size(); ++i) + alphaSum += alphas[i]; // compute matched and unmatched nodes for all trees and barycenter std::vector baryNodesMatched(baryTree->getNumberOfNodes(),false); @@ -843,7 +846,6 @@ namespace ttk { } } // compute size of new barycenter tree - int oldSize = baryTree->getNumberOfNodes(); int newSize = baryTree->getNumberOfNodes(); for(unsigned int i=0; igetValue(lastB); dataType relativeValueB = lastValueB > currValueB ? lastValueB - currValueB : currValueB - lastValueB; relativeValueB = relativeValueB/pathRangeB; - parentEdgeLengths[lastB].emplace_back(relativeValueB * pathRangeT); + parentEdgeLengths[lastB].emplace_back(relativeValueB * pathRangeT * alphas[i]); // continue iteration lastB = currB; currB = baryTree->getParentSafe(currB); @@ -901,7 +903,8 @@ namespace ttk { for(auto l : parentEdgeLengths[child]){ avgEdgeLength += l; } - avgEdgeLength = avgEdgeLength/static_cast(trees.size()); + //avgEdgeLength = avgEdgeLength/static_cast(trees.size()); + avgEdgeLength = avgEdgeLength/alphaSum; newScalars[child] = newScalars[curr] + avgEdgeLength; std::cout << "Node relabel " << child << ": " << baryTree->getValue(child) << "->" << newScalars[child] << std::endl; if(newScalars[child] > maxScalar) maxScalar = newScalars[child]; @@ -951,12 +954,13 @@ namespace ttk { } // if next node in tree, add nodes else if(relativeValueB > relativeValueT){ - std::queue q; + q = std::queue(); std::vector currChildren; tree->getChildren(currT,currChildren); newIndices[currT] = newScalars.size(); ftm::idNode nI = newIndices[currT]; - newScalars.emplace_back(tree->getValue(currT)); + //newScalars.emplace_back(tree->getValue(currT)); + newScalars.emplace_back(relativeValueT * pathRangeB + bv2); baryTreeNew->makeNode(nI); baryTreeNew->setParent(nI, currB); baryTreeNew->deleteParent(lastNode); @@ -968,7 +972,9 @@ namespace ttk { q.emplace(child); newIndices[child] = newScalars.size(); nI = newIndices[child]; - newScalars.emplace_back(tree->getValue(child)); + //newScalars.emplace_back(tree->getValue(child)); + dataType edgeLength = tree->getValue(child) - tree->getValue(currT); + newScalars.emplace_back(newScalars[newIndices[currT]] + edgeLength * (alphas[i]/alphaSum)); baryTreeNew->makeNode(nI); baryTreeNew->setParent(nI, newIndices[currT]); if(tree->getNumberOfChildren(child) == 0){ @@ -984,8 +990,10 @@ namespace ttk { for(auto child : currChildren){ q.emplace(child); newIndices[child] = newScalars.size(); - ftm::idNode nI = newIndices[child]; - newScalars.emplace_back(tree->getValue(child)); + nI = newIndices[child]; + //newScalars.emplace_back(tree->getValue(child)); + dataType edgeLength = tree->getValue(child) - tree->getValue(currNode); + newScalars.emplace_back(newScalars[newIndices[currNode]] + edgeLength * (alphas[i]/alphaSum)); baryTree->makeNode(nI); baryTree->setParent(nI, newIndices[currNode]); if(tree->getNumberOfChildren(child) == 0){ @@ -1009,79 +1017,6 @@ namespace ttk { } } setTreeScalars(baryMergeTreeNew,newScalars); - // for(auto match : matchings[i]){ - // dataType bv1 = baryTree->getValue(match.first.first); - // dataType bv2 = baryTree->getValue(match.first.second); - // dataType tv1 = tree->getValue(match.second.first); - // dataType tv2 = tree->getValue(match.second.second); - // dataType pathRangeB = bv1 > bv2 ? bv1 - bv2 : bv2 - bv1; - // dataType pathRangeT = tv1 > tv2 ? tv1 - tv2 : tv2 - tv1; - // ftm::idNode currB = baryTree->getParentSafe(match.first.first); - // ftm::idNode currT = tree->getParentSafe(match.second.first); - // ftm::idNode lastB = match.first.first; - // ftm::idNode lastT = match.second.first; - // ftm::idNode lastNode = lastB; - // while(currB != match.first.second || currT != match.second.second){ - // dataType currValueB = baryTree->getValue(currB); - // dataType currValueT = tree->getValue(currT); - // dataType relativeValueB = bv1 > bv2 ? bv1 - currValueB : currValueB - bv1; - // dataType relativeValueT = tv1 > tv2 ? tv1 - currValueT : currValueT - tv1; - // relativeValueB = relativeValueB/pathRangeB; - // relativeValueT = relativeValueT/pathRangeT; - // // if next node in barycenter, ignore - // if(relativeValueB < relativeValueT){ - // // continue iteration - // lastB = currB; - // currB = baryTree->getParentSafe(currB); - // lastNode = lastB; - // } - // // if next node in tree, add nodes - // else if(relativeValueB > relativeValueT){ - // std::queue q; - // std::vector currChildren; - // tree->getChildren(currT,currChildren); - // ftm::idNode nI = newIndices[currT]; - // baryTree->makeNode(nI); - // baryTree->setParent(nI, currB); - // baryTree->deleteParent(lastNode); - // baryTree->setParent(lastNode, nI); - // baryTree->getNode(nI)->setOrigin(newIndices[tree->getNode(currT)->getOrigin()]); - // lastNode = newIndices[currT]; - // for(auto child : currChildren){ - // if(child==lastT) continue; - // q.emplace(child); - // ftm::idNode nI = newIndices[child]; - // baryTree->makeNode(nI); - // baryTree->setParent(nI, newIndices[currT]); - // baryTree->getNode(nI)->setOrigin(newIndices[tree->getNode(child)->getOrigin()]); - // } - // while(!q.empty()){ - // auto currNode = q.front(); - // q.pop(); - // currChildren.clear(); - // tree->getChildren(currNode,currChildren); - // for(auto child : currChildren){ - // q.emplace(child); - // ftm::idNode nI = newIndices[child]; - // baryTree->makeNode(nI); - // baryTree->setParent(nI, newIndices[currNode]); - // baryTree->getNode(nI)->setOrigin(newIndices[tree->getNode(child)->getOrigin()]); - // } - // } - // // continue iteration - // lastT = currT; - // currT = tree->getParentSafe(currT); - // } - // else{ - // // this should not happen - // printErr("Impossible Matching behaviour."); - // lastB = currB; - // lastT = currT; - // currB = baryTree->getParentSafe(currB); - // currT = tree->getParentSafe(currT); - // } - // } - // } } ftm::cleanMergeTree(baryMergeTreeNew); @@ -1539,10 +1474,10 @@ namespace ttk { if(epsilonTree2_ != 0){ std::vector> treeNodeMerged( tree->getNumberOfNodes() ); mergeSaddle(tree, epsilonTree2_, treeNodeMerged); - for(unsigned int i=0; igetNode(j)->getOrigin(); - tree->getNode(j)->setOrigin(i); + tree->getNode(k)->setOrigin(j); tree->getNode(nodeToDelete)->setOrigin(-1); } } @@ -1550,7 +1485,7 @@ namespace ttk { } else{ std::vector nodeCorr(tree->getNumberOfNodes()); - for(unsigned int i=0; i Date: Mon, 5 Dec 2022 17:39:44 +0100 Subject: [PATCH 16/72] Bugfixes for MergeTreeBarycenter with Path Mapping Distance. Still not working for join trees. --- .../mergeTreeClustering/MergeTreeBarycenter.h | 65 ++++++++++++------- .../mergeTreeClustering/PathMappingDistance.h | 33 ++++++++++ 2 files changed, 75 insertions(+), 23 deletions(-) diff --git a/core/base/mergeTreeClustering/MergeTreeBarycenter.h b/core/base/mergeTreeClustering/MergeTreeBarycenter.h index aa053196b1..d815693ece 100644 --- a/core/base/mergeTreeClustering/MergeTreeBarycenter.h +++ b/core/base/mergeTreeClustering/MergeTreeBarycenter.h @@ -832,6 +832,7 @@ namespace ttk { double alphaSum = 0; for(unsigned int i = 0; i < trees.size(); ++i) alphaSum += alphas[i]; + bool joinTrees = trees[0]->isJoinTree(); // compute matched and unmatched nodes for all trees and barycenter std::vector baryNodesMatched(baryTree->getNumberOfNodes(),false); @@ -855,7 +856,6 @@ namespace ttk { // delete not-matched nodes in barycenter for(ftm::idNode i=0; igetNumberOfNodes(); i++){ if(not baryNodesMatched[i]){ - std::cout << "Node deleted: " << baryTree->getValue(i) << std::endl; baryTree->getNode(i)->setOrigin(-1); baryTree->deleteNode(i); } @@ -872,7 +872,6 @@ namespace ttk { dataType tv2 = tree->getValue(match.second.second); dataType pathRangeB = bv1 > bv2 ? bv1 - bv2 : bv2 - bv1; dataType pathRangeT = tv1 > tv2 ? tv1 - tv2 : tv2 - tv1; - std::cout << "Path matched: (" << match.first.first << "," << match.first.second << ")-(" << match.second.first << "," << match.second.second << ") ; " << pathRangeB << "-" << pathRangeT << std::endl; ftm::idNode currB = baryTree->getParentSafe(match.first.first); ftm::idNode lastB = match.first.first; while(lastB != match.first.second){ @@ -891,7 +890,6 @@ namespace ttk { q.push(baryTree->getRoot()); std::vector newScalars(baryTree->getNumberOfNodes(),0); newScalars[baryTree->getRoot()] = baryTree->getValue(baryTree->getRoot()); - dataType maxScalar = std::numeric_limits::min(); while(!q.empty()){ auto curr = q.front(); q.pop(); @@ -905,9 +903,7 @@ namespace ttk { } //avgEdgeLength = avgEdgeLength/static_cast(trees.size()); avgEdgeLength = avgEdgeLength/alphaSum; - newScalars[child] = newScalars[curr] + avgEdgeLength; - std::cout << "Node relabel " << child << ": " << baryTree->getValue(child) << "->" << newScalars[child] << std::endl; - if(newScalars[child] > maxScalar) maxScalar = newScalars[child]; + newScalars[child] = newScalars[curr] + (joinTrees ? - avgEdgeLength : avgEdgeLength); } } setTreeScalars(baryMergeTree, newScalars); @@ -960,11 +956,13 @@ namespace ttk { newIndices[currT] = newScalars.size(); ftm::idNode nI = newIndices[currT]; //newScalars.emplace_back(tree->getValue(currT)); - newScalars.emplace_back(relativeValueT * pathRangeB + bv2); + newScalars.emplace_back(bv2 + (joinTrees ? - relativeValueT * pathRangeB : relativeValueT * pathRangeB)); baryTreeNew->makeNode(nI); baryTreeNew->setParent(nI, currB); baryTreeNew->deleteParent(lastNode); baryTreeNew->setParent(lastNode, nI); + baryTreeNew->getNode(nI)->setOrigin(-1); + std::vector nodesWithoutLink; //baryTree->getNode(nI)->setOrigin(newIndices[tree->getNode(currT)->getOrigin()]); lastNode = newIndices[currT]; for(auto child : currChildren){ @@ -973,13 +971,18 @@ namespace ttk { newIndices[child] = newScalars.size(); nI = newIndices[child]; //newScalars.emplace_back(tree->getValue(child)); - dataType edgeLength = tree->getValue(child) - tree->getValue(currT); - newScalars.emplace_back(newScalars[newIndices[currT]] + edgeLength * (alphas[i]/alphaSum)); + dataType edgeLength = (joinTrees ? tree->getValue(currT) - tree->getValue(child) : tree->getValue(child) - tree->getValue(currT)); + newScalars.emplace_back(newScalars[newIndices[currT]] + (joinTrees ? - edgeLength * (alphas[i]/alphaSum) : edgeLength * (alphas[i]/alphaSum))); baryTreeNew->makeNode(nI); baryTreeNew->setParent(nI, newIndices[currT]); - if(tree->getNumberOfChildren(child) == 0){ - baryTreeNew->getNode(nI)->setOrigin(newIndices[tree->getNode(child)->getOrigin()]); - baryTreeNew->getNode(newIndices[tree->getNode(child)->getOrigin()])->setOrigin(nI); + baryTreeNew->getNode(nI)->setOrigin(-1); + if(tree->getNumberOfChildren(child) == 0 && newIndices[tree->getNode(child)->getOrigin()] >= 0){ + ftm::idNode ln = newIndices[tree->getNode(child)->getOrigin()]; + baryTreeNew->getNode(nI)->setOrigin(ln); + baryTreeNew->getNode(ln)->setOrigin(nI); + } + else{ + nodesWithoutLink.push_back(nI); } } while(!q.empty()){ @@ -992,16 +995,28 @@ namespace ttk { newIndices[child] = newScalars.size(); nI = newIndices[child]; //newScalars.emplace_back(tree->getValue(child)); - dataType edgeLength = tree->getValue(child) - tree->getValue(currNode); - newScalars.emplace_back(newScalars[newIndices[currNode]] + edgeLength * (alphas[i]/alphaSum)); - baryTree->makeNode(nI); - baryTree->setParent(nI, newIndices[currNode]); - if(tree->getNumberOfChildren(child) == 0){ - baryTreeNew->getNode(nI)->setOrigin(newIndices[tree->getNode(child)->getOrigin()]); - baryTreeNew->getNode(newIndices[tree->getNode(child)->getOrigin()])->setOrigin(nI); + dataType edgeLength = (joinTrees ? tree->getValue(currNode) - tree->getValue(child) : tree->getValue(child) - tree->getValue(currNode)); + newScalars.emplace_back(newScalars[newIndices[currNode]] + (joinTrees ? - edgeLength * (alphas[i]/alphaSum) : edgeLength * (alphas[i]/alphaSum))); + baryTreeNew->makeNode(nI); + baryTreeNew->getNode(nI)->setOrigin(-1); + baryTreeNew->setParent(nI, newIndices[currNode]); + if(tree->getNumberOfChildren(child) == 0 && newIndices[tree->getNode(child)->getOrigin()] >= 0){ + ftm::idNode ln = newIndices[tree->getNode(child)->getOrigin()]; + baryTreeNew->getNode(nI)->setOrigin(ln); + baryTreeNew->getNode(ln)->setOrigin(nI); + } + else{ + nodesWithoutLink.push_back(nI); } } } + std::cout << baryTreeNew->getNode(newIndices[currT])->getOrigin() << " " << nodesWithoutLink.size() << std::endl; + if(baryTreeNew->getNode(newIndices[currT])->getOrigin() < 0){ + baryTreeNew->getNode(newIndices[currT])->setOrigin(nodesWithoutLink[0]); + } + for(ftm::idNode n : nodesWithoutLink){ + baryTreeNew->getNode(n)->setOrigin(newIndices[currT]); + } // continue iteration lastT = currT; currT = tree->getParentSafe(currT); @@ -1019,7 +1034,7 @@ namespace ttk { setTreeScalars(baryMergeTreeNew,newScalars); } - ftm::cleanMergeTree(baryMergeTreeNew); + ftm::cleanMergeTree(baryMergeTreeNew,true); baryMergeTree = baryMergeTreeNew; } @@ -1511,9 +1526,13 @@ namespace ttk { computeBarycenter(treesT, baryMergeTree, alphas, finalMatchings, finalAsgnDoubleInput, finalAsgnFirstInput); - // if(baseModule_==2){ - // preprocessTree(&(baryMergeTree.tree),false); - // } + if(baseModule_==2){ + ftm::FTMTree_MT* baryTree = &(baryMergeTree.tree); + for(ftm::idNode node=0; nodegetNumberOfNodes(); node++){ + baryTree->getNode(node)->setOrigin(-1); + } + preprocessTree(baryTree,false); + } // --- Postprocessing if(postprocess_) { diff --git a/core/base/mergeTreeClustering/PathMappingDistance.h b/core/base/mergeTreeClustering/PathMappingDistance.h index 60ae48f6cd..47b3f843ea 100644 --- a/core/base/mergeTreeClustering/PathMappingDistance.h +++ b/core/base/mergeTreeClustering/PathMappingDistance.h @@ -692,12 +692,45 @@ namespace ttk { traceMapping_path(tree1,tree2,children1[0],1,children2[0],1,predecessors1,predecessors2,depth1,depth2,memT,*outputMatching); dataType cost_mapping = 0; + dataType cost_ins = 0; + dataType cost_del = 0; + std::vector matchedNodes1(tree1->getNumberOfNodes(),false); + std::vector matchedNodes2(tree2->getNumberOfNodes(),false); for(auto m : *outputMatching){ + matchedNodes1[m.first.first] = true; + matchedNodes1[m.first.second] = true; + matchedNodes2[m.second.first] = true; + matchedNodes2[m.second.second] = true; + ftm::idNode cn = tree1->getParentSafe(m.first.first); + while(cn!=m.first.second){ + matchedNodes1[cn] = true; + cn = tree1->getParentSafe(cn); + } + cn = tree2->getParentSafe(m.second.first); + while(cn!=m.second.second){ + matchedNodes2[cn] = true; + cn = tree2->getParentSafe(cn); + } dataType cost = editCost_Persistence( m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2); cost_mapping += cost; std::cout << " (" << m.first.first << " " << m.first.second << ") - (" << m.second.first << " " << m.second.second << ") : " << cost << "\n"; } + for(ftm::idNode i=0; igetNumberOfNodes(); i++){ + if(!matchedNodes1[i]){ + dataType cost = editCost_Persistence(i, tree1->getParentSafe(i), -1, -1, tree1, tree2); + std::cout << " (" << i << " " << tree1->getParentSafe(i) << ") - (" << -1 << " " << -1 << ") : " << cost << "\n"; + cost_del += cost; + } + } + for(ftm::idNode i=0; igetNumberOfNodes(); i++){ + if(!matchedNodes2[i]){ + dataType cost = editCost_Persistence(-1, -1, i, tree2->getParentSafe(i), tree1, tree2); + std::cout << " (" << -1 << " " << -1 << ") - (" << i << " " << tree2->getParentSafe(i) << ") : " << cost << "\n"; + cost_ins += cost; + } + } + std::cout << res << " " << cost_mapping+cost_ins+cost_del << std::endl; std::cout << res << " " << cost_mapping << std::endl; } From 37230ab9b1de53b5d81cc1b19e951d6f9253c1bd Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Wed, 7 Dec 2022 16:11:26 +0100 Subject: [PATCH 17/72] Fixed bugs for barycenter computation with bdi-ed --- .../mergeTreeClustering/MergeTreeBarycenter.h | 89 +++++++++++-------- .../mergeTreeClustering/MergeTreeClustering.h | 38 +++++++- .../ttkMergeTreeClustering.cpp | 3 +- .../ttkMergeTreeClustering.h | 7 ++ paraview/xmls/MergeTreeClustering.xml | 49 ++++++++++ 5 files changed, 147 insertions(+), 39 deletions(-) diff --git a/core/base/mergeTreeClustering/MergeTreeBarycenter.h b/core/base/mergeTreeClustering/MergeTreeBarycenter.h index d815693ece..0b65105fb3 100644 --- a/core/base/mergeTreeClustering/MergeTreeBarycenter.h +++ b/core/base/mergeTreeClustering/MergeTreeBarycenter.h @@ -52,6 +52,7 @@ namespace ttk { int pathMetric_ = 0; int baseModule_ = 0; + int iterationLimit_ = 0; // Output std::vector finalDistances_; @@ -131,6 +132,10 @@ namespace ttk { pathMetric_ = m; } + void setIterationLimit(int l) { + iterationLimit_ = l; + } + /** * Implementation of the algorithm. */ @@ -833,11 +838,13 @@ namespace ttk { for(unsigned int i = 0; i < trees.size(); ++i) alphaSum += alphas[i]; bool joinTrees = trees[0]->isJoinTree(); + int oldSize = baryTree->getNumberOfNodes(); // compute matched and unmatched nodes for all trees and barycenter std::vector baryNodesMatched(baryTree->getNumberOfNodes(),false); std::vector> treeNodesMatched(trees.size()); for(unsigned int i=0; igetNumberOfNodes(),false); for(auto match : matchings[i]){ baryNodesMatched[match.first.first] = true; @@ -847,23 +854,36 @@ namespace ttk { } } // compute size of new barycenter tree - int newSize = baryTree->getNumberOfNodes(); + int newSize = oldSize; for(unsigned int i=0; i baryMergeTreeNew + = ftm::createEmptyMergeTree(newSize); + //newScalars.resize(newSize); + //ftm::setTreeScalars(baryMergeTreeNew, newScalars); + ftm::FTMTree_MT *baryTreeNew = &(baryMergeTreeNew.tree); + + // Copy the old tree structure + baryTreeNew->copyMergeTreeStructure(baryTree); + // delete not-matched nodes in barycenter for(ftm::idNode i=0; igetNumberOfNodes(); i++){ if(not baryNodesMatched[i]){ - baryTree->getNode(i)->setOrigin(-1); - baryTree->deleteNode(i); + baryTreeNew->getNode(i)->setOrigin(-1); + baryTreeNew->deleteNode(i); } } // relabel paths std::vector> parentEdgeLengths(baryTree->getNumberOfNodes()); for(unsigned int i=0; igetValue(match.first.first); @@ -872,7 +892,7 @@ namespace ttk { dataType tv2 = tree->getValue(match.second.second); dataType pathRangeB = bv1 > bv2 ? bv1 - bv2 : bv2 - bv1; dataType pathRangeT = tv1 > tv2 ? tv1 - tv2 : tv2 - tv1; - ftm::idNode currB = baryTree->getParentSafe(match.first.first); + ftm::idNode currB = baryTreeNew->getParentSafe(match.first.first); ftm::idNode lastB = match.first.first; while(lastB != match.first.second){ dataType currValueB = baryTree->getValue(currB); @@ -882,19 +902,20 @@ namespace ttk { parentEdgeLengths[lastB].emplace_back(relativeValueB * pathRangeT * alphas[i]); // continue iteration lastB = currB; - currB = baryTree->getParentSafe(currB); + currB = baryTreeNew->getParentSafe(currB); } } } std::queue q; - q.push(baryTree->getRoot()); - std::vector newScalars(baryTree->getNumberOfNodes(),0); - newScalars[baryTree->getRoot()] = baryTree->getValue(baryTree->getRoot()); + q.push(baryTreeNew->getRoot()); + //std::vector newScalars(baryTree->getNumberOfNodes(),0); + std::vector newScalars(newSize,0); + newScalars[baryTreeNew->getRoot()] = baryTree->getValue(baryTree->getRoot()); while(!q.empty()){ auto curr = q.front(); q.pop(); std::vector children; - baryTree->getChildren(curr,children); + baryTreeNew->getChildren(curr,children); for(auto child : children){ q.emplace(child); dataType avgEdgeLength = 0; @@ -906,36 +927,28 @@ namespace ttk { newScalars[child] = newScalars[curr] + (joinTrees ? - avgEdgeLength : avgEdgeLength); } } - setTreeScalars(baryMergeTree, newScalars); - - // Create new barycenter tree - ftm::MergeTree baryMergeTreeNew - = ftm::createEmptyMergeTree(newSize); - //newScalars.resize(newSize); - //ftm::setTreeScalars(baryMergeTreeNew, newScalars); - ftm::FTMTree_MT *baryTreeNew = &(baryMergeTreeNew.tree); - - // Copy the old tree structure - baryTreeNew->copyMergeTreeStructure(baryTree); - + setTreeScalars(baryMergeTreeNew, newScalars); + // insert new nodes + int currSize = oldSize; for(unsigned int i=0; i newIndices(tree->getNumberOfNodes(),-1); for(auto match : matchings[i]){ - dataType bv1 = baryTree->getValue(match.first.first); - dataType bv2 = baryTree->getValue(match.first.second); + dataType bv1 = baryTreeNew->getValue(match.first.first); + dataType bv2 = baryTreeNew->getValue(match.first.second); dataType tv1 = tree->getValue(match.second.first); dataType tv2 = tree->getValue(match.second.second); dataType pathRangeB = bv1 > bv2 ? bv1 - bv2 : bv2 - bv1; dataType pathRangeT = tv1 > tv2 ? tv1 - tv2 : tv2 - tv1; - ftm::idNode currB = baryTree->getParentSafe(match.first.first); + ftm::idNode currB = baryTreeNew->getParentSafe(match.first.first); ftm::idNode currT = tree->getParentSafe(match.second.first); ftm::idNode lastB = match.first.first; ftm::idNode lastT = match.second.first; ftm::idNode lastNode = lastB; while(currB != match.first.second || currT != match.second.second){ - dataType currValueB = baryTree->getValue(currB); + dataType currValueB = baryTreeNew->getValue(currB); dataType currValueT = tree->getValue(currT); dataType relativeValueB = bv1 > bv2 ? bv1 - currValueB : currValueB - bv1; dataType relativeValueT = tv1 > tv2 ? tv1 - currValueT : currValueT - tv1; @@ -945,7 +958,7 @@ namespace ttk { if(relativeValueB < relativeValueT){ // continue iteration lastB = currB; - currB = baryTree->getParentSafe(currB); + currB = baryTreeNew->getParentSafe(currB); lastNode = lastB; } // if next node in tree, add nodes @@ -953,26 +966,30 @@ namespace ttk { q = std::queue(); std::vector currChildren; tree->getChildren(currT,currChildren); - newIndices[currT] = newScalars.size(); + newIndices[currT] = currSize;//newScalars.size(); + currSize++; ftm::idNode nI = newIndices[currT]; //newScalars.emplace_back(tree->getValue(currT)); - newScalars.emplace_back(bv2 + (joinTrees ? - relativeValueT * pathRangeB : relativeValueT * pathRangeB)); + //newScalars.emplace_back(bv1 + (joinTrees ? relativeValueT * pathRangeB : - relativeValueT * pathRangeB)); + newScalars[nI] = bv1 + (joinTrees ? relativeValueT * pathRangeB : - relativeValueT * pathRangeB); baryTreeNew->makeNode(nI); baryTreeNew->setParent(nI, currB); baryTreeNew->deleteParent(lastNode); baryTreeNew->setParent(lastNode, nI); baryTreeNew->getNode(nI)->setOrigin(-1); std::vector nodesWithoutLink; - //baryTree->getNode(nI)->setOrigin(newIndices[tree->getNode(currT)->getOrigin()]); + //baryTreeNew->getNode(nI)->setOrigin(newIndices[tree->getNode(currT)->getOrigin()]); lastNode = newIndices[currT]; for(auto child : currChildren){ if(child==lastT) continue; q.emplace(child); - newIndices[child] = newScalars.size(); + newIndices[child] = currSize;//newScalars.size(); + currSize++; nI = newIndices[child]; //newScalars.emplace_back(tree->getValue(child)); dataType edgeLength = (joinTrees ? tree->getValue(currT) - tree->getValue(child) : tree->getValue(child) - tree->getValue(currT)); - newScalars.emplace_back(newScalars[newIndices[currT]] + (joinTrees ? - edgeLength * (alphas[i]/alphaSum) : edgeLength * (alphas[i]/alphaSum))); + //newScalars.emplace_back(newScalars[newIndices[currT]] + (joinTrees ? - edgeLength * (alphas[i]/alphaSum) : edgeLength * (alphas[i]/alphaSum))); + newScalars[nI] = newScalars[newIndices[currT]] + (joinTrees ? - edgeLength * (alphas[i]/alphaSum) : edgeLength * (alphas[i]/alphaSum)); baryTreeNew->makeNode(nI); baryTreeNew->setParent(nI, newIndices[currT]); baryTreeNew->getNode(nI)->setOrigin(-1); @@ -992,11 +1009,13 @@ namespace ttk { tree->getChildren(currNode,currChildren); for(auto child : currChildren){ q.emplace(child); - newIndices[child] = newScalars.size(); + newIndices[child] = currSize;//newScalars.size(); + currSize++; nI = newIndices[child]; //newScalars.emplace_back(tree->getValue(child)); dataType edgeLength = (joinTrees ? tree->getValue(currNode) - tree->getValue(child) : tree->getValue(child) - tree->getValue(currNode)); - newScalars.emplace_back(newScalars[newIndices[currNode]] + (joinTrees ? - edgeLength * (alphas[i]/alphaSum) : edgeLength * (alphas[i]/alphaSum))); + //newScalars.emplace_back(newScalars[newIndices[currNode]] + (joinTrees ? - edgeLength * (alphas[i]/alphaSum) : edgeLength * (alphas[i]/alphaSum))); + newScalars[nI] = newScalars[newIndices[currNode]] + (joinTrees ? - edgeLength * (alphas[i]/alphaSum) : edgeLength * (alphas[i]/alphaSum)); baryTreeNew->makeNode(nI); baryTreeNew->getNode(nI)->setOrigin(-1); baryTreeNew->setParent(nI, newIndices[currNode]); @@ -1026,7 +1045,7 @@ namespace ttk { printErr("Impossible Matching behaviour."); lastB = currB; lastT = currT; - currB = baryTree->getParentSafe(currB); + currB = baryTreeNew->getParentSafe(currB); currT = tree->getParentSafe(currT); } } @@ -1336,7 +1355,7 @@ namespace ttk { dataType minFrechet = std::numeric_limits::max(); int cptBlocked = 0; int NoIteration = 0; - while(not converged) { + while(not converged && NoIteration> &nodeCorr, bool useMinMaxPairT = true) { for(unsigned int i = 0; i < trees.size(); ++i) { - preprocessingPipeline( - trees[i], epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, - branchDecomposition_, useMinMaxPairT, cleanTree_, nodeCorr[i]); + if(baseModule_==2){ + ftm::FTMTree_MT *tree = &(trees[i].tree); + preprocessTree(tree, true); + + // - Delete null persistence pairs and persistence thresholding + persistenceThresholding(tree, persistenceThreshold_); + + // - Merge saddle points according epsilon + if(not isPersistenceDiagram_) { + if(epsilonTree2_ != 0){ + std::vector> treeNodeMerged( tree->getNumberOfNodes() ); + mergeSaddle(tree, epsilonTree2_, treeNodeMerged); + for(unsigned int j=0; jgetNode(j)->getOrigin(); + tree->getNode(k)->setOrigin(j); + tree->getNode(nodeToDelete)->setOrigin(-1); + } + } + ftm::cleanMergeTree(trees[i], nodeCorr[i], true); + } + else{ + std::vector nodeCorri(tree->getNumberOfNodes()); + for(unsigned int j=0; j(tree, false); + } + else{ + preprocessingPipeline( + trees[i], epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, + branchDecomposition_, useMinMaxPairT, cleanTree_, nodeCorr[i]); + } if(trees.size() < 40) printTreeStats(trees[i]); } diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index da969ecfb9..04bc0430d2 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -357,7 +357,8 @@ int ttkMergeTreeClustering::runCompute( mergeTreeBarycenter.setIsPersistenceDiagram(IsPersistenceDiagram); mergeTreeBarycenter.setAlpha(Alpha); mergeTreeBarycenter.setDeterministic(Deterministic); - mergeTreeBarycenter.setPersistenceThreshold(PersistenceThreshold); + mergeTreeBarycenter.setPersistenceThreshold(PersistenceThreshold); + mergeTreeBarycenter.setIterationLimit(iterationLimit); if(baseModule==2){ mergeTreeBarycenter.setPathMetric(this->pathMetric); mergeTreeBarycenter.setBranchDecomposition(false); diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h index f82d748dfb..3f6f055fbc 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h @@ -90,6 +90,7 @@ class TTKMERGETREECLUSTERING_EXPORT ttkMergeTreeClustering int pathMetric = 0; int branchMetric = 0; int baseModule = 0; + int iterationLimit = 0; // Output Options bool OutputTrees = true; @@ -340,6 +341,12 @@ class TTKMERGETREECLUSTERING_EXPORT ttkMergeTreeClustering resetDataVisualization(); } + void SetIterationLimit(int l) { + iterationLimit = l; + Modified(); + resetDataVisualization(); + } + // Output Options vtkSetMacro(BarycenterPositionAlpha, bool); vtkGetMacro(BarycenterPositionAlpha, bool); diff --git a/paraview/xmls/MergeTreeClustering.xml b/paraview/xmls/MergeTreeClustering.xml index 4f31e9441b..9a5f2a5d8b 100644 --- a/paraview/xmls/MergeTreeClustering.xml +++ b/paraview/xmls/MergeTreeClustering.xml @@ -186,6 +186,55 @@ Online examples: + + + + + + + + + + + + + + + + + + + + + + + Maximum number of iterations in barycenter computation. + + + Date: Wed, 7 Dec 2022 17:10:08 +0100 Subject: [PATCH 18/72] some cleanup in MergeTreeClustering --- .../BranchMappingDistance.h | 32 ++++---- .../mergeTreeClustering/MergeTreeBarycenter.h | 16 ++-- .../mergeTreeClustering/MergeTreeClustering.h | 8 +- .../mergeTreeClustering/PathMappingDistance.h | 82 +++++++++---------- .../ttkMergeTreeClustering.cpp | 2 +- .../ttkMergeTreeClustering.h | 12 +-- paraview/xmls/MergeTreeClustering.xml | 4 +- 7 files changed, 76 insertions(+), 80 deletions(-) diff --git a/core/base/mergeTreeClustering/BranchMappingDistance.h b/core/base/mergeTreeClustering/BranchMappingDistance.h index d65fd36382..0f6e888a86 100644 --- a/core/base/mergeTreeClustering/BranchMappingDistance.h +++ b/core/base/mergeTreeClustering/BranchMappingDistance.h @@ -607,7 +607,7 @@ namespace ttk { std::vector linkedNodes1(tree1->getNumberOfNodes(),-1); std::vector linkedNodes2(tree2->getNumberOfNodes(),-1); traceMapping_branch(tree1,tree2,children1[0],1,children2[0],1,predecessors1,predecessors2,depth1,depth2,memT,mapping); - dataType cost_mapping = 0; + //dataType cost_mapping = 0; for(auto m : mapping){ if(writeOptimalBranchDecomposition_ && m.first.first >=0 && m.first.second >=0){ tree1->getNode(m.first.first)->setOrigin(m.first.second); @@ -621,20 +621,20 @@ namespace ttk { linkedNodes2[m.second.first] = m.second.second; linkedNodes2[m.second.second] = m.second.first; } - dataType cost = this->baseMetric_ == 0 ? editCost_Wasserstein1( - m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2) - : this->baseMetric_ == 1 ? editCost_Wasserstein2( - m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2) - : this->baseMetric_ == 2 - ? editCost_Persistence( - m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2) - : editCost_Shifting( - m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2); - dataType cost_ = editCost_Wasserstein1( - m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2); - cost_mapping += cost_; - std::cout << "(" << m.first.first << " " << m.first.second << ") - (" << m.second.first << " " << m.second.second << ") : " << cost << " " << cost_;// << std::endl; - std::cout << "; (" << tree1->getValue(m.first.first) << " " << tree1->getValue(m.first.second) << ") - (" << tree2->getValue(m.second.first) << " " << tree2->getValue(m.second.second) << ")" << std::endl; + // dataType cost = this->baseMetric_ == 0 ? editCost_Wasserstein1( + // m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2) + // : this->baseMetric_ == 1 ? editCost_Wasserstein2( + // m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2) + // : this->baseMetric_ == 2 + // ? editCost_Persistence( + // m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2) + // : editCost_Shifting( + // m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2); + // dataType cost_ = editCost_Wasserstein1( + // m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2); + // cost_mapping += cost_; + //std::cout << "(" << m.first.first << " " << m.first.second << ") - (" << m.second.first << " " << m.second.second << ") : " << cost << " " << cost_;// << std::endl; + //std::cout << "; (" << tree1->getValue(m.first.first) << " " << tree1->getValue(m.first.second) << ") - (" << tree2->getValue(m.second.first) << " " << tree2->getValue(m.second.second) << ")" << std::endl; if(m.first.first == -1) continue; if(m.first.second == -1) continue; if(m.second.first == -1) continue; @@ -654,7 +654,7 @@ namespace ttk { if(matchedNodes[i]>=0) outputMatching->emplace_back(std::make_tuple(i,matchedNodes[i], 0.0)); } - std::cout << res << " " << cost_mapping << std::endl; + //std::cout << res << " " << cost_mapping << std::endl; } diff --git a/core/base/mergeTreeClustering/MergeTreeBarycenter.h b/core/base/mergeTreeClustering/MergeTreeBarycenter.h index 0b65105fb3..5d778583d3 100644 --- a/core/base/mergeTreeClustering/MergeTreeBarycenter.h +++ b/core/base/mergeTreeClustering/MergeTreeBarycenter.h @@ -52,7 +52,7 @@ namespace ttk { int pathMetric_ = 0; int baseModule_ = 0; - int iterationLimit_ = 0; + //int iterationLimit_ = 0; // Output std::vector finalDistances_; @@ -132,9 +132,9 @@ namespace ttk { pathMetric_ = m; } - void setIterationLimit(int l) { - iterationLimit_ = l; - } + // void setIterationLimit(int l) { + // iterationLimit_ = l; + // } /** * Implementation of the algorithm. @@ -295,10 +295,6 @@ namespace ttk { //baryTree = ftm::copyMergeTree(trees[bestIndex], true); baryTree = ftm::copyMergeTree(trees[bestIndex], baseModule_!=2); ftm::FTMTree_MT* bt = &(baryTree.tree); - std::cout << "Bary Root: " << bt->getRoot() << std::endl; - std::cout << "Tree Root: " << trees[bestIndex]->getRoot() << std::endl; - std::cout << "Bary Root Scalar Value: " << bt->getValue(bt->getRoot()) << std::endl; - std::cout << "Tree Root Scalar Value: " << trees[bestIndex]->getValue(trees[bestIndex]->getRoot()) << std::endl; limitSizeBarycenter(baryTree, trees); } @@ -1029,7 +1025,7 @@ namespace ttk { } } } - std::cout << baryTreeNew->getNode(newIndices[currT])->getOrigin() << " " << nodesWithoutLink.size() << std::endl; + //std::cout << baryTreeNew->getNode(newIndices[currT])->getOrigin() << " " << nodesWithoutLink.size() << std::endl; if(baryTreeNew->getNode(newIndices[currT])->getOrigin() < 0){ baryTreeNew->getNode(newIndices[currT])->setOrigin(nodesWithoutLink[0]); } @@ -1355,7 +1351,7 @@ namespace ttk { dataType minFrechet = std::numeric_limits::max(); int cptBlocked = 0; int NoIteration = 0; - while(not converged && NoIteration(trees[bestIndex], true); + = ftm::copyMergeTree(trees[bestIndex], baseModule_!=2); limitSizeBarycenter(allCentroids[0][i], trees, limitPercent); ftm::cleanMergeTree(allCentroids[0][i]); if(trees2.size() != 0) { allCentroids[1][i] - = ftm::copyMergeTree(trees2[bestIndex], true); + = ftm::copyMergeTree(trees2[bestIndex], baseModule_!=2); limitSizeBarycenter(allCentroids[1][i], trees2, limitPercent); ftm::cleanMergeTree(allCentroids[1][i]); } @@ -195,7 +195,7 @@ namespace ttk { distancesAndIndexes[i] = std::make_tuple(-bestDistance_[i], i); std::sort(distancesAndIndexes.begin(), distancesAndIndexes.end()); int bestIndex = std::get<1>(distancesAndIndexes[noNewCentroid]); - centroid = ftm::copyMergeTree(trees[bestIndex], true); + centroid = ftm::copyMergeTree(trees[bestIndex], baseModule_!=2); limitSizeBarycenter(centroid, trees); ftm::cleanMergeTree(centroid); } @@ -576,7 +576,7 @@ namespace ttk { lowerBound_[t][i] = 0; } else if(assignedTrees[i].size() == 1) { centroids[i] - = ftm::copyMergeTree(assignedTrees[i][0], true); + = ftm::copyMergeTree(assignedTrees[i][0], baseModule_!=2); limitSizeBarycenter(centroids[i], assignedTrees[i]); ftm::cleanMergeTree(centroids[i]); } else if(not samePreviousAssignment(i)) { diff --git a/core/base/mergeTreeClustering/PathMappingDistance.h b/core/base/mergeTreeClustering/PathMappingDistance.h index 47b3f843ea..783725f2d8 100644 --- a/core/base/mergeTreeClustering/PathMappingDistance.h +++ b/core/base/mergeTreeClustering/PathMappingDistance.h @@ -691,47 +691,47 @@ namespace ttk { outputMatching->clear(); traceMapping_path(tree1,tree2,children1[0],1,children2[0],1,predecessors1,predecessors2,depth1,depth2,memT,*outputMatching); - dataType cost_mapping = 0; - dataType cost_ins = 0; - dataType cost_del = 0; - std::vector matchedNodes1(tree1->getNumberOfNodes(),false); - std::vector matchedNodes2(tree2->getNumberOfNodes(),false); - for(auto m : *outputMatching){ - matchedNodes1[m.first.first] = true; - matchedNodes1[m.first.second] = true; - matchedNodes2[m.second.first] = true; - matchedNodes2[m.second.second] = true; - ftm::idNode cn = tree1->getParentSafe(m.first.first); - while(cn!=m.first.second){ - matchedNodes1[cn] = true; - cn = tree1->getParentSafe(cn); - } - cn = tree2->getParentSafe(m.second.first); - while(cn!=m.second.second){ - matchedNodes2[cn] = true; - cn = tree2->getParentSafe(cn); - } - dataType cost = editCost_Persistence( - m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2); - cost_mapping += cost; - std::cout << " (" << m.first.first << " " << m.first.second << ") - (" << m.second.first << " " << m.second.second << ") : " << cost << "\n"; - } - for(ftm::idNode i=0; igetNumberOfNodes(); i++){ - if(!matchedNodes1[i]){ - dataType cost = editCost_Persistence(i, tree1->getParentSafe(i), -1, -1, tree1, tree2); - std::cout << " (" << i << " " << tree1->getParentSafe(i) << ") - (" << -1 << " " << -1 << ") : " << cost << "\n"; - cost_del += cost; - } - } - for(ftm::idNode i=0; igetNumberOfNodes(); i++){ - if(!matchedNodes2[i]){ - dataType cost = editCost_Persistence(-1, -1, i, tree2->getParentSafe(i), tree1, tree2); - std::cout << " (" << -1 << " " << -1 << ") - (" << i << " " << tree2->getParentSafe(i) << ") : " << cost << "\n"; - cost_ins += cost; - } - } - std::cout << res << " " << cost_mapping+cost_ins+cost_del << std::endl; - std::cout << res << " " << cost_mapping << std::endl; + // dataType cost_mapping = 0; + // dataType cost_ins = 0; + // dataType cost_del = 0; + // std::vector matchedNodes1(tree1->getNumberOfNodes(),false); + // std::vector matchedNodes2(tree2->getNumberOfNodes(),false); + // for(auto m : *outputMatching){ + // matchedNodes1[m.first.first] = true; + // matchedNodes1[m.first.second] = true; + // matchedNodes2[m.second.first] = true; + // matchedNodes2[m.second.second] = true; + // ftm::idNode cn = tree1->getParentSafe(m.first.first); + // while(cn!=m.first.second){ + // matchedNodes1[cn] = true; + // cn = tree1->getParentSafe(cn); + // } + // cn = tree2->getParentSafe(m.second.first); + // while(cn!=m.second.second){ + // matchedNodes2[cn] = true; + // cn = tree2->getParentSafe(cn); + // } + // dataType cost = editCost_Persistence( + // m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2); + // cost_mapping += cost; + // // std::cout << " (" << m.first.first << " " << m.first.second << ") - (" << m.second.first << " " << m.second.second << ") : " << cost << "\n"; + // } + // for(ftm::idNode i=0; igetNumberOfNodes(); i++){ + // if(!matchedNodes1[i]){ + // dataType cost = editCost_Persistence(i, tree1->getParentSafe(i), -1, -1, tree1, tree2); + // // std::cout << " (" << i << " " << tree1->getParentSafe(i) << ") - (" << -1 << " " << -1 << ") : " << cost << "\n"; + // cost_del += cost; + // } + // } + // for(ftm::idNode i=0; igetNumberOfNodes(); i++){ + // if(!matchedNodes2[i]){ + // dataType cost = editCost_Persistence(-1, -1, i, tree2->getParentSafe(i), tree1, tree2); + // // std::cout << " (" << -1 << " " << -1 << ") - (" << i << " " << tree2->getParentSafe(i) << ") : " << cost << "\n"; + // cost_ins += cost; + // } + // } + // // std::cout << res << " " << cost_mapping+cost_ins+cost_del << std::endl; + // // std::cout << res << " " << cost_mapping << std::endl; } diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index 04bc0430d2..207ae80376 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -358,7 +358,7 @@ int ttkMergeTreeClustering::runCompute( mergeTreeBarycenter.setAlpha(Alpha); mergeTreeBarycenter.setDeterministic(Deterministic); mergeTreeBarycenter.setPersistenceThreshold(PersistenceThreshold); - mergeTreeBarycenter.setIterationLimit(iterationLimit); + //mergeTreeBarycenter.setIterationLimit(iterationLimit); if(baseModule==2){ mergeTreeBarycenter.setPathMetric(this->pathMetric); mergeTreeBarycenter.setBranchDecomposition(false); diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h index 3f6f055fbc..c19fe62f95 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h @@ -90,7 +90,7 @@ class TTKMERGETREECLUSTERING_EXPORT ttkMergeTreeClustering int pathMetric = 0; int branchMetric = 0; int baseModule = 0; - int iterationLimit = 0; + //int iterationLimit = 0; // Output Options bool OutputTrees = true; @@ -341,11 +341,11 @@ class TTKMERGETREECLUSTERING_EXPORT ttkMergeTreeClustering resetDataVisualization(); } - void SetIterationLimit(int l) { - iterationLimit = l; - Modified(); - resetDataVisualization(); - } + // void SetIterationLimit(int l) { + // iterationLimit = l; + // Modified(); + // resetDataVisualization(); + // } // Output Options vtkSetMacro(BarycenterPositionAlpha, bool); diff --git a/paraview/xmls/MergeTreeClustering.xml b/paraview/xmls/MergeTreeClustering.xml index 9a5f2a5d8b..9783d48b9a 100644 --- a/paraview/xmls/MergeTreeClustering.xml +++ b/paraview/xmls/MergeTreeClustering.xml @@ -186,7 +186,7 @@ Online examples: - Maximum number of iterations in barycenter computation. - + --> Date: Fri, 9 Dec 2022 15:45:00 +0100 Subject: [PATCH 19/72] [MergeTreeVisu] Branch Mapping planar layout --- .../MergeTreeVisualization.h | 49 ++++++++++++------- .../ttkMergeTreeVisualization.h | 4 +- 2 files changed, 34 insertions(+), 19 deletions(-) diff --git a/core/base/planarGraphLayout/MergeTreeVisualization.h b/core/base/planarGraphLayout/MergeTreeVisualization.h index a80928c95e..ff70ac694a 100644 --- a/core/base/planarGraphLayout/MergeTreeVisualization.h +++ b/core/base/planarGraphLayout/MergeTreeVisualization.h @@ -301,7 +301,8 @@ namespace ttk { std::queue queue; ftm::idNode treeRoot = tree->getRoot(); - ftm::idNode treeRootOrigin = tree->getNode(treeRoot)->getOrigin(); + // ftm::idNode treeRootOrigin = tree->getNode(treeRoot)->getOrigin(); + ftm::idNode lowestNode = tree->getLowestNode(treeRoot); queue.emplace(treeRoot); while(!queue.empty()) { ftm::idNode node = queue.front(); @@ -371,8 +372,7 @@ namespace ttk { // diff *= getNodePersistence(tree, treeRoot) / // refPersistence; dataType rootVal = tree->getValue(treeRoot); - dataType lowestNodeVal - = tree->getValue(tree->getLowestNode(treeRoot)); + dataType lowestNodeVal = tree->getValue(lowestNode); diff = (rootVal > lowestNodeVal ? rootVal - lowestNodeVal : lowestNodeVal - rootVal); offset = std::min(rootVal, lowestNodeVal); @@ -415,10 +415,13 @@ namespace ttk { printMsg("Move nodes given scalars", debug::Priority::VERBOSE); float rootY = retVec[treeSimplexId[treeRoot] * 2 + 1]; - float rootOriginY = retVec[treeSimplexId[treeRootOrigin] * 2 + 1]; + // float rootOriginY = retVec[treeSimplexId[treeRootOrigin] * 2 + 1]; + float rootOriginY = retVec[treeSimplexId[lowestNode] * 2 + 1]; float rootYmin = std::min(rootY, rootOriginY); float rootYmax = std::max(rootY, rootOriginY); - auto rootBirthDeath = tree->getBirthDeath(treeRoot); + + // TODO remove this code that should be useless + /*auto rootBirthDeath = tree->getBirthDeath(treeRoot); const double rootBirth = std::get<0>(rootBirthDeath); const double rootDeath = std::get<1>(rootBirthDeath); for(size_t i = 0; i < tree->getNumberOfNodes(); ++i) { @@ -426,27 +429,39 @@ namespace ttk { = (tree->getValue(i) - rootBirth) / (rootDeath - rootBirth); retVec[treeSimplexId[i] * 2 + 1] = retVec[treeSimplexId[i] * 2 + 1] * (rootYmax - rootYmin) + rootYmin; - } + }*/ std::stringstream ss4; ss4 << "MOVE SCALAR = " << t_move.getElapsedTime(); printMsg(ss4.str(), debug::Priority::VERBOSE); // ---------------------------------------------------- - // Scale pairs given persistence + // Sort leaves by branch depth // ---------------------------------------------------- - Timer t_scale; - printMsg("Scale pairs given persistence", debug::Priority::VERBOSE); - - dataType rootPers = tree->getNodePersistence(treeRoot); - std::vector leaves; tree->getLeavesFromTree(leaves); - auto compLowerPers = [&](const ftm::idNode a, const ftm::idNode b) { + /*auto compLowerPers = [&](const ftm::idNode a, const ftm::idNode b) { return tree->getNodePersistence(a) < tree->getNodePersistence(b); }; - std::sort(leaves.begin(), leaves.end(), compLowerPers); + std::sort(leaves.begin(), leaves.end(), compLowerPers);*/ + std::vector allNodeLevel; + tree->getAllNodeLevel(allNodeLevel); + auto compLevel = [&](const ftm::idNode a, const ftm::idNode b) { + return allNodeLevel[tree->getNode(a)->getOrigin()] + > allNodeLevel[tree->getNode(b)->getOrigin()]; + }; + std::sort(leaves.begin(), leaves.end(), compLevel); + + // ---------------------------------------------------- + // Scale pairs given persistence + // ---------------------------------------------------- + // TODO this code should also be useless + /*Timer t_scale; + printMsg("Scale pairs given persistence", debug::Priority::VERBOSE); + + dataType rootPers = tree->getNodePersistence(treeRoot); + std::stack stack; for(auto node : leaves) stack.emplace(node); @@ -502,7 +517,7 @@ namespace ttk { std::stringstream ss5; ss5 << "SCALE PERS. = " << t_scale.getElapsedTime(); - printMsg(ss5.str(), debug::Priority::VERBOSE); + printMsg(ss5.str(), debug::Priority::VERBOSE);*/ // ---------------------------------------------------- // Branches positionning and avoid edges crossing @@ -523,8 +538,8 @@ namespace ttk { std::vector allBranchOriginsSize(tree->getNumberOfNodes()); std::queue queueCrossing; - // ----- Get important and non-important pairs gap and store saddle nodes - // of each branch + // ----- Get important and non-important pairs gap and store branch + // origins of each branch int maxSize = std::numeric_limits::lowest(); for(auto leaf : leaves) queueCrossing.emplace(leaf); diff --git a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h index dbe7c8a2f6..7c6a9b9700 100644 --- a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h +++ b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h @@ -159,9 +159,9 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { void setIsPDSadMax(bool isSadMax) { isPDSadMax = isSadMax; } - + void setPathMappingLayout(bool pathLayout) { - pathMappingLayout = pathLayout; + pathMappingLayout = pathLayout; } // Offset From 94c831ca6002d77df9877190048afbdb1c4e395a Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Mon, 12 Dec 2022 16:32:08 +0100 Subject: [PATCH 20/72] MergeTreeClustering working with Path Mapping Distance --- .../mergeTreeClustering/MergeTreeBarycenter.h | 2 +- .../mergeTreeClustering/MergeTreeClustering.h | 74 ++++++++++++++----- .../ttkMergeTreeClustering.cpp | 2 + paraview/xmls/MergeTreeClustering.xml | 28 ++++--- 4 files changed, 77 insertions(+), 29 deletions(-) diff --git a/core/base/mergeTreeClustering/MergeTreeBarycenter.h b/core/base/mergeTreeClustering/MergeTreeBarycenter.h index 5d778583d3..2f53debdbe 100644 --- a/core/base/mergeTreeClustering/MergeTreeBarycenter.h +++ b/core/base/mergeTreeClustering/MergeTreeBarycenter.h @@ -291,7 +291,7 @@ namespace ttk { ftm::MergeTree &baryTree, bool distMinimizer = true) { int bestIndex = getBestInitTreeIndex(trees, distMinimizer); - bestIndex = trees.size()-1; + // bestIndex = trees.size()-1; //baryTree = ftm::copyMergeTree(trees[bestIndex], true); baryTree = ftm::copyMergeTree(trees[bestIndex], baseModule_!=2); ftm::FTMTree_MT* bt = &(baryTree.tree); diff --git a/core/base/mergeTreeClustering/MergeTreeClustering.h b/core/base/mergeTreeClustering/MergeTreeClustering.h index 346b7a4506..d082efed0a 100644 --- a/core/base/mergeTreeClustering/MergeTreeClustering.h +++ b/core/base/mergeTreeClustering/MergeTreeClustering.h @@ -438,15 +438,33 @@ namespace ttk { std::vector distances(assignedTrees[i].size(), 0); std::vector distances2(assignedTrees[i].size(), 0); treesMatchingVector matching(trees.size()), matching2(trees2.size()); - assignment( - assignedTrees[i], centroids[i], matching, distances, useDoubleInput_); - matchingsC[i] = matching; - if(trees2.size() != 0) { - assignment(assignedTrees2[i], centroids2[i], matching2, - distances2, useDoubleInput_, false); - matchingsC2[i] = matching2; - for(unsigned int j = 0; j < assignedTreesIndex[i].size(); ++j) - distances[j] = mixDistances(distances[j], distances2[j]); + if(baseModule_ == 2){ + std::vector,std::pair>>> matching_path(trees.size()); + assignment_path( + assignedTrees[i], centroids[i], matching_path, distances); + for(unsigned int j=0; j matchedNodes(assignedTrees[i][j]->getNumberOfNodes(),-1); + for(auto m : matching_path[j]){ + matchedNodes[m.second.first] = m.first.first; + matchedNodes[m.second.second] = m.first.second; + } + for(ftm::idNode k=0; k=0) matching[j].emplace_back(std::make_tuple(matchedNodes[k],k, 0.0)); + } + } + matchingsC[i] = matching; + } + else{ + assignment( + assignedTrees[i], centroids[i], matching, distances, useDoubleInput_); + matchingsC[i] = matching; + if(trees2.size() != 0) { + assignment(assignedTrees2[i], centroids2[i], matching2, + distances2, useDoubleInput_, false); + matchingsC2[i] = matching2; + for(unsigned int j = 0; j < assignedTreesIndex[i].size(); ++j) + distances[j] = mixDistances(distances[j], distances2[j]); + } } for(unsigned int j = 0; j < assignedTreesIndex[i].size(); ++j) { int index = assignedTreesIndex[i][j]; @@ -616,28 +634,50 @@ namespace ttk { std::vector>> &finalMatchings) { MergeTreeBarycenter mergeTreeBary; + mergeTreeBary.setDebugLevel(std::min(debugLevel_, 2)); + mergeTreeBary.setBaseModule(this->baseModule_); mergeTreeBary.setProgressiveComputation(false); - mergeTreeBary.setBranchDecomposition(true); - mergeTreeBary.setNormalizedWasserstein(normalizedWasserstein_); - mergeTreeBary.setNormalizedWassersteinReg(normalizedWassersteinReg_); - mergeTreeBary.setRescaledWasserstein(rescaledWasserstein_); - mergeTreeBary.setKeepSubtree(keepSubtree_); mergeTreeBary.setAssignmentSolver(assignmentSolverID_); mergeTreeBary.setIsCalled(true); mergeTreeBary.setThreadNumber(this->threadNumber_); mergeTreeBary.setDistanceSquared(true); // squared root - mergeTreeBary.setProgressiveBarycenter(progressiveBarycenter_); mergeTreeBary.setDeterministic(deterministic_); mergeTreeBary.setTol(tol_); mergeTreeBary.setBarycenterMaximumNumberOfPairs( barycenterMaximumNumberOfPairs_); mergeTreeBary.setBarycenterSizeLimitPercent(barycenterSizeLimitPercent_); + if(baseModule_==2){ + mergeTreeBary.setPathMetric(this->pathMetric_); + mergeTreeBary.setBranchDecomposition(false); + mergeTreeBary.setNormalizedWasserstein(false); + mergeTreeBary.setKeepSubtree(false); + mergeTreeBary.setUseMinMaxPair(false); + mergeTreeBary.setAddNodes(false); + mergeTreeBary.setPostprocess(false); + } + else{ + mergeTreeBary.setBranchDecomposition(true); + mergeTreeBary.setNormalizedWasserstein(normalizedWasserstein_); + mergeTreeBary.setNormalizedWassersteinReg(normalizedWassersteinReg_); + mergeTreeBary.setRescaledWasserstein(rescaledWasserstein_); + mergeTreeBary.setKeepSubtree(keepSubtree_); + mergeTreeBary.setProgressiveBarycenter(progressiveBarycenter_); + } + mergeTreeBary.computeBarycenter( trees, baryMergeTree, alphas, finalMatchings); addDeletedNodesTime_ += mergeTreeBary.getAddDeletedNodesTime(); + + if(baseModule_==2){ + ftm::FTMTree_MT* baryTree = &(baryMergeTree.tree); + for(ftm::idNode node=0; nodegetNumberOfNodes(); node++){ + baryTree->getNode(node)->setOrigin(-1); + } + preprocessTree(baryTree,false); + } } // ------------------------------------------------------------------------ @@ -802,7 +842,7 @@ namespace ttk { outputMatching2); // --- Postprocessing - if(postprocess_) { + if(baseModule_==0 && postprocess_) { // fixMergedRootOriginClustering(centroids); postprocessingClustering( trees, centroids, outputMatching, clusteringAssignment); @@ -875,7 +915,7 @@ namespace ttk { } else{ std::vector nodeCorri(tree->getNumberOfNodes()); - for(unsigned int j=0; j mergeTreeClustering; mergeTreeClustering.setAssignmentSolver(AssignmentSolver); + mergeTreeClustering.setBaseModule(this->baseModule); + mergeTreeClustering.setPathMetric(this->pathMetric); mergeTreeClustering.setEpsilonTree1(EpsilonTree1); mergeTreeClustering.setEpsilonTree2(EpsilonTree2); mergeTreeClustering.setEpsilon2Tree1(Epsilon2Tree1); diff --git a/paraview/xmls/MergeTreeClustering.xml b/paraview/xmls/MergeTreeClustering.xml index 9783d48b9a..45304705e0 100644 --- a/paraview/xmls/MergeTreeClustering.xml +++ b/paraview/xmls/MergeTreeClustering.xml @@ -289,27 +289,33 @@ Online examples: - - - - + + + + + + + + value="0" /> + property="Backend" + value="4" /> Date: Thu, 15 Dec 2022 18:00:48 +0100 Subject: [PATCH 21/72] [MergeTreeVisu] fix isImportantPair for general branch decomposition --- core/base/ftmTree/FTMTreeUtils_Template.h | 60 ++++++++++++++++++----- 1 file changed, 47 insertions(+), 13 deletions(-) diff --git a/core/base/ftmTree/FTMTreeUtils_Template.h b/core/base/ftmTree/FTMTreeUtils_Template.h index eb2505cad4..c711491180 100644 --- a/core/base/ftmTree/FTMTreeUtils_Template.h +++ b/core/base/ftmTree/FTMTreeUtils_Template.h @@ -37,21 +37,55 @@ namespace ttk { double threshold, std::vector &excludeLower, std::vector &excludeHigher) { - dataType rootPers = this->getNodePersistence(this->getRoot()); - if(threshold > 1) - threshold /= 100.0; + idNode treeRoot = this->getRoot(); + dataType rootValue = this->getValue(treeRoot); + dataType lowestNodeValue + = this->getValue(this->getLowestNode(treeRoot)); + dataType rootPers + = (rootValue > lowestNodeValue ? rootValue - lowestNodeValue + : lowestNodeValue - rootValue); + threshold /= 100.0; threshold = rootPers * threshold; - auto pers = this->getNodePersistence(nodeId); - - // Excluded pairs - bool isExcluded = false; - if(excludeLower.size() == excludeHigher.size()) - for(unsigned i = 0; i < excludeLower.size(); ++i) { - isExcluded |= (pers > rootPers * excludeLower[i] / 100.0 - and pers < rootPers * excludeHigher[i] / 100.0); - } - return pers > threshold and not isExcluded; + auto isImportantPairOneNode = [&](idNode node) { + auto pers = this->getNodePersistence(node); + + // Excluded pairs + bool isExcluded = false; + if(excludeLower.size() == excludeHigher.size()) + for(unsigned i = 0; i < excludeLower.size(); ++i) { + isExcluded |= (pers > rootPers * excludeLower[i] / 100.0 + and pers < rootPers * excludeHigher[i] / 100.0); + } + return (pers > threshold and not isExcluded); + }; + + if(isImportantPairOneNode(nodeId)) + return true; + + // Test if it is a parent of an important pair (for not persistence based + // branch decomposition) + bool parentOfImportantPair = false; + std::queue queue; + queue.emplace(nodeId); + while(!queue.empty()) { + idNode node = queue.front(); + queue.pop(); + + if(this->isLeaf(node)) + continue; + + parentOfImportantPair |= isImportantPairOneNode(node); + + if(parentOfImportantPair) + break; + std::vector children; + this->getChildren(node, children); + for(auto child : children) + queue.emplace(child); + } + + return parentOfImportantPair; } template From 4a1fddeef4d154397ae8254b19a3f84e3b829cdd Mon Sep 17 00:00:00 2001 From: MatPont Date: Fri, 13 Jan 2023 10:11:43 +0100 Subject: [PATCH 22/72] [PathLayout] add path layout filter parameter and remove some old code --- CMake/merge_tree_planar_layout.xml | 20 ++++ .../MergeTreeVisualization.h | 112 ++---------------- .../ttkMergeTreeClustering.h | 6 +- .../ttkMergeTreeTemporalReductionDecoding.h | 4 + .../ttkPlanarGraphLayout.h | 4 + 5 files changed, 42 insertions(+), 104 deletions(-) diff --git a/CMake/merge_tree_planar_layout.xml b/CMake/merge_tree_planar_layout.xml index bf4b57cd3f..333b3035d1 100644 --- a/CMake/merge_tree_planar_layout.xml +++ b/CMake/merge_tree_planar_layout.xml @@ -17,6 +17,25 @@ panel_visibility="advanced"> + + + + + + + + + + + diff --git a/core/base/planarGraphLayout/MergeTreeVisualization.h b/core/base/planarGraphLayout/MergeTreeVisualization.h index ff70ac694a..5d0616925b 100644 --- a/core/base/planarGraphLayout/MergeTreeVisualization.h +++ b/core/base/planarGraphLayout/MergeTreeVisualization.h @@ -17,6 +17,7 @@ namespace ttk { protected: // Visualization parameters bool branchDecompositionPlanarLayout_ = false; + bool pathPlanarLayout_ = false; double branchSpacing_ = 1.; bool rescaleTreesIndividually_ = false; double importantPairs_ = 50.; // important pairs threshold @@ -409,42 +410,14 @@ namespace ttk { } // ---------------------------------------------------- - // Move nodes given scalars + // Branches positionning and avoid edges crossing // ---------------------------------------------------- - Timer t_move; - printMsg("Move nodes given scalars", debug::Priority::VERBOSE); - - float rootY = retVec[treeSimplexId[treeRoot] * 2 + 1]; - // float rootOriginY = retVec[treeSimplexId[treeRootOrigin] * 2 + 1]; - float rootOriginY = retVec[treeSimplexId[lowestNode] * 2 + 1]; - float rootYmin = std::min(rootY, rootOriginY); - float rootYmax = std::max(rootY, rootOriginY); - - // TODO remove this code that should be useless - /*auto rootBirthDeath = tree->getBirthDeath(treeRoot); - const double rootBirth = std::get<0>(rootBirthDeath); - const double rootDeath = std::get<1>(rootBirthDeath); - for(size_t i = 0; i < tree->getNumberOfNodes(); ++i) { - retVec[treeSimplexId[i] * 2 + 1] - = (tree->getValue(i) - rootBirth) / (rootDeath - rootBirth); - retVec[treeSimplexId[i] * 2 + 1] - = retVec[treeSimplexId[i] * 2 + 1] * (rootYmax - rootYmin) + rootYmin; - }*/ - - std::stringstream ss4; - ss4 << "MOVE SCALAR = " << t_move.getElapsedTime(); - printMsg(ss4.str(), debug::Priority::VERBOSE); + Timer t_avoid; + printMsg("Avoid edges crossing", debug::Priority::VERBOSE); - // ---------------------------------------------------- // Sort leaves by branch depth - // ---------------------------------------------------- std::vector leaves; tree->getLeavesFromTree(leaves); - /*auto compLowerPers = [&](const ftm::idNode a, const ftm::idNode b) { - return tree->getNodePersistence(a) - < tree->getNodePersistence(b); - }; - std::sort(leaves.begin(), leaves.end(), compLowerPers);*/ std::vector allNodeLevel; tree->getAllNodeLevel(allNodeLevel); auto compLevel = [&](const ftm::idNode a, const ftm::idNode b) { @@ -453,78 +426,11 @@ namespace ttk { }; std::sort(leaves.begin(), leaves.end(), compLevel); - // ---------------------------------------------------- - // Scale pairs given persistence - // ---------------------------------------------------- - // TODO this code should also be useless - /*Timer t_scale; - printMsg("Scale pairs given persistence", debug::Priority::VERBOSE); - - dataType rootPers = tree->getNodePersistence(treeRoot); - - std::stack stack; - for(auto node : leaves) - stack.emplace(node); - std::vector nodeDone(tree->getNumberOfNodes(), false); - while(!stack.empty()) { - ftm::idNode node = stack.top(); - stack.pop(); - nodeDone[node] = true; - - if(node == treeRoot or node == treeRootOrigin - or tree->isNodeAlone(node)) - continue; - - dataType nodePers = tree->getNodePersistence(node); - ftm::idNode nodeOrigin = tree->getNode(node)->getOrigin(); - - // Manage leaf - if(tree->isLeaf(node)) { - float nodeDiff = (retVec[treeSimplexId[node] * 2] - - retVec[treeSimplexId[nodeOrigin] * 2]); - const auto sign = nodeDiff / std::abs(nodeDiff); - auto inc = sign * nodePers / rootPers * (rootYmax - rootYmin) / 2; - retVec[treeSimplexId[node] * 2] - = retVec[treeSimplexId[nodeOrigin] * 2] + inc; - - // Push nodes in the branch to the stack - ftm::idNode nodeParent = tree->getParentSafe(node); - ftm::idNode oldNodeParent = -1; - while(nodeParent != nodeOrigin) { - if(not nodeDone[nodeParent]) - stack.emplace(nodeParent); - else - break; - oldNodeParent = nodeParent; - nodeParent = tree->getParentSafe(nodeParent); - if(oldNodeParent == nodeParent) { - std::stringstream ss5; - ss5 << "treePlanarLayoutImpl oldNodeParent == nodeParent"; - printMsg(ss5.str(), debug::Priority::VERBOSE); - break; - } - } - } - - // Manage saddle - if(not tree->isLeaf(node) and not tree->isRoot(node)) { - float branchY - = retVec[treeSimplexId[tree->getNode(branching[node])->getOrigin()] - * 2]; - retVec[treeSimplexId[node] * 2] = branchY; - } - } - - std::stringstream ss5; - ss5 << "SCALE PERS. = " << t_scale.getElapsedTime(); - printMsg(ss5.str(), debug::Priority::VERBOSE);*/ - - // ---------------------------------------------------- - // Branches positionning and avoid edges crossing - // ---------------------------------------------------- - Timer t_avoid; - printMsg("Avoid edges crossing", debug::Priority::VERBOSE); - + // Init some variables + float rootY = retVec[treeSimplexId[treeRoot] * 2 + 1]; + float rootOriginY = retVec[treeSimplexId[lowestNode] * 2 + 1]; + float rootYmin = std::min(rootY, rootOriginY); + float rootYmax = std::max(rootY, rootOriginY); bool isJT = tree->isJoinTree(); auto compValue = [&](const ftm::idNode a, const ftm::idNode b) { return (isJT diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h index c19fe62f95..550b872768 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h @@ -90,13 +90,14 @@ class TTKMERGETREECLUSTERING_EXPORT ttkMergeTreeClustering int pathMetric = 0; int branchMetric = 0; int baseModule = 0; - //int iterationLimit = 0; + // int iterationLimit = 0; // Output Options bool OutputTrees = true; bool OutputSegmentation = false; bool PlanarLayout = false; bool BranchDecompositionPlanarLayout = false; + bool PathPlanarLayout = false; double BranchSpacing = 1.; bool RescaleTreesIndividually = false; double DimensionSpacing = 1.; @@ -363,6 +364,9 @@ class TTKMERGETREECLUSTERING_EXPORT ttkMergeTreeClustering vtkSetMacro(BranchDecompositionPlanarLayout, bool); vtkGetMacro(BranchDecompositionPlanarLayout, bool); + vtkSetMacro(PathPlanarLayout, bool); + vtkGetMacro(PathPlanarLayout, bool); + vtkSetMacro(BranchSpacing, double); vtkGetMacro(BranchSpacing, double); diff --git a/core/vtk/ttkMergeTreeTemporalReductionDecoding/ttkMergeTreeTemporalReductionDecoding.h b/core/vtk/ttkMergeTreeTemporalReductionDecoding/ttkMergeTreeTemporalReductionDecoding.h index 17f751efc2..de8a0b96cd 100644 --- a/core/vtk/ttkMergeTreeTemporalReductionDecoding/ttkMergeTreeTemporalReductionDecoding.h +++ b/core/vtk/ttkMergeTreeTemporalReductionDecoding/ttkMergeTreeTemporalReductionDecoding.h @@ -85,6 +85,7 @@ class TTKMERGETREETEMPORALREDUCTIONDECODING_EXPORT bool OutputTrees = true; bool PlanarLayout = false; bool BranchDecompositionPlanarLayout = false; + bool PathPlanarLayout = false; double BranchSpacing = 1.; bool RescaleTreesIndividually = false; double DimensionSpacing = 1.; @@ -155,6 +156,9 @@ class TTKMERGETREETEMPORALREDUCTIONDECODING_EXPORT vtkSetMacro(BranchDecompositionPlanarLayout, bool); vtkGetMacro(BranchDecompositionPlanarLayout, bool); + vtkSetMacro(PathPlanarLayout, bool); + vtkGetMacro(PathPlanarLayout, bool); + vtkSetMacro(BranchSpacing, double); vtkGetMacro(BranchSpacing, double); diff --git a/core/vtk/ttkPlanarGraphLayout/ttkPlanarGraphLayout.h b/core/vtk/ttkPlanarGraphLayout/ttkPlanarGraphLayout.h index 9e8df59cca..400dc50448 100644 --- a/core/vtk/ttkPlanarGraphLayout/ttkPlanarGraphLayout.h +++ b/core/vtk/ttkPlanarGraphLayout/ttkPlanarGraphLayout.h @@ -77,6 +77,7 @@ class TTKPLANARGRAPHLAYOUT_EXPORT ttkPlanarGraphLayout // --- Merge Tree Planar Layout bool InputIsAMergeTree = false; bool BranchDecompositionPlanarLayout = false; + bool PathPlanarLayout = false; double BranchSpacing = 1.; double ImportantPairs = 10.; // important pairs threshold int MaximumImportantPairs = 0; @@ -113,6 +114,9 @@ class TTKPLANARGRAPHLAYOUT_EXPORT ttkPlanarGraphLayout vtkSetMacro(BranchDecompositionPlanarLayout, bool); vtkGetMacro(BranchDecompositionPlanarLayout, bool); + vtkSetMacro(PathPlanarLayout, bool); + vtkGetMacro(PathPlanarLayout, bool); + vtkSetMacro(BranchSpacing, double); vtkGetMacro(BranchSpacing, double); From cd5bc07a557fd3783908560528e95602d6ecfe31 Mon Sep 17 00:00:00 2001 From: MatPont Date: Fri, 13 Jan 2023 14:05:51 +0100 Subject: [PATCH 23/72] [PathLayout] work on layout --- .../MergeTreeVisualization.h | 117 ++++++++++++++++-- .../ttkMergeTreeClustering.cpp | 75 ++++++----- .../ttkMergeTreeVisualization.h | 7 +- 3 files changed, 148 insertions(+), 51 deletions(-) diff --git a/core/base/planarGraphLayout/MergeTreeVisualization.h b/core/base/planarGraphLayout/MergeTreeVisualization.h index 5d0616925b..bc4e616a37 100644 --- a/core/base/planarGraphLayout/MergeTreeVisualization.h +++ b/core/base/planarGraphLayout/MergeTreeVisualization.h @@ -33,13 +33,16 @@ namespace ttk { MergeTreeVisualization() = default; ~MergeTreeVisualization() override = default; - // ========================================================================== + // ======================================================================== // Getter / Setter - // ========================================================================== + // ======================================================================== // Visualization parameters void setBranchDecompositionPlanarLayout(bool b) { branchDecompositionPlanarLayout_ = b; } + void setPathPlanarLayout(bool b) { + pathPlanarLayout_ = b; + } void setBranchSpacing(double d) { branchSpacing_ = d; } @@ -67,9 +70,9 @@ namespace ttk { parseExcludeImportantPairsString(d, excludeImportantPairsLowerValues_); } - // ========================================================================== - // Planar Layout - // ========================================================================== + // ======================================================================== + // Branch Decomposition Tree Planar Layout + // ======================================================================== // TODO manage multi pers pairs template void treePlanarLayoutBDImpl( @@ -263,6 +266,85 @@ namespace ttk { } } + // ======================================================================== + // Path Planar Layout + // ======================================================================== + // TODO manage multi pers pairs + template + void pathPlanarLayout(ftm::FTMTree_MT *tree, + std::vector &retVec, + std::vector &treeSimplexId, + std::vector &leaves, + double importantPairsGap) { + std::queue queue; + for(auto &node : leaves) + queue.emplace(node); + std::vector nodeDone(tree->getNumberOfNodes(), false); + std::vector> bounds(tree->getNumberOfNodes()); + while(!queue.empty()) { + ftm::idNode node = queue.front(); + queue.pop(); + if(nodeDone[node]) + continue; + + bool isNodeImportant = tree->isImportantPair( + node, importantPairs_, excludeImportantPairsLowerValues_, + excludeImportantPairsHigherValues_); + if(not isNodeImportant) + continue; + + if(!tree->isLeaf(node) and !tree->isRoot(node)) { + float nodeX = retVec[treeSimplexId[node] * 2]; + std::vector children; + tree->getChildren(node, children); + ftm::idNode child1 = children[0]; + ftm::idNode child2 = children[1]; + if(not nodeDone[child1] or not nodeDone[child2]) + printErr("not nodeDone[child1] or not nodeDone[child2]"); + float child1XMax = bounds[child1][1]; + double child1Shift = -child1XMax + nodeX - importantPairsGap / 2.0; + shiftSubtreeBounds(tree, child1, child1Shift, retVec, treeSimplexId); + float child2XMin = bounds[child2][0]; + double child2Shift = -child2XMin + nodeX + importantPairsGap / 2.0; + shiftSubtreeBounds(tree, child2, child2Shift, retVec, treeSimplexId); + bounds[node] = {std::min(bounds[child1][0], bounds[child2][0]), + std::max(bounds[child1][1], bounds[child2][1]), + std::min(bounds[child1][2], bounds[child2][2]), + std::max(bounds[child1][3], bounds[child2][3])}; + } else + bounds[node] + = {retVec[treeSimplexId[node] * 2], retVec[treeSimplexId[node] * 2], + retVec[treeSimplexId[node] * 2 + 1], + retVec[treeSimplexId[node] * 2 + 1]}; + + nodeDone[node] = true; + queue.emplace(tree->getParentSafe(node)); + } + } + + void shiftSubtreeBounds(ftm::FTMTree_MT *tree, + ftm::idNode subtreeRoot, + double shift, + std::vector &retVec, + std::vector &treeSimplexId) { + std::queue queue; + queue.emplace(subtreeRoot); + while(!queue.empty()) { + ftm::idNode node = queue.front(); + queue.pop(); + + retVec[treeSimplexId[node] * 2] += shift; + + std::vector children; + tree->getChildren(node, children); + for(auto &child : children) + queue.emplace(child); + } + } + + // ======================================================================== + // Merge Tree Planar Layout + // ======================================================================== // TODO manage multi pers pairs template void treePlanarLayoutImpl( @@ -596,11 +678,12 @@ namespace ttk { // ----- Correction of important/non-important pairs gap // TODO the gap between important pairs can be higher than the minimum gap // needed to avoid conflict. The gap is computed using the maximum number - // of non-important pairs attached to an inmportant pairs Unfortunately + // of non-important pairs attached to an important pairs. Unfortunately // the real gap can only be computed here, after the conflicts has been // avoided. The maximum real gap must be calculated and propagated to all // important branches and we also need to manage to avoid conflict with - // this new gap. Get real gap + // this new gap. + // Get real gap double realImportantPairsGap = std::numeric_limits::lowest(); /*if(customimportantPairsSpacing_) realImportantPairsGap = importantPairsGap; @@ -666,6 +749,15 @@ namespace ttk { ss6 << "AVOID CROSSING = " << t_avoid.getElapsedTime(); printMsg(ss6.str(), debug::Priority::VERBOSE); printMsg(debug::Separator::L2, debug::Priority::VERBOSE); + + // ---------------------------------------------------- + // Call Path Planar Layout if asked + // ---------------------------------------------------- + if(pathPlanarLayout_) { + pathPlanarLayout( + tree, retVec, treeSimplexId, leaves, importantPairsGap); + return; + } } template @@ -677,6 +769,9 @@ namespace ttk { treePlanarLayoutImpl(tree, oldBounds, refPersistence, res); } + // ======================================================================== + // Persistence Diagram Planar Layout + // ======================================================================== template void persistenceDiagramPlanarLayout(ftm::FTMTree_MT *tree, std::vector &res) { @@ -703,9 +798,9 @@ namespace ttk { } } - // ========================================================================== + // ======================================================================== // Bounds Utils - // ========================================================================== + // ======================================================================== void printTuple(std::tuple tup) { printMsg(debug::Separator::L2, debug::Priority::VERBOSE); std::stringstream ss; @@ -892,9 +987,9 @@ namespace ttk { return std::make_tuple(x_min, x_max, y_min, y_max, z_min, z_max); } - // ========================================================================== + // ======================================================================== // Utils - // ========================================================================== + // ======================================================================== void parseExcludeImportantPairsString(std::string &exludeString, std::vector &excludeVector) { excludeVector.clear(); diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index 70d2951e83..d6e702ca4b 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -1,13 +1,13 @@ +#include #include #include #include #include #include +#include #include #include #include -#include -#include #include // For port information #include // for new macro @@ -132,7 +132,8 @@ int ttkMergeTreeClustering::RequestData(vtkInformation *ttkNotUsed(request), // filter out new backends (not yet supported) if(baseModule == 1 && ComputeBarycenter) { - printErr("Invalid Backend chosen. Branch Mapping Distance not yet supported for Barycenter computation. Canceling computation."); + printErr("Invalid Backend chosen. Branch Mapping Distance not yet " + "supported for Barycenter computation. Canceling computation."); return 1; } @@ -248,7 +249,7 @@ int ttkMergeTreeClustering::runCompute( // Call base if(not ComputeBarycenter) { - if(baseModule==0){ + if(baseModule == 0) { MergeTreeDistance mergeTreeDistance; mergeTreeDistance.setAssignmentSolver(AssignmentSolver); mergeTreeDistance.setEpsilonTree1(EpsilonTree1); @@ -274,8 +275,7 @@ int ttkMergeTreeClustering::runCompute( intermediateMTrees[0], intermediateMTrees[1], outputMatching); trees1NodeCorrMesh = mergeTreeDistance.getTreesNodeCorr(); finalDistances = std::vector{distance}; - } - else if(baseModule==1){ + } else if(baseModule == 1) { BranchMappingDistance branchDist; branchDist.setBaseMetric(branchMetric); branchDist.setAssignmentSolver(AssignmentSolver); @@ -287,23 +287,28 @@ int ttkMergeTreeClustering::runCompute( branchDist.setEpsilonTree1(EpsilonTree1); branchDist.setEpsilonTree2(EpsilonTree2); branchDist.setPersistenceThreshold(PersistenceThreshold); - //branchDist.setUseMinMaxPair(UseMinMaxPair); + // branchDist.setUseMinMaxPair(UseMinMaxPair); branchDist.setDeleteMultiPersPairs(DeleteMultiPersPairs); - //branchDist.setEpsilon1UseFarthestSaddle(Epsilon1UseFarthestSaddle); + // branchDist.setEpsilon1UseFarthestSaddle(Epsilon1UseFarthestSaddle); branchDist.setPersistenceThreshold(PersistenceThreshold); branchDist.setThreadNumber(this->threadNumber_); branchDist.setDebugLevel(this->debugLevel_); - distance = branchDist.editDistance_branch(intermediateTrees[0], intermediateTrees[1], &outputMatching); - - std::vector nodeCorr1(intermediateTrees[0]->getNumberOfNodes()); - std::vector nodeCorr2(intermediateTrees[1]->getNumberOfNodes()); - for(unsigned int i=0; i>{nodeCorr1,nodeCorr2}; + distance = branchDist.editDistance_branch( + intermediateTrees[0], intermediateTrees[1], &outputMatching); + + std::vector nodeCorr1( + intermediateTrees[0]->getNumberOfNodes()); + std::vector nodeCorr2( + intermediateTrees[1]->getNumberOfNodes()); + for(unsigned int i = 0; i < nodeCorr1.size(); i++) + nodeCorr1[i] = i; + for(unsigned int i = 0; i < nodeCorr2.size(); i++) + nodeCorr2[i] = i; + trees1NodeCorrMesh + = std::vector>{nodeCorr1, nodeCorr2}; finalDistances = std::vector{distance}; - } - else{ + } else { PathMappingDistance pathDist; pathDist.setBaseMetric(pathMetric); pathDist.setAssignmentSolver(AssignmentSolver); @@ -314,21 +319,24 @@ int ttkMergeTreeClustering::runCompute( pathDist.setEpsilonTree1(EpsilonTree1); pathDist.setEpsilonTree2(EpsilonTree2); pathDist.setPersistenceThreshold(PersistenceThreshold); - //pathDist.setUseMinMaxPair(UseMinMaxPair); + // pathDist.setUseMinMaxPair(UseMinMaxPair); pathDist.setDeleteMultiPersPairs(DeleteMultiPersPairs); - //pathDist.setEpsilon1UseFarthestSaddle(Epsilon1UseFarthestSaddle); + // pathDist.setEpsilon1UseFarthestSaddle(Epsilon1UseFarthestSaddle); pathDist.setPersistenceThreshold(PersistenceThreshold); pathDist.setThreadNumber(this->threadNumber_); pathDist.setDebugLevel(this->debugLevel_); - distance = pathDist.editDistance_path(intermediateTrees[0], intermediateTrees[1], &outputMatching); + distance = pathDist.editDistance_path( + intermediateTrees[0], intermediateTrees[1], &outputMatching); trees1NodeCorrMesh = pathDist.getTreesNodeCorr(); - // std::vector nodeCorr1(intermediateTrees[0]->getNumberOfNodes()); - // std::vector nodeCorr2(intermediateTrees[1]->getNumberOfNodes()); - // for(ttk::SimplexId i=0; i>{nodeCorr1,nodeCorr2}; + // std::vector + // nodeCorr1(intermediateTrees[0]->getNumberOfNodes()); + // std::vector + // nodeCorr2(intermediateTrees[1]->getNumberOfNodes()); for(ttk::SimplexId + // i=0; i>{nodeCorr1,nodeCorr2}; finalDistances = std::vector{distance}; } } else { @@ -348,8 +356,8 @@ int ttkMergeTreeClustering::runCompute( mergeTreeBarycenter.setAlpha(Alpha); mergeTreeBarycenter.setDeterministic(Deterministic); mergeTreeBarycenter.setPersistenceThreshold(PersistenceThreshold); - //mergeTreeBarycenter.setIterationLimit(iterationLimit); - if(baseModule==2){ + // mergeTreeBarycenter.setIterationLimit(iterationLimit); + if(baseModule == 2) { mergeTreeBarycenter.setPathMetric(this->pathMetric); mergeTreeBarycenter.setBranchDecomposition(false); mergeTreeBarycenter.setNormalizedWasserstein(false); @@ -357,8 +365,7 @@ int ttkMergeTreeClustering::runCompute( mergeTreeBarycenter.setUseMinMaxPair(false); mergeTreeBarycenter.setAddNodes(false); mergeTreeBarycenter.setPostprocess(false); - } - else{ + } else { mergeTreeBarycenter.setBranchDecomposition(BranchDecomposition); mergeTreeBarycenter.setNormalizedWasserstein(NormalizedWasserstein); mergeTreeBarycenter.setKeepSubtree(KeepSubtree); @@ -590,7 +597,7 @@ int ttkMergeTreeClustering::runOutput( visuMaker.setExcludeImportantPairsHigher(ExcludeImportantPairsHigher); visuMaker.setExcludeImportantPairsLower(ExcludeImportantPairsLower); visuMaker.setIsPersistenceDiagram(IsPersistenceDiagram); - visuMaker.setPathMappingLayout(baseModule==2); + visuMaker.setPathPlanarLayout(baseModule == 2); nodeCorr.clear(); // First tree @@ -695,7 +702,7 @@ int ttkMergeTreeClustering::runOutput( visuMakerMatching.setVtkOutputNode1(vtkOutputNode2); visuMakerMatching.setNodeCorr1(nodeCorr); visuMakerMatching.setDebugLevel(this->debugLevel_); - visuMakerMatching.setPathMappingLayout(baseModule==2); + visuMakerMatching.setPathPlanarLayout(baseModule == 2); visuMakerMatching.makeMatchingOutput(tree1, tree2); @@ -799,7 +806,7 @@ int ttkMergeTreeClustering::runOutput( visuMaker.setDebugLevel(this->debugLevel_); visuMaker.setIsPersistenceDiagram(IsPersistenceDiagram); visuMaker.setIsPDSadMax(JoinSplitMixtureCoefficient == 0); - visuMaker.setPathMappingLayout(baseModule==2); + visuMaker.setPathPlanarLayout(baseModule == 2); visuMaker.makeTreesOutput( intermediateTrees, barycentersTree); @@ -917,7 +924,7 @@ int ttkMergeTreeClustering::runOutput( visuMakerBary.setDebugLevel(this->debugLevel_); visuMakerBary.setIsPersistenceDiagram(IsPersistenceDiagram); visuMakerBary.setIsPDSadMax(JoinSplitMixtureCoefficient == 0); - visuMakerBary.setPathMappingLayout(baseModule==2); + visuMakerBary.setPathPlanarLayout(baseModule == 2); visuMakerBary.makeTreesOutput( intermediateTrees, barycentersTree); @@ -993,7 +1000,7 @@ int ttkMergeTreeClustering::runOutput( visuMakerMatching.setPrintTreeId(i); visuMakerMatching.setPrintClusterId(c); visuMakerMatching.setDebugLevel(this->debugLevel_); - visuMakerMatching.setPathMappingLayout(baseModule==2); + visuMakerMatching.setPathPlanarLayout(baseModule == 2); visuMakerMatching.makeMatchingOutput( intermediateTrees, barycentersTree); diff --git a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h index 7c6a9b9700..25de9b8dee 100644 --- a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h +++ b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h @@ -44,7 +44,6 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { bool outputTreeNodeIndex = false; bool isPersistenceDiagram = false; bool isPDSadMax = true; - bool pathMappingLayout = false; // Shift mode // -1: None ; 0: Star ; 1: Star Barycenter ; 2: Line ; 3: Double Line @@ -160,10 +159,6 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { isPDSadMax = isSadMax; } - void setPathMappingLayout(bool pathLayout) { - pathMappingLayout = pathLayout; - } - // Offset void setISampleOffset(int offset) { iSampleOffset = offset; @@ -1113,7 +1108,7 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { SimplexId nextPointId = points->InsertNextPoint(point); treeSimplexId[node] = nextPointId; nodeCorr[i][node] = nextPointId; - if(dummyNode and not pathMappingLayout) + if(dummyNode and not pathPlanarLayout_) nodeCorr[i][node] = treeDummySimplexId[node]; if(isPersistenceDiagram) nodeCorr[i][node] = nextPointId; From e079a632219abb333d3ff70b86126776bf3f3d09 Mon Sep 17 00:00:00 2001 From: MatPont Date: Fri, 13 Jan 2023 16:26:10 +0100 Subject: [PATCH 24/72] [MergeTreeVisu] fix is important pair for general BD and put back persistence pre-positioning --- core/base/ftmTree/FTMTreeUtils_Template.h | 24 +++++-- .../MergeTreeVisualization.h | 69 +++++++++++++++++-- 2 files changed, 81 insertions(+), 12 deletions(-) diff --git a/core/base/ftmTree/FTMTreeUtils_Template.h b/core/base/ftmTree/FTMTreeUtils_Template.h index c711491180..787095cfb0 100644 --- a/core/base/ftmTree/FTMTreeUtils_Template.h +++ b/core/base/ftmTree/FTMTreeUtils_Template.h @@ -65,9 +65,13 @@ namespace ttk { // Test if it is a parent of an important pair (for not persistence based // branch decomposition) - bool parentOfImportantPair = false; + idNode saddleNode + = (this->isLeaf(nodeId) ? this->getNode(nodeId)->getOrigin() : nodeId); + idNode leafNode + = (this->isLeaf(nodeId) ? nodeId : this->getNode(nodeId)->getOrigin()); std::queue queue; - queue.emplace(nodeId); + std::vector nodeDone(this->getNumberOfNodes(), false); + queue.emplace(leafNode); while(!queue.empty()) { idNode node = queue.front(); queue.pop(); @@ -75,17 +79,23 @@ namespace ttk { if(this->isLeaf(node)) continue; - parentOfImportantPair |= isImportantPairOneNode(node); + if(isImportantPairOneNode(node)) + return true; + + nodeDone[node] = true; + + idNode parent = this->getParentSafe(node); + if(parent != saddleNode) + queue.emplace(parent); - if(parentOfImportantPair) - break; std::vector children; this->getChildren(node, children); for(auto child : children) - queue.emplace(child); + if(not nodeDone[child]) + queue.emplace(child); } - return parentOfImportantPair; + return false; } template diff --git a/core/base/planarGraphLayout/MergeTreeVisualization.h b/core/base/planarGraphLayout/MergeTreeVisualization.h index 5d0616925b..4a2ceac96d 100644 --- a/core/base/planarGraphLayout/MergeTreeVisualization.h +++ b/core/base/planarGraphLayout/MergeTreeVisualization.h @@ -302,7 +302,7 @@ namespace ttk { std::queue queue; ftm::idNode treeRoot = tree->getRoot(); - // ftm::idNode treeRootOrigin = tree->getNode(treeRoot)->getOrigin(); + ftm::idNode treeRootOrigin = tree->getNode(treeRoot)->getOrigin(); ftm::idNode lowestNode = tree->getLowestNode(treeRoot); queue.emplace(treeRoot); while(!queue.empty()) { @@ -410,11 +410,8 @@ namespace ttk { } // ---------------------------------------------------- - // Branches positionning and avoid edges crossing + // Scale pairs given persistence // ---------------------------------------------------- - Timer t_avoid; - printMsg("Avoid edges crossing", debug::Priority::VERBOSE); - // Sort leaves by branch depth std::vector leaves; tree->getLeavesFromTree(leaves); @@ -431,6 +428,68 @@ namespace ttk { float rootOriginY = retVec[treeSimplexId[lowestNode] * 2 + 1]; float rootYmin = std::min(rootY, rootOriginY); float rootYmax = std::max(rootY, rootOriginY); + + Timer t_scale; + printMsg("Scale pairs given persistence", debug::Priority::VERBOSE); + dataType rootPers = tree->getNodePersistence(treeRoot); + std::stack stack; + for(auto node : leaves) + stack.emplace(node); + std::vector nodeDone(tree->getNumberOfNodes(), false); + while(!stack.empty()) { + ftm::idNode node = stack.top(); + stack.pop(); + nodeDone[node] = true; + if(node == treeRoot or node == treeRootOrigin + or tree->isNodeAlone(node)) + continue; + dataType nodePers = tree->getNodePersistence(node); + ftm::idNode nodeOrigin = tree->getNode(node)->getOrigin(); + // Manage leaf + if(tree->isLeaf(node)) { + float nodeDiff = (retVec[treeSimplexId[node] * 2] + - retVec[treeSimplexId[nodeOrigin] * 2]); + const auto sign = nodeDiff / std::abs(nodeDiff); + auto inc = sign * nodePers / rootPers * (rootYmax - rootYmin) / 2; + retVec[treeSimplexId[node] * 2] + = retVec[treeSimplexId[nodeOrigin] * 2] + inc; + // Push nodes in the branch to the stack + ftm::idNode nodeParent = tree->getParentSafe(node); + ftm::idNode oldNodeParent = -1; + while(nodeParent != nodeOrigin) { + if(not nodeDone[nodeParent]) + stack.emplace(nodeParent); + else + break; + oldNodeParent = nodeParent; + nodeParent = tree->getParentSafe(nodeParent); + if(oldNodeParent == nodeParent) { + std::stringstream ss5; + ss5 << "treePlanarLayoutImpl oldNodeParent == nodeParent"; + printMsg(ss5.str(), debug::Priority::VERBOSE); + break; + } + } + } + // Manage saddle + if(not tree->isLeaf(node) and not tree->isRoot(node)) { + float branchY + = retVec[treeSimplexId[tree->getNode(branching[node])->getOrigin()] + * 2]; + retVec[treeSimplexId[node] * 2] = branchY; + } + } + std::stringstream ss5; + ss5 << "SCALE PERS. = " << t_scale.getElapsedTime(); + printMsg(ss5.str(), debug::Priority::VERBOSE); + + // ---------------------------------------------------- + // Branches positionning and avoid edges crossing + // ---------------------------------------------------- + Timer t_avoid; + printMsg("Avoid edges crossing", debug::Priority::VERBOSE); + + // Init some variables bool isJT = tree->isJoinTree(); auto compValue = [&](const ftm::idNode a, const ftm::idNode b) { return (isJT From 0f0c94052cf39a9149f60cb536376bc15c6859b0 Mon Sep 17 00:00:00 2001 From: MatPont Date: Fri, 13 Jan 2023 16:52:55 +0100 Subject: [PATCH 25/72] [MergeTreeVisu] fix is important pair for general BD --- core/base/ftmTree/FTMTreeUtils_Template.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/core/base/ftmTree/FTMTreeUtils_Template.h b/core/base/ftmTree/FTMTreeUtils_Template.h index 787095cfb0..4549999ad5 100644 --- a/core/base/ftmTree/FTMTreeUtils_Template.h +++ b/core/base/ftmTree/FTMTreeUtils_Template.h @@ -76,9 +76,6 @@ namespace ttk { idNode node = queue.front(); queue.pop(); - if(this->isLeaf(node)) - continue; - if(isImportantPairOneNode(node)) return true; @@ -86,7 +83,8 @@ namespace ttk { idNode parent = this->getParentSafe(node); if(parent != saddleNode) - queue.emplace(parent); + if(not nodeDone[parent]) + queue.emplace(parent); std::vector children; this->getChildren(node, children); From bf615337199a4258c16aec383efd9a7d55d244f5 Mon Sep 17 00:00:00 2001 From: MatPont Date: Fri, 13 Jan 2023 18:33:01 +0100 Subject: [PATCH 26/72] [MergeTreeVisu] work on path planar layout --- .../MergeTreeVisualization.h | 86 +++++++++++++------ .../ttkMergeTreeClustering.cpp | 3 + .../ttkMergeTreeTemporalReductionDecoding.cpp | 1 + .../ttkPlanarGraphLayout.cpp | 1 + 4 files changed, 67 insertions(+), 24 deletions(-) diff --git a/core/base/planarGraphLayout/MergeTreeVisualization.h b/core/base/planarGraphLayout/MergeTreeVisualization.h index d9327af859..44d9eda77f 100644 --- a/core/base/planarGraphLayout/MergeTreeVisualization.h +++ b/core/base/planarGraphLayout/MergeTreeVisualization.h @@ -279,46 +279,84 @@ namespace ttk { std::queue queue; for(auto &node : leaves) queue.emplace(node); - std::vector nodeDone(tree->getNumberOfNodes(), false); std::vector> bounds(tree->getNumberOfNodes()); + std::vector nodeDone(tree->getNumberOfNodes(), false); + std::vector parentOfImportantPair(tree->getNumberOfNodes(), false); + std::vector childSize(tree->getNumberOfNodes()), + noChildDone(tree->getNumberOfNodes(), 0); + for(unsigned int i = 0; i < tree->getNumberOfNodes(); ++i) { + std::vector children; + tree->getChildren(i, children); + childSize[i] = children.size(); + } while(!queue.empty()) { ftm::idNode node = queue.front(); queue.pop(); if(nodeDone[node]) continue; + std::vector children; + if(!tree->isLeaf(node) and !tree->isRoot(node)) + tree->getChildren(node, children); + + // Shift children bool isNodeImportant = tree->isImportantPair( node, importantPairs_, excludeImportantPairsLowerValues_, excludeImportantPairsHigherValues_); - if(not isNodeImportant) - continue; - - if(!tree->isLeaf(node) and !tree->isRoot(node)) { - float nodeX = retVec[treeSimplexId[node] * 2]; - std::vector children; - tree->getChildren(node, children); - ftm::idNode child1 = children[0]; - ftm::idNode child2 = children[1]; - if(not nodeDone[child1] or not nodeDone[child2]) - printErr("not nodeDone[child1] or not nodeDone[child2]"); - float child1XMax = bounds[child1][1]; - double child1Shift = -child1XMax + nodeX - importantPairsGap / 2.0; - shiftSubtreeBounds(tree, child1, child1Shift, retVec, treeSimplexId); - float child2XMin = bounds[child2][0]; - double child2Shift = -child2XMin + nodeX + importantPairsGap / 2.0; - shiftSubtreeBounds(tree, child2, child2Shift, retVec, treeSimplexId); - bounds[node] = {std::min(bounds[child1][0], bounds[child2][0]), - std::max(bounds[child1][1], bounds[child2][1]), - std::min(bounds[child1][2], bounds[child2][2]), - std::max(bounds[child1][3], bounds[child2][3])}; - } else + if(isNodeImportant) { bounds[node] = {retVec[treeSimplexId[node] * 2], retVec[treeSimplexId[node] * 2], retVec[treeSimplexId[node] * 2 + 1], retVec[treeSimplexId[node] * 2 + 1]}; + parentOfImportantPair[node] = true; + if(!tree->isLeaf(node) and !tree->isRoot(node)) { + float nodeX = retVec[treeSimplexId[node] * 2]; + ftm::idNode child1 = children[0]; + ftm::idNode child2 = children[1]; + if(not nodeDone[child1] or not nodeDone[child2]) + printErr("not nodeDone[child1] or not nodeDone[child2]"); + if(children.size() != 2) + printWrn("children.size() != 2"); + float child1XMax = bounds[child1][1]; + double child1Shift = -child1XMax + nodeX - importantPairsGap / 2.0; + shiftSubtreeBounds( + tree, child1, child1Shift, retVec, treeSimplexId); + bounds[child1][0] += child1Shift; + bounds[child1][1] += child1Shift; + float child2XMin = bounds[child2][0]; + double child2Shift = -child2XMin + nodeX + importantPairsGap / 2.0; + shiftSubtreeBounds( + tree, child2, child2Shift, retVec, treeSimplexId); + bounds[child2][0] += child2Shift; + bounds[child2][1] += child2Shift; + } + } + + // Update bounds + if(!tree->isLeaf(node) and !tree->isRoot(node)) { + for(auto &child : children) { + bool isChildImportant = tree->isImportantPair( + child, importantPairs_, excludeImportantPairsLowerValues_, + excludeImportantPairsHigherValues_); + if((isChildImportant or parentOfImportantPair[child]) + and not parentOfImportantPair[node]) + bounds[node] = bounds[child]; + if(isChildImportant or parentOfImportantPair[child]) { + bounds[node] = {std::min(bounds[node][0], bounds[child][0]), + std::max(bounds[node][1], bounds[child][1]), + std::min(bounds[node][2], bounds[child][2]), + std::max(bounds[node][3], bounds[child][3])}; + parentOfImportantPair[node] = true; + } + } + } + // nodeDone[node] = true; - queue.emplace(tree->getParentSafe(node)); + ftm::idNode parent = tree->getParentSafe(node); + noChildDone[parent] += 1; + if(noChildDone[parent] == childSize[parent]) + queue.emplace(parent); } } diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index d6e702ca4b..14b2f3671c 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -582,6 +582,7 @@ int ttkMergeTreeClustering::runOutput( visuMaker.setPlanarLayout(PlanarLayout); visuMaker.setBranchDecompositionPlanarLayout( BranchDecompositionPlanarLayout); + visuMaker.setPathPlanarLayout(PathPlanarLayout); visuMaker.setBranchSpacing(BranchSpacing); visuMaker.setRescaleTreesIndividually(RescaleTreesIndividually); visuMaker.setOutputSegmentation(OutputSegmentation); @@ -774,6 +775,7 @@ int ttkMergeTreeClustering::runOutput( visuMaker.setPlanarLayout(PlanarLayout); visuMaker.setBranchDecompositionPlanarLayout( BranchDecompositionPlanarLayout); + visuMaker.setPathPlanarLayout(PathPlanarLayout); visuMaker.setBranchSpacing(BranchSpacing); visuMaker.setRescaleTreesIndividually(RescaleTreesIndividually); visuMaker.setOutputSegmentation(OutputSegmentation); @@ -887,6 +889,7 @@ int ttkMergeTreeClustering::runOutput( visuMakerBary.setPlanarLayout(PlanarLayout); visuMakerBary.setBranchDecompositionPlanarLayout( BranchDecompositionPlanarLayout); + visuMakerBary.setPathPlanarLayout(PathPlanarLayout); visuMakerBary.setBranchSpacing(BranchSpacing); visuMakerBary.setRescaleTreesIndividually(RescaleTreesIndividually); visuMakerBary.setOutputSegmentation(false); diff --git a/core/vtk/ttkMergeTreeTemporalReductionDecoding/ttkMergeTreeTemporalReductionDecoding.cpp b/core/vtk/ttkMergeTreeTemporalReductionDecoding/ttkMergeTreeTemporalReductionDecoding.cpp index bcc7368179..d783884f4d 100644 --- a/core/vtk/ttkMergeTreeTemporalReductionDecoding/ttkMergeTreeTemporalReductionDecoding.cpp +++ b/core/vtk/ttkMergeTreeTemporalReductionDecoding/ttkMergeTreeTemporalReductionDecoding.cpp @@ -274,6 +274,7 @@ int ttkMergeTreeTemporalReductionDecoding::runOutput( visuMaker.setPlanarLayout(PlanarLayout); visuMaker.setBranchDecompositionPlanarLayout( BranchDecompositionPlanarLayout); + visuMaker.setPathPlanarLayout(PathPlanarLayout); visuMaker.setRescaleTreesIndividually(RescaleTreesIndividually); visuMaker.setOutputSegmentation(OutputSegmentation); visuMaker.setDimensionSpacing(DimensionSpacing); diff --git a/core/vtk/ttkPlanarGraphLayout/ttkPlanarGraphLayout.cpp b/core/vtk/ttkPlanarGraphLayout/ttkPlanarGraphLayout.cpp index 0b8dcdeb70..efce737ca9 100644 --- a/core/vtk/ttkPlanarGraphLayout/ttkPlanarGraphLayout.cpp +++ b/core/vtk/ttkPlanarGraphLayout/ttkPlanarGraphLayout.cpp @@ -139,6 +139,7 @@ int ttkPlanarGraphLayout::mergeTreePlanarLayoutCallTemplate( visuMaker.setPlanarLayout(true); visuMaker.setOutputSegmentation(false); visuMaker.setBranchDecompositionPlanarLayout(BranchDecompositionPlanarLayout); + visuMaker.setPathPlanarLayout(PathPlanarLayout); visuMaker.setBranchSpacing(BranchSpacing); visuMaker.setImportantPairs(ImportantPairs); visuMaker.setMaximumImportantPairs(MaximumImportantPairs); From c962b63623c44466876ee6ac6deb781500c783b5 Mon Sep 17 00:00:00 2001 From: MatPont Date: Wed, 18 Jan 2023 19:09:52 +0100 Subject: [PATCH 27/72] [MergeTreeClustering] path planar layout option in vtk layer --- .../ttkMergeTreeClustering.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index 14b2f3671c..bc7ca15076 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -582,7 +582,6 @@ int ttkMergeTreeClustering::runOutput( visuMaker.setPlanarLayout(PlanarLayout); visuMaker.setBranchDecompositionPlanarLayout( BranchDecompositionPlanarLayout); - visuMaker.setPathPlanarLayout(PathPlanarLayout); visuMaker.setBranchSpacing(BranchSpacing); visuMaker.setRescaleTreesIndividually(RescaleTreesIndividually); visuMaker.setOutputSegmentation(OutputSegmentation); @@ -598,7 +597,8 @@ int ttkMergeTreeClustering::runOutput( visuMaker.setExcludeImportantPairsHigher(ExcludeImportantPairsHigher); visuMaker.setExcludeImportantPairsLower(ExcludeImportantPairsLower); visuMaker.setIsPersistenceDiagram(IsPersistenceDiagram); - visuMaker.setPathPlanarLayout(baseModule == 2); + visuMaker.setPathPlanarLayout(PathPlanarLayout); + // visuMaker.setPathPlanarLayout(baseModule == 2); nodeCorr.clear(); // First tree @@ -703,7 +703,8 @@ int ttkMergeTreeClustering::runOutput( visuMakerMatching.setVtkOutputNode1(vtkOutputNode2); visuMakerMatching.setNodeCorr1(nodeCorr); visuMakerMatching.setDebugLevel(this->debugLevel_); - visuMakerMatching.setPathPlanarLayout(baseModule == 2); + visuMakerMatching.setPathPlanarLayout(PathPlanarLayout); + // visuMakerMatching.setPathPlanarLayout(baseModule == 2); visuMakerMatching.makeMatchingOutput(tree1, tree2); @@ -775,7 +776,6 @@ int ttkMergeTreeClustering::runOutput( visuMaker.setPlanarLayout(PlanarLayout); visuMaker.setBranchDecompositionPlanarLayout( BranchDecompositionPlanarLayout); - visuMaker.setPathPlanarLayout(PathPlanarLayout); visuMaker.setBranchSpacing(BranchSpacing); visuMaker.setRescaleTreesIndividually(RescaleTreesIndividually); visuMaker.setOutputSegmentation(OutputSegmentation); @@ -808,7 +808,8 @@ int ttkMergeTreeClustering::runOutput( visuMaker.setDebugLevel(this->debugLevel_); visuMaker.setIsPersistenceDiagram(IsPersistenceDiagram); visuMaker.setIsPDSadMax(JoinSplitMixtureCoefficient == 0); - visuMaker.setPathPlanarLayout(baseModule == 2); + visuMaker.setPathPlanarLayout(PathPlanarLayout); + // visuMaker.setPathPlanarLayout(baseModule == 2); visuMaker.makeTreesOutput( intermediateTrees, barycentersTree); @@ -889,7 +890,6 @@ int ttkMergeTreeClustering::runOutput( visuMakerBary.setPlanarLayout(PlanarLayout); visuMakerBary.setBranchDecompositionPlanarLayout( BranchDecompositionPlanarLayout); - visuMakerBary.setPathPlanarLayout(PathPlanarLayout); visuMakerBary.setBranchSpacing(BranchSpacing); visuMakerBary.setRescaleTreesIndividually(RescaleTreesIndividually); visuMakerBary.setOutputSegmentation(false); @@ -927,7 +927,8 @@ int ttkMergeTreeClustering::runOutput( visuMakerBary.setDebugLevel(this->debugLevel_); visuMakerBary.setIsPersistenceDiagram(IsPersistenceDiagram); visuMakerBary.setIsPDSadMax(JoinSplitMixtureCoefficient == 0); - visuMakerBary.setPathPlanarLayout(baseModule == 2); + visuMakerBary.setPathPlanarLayout(PathPlanarLayout); + // visuMakerBary.setPathPlanarLayout(baseModule == 2); visuMakerBary.makeTreesOutput( intermediateTrees, barycentersTree); @@ -1003,7 +1004,8 @@ int ttkMergeTreeClustering::runOutput( visuMakerMatching.setPrintTreeId(i); visuMakerMatching.setPrintClusterId(c); visuMakerMatching.setDebugLevel(this->debugLevel_); - visuMakerMatching.setPathPlanarLayout(baseModule == 2); + visuMakerMatching.setPathPlanarLayout(PathPlanarLayout); + // visuMakerMatching.setPathPlanarLayout(baseModule == 2); visuMakerMatching.makeMatchingOutput( intermediateTrees, barycentersTree); From 028d6bee7efd70668cc548f6627c10ebfa09008b Mon Sep 17 00:00:00 2001 From: MatPont Date: Wed, 18 Jan 2023 19:10:10 +0100 Subject: [PATCH 28/72] [MergeTreeVisu] path layout dummy node --- .../ttkMergeTreeVisualization.h | 52 ++++++++++++++++--- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h index 25de9b8dee..1996e95f80 100644 --- a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h +++ b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h @@ -968,7 +968,6 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { // Internal arrays printMsg("// Internal arrays", ttk::debug::Priority::VERBOSE); - int cptNode = 0; nodeCorr[i].resize(trees[i]->getNumberOfNodes()); std::vector treeSimplexId(trees[i]->getNumberOfNodes()); std::vector treeDummySimplexId(trees[i]->getNumberOfNodes()); @@ -991,6 +990,24 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { maxBirth = std::numeric_limits::lowest(); SimplexId minBirthNode = 0, maxBirthNode = 0; + // Init layoutCorr + int cptNode = 0; + std::queue queueLayoutCorr; + queueLayoutCorr.emplace(trees[i]->getRoot()); + while(!queueLayoutCorr.empty()) { + idNode node = queueLayoutCorr.front(); + queueLayoutCorr.pop(); + + // Push children to the queue + std::vector children; + trees[i]->getChildren(node, children); + for(auto child : children) + queueLayoutCorr.emplace(child); + + layoutCorr[node] = cptNode; + cptNode += 2; + } + // ---------------------------- // Tree traversal // ---------------------------- @@ -1049,11 +1066,9 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { getPoint(treesNodes[i], nodeMesh, point); } if(PlanarLayout) { - layoutCorr[node] = cptNode; - point[0] = layout[cptNode]; - point[1] = layout[cptNode + 1]; + point[0] = layout[layoutCorr[node]]; + point[1] = layout[layoutCorr[node] + 1]; point[2] = 0; - cptNode += 2; } point[0] += diff_x; point[1] += diff_y; @@ -1119,6 +1134,9 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { ? node : treeBranching[node]); + // Path Layout Dummy Node + bool pathDummyNode = false; + // -------------- // Insert cell connecting parent // -------------- @@ -1153,12 +1171,32 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { } else pointIds[1] = treeSimplexId[nodeParent]; + // Path Layout Dummy Cell + bool isNodeParentImportant = trees[i]->isImportantPair( + nodeParent, importantPairs_, excludeImportantPairsLowerValues_, + excludeImportantPairsHigherValues_); + bool pathDummyCell + = not dummyCell and pathPlanarLayout_ and isNodeParentImportant; + if(pathDummyCell) { + std::cout << "pathDummyCell" << std::endl; + pathDummyNode = true; + double pathDummyPoint[3] + = {layout[layoutCorr[node]] + diff_x, + layout[layoutCorr[nodeParent] + 1] + diff_y, 0. + diff_z}; + SimplexId pathDummyPointId + = points->InsertNextPoint(pathDummyPoint); + vtkIdType pathDummyCellPointIds[2]; + pathDummyCellPointIds[0] = pathDummyPointId; + pathDummyCellPointIds[1] = treeSimplexId[nodeParent]; + vtkArcs->InsertNextCell(VTK_LINE, 2, pathDummyCellPointIds); + pointIds[1] = pathDummyPointId; + } vtkArcs->InsertNextCell(VTK_LINE, 2, pointIds); // -------------- // Arc field // -------------- - int toAdd = (dummyCell ? 2 : 1); + int toAdd = (dummyCell ? 2 : 1) + (pathDummyCell ? 1 : 0); for(int toAddT = 0; toAddT < toAdd; ++toAddT) { // Add arc matching percentage if(ShiftMode == 1) { // Star Barycenter @@ -1277,7 +1315,7 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { // -------------- // Node field // -------------- - int toAdd = (dummyNode ? 2 : 1); + int toAdd = (dummyNode ? 2 : 1) + (pathDummyNode ? 1 : 0); for(int toAddT = 0; toAddT < toAdd; ++toAddT) { // Add node id nodeID->InsertNextTuple1(treeSimplexId[node]); From df0b6b633eceb55634f7e0d58f1b3250e0dfc4c0 Mon Sep 17 00:00:00 2001 From: MatPont Date: Wed, 18 Jan 2023 19:37:20 +0100 Subject: [PATCH 29/72] [MergeTreeVisu] path planar layout shift according lowest node --- .../MergeTreeVisualization.h | 26 ++++++++++++++++--- .../ttkMergeTreeVisualization.h | 1 - 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/core/base/planarGraphLayout/MergeTreeVisualization.h b/core/base/planarGraphLayout/MergeTreeVisualization.h index 44d9eda77f..27d7d718ce 100644 --- a/core/base/planarGraphLayout/MergeTreeVisualization.h +++ b/core/base/planarGraphLayout/MergeTreeVisualization.h @@ -284,6 +284,8 @@ namespace ttk { std::vector parentOfImportantPair(tree->getNumberOfNodes(), false); std::vector childSize(tree->getNumberOfNodes()), noChildDone(tree->getNumberOfNodes(), 0); + std::vector lowestValue(tree->getNumberOfNodes()); + bool isJT = tree->isJoinTree(); for(unsigned int i = 0; i < tree->getNumberOfNodes(); ++i) { std::vector children; tree->getChildren(i, children); @@ -317,14 +319,21 @@ namespace ttk { printErr("not nodeDone[child1] or not nodeDone[child2]"); if(children.size() != 2) printWrn("children.size() != 2"); - float child1XMax = bounds[child1][1]; - double child1Shift = -child1XMax + nodeX - importantPairsGap / 2.0; + + double sign = (lowestValue[child1] > lowestValue[child2] ? -1 : 1); + if(isJT) + sign *= -1; + + float child1XBound = bounds[child1][(sign == -1 ? 1 : 0)]; + double child1Shift + = -child1XBound + nodeX + sign * importantPairsGap / 2.0; shiftSubtreeBounds( tree, child1, child1Shift, retVec, treeSimplexId); bounds[child1][0] += child1Shift; bounds[child1][1] += child1Shift; - float child2XMin = bounds[child2][0]; - double child2Shift = -child2XMin + nodeX + importantPairsGap / 2.0; + float child2XBound = bounds[child2][(sign == -1 ? 0 : 1)]; + double child2Shift + = -child2XBound + nodeX + sign * -1 * importantPairsGap / 2.0; shiftSubtreeBounds( tree, child2, child2Shift, retVec, treeSimplexId); bounds[child2][0] += child2Shift; @@ -351,6 +360,15 @@ namespace ttk { } } + // Update lowest value + lowestValue[node] = tree->getValue(node); + for(auto &child : children) { + if(isJT) + lowestValue[node] = std::min(lowestValue[node], lowestValue[child]); + else + lowestValue[node] = std::max(lowestValue[node], lowestValue[child]); + } + // nodeDone[node] = true; ftm::idNode parent = tree->getParentSafe(node); diff --git a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h index 1996e95f80..1275eca702 100644 --- a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h +++ b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h @@ -1178,7 +1178,6 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { bool pathDummyCell = not dummyCell and pathPlanarLayout_ and isNodeParentImportant; if(pathDummyCell) { - std::cout << "pathDummyCell" << std::endl; pathDummyNode = true; double pathDummyPoint[3] = {layout[layoutCorr[node]] + diff_x, From 8b3519055e3a7e6363e78117f8e8bf375581eac7 Mon Sep 17 00:00:00 2001 From: MatPont Date: Fri, 3 Feb 2023 09:12:56 +0100 Subject: [PATCH 30/72] [MergeTreeVisu] fix y dimension shift for 1 barycenter and 2 trees --- .../ttkMergeTreeVisualization.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h index 1275eca702..b9b00334b9 100644 --- a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h +++ b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h @@ -952,14 +952,20 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { } } double new_diff_x = PlanarLayout ? -minX : -std::get<0>(allBounds[i]); - if(DimensionToShift == 2) { // is Z + bool diffYAllowed + = (not clusteringOutput + or (trees.size() == 2 and barycenters.size() == 1)); + if(DimensionToShift == 2) { + // is Z diff_z = -diff_x; diff_x = new_diff_x; - } else if(not clusteringOutput and DimensionToShift == 1) { // is Y + } else if(diffYAllowed and DimensionToShift == 1) { + // is Y diff_y = diff_x; diff_x = new_diff_x; - } else if(DimensionToShift == 3) { // Custom - if(not clusteringOutput) + } else if(DimensionToShift == 3) { + // Custom + if(diffYAllowed) diff_y = YShift * diff_x + (1 - YShift) * diff_y; diff_z = ZShift * -diff_x + (1 - ZShift) * diff_z; diff_x = XShift * diff_x + (1 - XShift) * new_diff_x; From 9e9bb5663fe886e09fc80851726ebe7ae31fc33c Mon Sep 17 00:00:00 2001 From: MatPont Date: Fri, 3 Feb 2023 11:06:33 +0100 Subject: [PATCH 31/72] [MergeTreeBarycenter] remove unused variable --- core/base/mergeTreeClustering/MergeTreeBarycenter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/base/mergeTreeClustering/MergeTreeBarycenter.h b/core/base/mergeTreeClustering/MergeTreeBarycenter.h index e070d9b826..910d89e439 100644 --- a/core/base/mergeTreeClustering/MergeTreeBarycenter.h +++ b/core/base/mergeTreeClustering/MergeTreeBarycenter.h @@ -294,7 +294,7 @@ namespace ttk { // bestIndex = trees.size()-1; //baryTree = ftm::copyMergeTree(trees[bestIndex], true); baryTree = ftm::copyMergeTree(trees[bestIndex], baseModule_!=2); - ftm::FTMTree_MT* bt = &(baryTree.tree); + // ftm::FTMTree_MT* bt = &(baryTree.tree); limitSizeBarycenter(baryTree, trees); } From 22c300a1a821153c67dbeebd232cb0e4024d7cae Mon Sep 17 00:00:00 2001 From: MatPont Date: Fri, 3 Feb 2023 11:06:53 +0100 Subject: [PATCH 32/72] [MergeTreeVisu] work on trees layout alignment given barycenter --- .../ttkMergeTreeVisualization.h | 147 +++++++++++------- 1 file changed, 90 insertions(+), 57 deletions(-) diff --git a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h index b9b00334b9..3ffb5ea1fd 100644 --- a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h +++ b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h @@ -594,6 +594,7 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { NumberOfBarycenters = std::max(NumberOfBarycenters, 1); // to always enter the outer loop PlanarLayout |= isPersistenceDiagram; + bool alignTrees = trees.size() == 2 and barycenters.size() == 1; // TreeNodeIdRev for(int i = 0; i < numInputs; ++i) { @@ -847,29 +848,34 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { continue; // Manage important pairs threshold - importantPairs_ = importantPairsOriginal; - if(MaximumImportantPairs > 0 or MinimumImportantPairs > 0) { - std::vector> pairs; - trees[i]->getPersistencePairsFromTree(pairs, false); - if(MaximumImportantPairs > 0) { - int firstIndex = pairs.size() - MaximumImportantPairs; - firstIndex - = std::max(std::min(firstIndex, int(pairs.size()) - 1), 0); - double tempThreshold = 0.999 * std::get<2>(pairs[firstIndex]) - / std::get<2>(pairs[pairs.size() - 1]); - tempThreshold *= 100; - importantPairs_ = std::max(importantPairs_, tempThreshold); - } - if(MinimumImportantPairs > 0) { - int firstIndex = pairs.size() - MinimumImportantPairs; - firstIndex - = std::max(std::min(firstIndex, int(pairs.size()) - 1), 0); - double tempThreshold = 0.999 * std::get<2>(pairs[firstIndex]) - / std::get<2>(pairs[pairs.size() - 1]); - tempThreshold *= 100; - importantPairs_ = std::min(importantPairs_, tempThreshold); - } - } + auto fixImportantPairsThreshold + = [&importantPairsOriginal, this](FTMTree_MT *tree) { + double importantPairs = importantPairsOriginal; + if(MaximumImportantPairs > 0 or MinimumImportantPairs > 0) { + std::vector> pairs; + tree->getPersistencePairsFromTree(pairs, false); + if(MaximumImportantPairs > 0) { + int firstIndex = pairs.size() - MaximumImportantPairs; + firstIndex + = std::max(std::min(firstIndex, int(pairs.size()) - 1), 0); + double tempThreshold = 0.999 * std::get<2>(pairs[firstIndex]) + / std::get<2>(pairs[pairs.size() - 1]); + tempThreshold *= 100; + importantPairs = std::max(importantPairs, tempThreshold); + } + if(MinimumImportantPairs > 0) { + int firstIndex = pairs.size() - MinimumImportantPairs; + firstIndex + = std::max(std::min(firstIndex, int(pairs.size()) - 1), 0); + double tempThreshold = 0.999 * std::get<2>(pairs[firstIndex]) + / std::get<2>(pairs[pairs.size() - 1]); + tempThreshold *= 100; + importantPairs = std::min(importantPairs, tempThreshold); + } + } + return importantPairs; + }; + importantPairs_ = fixImportantPairsThreshold(trees[i]); // Get is interpolated tree (temporal subsampling) bool isInterpolatedTree = false; @@ -920,8 +926,46 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { break; } + // isImportantPairVector + auto getIsImportantPairVector + = [this](FTMTree_MT *tree, std::vector &isImportantPairVector, + double importantPairs) { + isImportantPairVector.resize(tree->getNumberOfNodes()); + for(unsigned int n = 0; n < isImportantPairVector.size(); ++n) + isImportantPairVector[n] = tree->isImportantPair( + n, importantPairs, excludeImportantPairsLowerValues_, + excludeImportantPairsHigherValues_); + }; + std::vector isImportantPairVector; + getIsImportantPairVector( + trees[i], isImportantPairVector, importantPairs_); + + // Layout correspondence function + auto getLayoutCorr + = [](FTMTree_MT *tree, std::vector &layoutCorr) { + layoutCorr.resize(tree->getNumberOfNodes()); + int cptNode = 0; + std::queue queueLayoutCorr; + queueLayoutCorr.emplace(tree->getRoot()); + while(!queueLayoutCorr.empty()) { + idNode node = queueLayoutCorr.front(); + queueLayoutCorr.pop(); + + // Push children to the queue + std::vector children; + tree->getChildren(node, children); + for(auto child : children) + queueLayoutCorr.emplace(child); + + layoutCorr[node] = cptNode; + cptNode += 2; + } + }; + // Planar layout printMsg("// Planar Layout", ttk::debug::Priority::VERBOSE); + std::vector layoutCorr; + getLayoutCorr(trees[i], layoutCorr); std::vector layout; if(PlanarLayout) { double refPersistence; @@ -931,10 +975,28 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { else refPersistence = trees[0]->getNodePersistence(trees[0]->getRoot()); - if(not isPersistenceDiagram) + if(not isPersistenceDiagram) { treePlanarLayout( trees[i], allBaryBounds[c], refPersistence, layout); - else { + if(alignTrees and ShiftMode != 1) { + std::vector layoutBary; + treePlanarLayout( + barycenters[0], allBaryBounds[c], refPersistence, layoutBary); + std::vector layoutBaryCorr; + getLayoutCorr(barycenters[0], layoutBaryCorr); + std::vector isImportantPairBaryVector; + double isImportantPairBary + = fixImportantPairsThreshold(barycenters[0]); + getIsImportantPairVector( + barycenters[0], isImportantPairBaryVector, isImportantPairBary); + for(auto match : outputMatchingBarycenter[0][i]) { + layout[layoutCorr[std::get<1>(match)]] + = layoutBary[layoutBaryCorr[std::get<0>(match)]]; + isImportantPairVector[std::get<1>(match)] + = isImportantPairBaryVector[std::get<0>(match)]; + } + } + } else { persistenceDiagramPlanarLayout(trees[i], layout); } } @@ -977,7 +1039,6 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { nodeCorr[i].resize(trees[i]->getNumberOfNodes()); std::vector treeSimplexId(trees[i]->getNumberOfNodes()); std::vector treeDummySimplexId(trees[i]->getNumberOfNodes()); - std::vector layoutCorr(trees[i]->getNumberOfNodes()); std::vector treeMatching(trees[i]->getNumberOfNodes(), -1); if(clusteringOutput and ShiftMode != 1) for(auto match : outputMatchingBarycenter[c][i]) @@ -996,24 +1057,6 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { maxBirth = std::numeric_limits::lowest(); SimplexId minBirthNode = 0, maxBirthNode = 0; - // Init layoutCorr - int cptNode = 0; - std::queue queueLayoutCorr; - queueLayoutCorr.emplace(trees[i]->getRoot()); - while(!queueLayoutCorr.empty()) { - idNode node = queueLayoutCorr.front(); - queueLayoutCorr.pop(); - - // Push children to the queue - std::vector children; - trees[i]->getChildren(node, children); - for(auto child : children) - queueLayoutCorr.emplace(child); - - layoutCorr[node] = cptNode; - cptNode += 2; - } - // ---------------------------- // Tree traversal // ---------------------------- @@ -1178,9 +1221,7 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { pointIds[1] = treeSimplexId[nodeParent]; // Path Layout Dummy Cell - bool isNodeParentImportant = trees[i]->isImportantPair( - nodeParent, importantPairs_, excludeImportantPairsLowerValues_, - excludeImportantPairsHigherValues_); + bool isNodeParentImportant = isImportantPairVector[nodeParent]; bool pathDummyCell = not dummyCell and pathPlanarLayout_ and isNodeParentImportant; if(pathDummyCell) { @@ -1261,12 +1302,7 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { treeIDArc->InsertNextTuple1(i); // Add isImportantPair - bool isImportant = false; - idNode nodeToGetImportance = nodeBranching; - isImportant = trees[i]->isImportantPair( - nodeToGetImportance, importantPairs_, - excludeImportantPairsLowerValues_, - excludeImportantPairsHigherValues_); + bool isImportant = isImportantPairVector[nodeBranching]; isImportantPairsArc->InsertNextTuple1(isImportant); // Add isDummyArc @@ -1433,10 +1469,7 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { isInterpolatedTreeNode->InsertNextTuple1(isInterpolatedTree); // Add isImportantPair - bool isImportant = false; - isImportant = trees[i]->isImportantPair( - node, importantPairs_, excludeImportantPairsLowerValues_, - excludeImportantPairsHigherValues_); + bool isImportant = isImportantPairVector[node]; isImportantPairsNode->InsertNextTuple1(isImportant); // Add treeNodeId From e6f564837c3fdac3bc52d4b6b0aeb7b2da1f8dec Mon Sep 17 00:00:00 2001 From: MatPont Date: Fri, 3 Feb 2023 17:47:28 +0100 Subject: [PATCH 33/72] [MergeTreeVisu] work on special cases of tree planar layout alignment to barycenter --- .../ttkMergeTreeVisualization.h | 62 ++++++++++++++++++- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h index 3ffb5ea1fd..008cb9be3c 100644 --- a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h +++ b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h @@ -967,6 +967,11 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { std::vector layoutCorr; getLayoutCorr(trees[i], layoutCorr); std::vector layout; + // TODO remove baryMatchingVector if it is not used + std::vector baryMatchingVector; + // TODO put this declaration just before it is used if the vector is + // not needed elsewhere + std::vector isImportantPairBaryVector; if(PlanarLayout) { double refPersistence; if(clusteringOutput) @@ -978,23 +983,69 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { if(not isPersistenceDiagram) { treePlanarLayout( trees[i], allBaryBounds[c], refPersistence, layout); + // Planar Layout alignment given barycenter if(alignTrees and ShiftMode != 1) { + // Create barycenter layout std::vector layoutBary; treePlanarLayout( barycenters[0], allBaryBounds[c], refPersistence, layoutBary); std::vector layoutBaryCorr; getLayoutCorr(barycenters[0], layoutBaryCorr); - std::vector isImportantPairBaryVector; + // Get barycenter important pairs bool vector double isImportantPairBary = fixImportantPairsThreshold(barycenters[0]); getIsImportantPairVector( barycenters[0], isImportantPairBaryVector, isImportantPairBary); + baryMatchingVector.resize(barycenters[0]->getNumberOfNodes(), -1); + for(auto match : outputMatchingBarycenter[0][i]) + baryMatchingVector[std::get<0>(match)] = std::get<1>(match); + std::vector shifts(trees[i]->getNumberOfNodes(), 0); for(auto match : outputMatchingBarycenter[0][i]) { - layout[layoutCorr[std::get<1>(match)]] - = layoutBary[layoutBaryCorr[std::get<0>(match)]]; + // Update tree important pair according barycenter isImportantPairVector[std::get<1>(match)] = isImportantPairBaryVector[std::get<0>(match)]; + // Update tree layout according barycenter layout + layout[layoutCorr[std::get<1>(match)]] + = layoutBary[layoutBaryCorr[std::get<0>(match)]]; + if(not isImportantPairVector[std::get<1>(match)]) { + // Search for birth swap with an important pair + ttk::ftm::idNode node = std::get<0>(match); + while(not isImportantPairBaryVector[node]) + node = barycenters[0]->getParentSafe(node); + bool baryNodeSup + = barycenters[0]->getValue(node) + > barycenters[0]->getValue(std::get<0>(match)); + bool treeNodeSup + = trees[i]->getValue(baryMatchingVector[node]) + > trees[i]->getValue(std::get<1>(match)); + if((not baryNodeSup and treeNodeSup) + or (baryNodeSup and not treeNodeSup)) { + float shift + = std::abs(layout[layoutCorr[std::get<1>(match)]] + - layoutBary[layoutBaryCorr[node]]); + layout[layoutCorr[std::get<1>(match)]] + = layoutBary[layoutBaryCorr[node]]; + std::queue queueShift; + queueShift.emplace( + trees[i]->getNode(std::get<1>(match))->getOrigin()); + while(!queueShift.empty()) { + ttk::ftm::idNode nodeToShift = queueShift.front(); + queueShift.pop(); + shifts[nodeToShift] += shift; + ttk::ftm::idNode nodeToShiftParent + = trees[i]->getParentSafe(nodeToShift); + if(nodeToShiftParent != std::get<1>(match)) + queueShift.emplace(nodeToShiftParent); + std::vector children; + trees[i]->getChildren(nodeToShift, children); + for(auto &child : children) + queueShift.emplace(child); + } + } + } } + for(unsigned int s = 0; s < shifts.size(); ++s) + layout[layoutCorr[s]] += shifts[s]; } } else { persistenceDiagramPlanarLayout(trees[i], layout); @@ -1224,6 +1275,11 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { bool isNodeParentImportant = isImportantPairVector[nodeParent]; bool pathDummyCell = not dummyCell and pathPlanarLayout_ and isNodeParentImportant; + if(not pathDummyCell and alignTrees and ShiftMode != 1) { + pathDummyCell = pathPlanarLayout_ + and layout[layoutCorr[node]] + != layout[layoutCorr[nodeParent]]; + } if(pathDummyCell) { pathDummyNode = true; double pathDummyPoint[3] From f0d49026a3782ce6e061914abc62119037565edc Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Wed, 15 Feb 2023 17:25:08 +0100 Subject: [PATCH 34/72] temporal reduction working for path mappings --- .../MergeTreeTemporalReductionDecoding.h | 163 +++++++++++++----- .../MergeTreeTemporalReductionEncoding.h | 138 +++++++++++---- .../ttkMergeTreeTemporalReductionDecoding.h | 9 + .../ttkMergeTreeTemporalReductionEncoding.h | 9 + .../MergeTreeTemporalReductionDecoding.xml | 13 ++ .../MergeTreeTemporalReductionEncoding.xml | 25 +++ 6 files changed, 281 insertions(+), 76 deletions(-) diff --git a/core/base/mergeTreeTemporalReductionDecoding/MergeTreeTemporalReductionDecoding.h b/core/base/mergeTreeTemporalReductionDecoding/MergeTreeTemporalReductionDecoding.h index 06870f2761..a7fe04b407 100644 --- a/core/base/mergeTreeTemporalReductionDecoding/MergeTreeTemporalReductionDecoding.h +++ b/core/base/mergeTreeTemporalReductionDecoding/MergeTreeTemporalReductionDecoding.h @@ -25,6 +25,7 @@ #include #include #include +#include namespace ttk { @@ -36,43 +37,70 @@ namespace ttk { public MergeTreeBase { protected: std::vector finalDistances_, distancesToKeyFrames_; + bool usePathMappings_ = false; public: MergeTreeTemporalReductionDecoding(); + void setPathMappings(bool usePM) { + usePathMappings_ = usePM; + } + template dataType computeDistance( ftm::MergeTree &mTree1, ftm::MergeTree &mTree2, std::vector> &matching) { - MergeTreeDistance mergeTreeDistance; - mergeTreeDistance.setAssignmentSolver(assignmentSolverID_); - mergeTreeDistance.setEpsilonTree1(epsilonTree1_); - mergeTreeDistance.setEpsilonTree2(epsilonTree2_); - mergeTreeDistance.setEpsilon2Tree1(epsilon2Tree1_); - mergeTreeDistance.setEpsilon2Tree2(epsilon2Tree2_); - mergeTreeDistance.setEpsilon3Tree1(epsilon3Tree1_); - mergeTreeDistance.setEpsilon3Tree2(epsilon3Tree2_); - mergeTreeDistance.setProgressiveComputation(progressiveComputation_); - mergeTreeDistance.setBranchDecomposition(branchDecomposition_); - mergeTreeDistance.setParallelize(parallelize_); - mergeTreeDistance.setPersistenceThreshold(persistenceThreshold_); - mergeTreeDistance.setNormalizedWasserstein(normalizedWasserstein_); - mergeTreeDistance.setNormalizedWassersteinReg(normalizedWassersteinReg_); - mergeTreeDistance.setRescaledWasserstein(rescaledWasserstein_); - mergeTreeDistance.setKeepSubtree(keepSubtree_); - mergeTreeDistance.setUseMinMaxPair(useMinMaxPair_); - mergeTreeDistance.setThreadNumber(this->threadNumber_); - mergeTreeDistance.setDistanceSquared(true); // squared root - mergeTreeDistance.setDebugLevel(2); - mergeTreeDistance.setPreprocess(false); - mergeTreeDistance.setPostprocess(false); - // mergeTreeDistance.setIsCalled(true); - - dataType distance - = mergeTreeDistance.execute(mTree1, mTree2, matching); - - return distance; + + if(usePathMappings_){ + PathMappingDistance mergeTreeDistance; + mergeTreeDistance.setAssignmentSolver(assignmentSolverID_); + mergeTreeDistance.setEpsilonTree1(epsilonTree1_); + mergeTreeDistance.setEpsilonTree2(epsilonTree2_); + mergeTreeDistance.setPersistenceThreshold(persistenceThreshold_); + mergeTreeDistance.setThreadNumber(this->threadNumber_); + mergeTreeDistance.setDistanceSquared(false); // squared root + mergeTreeDistance.setDebugLevel(2); + mergeTreeDistance.setPreprocess(false); + mergeTreeDistance.setComputeMapping(true); + + ftm::FTMTree_MT* mt1 = &(mTree1.tree); + ftm::FTMTree_MT* mt2 = &(mTree2.tree); + dataType distance + = mergeTreeDistance.editDistance_path(mt1, mt2, &matching); + + return distance; + } + else{ + MergeTreeDistance mergeTreeDistance; + mergeTreeDistance.setAssignmentSolver(assignmentSolverID_); + mergeTreeDistance.setEpsilonTree1(epsilonTree1_); + mergeTreeDistance.setEpsilonTree2(epsilonTree2_); + mergeTreeDistance.setEpsilon2Tree1(epsilon2Tree1_); + mergeTreeDistance.setEpsilon2Tree2(epsilon2Tree2_); + mergeTreeDistance.setEpsilon3Tree1(epsilon3Tree1_); + mergeTreeDistance.setEpsilon3Tree2(epsilon3Tree2_); + mergeTreeDistance.setProgressiveComputation(progressiveComputation_); + mergeTreeDistance.setBranchDecomposition(branchDecomposition_); + mergeTreeDistance.setParallelize(parallelize_); + mergeTreeDistance.setPersistenceThreshold(persistenceThreshold_); + mergeTreeDistance.setNormalizedWasserstein(normalizedWasserstein_); + mergeTreeDistance.setNormalizedWassersteinReg(normalizedWassersteinReg_); + mergeTreeDistance.setRescaledWasserstein(rescaledWasserstein_); + mergeTreeDistance.setKeepSubtree(keepSubtree_); + mergeTreeDistance.setUseMinMaxPair(useMinMaxPair_); + mergeTreeDistance.setThreadNumber(this->threadNumber_); + mergeTreeDistance.setDistanceSquared(true); // squared root + mergeTreeDistance.setDebugLevel(2); + mergeTreeDistance.setPreprocess(false); + mergeTreeDistance.setPostprocess(false); + // mergeTreeDistance.setIsCalled(true); + + dataType distance + = mergeTreeDistance.execute(mTree1, mTree2, matching); + + return distance; + } } template @@ -98,10 +126,6 @@ namespace ttk { mergeTreeBarycenter.setBranchDecomposition(branchDecomposition_); mergeTreeBarycenter.setParallelize(parallelize_); mergeTreeBarycenter.setPersistenceThreshold(persistenceThreshold_); - mergeTreeBarycenter.setNormalizedWasserstein(normalizedWasserstein_); - mergeTreeBarycenter.setNormalizedWassersteinReg( - normalizedWassersteinReg_); - mergeTreeBarycenter.setRescaledWasserstein(rescaledWasserstein_); mergeTreeBarycenter.setKeepSubtree(keepSubtree_); mergeTreeBarycenter.setUseMinMaxPair(useMinMaxPair_); mergeTreeBarycenter.setThreadNumber(this->threadNumber_); @@ -111,6 +135,22 @@ namespace ttk { mergeTreeBarycenter.setPostprocess(false); // mergeTreeBarycenter.setIsCalled(true); + if(usePathMappings_){ + mergeTreeBarycenter.setBaseModule(2); + mergeTreeBarycenter.setBranchDecomposition(false); + mergeTreeBarycenter.setNormalizedWasserstein(false); + mergeTreeBarycenter.setKeepSubtree(false); + mergeTreeBarycenter.setUseMinMaxPair(false); + mergeTreeBarycenter.setAddNodes(false); + mergeTreeBarycenter.setPostprocess(false); + } + else{ + mergeTreeBarycenter.setBranchDecomposition(true); + mergeTreeBarycenter.setNormalizedWasserstein(normalizedWasserstein_); + mergeTreeBarycenter.setNormalizedWassersteinReg(normalizedWassersteinReg_); + mergeTreeBarycenter.setRescaledWasserstein(rescaledWasserstein_); + } + std::vector> intermediateTrees; intermediateTrees.push_back(mTree1); intermediateTrees.push_back(mTree2); @@ -132,13 +172,50 @@ namespace ttk { Timer t_tempSub; // --- Preprocessing - treesNodeCorr_ = std::vector>(mTrees.size()); - for(unsigned int i = 0; i < mTrees.size(); ++i) { - preprocessingPipeline( - mTrees[i], epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, - branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[i]); + if(!usePathMappings_){ + treesNodeCorr_ = std::vector>(mTrees.size()); + for(unsigned int i = 0; i < mTrees.size(); ++i) { + preprocessingPipeline( + mTrees[i], epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, + branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[i]); + } + printTreesStats(mTrees); + } + + if(usePathMappings_){ + treesNodeCorr_ = std::vector>(mTrees.size()); + printMsg("uses path mapping distance"); + for(unsigned int i = 0; i < mTrees.size(); ++i) { + ftm::FTMTree_MT *tree = &(mTrees[i].tree); + preprocessTree(tree, true); + + // - Delete null persistence pairs and persistence thresholding + persistenceThresholding(tree, persistenceThreshold_); + + // - Merge saddle points according epsilon + if(not isPersistenceDiagram_) { + if(epsilonTree2_ != 0){ + std::vector> treeNodeMerged( tree->getNumberOfNodes() ); + mergeSaddle(tree, epsilonTree2_, treeNodeMerged); + for(unsigned int j=0; jgetNode(j)->getOrigin(); + tree->getNode(k)->setOrigin(j); + tree->getNode(nodeToDelete)->setOrigin(-1); + } + } + ftm::cleanMergeTree(mTrees[i], treesNodeCorr_[i], true); + } + else{ + std::vector nodeCorri(tree->getNumberOfNodes()); + for(unsigned int j=0; j(tree, false); + } } - printTreesStats(mTrees); // --- Execute distancesToKeyFrames_ = std::vector(coefs.size() * 2); @@ -171,10 +248,12 @@ namespace ttk { = computeDistance(allMT[i], allMT[i + 1], allMatching[i]); // --- Postprocessing - for(unsigned int i = 0; i < allMT.size(); ++i) - postprocessingPipeline(&(allMT[i].tree)); - for(unsigned int i = 0; i < mTrees.size(); ++i) - postprocessingPipeline(&(mTrees[i].tree)); + if(!usePathMappings_){ + for(unsigned int i = 0; i < allMT.size(); ++i) + postprocessingPipeline(&(allMT[i].tree)); + for(unsigned int i = 0; i < mTrees.size(); ++i) + postprocessingPipeline(&(mTrees[i].tree)); + } // --- Print results std::stringstream ss, ss2, ss3; diff --git a/core/base/mergeTreeTemporalReductionEncoding/MergeTreeTemporalReductionEncoding.h b/core/base/mergeTreeTemporalReductionEncoding/MergeTreeTemporalReductionEncoding.h index bd88c1cb4f..dac749e3a2 100644 --- a/core/base/mergeTreeTemporalReductionEncoding/MergeTreeTemporalReductionEncoding.h +++ b/core/base/mergeTreeTemporalReductionEncoding/MergeTreeTemporalReductionEncoding.h @@ -26,6 +26,7 @@ #include #include #include +#include namespace ttk { @@ -37,6 +38,7 @@ namespace ttk { public MergeTreeBase { protected: double removalPercentage_ = 50.; + bool usePathMappings_ = false; bool useL2Distance_ = false; std::vector> fieldL2_; bool useCustomTimeVariable_ = false; @@ -53,6 +55,10 @@ namespace ttk { useL2Distance_ = useL2; } + void setPathMappings(bool usePM) { + usePathMappings_ = usePM; + } + template dataType computeL2Distance(std::vector &img1, std::vector &img2, @@ -91,34 +97,52 @@ namespace ttk { dataType computeDistance(ftm::MergeTree &mTree1, ftm::MergeTree &mTree2, bool emptyTreeDistance = false) { - MergeTreeDistance mergeTreeDistance; - mergeTreeDistance.setAssignmentSolver(assignmentSolverID_); - mergeTreeDistance.setEpsilonTree1(epsilonTree1_); - mergeTreeDistance.setEpsilonTree2(epsilonTree2_); - mergeTreeDistance.setEpsilon2Tree1(epsilon2Tree1_); - mergeTreeDistance.setEpsilon2Tree2(epsilon2Tree2_); - mergeTreeDistance.setEpsilon3Tree1(epsilon3Tree1_); - mergeTreeDistance.setEpsilon3Tree2(epsilon3Tree2_); - mergeTreeDistance.setProgressiveComputation(progressiveComputation_); - mergeTreeDistance.setBranchDecomposition(branchDecomposition_); - mergeTreeDistance.setParallelize(parallelize_); - mergeTreeDistance.setPersistenceThreshold(persistenceThreshold_); - mergeTreeDistance.setNormalizedWasserstein(normalizedWasserstein_); - mergeTreeDistance.setNormalizedWassersteinReg(normalizedWassersteinReg_); - mergeTreeDistance.setRescaledWasserstein(rescaledWasserstein_); - mergeTreeDistance.setKeepSubtree(keepSubtree_); - mergeTreeDistance.setUseMinMaxPair(useMinMaxPair_); - mergeTreeDistance.setThreadNumber(this->threadNumber_); - mergeTreeDistance.setDistanceSquared(true); // squared root - mergeTreeDistance.setDebugLevel(2); - mergeTreeDistance.setPreprocess(false); - mergeTreeDistance.setPostprocess(false); - // mergeTreeDistance.setIsCalled(true); - mergeTreeDistance.setOnlyEmptyTreeDistance(emptyTreeDistance); - - std::vector> matching; - dataType distance - = mergeTreeDistance.execute(mTree1, mTree2, matching); + dataType distance; + if(usePathMappings_){ + PathMappingDistance mergeTreeDistance; + mergeTreeDistance.setAssignmentSolver(assignmentSolverID_); + mergeTreeDistance.setEpsilonTree1(epsilonTree1_); + mergeTreeDistance.setEpsilonTree2(epsilonTree2_); + mergeTreeDistance.setPersistenceThreshold(persistenceThreshold_); + mergeTreeDistance.setThreadNumber(this->threadNumber_); + mergeTreeDistance.setDistanceSquared(false); + mergeTreeDistance.setDebugLevel(2); // ToDo: Why?? + mergeTreeDistance.setPreprocess(false); + mergeTreeDistance.setComputeMapping(false); + + ftm::FTMTree_MT* mt1 = &(mTree1.tree); + ftm::FTMTree_MT* mt2 = &(mTree2.tree); + distance = mergeTreeDistance.editDistance_path(mt1, mt2); + } + else{ + MergeTreeDistance mergeTreeDistance; + mergeTreeDistance.setAssignmentSolver(assignmentSolverID_); + mergeTreeDistance.setEpsilonTree1(epsilonTree1_); + mergeTreeDistance.setEpsilonTree2(epsilonTree2_); + mergeTreeDistance.setEpsilon2Tree1(epsilon2Tree1_); + mergeTreeDistance.setEpsilon2Tree2(epsilon2Tree2_); + mergeTreeDistance.setEpsilon3Tree1(epsilon3Tree1_); + mergeTreeDistance.setEpsilon3Tree2(epsilon3Tree2_); + mergeTreeDistance.setProgressiveComputation(progressiveComputation_); + mergeTreeDistance.setBranchDecomposition(branchDecomposition_); + mergeTreeDistance.setParallelize(parallelize_); + mergeTreeDistance.setPersistenceThreshold(persistenceThreshold_); + mergeTreeDistance.setNormalizedWasserstein(normalizedWasserstein_); + mergeTreeDistance.setNormalizedWassersteinReg(normalizedWassersteinReg_); + mergeTreeDistance.setRescaledWasserstein(rescaledWasserstein_); + mergeTreeDistance.setKeepSubtree(keepSubtree_); + mergeTreeDistance.setUseMinMaxPair(useMinMaxPair_); + mergeTreeDistance.setThreadNumber(this->threadNumber_); + mergeTreeDistance.setDistanceSquared(true); // squared root + mergeTreeDistance.setDebugLevel(2); + mergeTreeDistance.setPreprocess(false); + mergeTreeDistance.setPostprocess(false); + // mergeTreeDistance.setIsCalled(true); + mergeTreeDistance.setOnlyEmptyTreeDistance(emptyTreeDistance); + + std::vector> matching; + distance = mergeTreeDistance.execute(mTree1, mTree2, matching); + } return distance; } @@ -139,10 +163,6 @@ namespace ttk { mergeTreeBarycenter.setBranchDecomposition(branchDecomposition_); mergeTreeBarycenter.setParallelize(parallelize_); mergeTreeBarycenter.setPersistenceThreshold(persistenceThreshold_); - mergeTreeBarycenter.setNormalizedWasserstein(normalizedWasserstein_); - mergeTreeBarycenter.setNormalizedWassersteinReg( - normalizedWassersteinReg_); - mergeTreeBarycenter.setRescaledWasserstein(rescaledWasserstein_); mergeTreeBarycenter.setKeepSubtree(keepSubtree_); mergeTreeBarycenter.setUseMinMaxPair(useMinMaxPair_); mergeTreeBarycenter.setThreadNumber(this->threadNumber_); @@ -152,6 +172,22 @@ namespace ttk { mergeTreeBarycenter.setPostprocess(false); // mergeTreeBarycenter.setIsCalled(true); + if(usePathMappings_){ + mergeTreeBarycenter.setBaseModule(2); + mergeTreeBarycenter.setBranchDecomposition(false); + mergeTreeBarycenter.setNormalizedWasserstein(false); + mergeTreeBarycenter.setKeepSubtree(false); + mergeTreeBarycenter.setUseMinMaxPair(false); + mergeTreeBarycenter.setAddNodes(false); + mergeTreeBarycenter.setPostprocess(false); + } + else{ + mergeTreeBarycenter.setBranchDecomposition(true); + mergeTreeBarycenter.setNormalizedWasserstein(normalizedWasserstein_); + mergeTreeBarycenter.setNormalizedWassersteinReg(normalizedWassersteinReg_); + mergeTreeBarycenter.setRescaledWasserstein(rescaledWasserstein_); + } + std::vector> intermediateTrees; intermediateTrees.push_back(mTree1); intermediateTrees.push_back(mTree2); @@ -319,7 +355,7 @@ namespace ttk { Timer t_tempSub; // --- Preprocessing - if(not useL2Distance_) { + if(not useL2Distance_ && not usePathMappings_) { treesNodeCorr_ = std::vector>(mTrees.size()); for(unsigned int i = 0; i < mTrees.size(); ++i) { preprocessingPipeline(mTrees[i], epsilonTree2_, @@ -329,6 +365,40 @@ namespace ttk { } printTreesStats(mTrees); } + if(usePathMappings_){ + treesNodeCorr_ = std::vector>(mTrees.size()); + printMsg("uses path mapping distance"); + for(unsigned int i = 0; i < mTrees.size(); ++i) { + ftm::FTMTree_MT *tree = &(mTrees[i].tree); + preprocessTree(tree, true); + + // - Delete null persistence pairs and persistence thresholding + persistenceThresholding(tree, persistenceThreshold_); + + // - Merge saddle points according epsilon + if(not isPersistenceDiagram_) { + if(epsilonTree2_ != 0){ + std::vector> treeNodeMerged( tree->getNumberOfNodes() ); + mergeSaddle(tree, epsilonTree2_, treeNodeMerged); + for(unsigned int j=0; jgetNode(j)->getOrigin(); + tree->getNode(k)->setOrigin(j); + tree->getNode(nodeToDelete)->setOrigin(-1); + } + } + ftm::cleanMergeTree(mTrees[i], treesNodeCorr_[i], true); + } + else{ + std::vector nodeCorri(tree->getNumberOfNodes()); + for(unsigned int j=0; j(tree, false); + } + } // --- Execute std::vector> barycenters(mTrees.size()); @@ -374,7 +444,7 @@ namespace ttk { } // --- Postprocessing - if(not useL2Distance_) { + if(not useL2Distance_ && not usePathMappings_) { for(unsigned int i = 0; i < allMT.size(); ++i) postprocessingPipeline(&(allMT[i].tree)); for(unsigned int i = 0; i < mTrees.size(); ++i) diff --git a/core/vtk/ttkMergeTreeTemporalReductionDecoding/ttkMergeTreeTemporalReductionDecoding.h b/core/vtk/ttkMergeTreeTemporalReductionDecoding/ttkMergeTreeTemporalReductionDecoding.h index 17f751efc2..684d7420ed 100644 --- a/core/vtk/ttkMergeTreeTemporalReductionDecoding/ttkMergeTreeTemporalReductionDecoding.h +++ b/core/vtk/ttkMergeTreeTemporalReductionDecoding/ttkMergeTreeTemporalReductionDecoding.h @@ -145,6 +145,15 @@ class TTKMERGETREETEMPORALREDUCTIONDECODING_EXPORT return assignmentSolverID_; } + void SetUsePathMappings(double usePM) { + usePathMappings_ = usePM; + Modified(); + resetDataVisualization(); + } + double GetPathMappings() { + return usePathMappings_; + } + // Output Options vtkSetMacro(OutputTrees, bool); vtkGetMacro(OutputTrees, bool); diff --git a/core/vtk/ttkMergeTreeTemporalReductionEncoding/ttkMergeTreeTemporalReductionEncoding.h b/core/vtk/ttkMergeTreeTemporalReductionEncoding/ttkMergeTreeTemporalReductionEncoding.h index 1094d2be9b..84c027efd0 100644 --- a/core/vtk/ttkMergeTreeTemporalReductionEncoding/ttkMergeTreeTemporalReductionEncoding.h +++ b/core/vtk/ttkMergeTreeTemporalReductionEncoding/ttkMergeTreeTemporalReductionEncoding.h @@ -191,6 +191,15 @@ class TTKMERGETREETEMPORALREDUCTIONENCODING_EXPORT return useL2Distance_; } + void SetUsePathMappings(double usePM) { + usePathMappings_ = usePM; + Modified(); + resetDataVisualization(); + } + double GetPathMappings() { + return usePathMappings_; + } + void SetUseCustomTimeVariable(bool useCustomTime) { useCustomTimeVariable_ = useCustomTime; Modified(); diff --git a/paraview/xmls/MergeTreeTemporalReductionDecoding.xml b/paraview/xmls/MergeTreeTemporalReductionDecoding.xml index 5e04f6151f..5a1206ff99 100644 --- a/paraview/xmls/MergeTreeTemporalReductionDecoding.xml +++ b/paraview/xmls/MergeTreeTemporalReductionDecoding.xml @@ -80,6 +80,18 @@ Online examples: + + + Use the path mapping distance instead of wasserstein distance. + + + + + diff --git a/paraview/xmls/MergeTreeTemporalReductionEncoding.xml b/paraview/xmls/MergeTreeTemporalReductionEncoding.xml index 272de5f71e..a31f98bd5b 100644 --- a/paraview/xmls/MergeTreeTemporalReductionEncoding.xml +++ b/paraview/xmls/MergeTreeTemporalReductionEncoding.xml @@ -75,12 +75,30 @@ Online examples: + + + Use the path mapping distance instead of wasserstein distance. + + + + + + + Allows to use a custom time variable for each data in input. By default the nth input is considered to be the timestep n. @@ -121,6 +139,12 @@ Online examples: number_of_elements="1" default_values="0" panel_visibility="advanced"> + + + Use the L2 distance and L2 barycenter of the original data to compute the reduction (needs to have the Segmentation output of FTMTree). @@ -130,6 +154,7 @@ Online examples: + From ef248d6cffe2398cd46a93f11fef728f0af71cec Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Wed, 1 Mar 2023 16:06:27 +0100 Subject: [PATCH 35/72] added some debugging and testing options to MergeTreeClustering --- .../mergeTreeClustering/MergeTreeBarycenter.h | 87 +++++++++++++++---- .../mergeTreeClustering/PathMappingDistance.h | 1 + .../ttkMergeTreeClustering.cpp | 4 + .../ttkMergeTreeClustering.h | 28 ++++++ paraview/xmls/MergeTreeClustering.xml | 83 ++++++++++++++++++ 5 files changed, 187 insertions(+), 16 deletions(-) diff --git a/core/base/mergeTreeClustering/MergeTreeBarycenter.h b/core/base/mergeTreeClustering/MergeTreeBarycenter.h index 910d89e439..601c9b9f5f 100644 --- a/core/base/mergeTreeClustering/MergeTreeBarycenter.h +++ b/core/base/mergeTreeClustering/MergeTreeBarycenter.h @@ -24,6 +24,9 @@ #include "MergeTreeDistance.h" #include "PathMappingDistance.h" +#include +#include + namespace ttk { /** @@ -52,6 +55,10 @@ namespace ttk { int pathMetric_ = 0; int baseModule_ = 0; + bool useMedianBarycenter_ = false; + bool useFixedInit_ = false; + bool useEarlyOut_ = false; + int fixedInitNumber_ = 0; //int iterationLimit_ = 0; // Output @@ -132,6 +139,22 @@ namespace ttk { pathMetric_ = m; } + void setUseMedianBarycenter(bool useMedian) { + useMedianBarycenter_ = useMedian; + } + + void setUseFixedInit(bool useFixedInit) { + useFixedInit_ = useFixedInit; + } + + void setUseEarlyOut(bool useEarlyOut) { + useEarlyOut_ = useEarlyOut; + } + + void setFixedInitNumber(int fixedInitNumber) { + fixedInitNumber_ = fixedInitNumber; + } + // void setIterationLimit(int l) { // iterationLimit_ = l; // } @@ -290,8 +313,13 @@ namespace ttk { void initBarycenterTree(std::vector &trees, ftm::MergeTree &baryTree, bool distMinimizer = true) { - int bestIndex = getBestInitTreeIndex(trees, distMinimizer); - // bestIndex = trees.size()-1; + int bestIndex; + if(useFixedInit_){ + if(fixedInitNumber_ >= 0 && fixedInitNumber_ < trees.size()) bestIndex = fixedInitNumber_; + else bestIndex = 0; + } + else bestIndex = getBestInitTreeIndex(trees, distMinimizer); + // bestIndex = 10; //baryTree = ftm::copyMergeTree(trees[bestIndex], true); baryTree = ftm::copyMergeTree(trees[bestIndex], baseModule_!=2); // ftm::FTMTree_MT* bt = &(baryTree.tree); @@ -850,7 +878,7 @@ namespace ttk { // compute size of new barycenter tree int newSize = oldSize; for(unsigned int i=0; igetValue(lastB); dataType relativeValueB = lastValueB > currValueB ? lastValueB - currValueB : currValueB - lastValueB; relativeValueB = relativeValueB/pathRangeB; - parentEdgeLengths[lastB].emplace_back(relativeValueB * pathRangeT * alphas[i]); + if(useMedianBarycenter_) parentEdgeLengths[lastB].emplace_back(relativeValueB * pathRangeT); + else parentEdgeLengths[lastB].emplace_back(relativeValueB * pathRangeT * alphas[i]); // continue iteration lastB = currB; currB = baryTreeNew->getParentSafe(currB); @@ -912,13 +941,21 @@ namespace ttk { baryTreeNew->getChildren(curr,children); for(auto child : children){ q.emplace(child); - dataType avgEdgeLength = 0; - for(auto l : parentEdgeLengths[child]){ - avgEdgeLength += l; + if(useMedianBarycenter_){ + auto m = parentEdgeLengths[child].begin() + parentEdgeLengths[child].size()/2; + std::nth_element(parentEdgeLengths[child].begin(), m, parentEdgeLengths[child].end()); + auto medianEdgeLength = parentEdgeLengths[child][parentEdgeLengths[child].size()/2]; + newScalars[child] = newScalars[curr] + (joinTrees ? - medianEdgeLength : medianEdgeLength); + } + else{ + dataType avgEdgeLength = 0; + for(auto l : parentEdgeLengths[child]){ + avgEdgeLength += l; + } + //avgEdgeLength = avgEdgeLength/static_cast(trees.size()); + avgEdgeLength = avgEdgeLength/alphaSum; + newScalars[child] = newScalars[curr] + (joinTrees ? - avgEdgeLength : avgEdgeLength); } - //avgEdgeLength = avgEdgeLength/static_cast(trees.size()); - avgEdgeLength = avgEdgeLength/alphaSum; - newScalars[child] = newScalars[curr] + (joinTrees ? - avgEdgeLength : avgEdgeLength); } } setTreeScalars(baryMergeTreeNew, newScalars); @@ -926,7 +963,7 @@ namespace ttk { // insert new nodes int currSize = oldSize; for(unsigned int i=0; i newIndices(tree->getNumberOfNodes(),-1); for(auto match : matchings[i]){ @@ -1349,7 +1386,8 @@ namespace ttk { dataType minFrechet = std::numeric_limits::max(); int cptBlocked = 0; int NoIteration = 0; - while(not converged){// && NoIterationthreadNumber_, debug::LineMode::NEW, debug::Priority::INFO); printBaryStats(baryTree); ss4 << "Frechet energy : " << frechetEnergy; + ss5 << "Frechet energy non-squared: " << currentFrechetEnergy2; printMsg(ss4.str()); + printMsg(ss5.str()); minFrechet = std::min(minFrechet, frechetEnergy); if(not converged and (not progressiveBarycenter_ or treesUnscaled)) { cptBlocked = (minFrechet < frechetEnergy) ? cptBlocked + 1 : 0; converged = (cptBlocked >= 10); } + if(!useEarlyOut_) converged = false; // --- Persistence scaling if(progressiveBarycenter_) { @@ -1426,6 +1471,11 @@ namespace ttk { } } + // std::ofstream energyFile; + // energyFile.open("/home/wetzels/ttk/energy.txt"); + // energyFile << energySequence.str(); + // energyFile.close(); + // Final processing printMsg(debug::Separator::L2); printMsg("Final assignment"); @@ -1454,12 +1504,17 @@ namespace ttk { for(auto dist : distances) finalDistances_.push_back(dist); dataType currentFrechetEnergy = 0; - for(unsigned int i = 0; i < trees.size(); ++i) - currentFrechetEnergy += alphas[i] * distances[i] * distances[i]; + dataType currentFrechetEnergy2 = 0; + for(unsigned int i = 0; i < trees.size(); ++i){ + currentFrechetEnergy2 += alphas[i] * distances[i]; + currentFrechetEnergy += alphas[i] * distances[i] * distances[i]; + } std::stringstream ss, ss2; ss << "Frechet energy : " << currentFrechetEnergy; + ss2 << "Frechet energy non-squared: " << currentFrechetEnergy2; printMsg(ss.str()); + printMsg(ss2.str()); auto barycenterTime = t_bary.getElapsedTime() - addDeletedNodesTime_; printMsg("Total", 1, barycenterTime, this->threadNumber_, debug::LineMode::NEW, debug::Priority::INFO); diff --git a/core/base/mergeTreeClustering/PathMappingDistance.h b/core/base/mergeTreeClustering/PathMappingDistance.h index 783725f2d8..6a2499d94e 100644 --- a/core/base/mergeTreeClustering/PathMappingDistance.h +++ b/core/base/mergeTreeClustering/PathMappingDistance.h @@ -457,6 +457,7 @@ namespace ttk { size_t dim3 = (depth1 + 1) * dim2; size_t dim4 = (nn2 + 1) * dim3; + //std::cout << (nn1 + 1) * (depth1 + 1) * (nn2 + 1) * (depth2 + 1) * sizeof(dataType) << std::endl; std::vector memT((nn1 + 1) * (depth1 + 1) * (nn2 + 1) * (depth2 + 1)); diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index bc7ca15076..bb74b22ebf 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -356,6 +356,9 @@ int ttkMergeTreeClustering::runCompute( mergeTreeBarycenter.setAlpha(Alpha); mergeTreeBarycenter.setDeterministic(Deterministic); mergeTreeBarycenter.setPersistenceThreshold(PersistenceThreshold); + mergeTreeBarycenter.setUseFixedInit(useFixedInit); + mergeTreeBarycenter.setFixedInitNumber(fixedInitNumber); + mergeTreeBarycenter.setUseEarlyOut(useEarlyOut); // mergeTreeBarycenter.setIterationLimit(iterationLimit); if(baseModule == 2) { mergeTreeBarycenter.setPathMetric(this->pathMetric); @@ -365,6 +368,7 @@ int ttkMergeTreeClustering::runCompute( mergeTreeBarycenter.setUseMinMaxPair(false); mergeTreeBarycenter.setAddNodes(false); mergeTreeBarycenter.setPostprocess(false); + mergeTreeBarycenter.setUseMedianBarycenter(useMedianBarycenter); } else { mergeTreeBarycenter.setBranchDecomposition(BranchDecomposition); mergeTreeBarycenter.setNormalizedWasserstein(NormalizedWasserstein); diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h index 550b872768..fa856938cd 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h @@ -90,6 +90,10 @@ class TTKMERGETREECLUSTERING_EXPORT ttkMergeTreeClustering int pathMetric = 0; int branchMetric = 0; int baseModule = 0; + bool useMedianBarycenter = false; + bool useFixedInit = false; + int fixedInitNumber = 0; + bool useEarlyOut = true; // int iterationLimit = 0; // Output Options @@ -342,6 +346,30 @@ class TTKMERGETREECLUSTERING_EXPORT ttkMergeTreeClustering resetDataVisualization(); } + void SetUseMedianBarycenter(bool useMedian) { + useMedianBarycenter = useMedian; + Modified(); + resetDataVisualization(); + } + + void SetUseFixedInit(bool ufi) { + useFixedInit = ufi; + Modified(); + resetDataVisualization(); + } + + void SetFixedInitNumber(int fi) { + fixedInitNumber = fi; + Modified(); + resetDataVisualization(); + } + + void SetUseEarlyOut(bool eo) { + useEarlyOut = eo; + Modified(); + resetDataVisualization(); + } + // void SetIterationLimit(int l) { // iterationLimit = l; // Modified(); diff --git a/paraview/xmls/MergeTreeClustering.xml b/paraview/xmls/MergeTreeClustering.xml index 45304705e0..3d488ac388 100644 --- a/paraview/xmls/MergeTreeClustering.xml +++ b/paraview/xmls/MergeTreeClustering.xml @@ -186,6 +186,85 @@ Online examples: + + + + + + + + + + + Use median update procedure instead of average. + + + + + + + + + + Use fixed member for initial barycenter candidate. + + + + + + + + + + Member index for initial barycenter candidate. + + + + + + + + + Stop barycenter iteration when convergence good enough. + + + + ${MERGE_TREE_PREPROCESS_WIDGETS} From 147ab25e21b8a47829ed5ca45a4af4ce27121d70 Mon Sep 17 00:00:00 2001 From: MatPont Date: Thu, 2 Mar 2023 13:13:00 +0100 Subject: [PATCH 36/72] [MergeTreeVisu] fix dummy nodes and cells --- .../ttkMergeTreeVisualization.h | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h index 008cb9be3c..fb0870dace 100644 --- a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h +++ b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h @@ -1189,10 +1189,10 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { prevXMax = 0; } - // TODO too many dummy nodes are created bool dummyNode = PlanarLayout and not branchDecompositionPlanarLayout_ - and (!trees[i]->isRoot(node) or isPersistenceDiagram); + and ((!trees[i]->isRoot(node) and !trees[i]->isLeaf(node)) + or isPersistenceDiagram); if(dummyNode) { double pointToAdd[3]; if(not isPersistenceDiagram) @@ -1273,12 +1273,14 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { // Path Layout Dummy Cell bool isNodeParentImportant = isImportantPairVector[nodeParent]; - bool pathDummyCell - = not dummyCell and pathPlanarLayout_ and isNodeParentImportant; + bool pathDummyCell = not dummyCell and pathPlanarLayout_ + and isNodeParentImportant + and !trees[i]->isRoot(nodeParent); if(not pathDummyCell and alignTrees and ShiftMode != 1) { - pathDummyCell = pathPlanarLayout_ - and layout[layoutCorr[node]] - != layout[layoutCorr[nodeParent]]; + pathDummyCell + = not dummyCell and pathPlanarLayout_ + and layout[layoutCorr[node]] != layout[layoutCorr[nodeParent]] + and !trees[i]->isRoot(nodeParent); } if(pathDummyCell) { pathDummyNode = true; @@ -1298,7 +1300,7 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { // -------------- // Arc field // -------------- - int toAdd = (dummyCell ? 2 : 1) + (pathDummyCell ? 1 : 0); + int toAdd = 1 + (dummyCell ? 1 : 0) + (pathDummyCell ? 1 : 0); for(int toAddT = 0; toAddT < toAdd; ++toAddT) { // Add arc matching percentage if(ShiftMode == 1) { // Star Barycenter @@ -1362,7 +1364,7 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { isImportantPairsArc->InsertNextTuple1(isImportant); // Add isDummyArc - bool isDummy = toAdd == 2 and toAddT == 0; + bool isDummy = toAdd >= 2 and toAddT == (toAdd - 2); isDummyArc->InsertNextTuple1(isDummy); // Add isInterpolatedTree @@ -1412,7 +1414,7 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { // -------------- // Node field // -------------- - int toAdd = (dummyNode ? 2 : 1) + (pathDummyNode ? 1 : 0); + int toAdd = 1 + (dummyNode ? 1 : 0) + (pathDummyNode ? 1 : 0); for(int toAddT = 0; toAddT < toAdd; ++toAddT) { // Add node id nodeID->InsertNextTuple1(treeSimplexId[node]); @@ -1432,7 +1434,9 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { vertexID->InsertNextTuple1(nodeVertexId); // Add node scalar - scalar->InsertNextTuple1(trees[i]->getValue(node)); + auto scalarValue = trees[i]->getValue(node); + + scalar->InsertNextTuple1(scalarValue); // Add criticalType printMsg("// Add criticalType", ttk::debug::Priority::VERBOSE); @@ -1519,6 +1523,14 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { // Add isDummyNode bool isDummy = toAdd == 2 and toAddT == 1 and !trees[i]->isRoot(node); + if(pathPlanarLayout_) { + isDummy = (toAdd >= 2 and dummyNode and toAddT == 0); + isDummy = isDummy + or (pathDummyNode + and ((toAdd == 2 and toAddT == 1) + or (toAdd == 3 and toAddT == 2))); + isDummy = isDummy and !trees[i]->isRoot(node); + } isDummyNode->InsertNextTuple1(isDummy); // Add isInterpolatedTree From 52de90875560ffc424e2f9c7d8cdc70726b1b5eb Mon Sep 17 00:00:00 2001 From: MatPont Date: Thu, 2 Mar 2023 15:04:57 +0100 Subject: [PATCH 37/72] [MT-AE] work on path layout points and cells data --- .../ttkMergeTreeVisualization.h | 54 ++++++++++--------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h index fb0870dace..8a4a12df9a 100644 --- a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h +++ b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h @@ -1118,6 +1118,7 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { idNode node = queue.front(); queue.pop(); idNode nodeOrigin = trees[i]->getNode(node)->getOrigin(); + idNode nodeParent = trees[i]->getParentSafe(node); // Push children to the queue printMsg( @@ -1246,7 +1247,6 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { vtkIdType pointIds[2]; pointIds[0] = treeSimplexId[node]; - idNode nodeParent = trees[i]->getParentSafe(node); // TODO too many dummy cells are created bool dummyCell = PlanarLayout and not branchDecompositionPlanarLayout_ @@ -1416,11 +1416,15 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { // -------------- int toAdd = 1 + (dummyNode ? 1 : 0) + (pathDummyNode ? 1 : 0); for(int toAddT = 0; toAddT < toAdd; ++toAddT) { + bool isPathDummyNode = pathDummyNode and toAdd >= 2 + and toAddT == (toAdd - 1) + and !trees[i]->isRoot(node); + auto nodeToGet = (isPathDummyNode ? nodeParent : node); // Add node id - nodeID->InsertNextTuple1(treeSimplexId[node]); + nodeID->InsertNextTuple1(treeSimplexId[nodeToGet]); // Add trueNodeId - trueNodeID->InsertNextTuple1(node); + trueNodeID->InsertNextTuple1(nodeToGet); // Add VertexId int nodeVertexId = -1; @@ -1434,8 +1438,7 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { vertexID->InsertNextTuple1(nodeVertexId); // Add node scalar - auto scalarValue = trees[i]->getValue(node); - + auto scalarValue = trees[i]->getValue(nodeToGet); scalar->InsertNextTuple1(scalarValue); // Add criticalType @@ -1472,29 +1475,31 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { criticalType->InsertNextTuple1(criticalTypeT); // Add node matching percentage - if(ShiftMode == 1) { // Star Barycenter + if(ShiftMode == 1) // Star Barycenter percentMatch->InsertNextTuple1(allBaryPercentMatch[c][node]); - } // Add node branch bary id printMsg( "// Add node bary branch id", ttk::debug::Priority::VERBOSE); if(clusteringOutput and ShiftMode != 1) { int tBranchID = -1; - if(treeMatching[node] < allBaryBranchingID[c].size()) { - tBranchID = allBaryBranchingID[c][treeMatching[node]]; - if(!trees[i]->isLeaf(node) - && treeMatching[nodeOrigin] < allBaryBranchingID[c].size()) - tBranchID = allBaryBranchingID[c][treeMatching[nodeOrigin]]; + auto nodeT + = (isPathDummyNode + ? trees[i]->getNode(treeBranching[node])->getOrigin() + : (trees[i]->isLeaf(node) ? node : nodeOrigin)); + if(treeMatching[nodeT] < allBaryBranchingID[c].size()) { + tBranchID = allBaryBranchingID[c][treeMatching[nodeT]]; } branchBaryNodeID->InsertNextTuple1(tBranchID); } // Add node branch id if(not isPersistenceDiagram) { - int tBranchID = treeBranchingID[node]; - if(not trees[i]->isLeaf(node)) - tBranchID = treeBranchingID[nodeOrigin]; + auto nodeT + = (isPathDummyNode + ? trees[i]->getNode(treeBranching[node])->getOrigin() + : (trees[i]->isLeaf(node) ? node : nodeOrigin)); + int tBranchID = treeBranchingID[nodeT]; branchNodeID->InsertNextTuple1(tBranchID); } @@ -1524,12 +1529,9 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { bool isDummy = toAdd == 2 and toAddT == 1 and !trees[i]->isRoot(node); if(pathPlanarLayout_) { - isDummy = (toAdd >= 2 and dummyNode and toAddT == 0); - isDummy = isDummy - or (pathDummyNode - and ((toAdd == 2 and toAddT == 1) - or (toAdd == 3 and toAddT == 2))); - isDummy = isDummy and !trees[i]->isRoot(node); + isDummy = (toAdd >= 2 and dummyNode and toAddT == 0 + and !trees[i]->isRoot(node)); + isDummy = isDummy or isPathDummyNode; } isDummyNode->InsertNextTuple1(isDummy); @@ -1537,11 +1539,11 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { isInterpolatedTreeNode->InsertNextTuple1(isInterpolatedTree); // Add isImportantPair - bool isImportant = isImportantPairVector[node]; + bool isImportant = isImportantPairVector[nodeToGet]; isImportantPairsNode->InsertNextTuple1(isImportant); // Add treeNodeId - treeNodeId->InsertNextTuple1(node); + treeNodeId->InsertNextTuple1(nodeToGet); // Add treeNodeIdOrigin treeNodeIdOrigin->InsertNextTuple1(nodeOrigin); @@ -1563,13 +1565,13 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { // Add custom arrays for(unsigned int ca = 0; ca < customArrays.size(); ++ca) customArraysValues[ca].emplace_back( - std::get<1>(customArrays[ca])[node]); + std::get<1>(customArrays[ca])[nodeToGet]); for(unsigned int ca = 0; ca < customIntArrays.size(); ++ca) customIntArraysValues[ca].emplace_back( - std::get<1>(customIntArrays[ca])[node]); + std::get<1>(customIntArrays[ca])[nodeToGet]); for(unsigned int ca = 0; ca < customStringArrays.size(); ++ca) customStringArraysValues[ca].emplace_back( - std::get<1>(customStringArrays[ca])[node]); + std::get<1>(customStringArrays[ca])[nodeToGet]); pointCount++; } From 13810823f78495edbab92b35c19831eeb6660c89 Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Thu, 2 Mar 2023 17:46:38 +0100 Subject: [PATCH 38/72] Added path mapping output to vtk layer of MergeTreeClustering --- .../mergeTreeClustering/MergeTreeBarycenter.h | 57 ++++++++++++++++++- .../mergeTreeClustering/MergeTreeClustering.h | 4 +- .../ttkMergeTreeClustering.cpp | 14 ++++- 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/core/base/mergeTreeClustering/MergeTreeBarycenter.h b/core/base/mergeTreeClustering/MergeTreeBarycenter.h index 601c9b9f5f..f0b6442139 100644 --- a/core/base/mergeTreeClustering/MergeTreeBarycenter.h +++ b/core/base/mergeTreeClustering/MergeTreeBarycenter.h @@ -1358,6 +1358,8 @@ namespace ttk { std::vector &alphas, std::vector>> &finalMatchings, + std::vector,std::pair>>> + &finalMatchings_path, bool finalAsgnDoubleInput = false, bool finalAsgnFirstInput = true) { Timer t_bary; @@ -1485,6 +1487,7 @@ namespace ttk { std::vector,std::pair>>> matchings_path(trees.size()); assignment_path(trees, baryMergeTree, matchings_path, distances); + finalMatchings_path = matchings_path; for(unsigned int i=0; i matchedNodes(trees[i]->getNumberOfNodes(),-1); @@ -1538,6 +1541,8 @@ namespace ttk { std::vector &alphas, std::vector>> &finalMatchings, + std::vector,std::pair>>> + &finalMatchings_path, ftm::MergeTree &baryMergeTree, bool finalAsgnDoubleInput = false, bool finalAsgnFirstInput = true) { @@ -1591,7 +1596,7 @@ namespace ttk { initBarycenterTree(treesT, baryMergeTree); // --- Execute - computeBarycenter(treesT, baryMergeTree, alphas, finalMatchings, + computeBarycenter(treesT, baryMergeTree, alphas, finalMatchings, finalMatchings_path, finalAsgnDoubleInput, finalAsgnFirstInput); if(baseModule_==2){ @@ -1618,11 +1623,35 @@ namespace ttk { } } + template + void execute( + std::vector> &trees, + std::vector &alphas, + std::vector>> + &finalMatchings, + ftm::MergeTree &baryMergeTree, + bool finalAsgnDoubleInput = false, + bool finalAsgnFirstInput = true) { + + std::vector,std::pair>>> + finalMatchings_path; + execute(trees, + alphas, + finalMatchings, + finalMatchings_path, + baryMergeTree, + finalAsgnDoubleInput, + finalAsgnFirstInput); + + } + template void execute( std::vector> &trees, std::vector>> &finalMatchings, + std::vector,std::pair>>> + &finalMatchings_path, ftm::MergeTree &baryMergeTree, bool finalAsgnDoubleInput = false, bool finalAsgnFirstInput = true) { @@ -1635,7 +1664,31 @@ namespace ttk { alphas.push_back(1 - alpha_); } - execute(trees, alphas, finalMatchings, baryMergeTree, + execute(trees, alphas, finalMatchings, finalMatchings_path, baryMergeTree, + finalAsgnDoubleInput, finalAsgnFirstInput); + } + + template + void execute( + std::vector> &trees, + std::vector>> + &finalMatchings, + ftm::MergeTree &baryMergeTree, + bool finalAsgnDoubleInput = false, + bool finalAsgnFirstInput = true) { + std::vector alphas; + if(trees.size() != 2) { + for(unsigned int i = 0; i < trees.size(); ++i) + alphas.push_back(1.0 / trees.size()); + } else { + alphas.push_back(alpha_); + alphas.push_back(1 - alpha_); + } + + std::vector,std::pair>>> + finalMatchings_path; + + execute(trees, alphas, finalMatchings, finalMatchings_path, baryMergeTree, finalAsgnDoubleInput, finalAsgnFirstInput); } diff --git a/core/base/mergeTreeClustering/MergeTreeClustering.h b/core/base/mergeTreeClustering/MergeTreeClustering.h index d082efed0a..4208522138 100644 --- a/core/base/mergeTreeClustering/MergeTreeClustering.h +++ b/core/base/mergeTreeClustering/MergeTreeClustering.h @@ -666,8 +666,10 @@ namespace ttk { mergeTreeBary.setProgressiveBarycenter(progressiveBarycenter_); } + std::vector,std::pair>>> + finalMatchings_path; mergeTreeBary.computeBarycenter( - trees, baryMergeTree, alphas, finalMatchings); + trees, baryMergeTree, alphas, finalMatchings, finalMatchings_path); addDeletedNodesTime_ += mergeTreeBary.getAddDeletedNodesTime(); diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index bb74b22ebf..7142b619af 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -383,10 +383,22 @@ int ttkMergeTreeClustering::runCompute( Epsilon1UseFarthestSaddle); } + std::vector,std::pair>>> + outputMatchings_path; mergeTreeBarycenter.execute( - intermediateMTrees, outputMatchingBarycenter[0], barycenters[0]); + intermediateMTrees, outputMatchingBarycenter[0], outputMatchings_path, barycenters[0]); trees1NodeCorrMesh = mergeTreeBarycenter.getTreesNodeCorr(); finalDistances = mergeTreeBarycenter.getFinalDistances(); + + std::cout << "Path Mappings:\n"; + for(auto matching : outputMatchings_path){ + std::cout << "---------------------------\n"; + for(auto m : matching){ + std::cout << "(" << m.first.first << "," << m.first.second << ") - "; + std::cout << "(" << m.second.first << "," << m.second.second << ")" << std::endl; + } + std::cout << "---------------------------\n"; + } } else { MergeTreeClustering mergeTreeClustering; mergeTreeClustering.setAssignmentSolver(AssignmentSolver); From d05943d3be907e10880a7494550111b42cbce67a Mon Sep 17 00:00:00 2001 From: MatPont Date: Thu, 2 Mar 2023 21:46:07 +0100 Subject: [PATCH 39/72] [MergeTreeVisu] path ids first version --- .../ttkMergeTreeClustering.cpp | 25 ++- .../ttkMergeTreeClustering.h | 6 +- .../ttkMergeTreeVisualization.h | 190 ++++++++++++++++-- 3 files changed, 194 insertions(+), 27 deletions(-) diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index 7142b619af..0f196a8419 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -383,22 +383,23 @@ int ttkMergeTreeClustering::runCompute( Epsilon1UseFarthestSaddle); } - std::vector,std::pair>>> - outputMatchings_path; mergeTreeBarycenter.execute( - intermediateMTrees, outputMatchingBarycenter[0], outputMatchings_path, barycenters[0]); + intermediateMTrees, outputMatchingBarycenter[0], + outputMatchings_path[0], barycenters[0]); trees1NodeCorrMesh = mergeTreeBarycenter.getTreesNodeCorr(); finalDistances = mergeTreeBarycenter.getFinalDistances(); - std::cout << "Path Mappings:\n"; - for(auto matching : outputMatchings_path){ + /*std::cout << "Path Mappings:\n"; + for(auto matching : outputMatchings_path[0]) { std::cout << "---------------------------\n"; - for(auto m : matching){ + std::cout << intermediateMTrees[i]->printTree().str() << std::: + for(auto m : matching) { std::cout << "(" << m.first.first << "," << m.first.second << ") - "; - std::cout << "(" << m.second.first << "," << m.second.second << ")" << std::endl; + std::cout << "(" << m.second.first << "," << m.second.second << ")" + << std::endl; } std::cout << "---------------------------\n"; - } + }*/ } else { MergeTreeClustering mergeTreeClustering; mergeTreeClustering.setAssignmentSolver(AssignmentSolver); @@ -772,9 +773,9 @@ int ttkMergeTreeClustering::runOutput( } } for(unsigned int c = 0; c < NumberOfBarycenters; ++c) { -#ifdef TTK_ENABLE_OPENMP -#pragma omp parallel for schedule(dynamic) num_threads(this->threadNumber_) -#endif + /*#ifdef TTK_ENABLE_OPENMP + #pragma omp parallel for schedule(dynamic) + num_threads(this->threadNumber_) #endif*/ for(int i = 0; i < numInputs; ++i) { if(clusteringAssignment[i] != (int)c) continue; @@ -819,6 +820,7 @@ int ttkMergeTreeClustering::runOutput( visuMaker.setVtkOutputSegmentation(vtkOutputSegmentation); visuMaker.setClusteringAssignment(clusteringAssignment); visuMaker.setOutputMatchingBarycenter(outputMatchingBarycenter); + visuMaker.setPathMatchings(outputMatchings_path); visuMaker.setPrintTreeId(i); visuMaker.setPrintClusterId(c); visuMaker.setDebugLevel(this->debugLevel_); @@ -934,6 +936,7 @@ int ttkMergeTreeClustering::runOutput( visuMakerBary.setVtkOutputSegmentation(vtkOutputSegmentation); visuMakerBary.setClusteringAssignment(clusteringAssignment); visuMakerBary.setOutputMatchingBarycenter(outputMatchingBarycenter); + visuMakerBary.setPathMatchings(outputMatchings_path); visuMakerBary.setPrintTreeId(c); visuMakerBary.setPrintClusterId(c); if(numInputs == 2 and NumberOfBarycenters == 1) { diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h index fa856938cd..dd8451f093 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h @@ -135,6 +135,10 @@ class TTKMERGETREECLUSTERING_EXPORT ttkMergeTreeClustering std::vector>>> outputMatchingBarycenter, outputMatchingBarycenter2; + std::vector, + std::pair>>>> + outputMatchings_path; // Barycenter std::vector> barycentersS, barycentersS2; @@ -164,13 +168,13 @@ class TTKMERGETREECLUSTERING_EXPORT ttkMergeTreeClustering std::vector< std::vector>>( numInputs)); - outputMatchingBarycenter2 = std::vector>>>( NumberOfBarycenters, std::vector< std::vector>>( numInputs2)); + outputMatchings_path.resize(NumberOfBarycenters); // Barycenter barycentersS diff --git a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h index 8a4a12df9a..a6481f694d 100644 --- a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h +++ b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h @@ -75,6 +75,12 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { std::vector>>> outputMatchingBarycenter; + // Path layout + std::vector, + std::pair>>>> + pathMatchings; + // Barycenter output std::vector> allBaryPercentMatch; @@ -221,6 +227,68 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { outputMatchingBarycenter = matching; } + // Path layout + void setPathMatchings( + std::vector, + std::pair>>>> + &matchings) { + pathMatchings = matchings; + } + void getTreePathing( + FTMTree_MT *tree, + std::vector< + std::vector, + std::pair>>> + &matchings, + bool isFirstTree, + std::vector &pathing, + std::vector &pathingID) { + pathing = std::vector(tree->getNumberOfNodes()); + pathingID = std::vector(tree->getNumberOfNodes(), -1); + std::vector nodeLevel; + tree->getAllNodeLevel(nodeLevel); + int pathID = 0; + std::vector> processed( + tree->getNumberOfNodes(), + std::vector(tree->getNumberOfNodes(), false)); + for(auto &matching : matchings) { + for(auto &match : matching) { + auto first = (isFirstTree ? match.first.first : match.second.first); + auto second = (isFirstTree ? match.first.second : match.second.second); + auto lowest = (nodeLevel[first] < nodeLevel[second] ? second : first); + auto highest = (nodeLevel[first] < nodeLevel[second] ? first : second); + if(processed[lowest][highest]) + continue; + processed[lowest][highest] = true; + while(lowest != highest) { + pathing[lowest] = highest; + pathingID[lowest] = pathID; + lowest = tree->getParentSafe(lowest); + } + if(tree->isRoot(highest)) { + pathing[highest] = highest; + pathingID[highest] = pathID; + } + ++pathID; + } + } + } + void getTreePathing( + FTMTree_MT *tree, + std::vector, + std::pair>> + &matching, + bool isFirstTree, + std::vector &pathing, + std::vector &pathingID) { + std::vector< + std::vector, + std::pair>>> + matchings{matching}; + getTreePathing(tree, matchings, isFirstTree, pathing, pathingID); + } + // Barycenter output std::vector> getAllBaryPercentMatch() { return allBaryPercentMatch; @@ -636,13 +704,18 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { std::vector> allBaryBounds(barycenters.size()); - std::vector> allBaryBranching(barycenters.size()); - std::vector> allBaryBranchingID(barycenters.size()); + std::vector> allBaryBranching(barycenters.size()), + allBaryPathing(barycenters.size()); + std::vector> allBaryBranchingID(barycenters.size()), + allBaryPathingID(barycenters.size()); for(size_t c = 0; c < barycenters.size(); ++c) { allBaryBounds[c] = getMaximalBounds(allBounds, clusteringAssignment, c); if(not isPersistenceDiagram) barycenters[c]->getTreeBranching( allBaryBranching[c], allBaryBranchingID[c]); + if(pathPlanarLayout_ and !pathMatchings.empty()) + getTreePathing(barycenters[c], pathMatchings[c], true, + allBaryPathing[c], allBaryPathingID[c]); } if(not clusteringOutput) allBaryBounds.emplace_back( @@ -677,6 +750,8 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { isDummyNode->SetName("isDummyNode"); vtkNew branchNodeID{}; branchNodeID->SetName("BranchNodeID"); + vtkNew pathNodeID{}; + pathNodeID->SetName("PathNodeID"); vtkNew scalar{}; scalar->SetName("Scalar"); vtkNew isImportantPairsNode{}; @@ -693,6 +768,8 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { treeIDNode->SetName("TreeID"); vtkNew branchBaryNodeID{}; branchBaryNodeID->SetName("BranchBaryNodeID"); + vtkNew pathBaryNodeID{}; + pathBaryNodeID->SetName("PathBaryNodeID"); vtkNew isInterpolatedTreeNode{}; isInterpolatedTreeNode->SetName("isInterpolatedTree"); @@ -731,6 +808,8 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { isDummyArc->SetName("isDummyArc"); vtkNew branchID{}; branchID->SetName("BranchID"); + vtkNew pathID{}; + pathID->SetName("PathID"); vtkNew upNodeId{}; upNodeId->SetName("upNodeId"); vtkNew downNodeId{}; @@ -740,6 +819,8 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { treeIDArc->SetName((isPersistenceDiagram ? "DiagramID" : "TreeID")); vtkNew branchBaryID{}; branchBaryID->SetName("BranchBaryNodeID"); + vtkNew pathBaryID{}; + pathBaryID->SetName("PathBaryNodeID"); vtkNew isInterpolatedTreeArc{}; isInterpolatedTreeArc->SetName("isInterpolatedTree"); @@ -885,10 +966,44 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { // Get branching printMsg("// Get branching", ttk::debug::Priority::VERBOSE); - std::vector treeBranching; - std::vector treeBranchingID; - if(not isPersistenceDiagram) + std::vector treeBranching, treePathing; + std::vector treeBranchingID, treePathingID; + std::vector isRootPath; + std::vector pathOrigin; + if(not isPersistenceDiagram) { trees[i]->getTreeBranching(treeBranching, treeBranchingID); + if(pathPlanarLayout_ and !pathMatchings.empty()) { + isRootPath.resize(trees[i]->getNumberOfNodes()); + std::fill(isRootPath.begin(), isRootPath.end(), false); + pathOrigin.resize(trees[i]->getNumberOfNodes()); + if(ShiftMode == 1) + getTreePathing( + trees[i], pathMatchings[c], true, treePathing, treePathingID); + else + getTreePathing(trees[i], pathMatchings[c][i], false, treePathing, + treePathingID); + bool isFirstTree = (ShiftMode == 1); + std::vector nodeLevel; + trees[i]->getAllNodeLevel(nodeLevel); + for(unsigned int j = 0; j < pathMatchings[c].size(); ++j) { + if((int)j != i and ShiftMode != 1) + continue; + for(auto &match : pathMatchings[c][j]) { + auto first + = (isFirstTree ? match.first.first : match.second.first); + auto second + = (isFirstTree ? match.first.second : match.second.second); + auto lowest + = (nodeLevel[first] < nodeLevel[second] ? second : first); + auto highest + = (nodeLevel[first] < nodeLevel[second] ? first : second); + isRootPath[highest] = true; + pathOrigin[lowest] = highest; + pathOrigin[highest] = lowest; + } + } + } + } // Get shift printMsg("// Get shift", ttk::debug::Priority::VERBOSE); @@ -1310,21 +1425,36 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { allBaryPercentMatch[c][nodeToGet]); } - // Add branch bary ID + // Add branch/path bary ID printMsg( "// Push arc bary branch id", ttk::debug::Priority::VERBOSE); if(clusteringOutput and ShiftMode != 1) { + // Branch int tBranchID = -1; auto nodeToGet = node; if(treeMatching[nodeToGet] < allBaryBranchingID[c].size()) tBranchID = allBaryBranchingID[c][treeMatching[nodeToGet]]; branchBaryID->InsertNextTuple1(tBranchID); + // Path + if(pathPlanarLayout_ and !pathMatchings.empty()) { + int tPathID = -1; + nodeToGet = node; + if(treeMatching[nodeToGet] < allBaryPathingID[c].size()) + tPathID = allBaryPathingID[c][treeMatching[nodeToGet]]; + pathBaryID->InsertNextTuple1(tPathID); + } } - // Add branch ID + // Add branch/path ID if(not isPersistenceDiagram) { + // Branch int tBranchID = treeBranchingID[node]; branchID->InsertNextTuple1(tBranchID); + // Path + if(pathPlanarLayout_ and !pathMatchings.empty()) { + int tPathID = treePathingID[node]; + pathID->InsertNextTuple1(tPathID); + } } // Add up and down nodeId @@ -1478,29 +1608,51 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { if(ShiftMode == 1) // Star Barycenter percentMatch->InsertNextTuple1(allBaryPercentMatch[c][node]); - // Add node branch bary id + // Add node branch/path bary id printMsg( "// Add node bary branch id", ttk::debug::Priority::VERBOSE); if(clusteringOutput and ShiftMode != 1) { + // Branch int tBranchID = -1; - auto nodeT + auto branchNode = (isPathDummyNode ? trees[i]->getNode(treeBranching[node])->getOrigin() : (trees[i]->isLeaf(node) ? node : nodeOrigin)); - if(treeMatching[nodeT] < allBaryBranchingID[c].size()) { - tBranchID = allBaryBranchingID[c][treeMatching[nodeT]]; - } + if(treeMatching[branchNode] < allBaryBranchingID[c].size()) + tBranchID = allBaryBranchingID[c][treeMatching[branchNode]]; branchBaryNodeID->InsertNextTuple1(tBranchID); + // Path + if(pathPlanarLayout_ and !pathMatchings.empty()) { + int tPathID = -1; + auto pathNode + = (isPathDummyNode + ? node + : (not isRootPath[node] ? node : pathOrigin[node])); + if(treeMatching[pathNode] < allBaryPathingID[c].size()) + tPathID = allBaryPathingID[c][treeMatching[pathNode]]; + pathBaryNodeID->InsertNextTuple1(tPathID); + } } - // Add node branch id + // Add node branch/path id if(not isPersistenceDiagram) { - auto nodeT + // Branch + auto branchNode = (isPathDummyNode ? trees[i]->getNode(treeBranching[node])->getOrigin() : (trees[i]->isLeaf(node) ? node : nodeOrigin)); - int tBranchID = treeBranchingID[nodeT]; + int tBranchID = treeBranchingID[branchNode]; branchNodeID->InsertNextTuple1(tBranchID); + // Path + if(pathPlanarLayout_ and !pathMatchings.empty()) { + auto pathNode + = (isPathDummyNode + ? node + : (not isRootPath[node] ? node : pathOrigin[node])); + // auto pathNode = node; + int tPathID = treePathingID[pathNode]; + pathNodeID->InsertNextTuple1(tPathID); + } } // Add node persistence @@ -1683,11 +1835,15 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { vtkOutputNode->GetPointData()->AddArray(nodeID); vtkOutputNode->GetPointData()->AddArray(branchNodeID); vtkOutputNode->GetPointData()->AddArray(isDummyNode); + if(pathPlanarLayout_ and !pathMatchings.empty()) + vtkOutputNode->GetPointData()->AddArray(pathNodeID); } if(not branchDecompositionPlanarLayout_ and not isPersistenceDiagram) vtkOutputNode->GetPointData()->AddArray(scalar); if(clusteringOutput and ShiftMode != 1) { vtkOutputNode->GetPointData()->AddArray(branchBaryNodeID); + if(pathPlanarLayout_ and !pathMatchings.empty()) + vtkOutputNode->GetPointData()->AddArray(pathBaryNodeID); vtkOutputNode->GetPointData()->AddArray(persistenceBaryNode); vtkOutputNode->GetPointData()->AddArray(persistenceBaryOrderNode); } @@ -1721,11 +1877,15 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { if(not isPersistenceDiagram) { vtkArcs->GetCellData()->AddArray(isDummyArc); vtkArcs->GetCellData()->AddArray(branchID); + if(pathPlanarLayout_ and !pathMatchings.empty()) + vtkArcs->GetCellData()->AddArray(pathID); vtkArcs->GetCellData()->AddArray(upNodeId); vtkArcs->GetCellData()->AddArray(downNodeId); } if(clusteringOutput and ShiftMode != 1) { vtkArcs->GetCellData()->AddArray(branchBaryID); + if(pathPlanarLayout_ and !pathMatchings.empty()) + vtkArcs->GetCellData()->AddArray(pathBaryID); vtkArcs->GetCellData()->AddArray(persistenceBaryArc); vtkArcs->GetCellData()->AddArray(persistenceBaryOrderArc); } From 0ca7d80268dfd849dd1316b6cb70ed9d279b3807 Mon Sep 17 00:00:00 2001 From: MatPont Date: Wed, 8 Mar 2023 17:36:20 +0100 Subject: [PATCH 40/72] [MergeTreeVisu] fix path layout seg fault for Wasserstein distance --- .../ttkMergeTreeVisualization.h | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h index a6481f694d..eceb96c521 100644 --- a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h +++ b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h @@ -713,7 +713,8 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { if(not isPersistenceDiagram) barycenters[c]->getTreeBranching( allBaryBranching[c], allBaryBranchingID[c]); - if(pathPlanarLayout_ and !pathMatchings.empty()) + if(pathPlanarLayout_ and !pathMatchings.empty() + and !pathMatchings[c].empty()) getTreePathing(barycenters[c], pathMatchings[c], true, allBaryPathing[c], allBaryPathingID[c]); } @@ -972,7 +973,8 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { std::vector pathOrigin; if(not isPersistenceDiagram) { trees[i]->getTreeBranching(treeBranching, treeBranchingID); - if(pathPlanarLayout_ and !pathMatchings.empty()) { + if(pathPlanarLayout_ and !pathMatchings.empty() + and !pathMatchings[c].empty()) { isRootPath.resize(trees[i]->getNumberOfNodes()); std::fill(isRootPath.begin(), isRootPath.end(), false); pathOrigin.resize(trees[i]->getNumberOfNodes()); @@ -1436,7 +1438,8 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { tBranchID = allBaryBranchingID[c][treeMatching[nodeToGet]]; branchBaryID->InsertNextTuple1(tBranchID); // Path - if(pathPlanarLayout_ and !pathMatchings.empty()) { + if(pathPlanarLayout_ and !pathMatchings.empty() + and !pathMatchings[c].empty()) { int tPathID = -1; nodeToGet = node; if(treeMatching[nodeToGet] < allBaryPathingID[c].size()) @@ -1451,7 +1454,8 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { int tBranchID = treeBranchingID[node]; branchID->InsertNextTuple1(tBranchID); // Path - if(pathPlanarLayout_ and !pathMatchings.empty()) { + if(pathPlanarLayout_ and !pathMatchings.empty() + and !pathMatchings[c].empty()) { int tPathID = treePathingID[node]; pathID->InsertNextTuple1(tPathID); } @@ -1622,7 +1626,8 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { tBranchID = allBaryBranchingID[c][treeMatching[branchNode]]; branchBaryNodeID->InsertNextTuple1(tBranchID); // Path - if(pathPlanarLayout_ and !pathMatchings.empty()) { + if(pathPlanarLayout_ and !pathMatchings.empty() + and !pathMatchings[c].empty()) { int tPathID = -1; auto pathNode = (isPathDummyNode @@ -1644,7 +1649,8 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { int tBranchID = treeBranchingID[branchNode]; branchNodeID->InsertNextTuple1(tBranchID); // Path - if(pathPlanarLayout_ and !pathMatchings.empty()) { + if(pathPlanarLayout_ and !pathMatchings.empty() + and !pathMatchings[c].empty()) { auto pathNode = (isPathDummyNode ? node @@ -1835,14 +1841,16 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { vtkOutputNode->GetPointData()->AddArray(nodeID); vtkOutputNode->GetPointData()->AddArray(branchNodeID); vtkOutputNode->GetPointData()->AddArray(isDummyNode); - if(pathPlanarLayout_ and !pathMatchings.empty()) + if(pathPlanarLayout_ and !pathMatchings.empty() + and !pathMatchings[0].empty()) vtkOutputNode->GetPointData()->AddArray(pathNodeID); } if(not branchDecompositionPlanarLayout_ and not isPersistenceDiagram) vtkOutputNode->GetPointData()->AddArray(scalar); if(clusteringOutput and ShiftMode != 1) { vtkOutputNode->GetPointData()->AddArray(branchBaryNodeID); - if(pathPlanarLayout_ and !pathMatchings.empty()) + if(pathPlanarLayout_ and !pathMatchings.empty() + and !pathMatchings[0].empty()) vtkOutputNode->GetPointData()->AddArray(pathBaryNodeID); vtkOutputNode->GetPointData()->AddArray(persistenceBaryNode); vtkOutputNode->GetPointData()->AddArray(persistenceBaryOrderNode); @@ -1877,14 +1885,16 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { if(not isPersistenceDiagram) { vtkArcs->GetCellData()->AddArray(isDummyArc); vtkArcs->GetCellData()->AddArray(branchID); - if(pathPlanarLayout_ and !pathMatchings.empty()) + if(pathPlanarLayout_ and !pathMatchings.empty() + and !pathMatchings[0].empty()) vtkArcs->GetCellData()->AddArray(pathID); vtkArcs->GetCellData()->AddArray(upNodeId); vtkArcs->GetCellData()->AddArray(downNodeId); } if(clusteringOutput and ShiftMode != 1) { vtkArcs->GetCellData()->AddArray(branchBaryID); - if(pathPlanarLayout_ and !pathMatchings.empty()) + if(pathPlanarLayout_ and !pathMatchings.empty() + and !pathMatchings[0].empty()) vtkArcs->GetCellData()->AddArray(pathBaryID); vtkArcs->GetCellData()->AddArray(persistenceBaryArc); vtkArcs->GetCellData()->AddArray(persistenceBaryOrderArc); From aedc5cf2d1a6ab8fad457e0c4b3c326363f0274e Mon Sep 17 00:00:00 2001 From: MatPont Date: Wed, 8 Mar 2023 22:07:00 +0100 Subject: [PATCH 41/72] [MergeTreeVisu] disable barycenter alignment for Wasserstein distance --- .../vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp | 2 ++ core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h | 1 + core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h | 8 +++++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index 0f196a8419..620fc79689 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -827,6 +827,7 @@ int ttkMergeTreeClustering::runOutput( visuMaker.setIsPersistenceDiagram(IsPersistenceDiagram); visuMaker.setIsPDSadMax(JoinSplitMixtureCoefficient == 0); visuMaker.setPathPlanarLayout(PathPlanarLayout); + visuMaker.setEnableBarycenterAlignment(baseModule == 2); // visuMaker.setPathPlanarLayout(baseModule == 2); visuMaker.makeTreesOutput( @@ -947,6 +948,7 @@ int ttkMergeTreeClustering::runOutput( visuMakerBary.setIsPersistenceDiagram(IsPersistenceDiagram); visuMakerBary.setIsPDSadMax(JoinSplitMixtureCoefficient == 0); visuMakerBary.setPathPlanarLayout(PathPlanarLayout); + visuMakerBary.setEnableBarycenterAlignment(baseModule == 2); // visuMakerBary.setPathPlanarLayout(baseModule == 2); visuMakerBary.makeTreesOutput( diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h index dd8451f093..66ad7159fa 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h @@ -174,6 +174,7 @@ class TTKMERGETREECLUSTERING_EXPORT ttkMergeTreeClustering std::vector< std::vector>>( numInputs2)); + outputMatchings_path.clear(); outputMatchings_path.resize(NumberOfBarycenters); // Barycenter diff --git a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h index eceb96c521..7c9912610f 100644 --- a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h +++ b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h @@ -44,6 +44,7 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { bool outputTreeNodeIndex = false; bool isPersistenceDiagram = false; bool isPDSadMax = true; + bool enableBarycenterAlignment = false; // Shift mode // -1: None ; 0: Star ; 1: Star Barycenter ; 2: Line ; 3: Double Line @@ -165,6 +166,10 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { isPDSadMax = isSadMax; } + void setEnableBarycenterAlignment(bool eba) { + enableBarycenterAlignment = eba; + } + // Offset void setISampleOffset(int offset) { iSampleOffset = offset; @@ -662,7 +667,8 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { NumberOfBarycenters = std::max(NumberOfBarycenters, 1); // to always enter the outer loop PlanarLayout |= isPersistenceDiagram; - bool alignTrees = trees.size() == 2 and barycenters.size() == 1; + bool alignTrees = trees.size() == 2 and barycenters.size() == 1 + and enableBarycenterAlignment; // TreeNodeIdRev for(int i = 0; i < numInputs; ++i) { From 51e4d6ad8e82abbd5888e6d6c19f5d10b9227c1d Mon Sep 17 00:00:00 2001 From: MatPont Date: Mon, 13 Mar 2023 12:21:12 +0100 Subject: [PATCH 42/72] [MergeTreeVisu] true node ids in matching --- core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h index 7c9912610f..734ba7997e 100644 --- a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h +++ b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h @@ -517,6 +517,10 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { tree1NodeIdField->SetName("tree1NodeId"); vtkNew tree2NodeIdField{}; tree2NodeIdField->SetName("tree2NodeId"); + vtkNew mergeTree1NodeIdField{}; + mergeTree1NodeIdField->SetName("mergeTree1NodeId"); + vtkNew mergeTree2NodeIdField{}; + mergeTree2NodeIdField->SetName("mergeTree2NodeId"); vtkNew matchingPercentMatch{}; matchingPercentMatch->SetName("MatchingPercentMatch"); @@ -578,6 +582,8 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { "// Add tree1 and tree2 node ids", ttk::debug::Priority::VERBOSE); tree1NodeIdField->InsertNextTuple1(pointToGet1); tree2NodeIdField->InsertNextTuple1(pointToGet2); + mergeTree1NodeIdField->InsertNextTuple1(tree1NodeId); + mergeTree2NodeIdField->InsertNextTuple1(tree2NodeId); // Add matching ID matchingID->InsertNextTuple1(count); @@ -626,6 +632,8 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { vtkMatching->GetCellData()->AddArray(costArray); vtkMatching->GetCellData()->AddArray(tree1NodeIdField); vtkMatching->GetCellData()->AddArray(tree2NodeIdField); + vtkMatching->GetCellData()->AddArray(mergeTree1NodeIdField); + vtkMatching->GetCellData()->AddArray(mergeTree2NodeIdField); if(allBaryPercentMatch.size() != 0) vtkMatching->GetCellData()->AddArray(matchingPercentMatch); vtkOutputMatching->ShallowCopy(vtkMatching); From d60777bc335cffe81b9fcb93023471553c1c919f Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Fri, 31 Mar 2023 11:05:23 +0200 Subject: [PATCH 43/72] lots of changes on merge tree barycenter (mostly outputs for testing) --- .../mergeTreeClustering/MergeTreeBarycenter.h | 25 +++++++++++++++---- core/base/mergeTreeClustering/MergeTreeBase.h | 2 +- .../MergeTreeTemporalReductionEncoding.h | 2 +- .../ttkMergeTreeVisualization.h | 6 +++++ 4 files changed, 28 insertions(+), 7 deletions(-) diff --git a/core/base/mergeTreeClustering/MergeTreeBarycenter.h b/core/base/mergeTreeClustering/MergeTreeBarycenter.h index f0b6442139..fe5efa3a1f 100644 --- a/core/base/mergeTreeClustering/MergeTreeBarycenter.h +++ b/core/base/mergeTreeClustering/MergeTreeBarycenter.h @@ -57,7 +57,7 @@ namespace ttk { int baseModule_ = 0; bool useMedianBarycenter_ = false; bool useFixedInit_ = false; - bool useEarlyOut_ = false; + bool useEarlyOut_ = true; int fixedInitNumber_ = 0; //int iterationLimit_ = 0; @@ -315,7 +315,7 @@ namespace ttk { bool distMinimizer = true) { int bestIndex; if(useFixedInit_){ - if(fixedInitNumber_ >= 0 && fixedInitNumber_ < trees.size()) bestIndex = fixedInitNumber_; + if(fixedInitNumber_ >= 0 && fixedInitNumber_ < (int) trees.size()) bestIndex = fixedInitNumber_; else bestIndex = 0; } else bestIndex = getBestInitTreeIndex(trees, distMinimizer); @@ -1389,6 +1389,8 @@ namespace ttk { int cptBlocked = 0; int NoIteration = 0; std::stringstream energySequence; + int minBarySize = std::numeric_limits::max(); + int maxBarySize = 0; while(not converged && NoIteration<100){// && NoIterationthreadNumber_, debug::LineMode::NEW, debug::Priority::INFO); - printBaryStats(baryTree); + printBaryStats(baryTree,debug::Priority::INFO); ss4 << "Frechet energy : " << frechetEnergy; ss5 << "Frechet energy non-squared: " << currentFrechetEnergy2; printMsg(ss4.str()); printMsg(ss5.str()); + if((int) baryTree->getNumberOfNodes() > maxBarySize) maxBarySize = baryTree->getNumberOfNodes(); + if((int)baryTree->getNumberOfNodes() < minBarySize) minBarySize = baryTree->getNumberOfNodes(); + minFrechet = std::min(minFrechet, frechetEnergy); if(not converged and (not progressiveBarycenter_ or treesUnscaled)) { cptBlocked = (minFrechet < frechetEnergy) ? cptBlocked + 1 : 0; @@ -1513,16 +1518,26 @@ namespace ttk { currentFrechetEnergy += alphas[i] * distances[i] * distances[i]; } + auto barycenterTime = t_bary.getElapsedTime() - addDeletedNodesTime_; std::stringstream ss, ss2; ss << "Frechet energy : " << currentFrechetEnergy; ss2 << "Frechet energy non-squared: " << currentFrechetEnergy2; printMsg(ss.str()); printMsg(ss2.str()); - auto barycenterTime = t_bary.getElapsedTime() - addDeletedNodesTime_; printMsg("Total", 1, barycenterTime, this->threadNumber_, - debug::LineMode::NEW, debug::Priority::INFO); + debug::LineMode::NEW, debug::Priority::PERFORMANCE); // std::cout << "Bary Distance Time = " << allDistanceTime_ << std::endl; + std::stringstream ssIt; + ssIt << "Number of iterations: " << NoIteration; + printMsg(ssIt.str(),debug::Priority::PERFORMANCE); + std::stringstream ssMin; + ssMin << "Min barycenter bize: " << minBarySize; + printMsg(ssMin.str(),debug::Priority::PERFORMANCE); + std::stringstream ssMax; + ssMax << "Max barycenter bize: " << maxBarySize; + printMsg(ssMax.str(),debug::Priority::PERFORMANCE); + if(trees.size() == 2 and not isCalled_ && baseModule_!=2) verifyBarycenterTwoTrees( trees, baryMergeTree, finalMatchings, distances); diff --git a/core/base/mergeTreeClustering/MergeTreeBase.h b/core/base/mergeTreeClustering/MergeTreeBase.h index bb313e0c3e..c87fbefaff 100644 --- a/core/base/mergeTreeClustering/MergeTreeBase.h +++ b/core/base/mergeTreeClustering/MergeTreeBase.h @@ -1318,7 +1318,7 @@ namespace ttk { std::stringstream ss; ss << trees.size() << " trees average [node: " << avgNodes << " / " << avgNodesT << ", depth: " << avgDepth << "]"; - printMsg(ss.str()); + printMsg(ss.str(),debug::Priority::PERFORMANCE); } template diff --git a/core/base/mergeTreeTemporalReductionEncoding/MergeTreeTemporalReductionEncoding.h b/core/base/mergeTreeTemporalReductionEncoding/MergeTreeTemporalReductionEncoding.h index dac749e3a2..b0f6e1b96e 100644 --- a/core/base/mergeTreeTemporalReductionEncoding/MergeTreeTemporalReductionEncoding.h +++ b/core/base/mergeTreeTemporalReductionEncoding/MergeTreeTemporalReductionEncoding.h @@ -215,7 +215,7 @@ namespace ttk { std::vector treeRemoved(mTrees.size(), false); int toRemoved = mTrees.size() * removalPercentage_ / 100.; - toRemoved = std::min(toRemoved, (int)(mTrees.size() - 3)); + toRemoved = std::min(toRemoved, (int)(mTrees.size() - 2)); std::vector> images(fieldL2_.size()); for(size_t i = 0; i < fieldL2_.size(); ++i) diff --git a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h index 734ba7997e..a9b1268488 100644 --- a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h +++ b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h @@ -521,6 +521,8 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { mergeTree1NodeIdField->SetName("mergeTree1NodeId"); vtkNew mergeTree2NodeIdField{}; mergeTree2NodeIdField->SetName("mergeTree2NodeId"); + vtkNew isBarycenterNodeField{}; + isBarycenterNodeField->SetName("isBarycenterNode"); vtkNew matchingPercentMatch{}; matchingPercentMatch->SetName("MatchingPercentMatch"); @@ -556,6 +558,8 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { : nodeCorr1[0][tree1NodeId]; double *point1 = vtkOutputNode2->GetPoints()->GetPoint(pointToGet1); const SimplexId nextPointId1 = pointsM->InsertNextPoint(point1); + if(not clusteringOutput) isBarycenterNodeField->InsertNextTuple1(0); + else isBarycenterNodeField->InsertNextTuple1(1); pointIds[0] = nextPointId1; // Get second point @@ -564,6 +568,7 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { : nodeCorr1[1][tree2NodeId]; double *point2 = vtkOutputNode1->GetPoints()->GetPoint(pointToGet2); const SimplexId nextPointId2 = pointsM->InsertNextPoint(point2); + isBarycenterNodeField->InsertNextTuple1(0); pointIds[1] = nextPointId2; // Add cell @@ -634,6 +639,7 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { vtkMatching->GetCellData()->AddArray(tree2NodeIdField); vtkMatching->GetCellData()->AddArray(mergeTree1NodeIdField); vtkMatching->GetCellData()->AddArray(mergeTree2NodeIdField); + vtkMatching->GetPointData()->AddArray(isBarycenterNodeField); if(allBaryPercentMatch.size() != 0) vtkMatching->GetCellData()->AddArray(matchingPercentMatch); vtkOutputMatching->ShallowCopy(vtkMatching); From f3fc3b02dae2921bff554d8031b8509df0ab5998 Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Thu, 29 Feb 2024 12:32:47 +0100 Subject: [PATCH 44/72] started work on preprecessing for path mappings --- .../mergeTreeClustering/MergeTreeBarycenter.h | 101 +++++++++++++----- .../mergeTreeClustering/MergeTreeClustering.h | 2 +- .../ttkMergeTreeClustering.cpp | 2 +- 3 files changed, 77 insertions(+), 28 deletions(-) diff --git a/core/base/mergeTreeClustering/MergeTreeBarycenter.h b/core/base/mergeTreeClustering/MergeTreeBarycenter.h index 404939146d..159fe182c5 100644 --- a/core/base/mergeTreeClustering/MergeTreeBarycenter.h +++ b/core/base/mergeTreeClustering/MergeTreeBarycenter.h @@ -1444,34 +1444,83 @@ namespace ttk { treesNodeCorr_.resize(trees.size()); for(unsigned int i = 0; i < trees.size(); ++i){ if(baseModule_==2){ + branchDecomposition_ = false; ftm::FTMTree_MT *tree = &(trees[i].tree); - preprocessTree(tree, true); - - // - Delete null persistence pairs and persistence thresholding - persistenceThresholding(tree, persistenceThreshold_); - - // - Merge saddle points according epsilon - if(not isPersistenceDiagram_) { - if(epsilonTree2_ != 0){ - std::vector> treeNodeMerged( tree->getNumberOfNodes() ); - mergeSaddle(tree, epsilonTree2_, treeNodeMerged); - for(unsigned int j=0; jgetNode(j)->getOrigin(); - tree->getNode(k)->setOrigin(j); - tree->getNode(nodeToDelete)->setOrigin(-1); - } - } - ftm::cleanMergeTree(trees[i], treesNodeCorr_[i], true); - } - else{ - std::vector nodeCorr(tree->getNumberOfNodes()); - for(unsigned int j=0; j scalars(tree->getNumberOfNodes()); + std::vector> children(tree->getNumberOfNodes()); + std::vector origins(tree->getNumberOfNodes()); + std::vector parents(tree->getNumberOfNodes()); + std::vector parentsSafe(tree->getNumberOfNodes()); + for(ftm::idNode ni=0; nigetNumberOfNodes(); ni++){ + scalars[ni] = tree->getValue(ni); + origins[ni] = tree->getNode(ni)->getOrigin(); + parents[ni] = tree->getParent(ni); + parentsSafe[ni] = tree->getParentSafe(ni); + tree->getChildren(ni, children[ni]); + } + preprocessingPipeline(trees[i], epsilonTree2_, + epsilon2Tree2_, epsilon3Tree2_, + branchDecomposition_, useMinMaxPair_, + cleanTree_, treesNodeCorr_[i]); + std::vector scalars2(tree->getNumberOfNodes()); + std::vector> children2(tree->getNumberOfNodes()); + std::vector origins2(tree->getNumberOfNodes()); + std::vector parents2(tree->getNumberOfNodes()); + std::vector parentsSafe2(tree->getNumberOfNodes()); + for(ftm::idNode ni=0; nigetNumberOfNodes(); ni++){ + scalars2[ni] = tree->getValue(ni); + origins2[ni] = tree->getNode(ni)->getOrigin(); + parents2[ni] = tree->getParent(ni); + parentsSafe2[ni] = tree->getParentSafe(ni); + tree->getChildren(ni, children2[ni]); } - if(deleteMultiPersPairs_) - deleteMultiPersPairs(tree, false); + std::cout << "" << std::endl; + // ftm::FTMTree_MT *tree = &(trees[i].tree); + // preprocessTree(tree, true); + + // // - Delete null persistence pairs and persistence thresholding + // persistenceThresholding(tree, persistenceThreshold_); + + // // - Merge saddle points according epsilon + // if(not isPersistenceDiagram_) { + // if(epsilonTree2_ != 0){ + // std::vector> treeNodeMerged( tree->getNumberOfNodes() ); + // std::vector scalars(tree->getNumberOfNodes()); + // std::vector> children(tree->getNumberOfNodes()); + // std::vector origins(tree->getNumberOfNodes()); + // for(ftm::idNode ni=0; nigetNumberOfNodes(); ni++){ + // scalars[ni] = tree->getValue(ni); + // origins[ni] = tree->getNode(ni)->getOrigin(); + // tree->getChildren(ni, children[ni]); + // } + // mergeSaddle(tree, epsilonTree2_, treeNodeMerged); + // std::vector scalars2(tree->getNumberOfNodes()); + // std::vector> children2(tree->getNumberOfNodes()); + // std::vector origins2(tree->getNumberOfNodes()); + // for(ftm::idNode ni=0; nigetNumberOfNodes(); ni++){ + // scalars2[ni] = tree->getValue(ni); + // origins2[ni] = tree->getNode(ni)->getOrigin(); + // tree->getChildren(ni, children2[ni]); + // } + // for(unsigned int j=0; jgetNode(j)->getOrigin(); + // auto nodeToDelete = tree->getNode(k)->getOrigin(); + // tree->getNode(k)->setOrigin(j); + // tree->getNode(nodeToDelete)->setOrigin(-1); + // } + // } + // ftm::cleanMergeTree(trees[i], treesNodeCorr_[i], true); + // // ftm::cleanMergeTree(trees[i], treesNodeCorr_[i], false); + // } + // else{ + // std::vector nodeCorr(tree->getNumberOfNodes()); + // for(unsigned int j=0; j(tree, false); } else{ preprocessingPipeline(trees[i], epsilonTree2_, diff --git a/core/base/mergeTreeClustering/MergeTreeClustering.h b/core/base/mergeTreeClustering/MergeTreeClustering.h index 543b4692b9..ba1d0091ee 100644 --- a/core/base/mergeTreeClustering/MergeTreeClustering.h +++ b/core/base/mergeTreeClustering/MergeTreeClustering.h @@ -652,7 +652,7 @@ namespace ttk { mergeTreeBary.setBranchDecomposition(false); mergeTreeBary.setNormalizedWasserstein(false); mergeTreeBary.setKeepSubtree(false); - mergeTreeBary.setUseMinMaxPair(false); + // mergeTreeBary.setUseMinMaxPair(true); mergeTreeBary.setAddNodes(false); mergeTreeBary.setPostprocess(false); } diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index e0ddff0956..402a6d7a61 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -366,7 +366,7 @@ int ttkMergeTreeClustering::runCompute( mergeTreeBarycenter.setBranchDecomposition(false); mergeTreeBarycenter.setNormalizedWasserstein(false); mergeTreeBarycenter.setKeepSubtree(false); - mergeTreeBarycenter.setUseMinMaxPair(false); + // mergeTreeBarycenter.setUseMinMaxPair(false); mergeTreeBarycenter.setAddNodes(false); mergeTreeBarycenter.setPostprocess(false); mergeTreeBarycenter.setUseMedianBarycenter(useMedianBarycenter); From e0c4ad8b64e8539399d241669121bfb8820f8b16 Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Fri, 1 Mar 2024 10:53:00 +0100 Subject: [PATCH 45/72] preprocessing working for path mapping distance in clustering module --- .../mergeTreeClustering/MergeTreeBarycenter.h | 89 +------------------ core/base/mergeTreeClustering/MergeTreeBase.h | 20 ++++- 2 files changed, 20 insertions(+), 89 deletions(-) diff --git a/core/base/mergeTreeClustering/MergeTreeBarycenter.h b/core/base/mergeTreeClustering/MergeTreeBarycenter.h index 159fe182c5..04351b4725 100644 --- a/core/base/mergeTreeClustering/MergeTreeBarycenter.h +++ b/core/base/mergeTreeClustering/MergeTreeBarycenter.h @@ -1443,91 +1443,10 @@ namespace ttk { if(preprocess_) { treesNodeCorr_.resize(trees.size()); for(unsigned int i = 0; i < trees.size(); ++i){ - if(baseModule_==2){ - branchDecomposition_ = false; - ftm::FTMTree_MT *tree = &(trees[i].tree); - std::vector scalars(tree->getNumberOfNodes()); - std::vector> children(tree->getNumberOfNodes()); - std::vector origins(tree->getNumberOfNodes()); - std::vector parents(tree->getNumberOfNodes()); - std::vector parentsSafe(tree->getNumberOfNodes()); - for(ftm::idNode ni=0; nigetNumberOfNodes(); ni++){ - scalars[ni] = tree->getValue(ni); - origins[ni] = tree->getNode(ni)->getOrigin(); - parents[ni] = tree->getParent(ni); - parentsSafe[ni] = tree->getParentSafe(ni); - tree->getChildren(ni, children[ni]); - } - preprocessingPipeline(trees[i], epsilonTree2_, - epsilon2Tree2_, epsilon3Tree2_, - branchDecomposition_, useMinMaxPair_, - cleanTree_, treesNodeCorr_[i]); - std::vector scalars2(tree->getNumberOfNodes()); - std::vector> children2(tree->getNumberOfNodes()); - std::vector origins2(tree->getNumberOfNodes()); - std::vector parents2(tree->getNumberOfNodes()); - std::vector parentsSafe2(tree->getNumberOfNodes()); - for(ftm::idNode ni=0; nigetNumberOfNodes(); ni++){ - scalars2[ni] = tree->getValue(ni); - origins2[ni] = tree->getNode(ni)->getOrigin(); - parents2[ni] = tree->getParent(ni); - parentsSafe2[ni] = tree->getParentSafe(ni); - tree->getChildren(ni, children2[ni]); - } - std::cout << "" << std::endl; - // ftm::FTMTree_MT *tree = &(trees[i].tree); - // preprocessTree(tree, true); - - // // - Delete null persistence pairs and persistence thresholding - // persistenceThresholding(tree, persistenceThreshold_); - - // // - Merge saddle points according epsilon - // if(not isPersistenceDiagram_) { - // if(epsilonTree2_ != 0){ - // std::vector> treeNodeMerged( tree->getNumberOfNodes() ); - // std::vector scalars(tree->getNumberOfNodes()); - // std::vector> children(tree->getNumberOfNodes()); - // std::vector origins(tree->getNumberOfNodes()); - // for(ftm::idNode ni=0; nigetNumberOfNodes(); ni++){ - // scalars[ni] = tree->getValue(ni); - // origins[ni] = tree->getNode(ni)->getOrigin(); - // tree->getChildren(ni, children[ni]); - // } - // mergeSaddle(tree, epsilonTree2_, treeNodeMerged); - // std::vector scalars2(tree->getNumberOfNodes()); - // std::vector> children2(tree->getNumberOfNodes()); - // std::vector origins2(tree->getNumberOfNodes()); - // for(ftm::idNode ni=0; nigetNumberOfNodes(); ni++){ - // scalars2[ni] = tree->getValue(ni); - // origins2[ni] = tree->getNode(ni)->getOrigin(); - // tree->getChildren(ni, children2[ni]); - // } - // for(unsigned int j=0; jgetNode(j)->getOrigin(); - // auto nodeToDelete = tree->getNode(k)->getOrigin(); - // tree->getNode(k)->setOrigin(j); - // tree->getNode(nodeToDelete)->setOrigin(-1); - // } - // } - // ftm::cleanMergeTree(trees[i], treesNodeCorr_[i], true); - // // ftm::cleanMergeTree(trees[i], treesNodeCorr_[i], false); - // } - // else{ - // std::vector nodeCorr(tree->getNumberOfNodes()); - // for(unsigned int j=0; j(tree, false); - } - else{ - preprocessingPipeline(trees[i], epsilonTree2_, - epsilon2Tree2_, epsilon3Tree2_, - branchDecomposition_, useMinMaxPair_, - cleanTree_, treesNodeCorr_[i]); - } + preprocessingPipeline(trees[i], epsilonTree2_, + epsilon2Tree2_, epsilon3Tree2_, + branchDecomposition_, useMinMaxPair_, + cleanTree_, treesNodeCorr_[i], true, baseModule_==2); } printTreesStats(trees); } diff --git a/core/base/mergeTreeClustering/MergeTreeBase.h b/core/base/mergeTreeClustering/MergeTreeBase.h index 80243f3dbc..abadbe704d 100644 --- a/core/base/mergeTreeClustering/MergeTreeBase.h +++ b/core/base/mergeTreeClustering/MergeTreeBase.h @@ -636,7 +636,8 @@ namespace ttk { bool cleanTreeT, double persistenceThreshold, std::vector &nodeCorr, - bool deleteInconsistentNodes = true) { + bool deleteInconsistentNodes = true, + bool removeMergedSaddles = false) { Timer t_proc; ftm::FTMTree_MT *tree = &(mTree.tree); @@ -650,8 +651,18 @@ namespace ttk { std::vector> treeNodeMerged( tree->getNumberOfNodes()); if(not isPersistenceDiagram_ or convertToDiagram_) { - if(epsilonTree != 0) + if(epsilonTree != 0){ mergeSaddle(tree, epsilonTree, treeNodeMerged); + if(removeMergedSaddles){ + for(unsigned int j=0; jgetNode(k)->getOrigin(); + tree->getNode(k)->setOrigin(j); + tree->getNode(nodeToDelete)->setOrigin(-1); + } + } + } + } } // - Compute branch decomposition @@ -701,11 +712,12 @@ namespace ttk { bool useMinMaxPairT, bool cleanTreeT, std::vector &nodeCorr, - bool deleteInconsistentNodes = true) { + bool deleteInconsistentNodes = true, + bool removeMergedSaddles = false) { preprocessingPipeline( mTree, epsilonTree, epsilon2Tree, epsilon3Tree, branchDecompositionT, useMinMaxPairT, cleanTreeT, persistenceThreshold_, nodeCorr, - deleteInconsistentNodes); + deleteInconsistentNodes, removeMergedSaddles); } void reverseNodeCorr(ftm::FTMTree_MT *tree, std::vector &nodeCorr) { From 177451bcf472827fe6aecee98307dd6eda3701f1 Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Fri, 1 Mar 2024 13:46:20 +0100 Subject: [PATCH 46/72] started work on path mapping preprocessing for remaing modules --- .../BranchMappingDistance.h | 56 ++++--- .../mergeTreeClustering/MergeTreeClustering.h | 38 +---- .../mergeTreeClustering/PathMappingDistance.h | 139 +++++++++++------- .../MergeTreeDistanceMatrix.h | 4 +- .../MergeTreeTemporalReduction.h | 72 ++++----- .../MergeTreeTemporalReductionDecoding.h | 87 ++++++----- .../ttkMergeTreeClustering.cpp | 5 +- 7 files changed, 207 insertions(+), 194 deletions(-) diff --git a/core/base/mergeTreeClustering/BranchMappingDistance.h b/core/base/mergeTreeClustering/BranchMappingDistance.h index 0c5b43548c..1831404191 100644 --- a/core/base/mergeTreeClustering/BranchMappingDistance.h +++ b/core/base/mergeTreeClustering/BranchMappingDistance.h @@ -211,35 +211,45 @@ namespace ttk { } template - dataType editDistance_branch(ftm::FTMTree_MT *tree1, - ftm::FTMTree_MT *tree2, + dataType editDistance_branch(ftm::MergeTree &mTree1, + ftm::MergeTree &mTree2, std::vector> *outputMatching=nullptr) { // optional preprocessing - if(preprocess_ && !writeOptimalBranchDecomposition_){ - preprocessTree(tree1, true); - preprocessTree(tree2, true); + treesNodeCorr_.resize(2); + preprocessingPipeline( + mTree1, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, + branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[0],true,true); + preprocessingPipeline( + mTree2, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, + branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[1],true,true); + } - // - Delete null persistence pairs and persistence thresholding - persistenceThresholding(tree1, persistenceThreshold_); - persistenceThresholding(tree2, persistenceThreshold_); + ftm::FTMTree_MT *tree1 = (&mTree1.tree); + ftm::FTMTree_MT *tree2 = (&mTree2.tree); - // - Merge saddle points according epsilon - std::vector> treeNodeMerged1( tree1->getNumberOfNodes() ); - std::vector> treeNodeMerged2( tree2->getNumberOfNodes() ); - if(not isPersistenceDiagram_) { - if(epsilonTree1_ != 0) - mergeSaddle(tree1, epsilonTree1_, treeNodeMerged1); - if(epsilonTree2_ != 0) - mergeSaddle(tree2, epsilonTree2_, treeNodeMerged2); - } - - if(deleteMultiPersPairs_) - deleteMultiPersPairs(tree1, false); - if(deleteMultiPersPairs_) - deleteMultiPersPairs(tree2, false); - } + return editDistance_branch(tree1,tree2, outputMatching); + } + + template + dataType editDistance_branch(ftm::FTMTree_MT *tree1, + ftm::FTMTree_MT *tree2, + std::vector> *outputMatching=nullptr) { + + // // optional preprocessing + // if(preprocess_ && !writeOptimalBranchDecomposition_){ + // treesNodeCorr_.resize(2); + // preprocessingPipeline( + // mTree1, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, + // branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[0],true,true); + // preprocessingPipeline( + // mTree2, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, + // branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[1],true,true); + // } + + // ftm::FTMTree_MT *tree1 = (&mTree1.tree); + // ftm::FTMTree_MT *tree2 = (&mTree2.tree); // compute preorder of both trees (necessary for bottom-up dynamic programming) diff --git a/core/base/mergeTreeClustering/MergeTreeClustering.h b/core/base/mergeTreeClustering/MergeTreeClustering.h index ba1d0091ee..ab598f395a 100644 --- a/core/base/mergeTreeClustering/MergeTreeClustering.h +++ b/core/base/mergeTreeClustering/MergeTreeClustering.h @@ -893,41 +893,9 @@ namespace ttk { std::vector> &nodeCorr, bool useMinMaxPairT = true) { for(unsigned int i = 0; i < trees.size(); ++i) { - if(baseModule_==2){ - ftm::FTMTree_MT *tree = &(trees[i].tree); - preprocessTree(tree, true); - - // - Delete null persistence pairs and persistence thresholding - persistenceThresholding(tree, persistenceThreshold_); - - // - Merge saddle points according epsilon - if(not isPersistenceDiagram_) { - if(epsilonTree2_ != 0){ - std::vector> treeNodeMerged( tree->getNumberOfNodes() ); - mergeSaddle(tree, epsilonTree2_, treeNodeMerged); - for(unsigned int j=0; jgetNode(j)->getOrigin(); - tree->getNode(k)->setOrigin(j); - tree->getNode(nodeToDelete)->setOrigin(-1); - } - } - ftm::cleanMergeTree(trees[i], nodeCorr[i], true); - } - else{ - std::vector nodeCorri(tree->getNumberOfNodes()); - for(unsigned int j=0; j(tree, false); - } - else{ - preprocessingPipeline( - trees[i], epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, - branchDecomposition_, useMinMaxPairT, cleanTree_, nodeCorr[i]); - } + preprocessingPipeline( + trees[i], epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, + branchDecomposition_, useMinMaxPairT, cleanTree_, nodeCorr[i],true,baseModule_==2); if(trees.size() < 40) printTreeStats(trees[i]); } diff --git a/core/base/mergeTreeClustering/PathMappingDistance.h b/core/base/mergeTreeClustering/PathMappingDistance.h index 28ea2f9a6a..59305f3f81 100644 --- a/core/base/mergeTreeClustering/PathMappingDistance.h +++ b/core/base/mergeTreeClustering/PathMappingDistance.h @@ -340,62 +340,23 @@ namespace ttk { } template - dataType editDistance_path(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2, std::vector,std::pair>> *outputMatching) { - - // optional preprocessing - - if(preprocess_){ - preprocessTree(tree1, true); - preprocessTree(tree2, true); - - // - Delete null persistence pairs and persistence thresholding - persistenceThresholding(tree1, persistenceThreshold_); - persistenceThresholding(tree2, persistenceThreshold_); - - // - Merge saddle points according epsilon - if(not isPersistenceDiagram_) { - treesNodeCorr_.resize(2); - if(epsilonTree1_ != 0){ - std::vector> treeNodeMerged1( tree1->getNumberOfNodes() ); - mergeSaddle(tree1, epsilonTree1_, treeNodeMerged1); - for(unsigned int i=0; igetNode(j)->getOrigin(); - tree1->getNode(j)->setOrigin(i); - tree1->getNode(nodeToDelete)->setOrigin(-1); - } - } - ftm::cleanMergeTree(tree1, treesNodeCorr_[0], true); - } - else{ - std::vector nodeCorr1(tree1->getNumberOfNodes()); - for(unsigned int i=0; i> treeNodeMerged2( tree2->getNumberOfNodes() ); - mergeSaddle(tree2, epsilonTree2_, treeNodeMerged2); - for(unsigned int i=0; igetNode(j)->getOrigin(); - tree2->getNode(j)->setOrigin(i); - tree2->getNode(nodeToDelete)->setOrigin(-1); - } - } - ftm::cleanMergeTree(tree2, treesNodeCorr_[1], true); - } - else{ - std::vector nodeCorr2(tree2->getNumberOfNodes()); - for(unsigned int i=0; i(tree1, false); - if(deleteMultiPersPairs_) - deleteMultiPersPairs(tree2, false); - } + dataType editDistance_path(ftm::FTMTree_MT *tree1, + ftm::FTMTree_MT *tree2, + std::vector,std::pair>> *outputMatching) { + + // // optional preprocessing + // if(preprocess_) { + // treesNodeCorr_.resize(2); + // preprocessingPipeline( + // mTree1, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, + // branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[0],true,true); + // preprocessingPipeline( + // mTree2, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, + // branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[1],true,true); + // } + + // ftm::FTMTree_MT *tree1 = (&mTree1.tree); + // ftm::FTMTree_MT *tree2 = (&mTree2.tree); // compute preorder of both trees (necessary for bottom-up dynamic programming) @@ -739,6 +700,28 @@ namespace ttk { return squared_ ? std::sqrt(res) : res; } + template + dataType editDistance_path(ftm::MergeTree &mTree1, + ftm::MergeTree &mTree2, + std::vector,std::pair>> *outputMatching) { + + // optional preprocessing + if(preprocess_) { + treesNodeCorr_.resize(2); + preprocessingPipeline( + mTree1, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, + branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[0],true,true); + preprocessingPipeline( + mTree2, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, + branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[1],true,true); + } + + ftm::FTMTree_MT *tree1 = (&mTree1.tree); + ftm::FTMTree_MT *tree2 = (&mTree2.tree); + + return editDistance_path(tree1,tree2,outputMatching); + } + template dataType editDistance_path(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2, std::vector> *outputMatching){ @@ -760,9 +743,53 @@ namespace ttk { } + template + dataType editDistance_path(ftm::MergeTree &mTree1, + ftm::MergeTree &mTree2, + std::vector> *outputMatching){ + + // optional preprocessing + if(preprocess_) { + treesNodeCorr_.resize(2); + preprocessingPipeline( + mTree1, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, + branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[0],true,true); + preprocessingPipeline( + mTree2, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, + branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[1],true,true); + } + + ftm::FTMTree_MT *tree1 = (&mTree1.tree); + ftm::FTMTree_MT *tree2 = (&mTree2.tree); + + return editDistance_path(tree1,tree2,outputMatching); + + } + template dataType editDistance_path(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2){ return editDistance_path(tree1,tree2,(std::vector,std::pair>>*) nullptr); } + + template + dataType editDistance_path(ftm::MergeTree &mTree1, + ftm::MergeTree &mTree2){ + + // optional preprocessing + if(preprocess_) { + treesNodeCorr_.resize(2); + preprocessingPipeline( + mTree1, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, + branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[0],true,true); + preprocessingPipeline( + mTree2, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, + branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[1],true,true); + } + + ftm::FTMTree_MT *tree1 = (&mTree1.tree); + ftm::FTMTree_MT *tree2 = (&mTree2.tree); + + return editDistance_path(tree1,tree2,(std::vector,std::pair>>*) nullptr); + } }; } // namespace ttk diff --git a/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h b/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h index 6f2b762515..9ffd6ca5a7 100644 --- a/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h +++ b/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h @@ -105,11 +105,11 @@ namespace ttk { distanceMatrix[i][j] = 0; } else if(baseModule_ == 1) { dataType dist = branchDist.editDistance_branch( - &(ftmtrees[i].tree), &(ftmtrees[j].tree)); + ftmtrees[i], ftmtrees[j]); distanceMatrix[i][j] = static_cast(dist); } else if(baseModule_ == 2) { dataType dist = pathDist.editDistance_path( - &(ftmtrees[i].tree), &(ftmtrees[j].tree)); + ftmtrees[i], ftmtrees[j]); distanceMatrix[i][j] = static_cast(dist); } // distance matrix is symmetric diff --git a/core/base/mergeTreeTemporalReduction/MergeTreeTemporalReduction.h b/core/base/mergeTreeTemporalReduction/MergeTreeTemporalReduction.h index bbdb6f8139..518d663f55 100644 --- a/core/base/mergeTreeTemporalReduction/MergeTreeTemporalReduction.h +++ b/core/base/mergeTreeTemporalReduction/MergeTreeTemporalReduction.h @@ -351,50 +351,50 @@ namespace ttk { Timer t_tempSub; // --- Preprocessing - if(not useL2Distance_ && not usePathMappings_) { + if(not useL2Distance_){//} && not usePathMappings_) { treesNodeCorr_ = std::vector>(mTrees.size()); for(unsigned int i = 0; i < mTrees.size(); ++i) { preprocessingPipeline(mTrees[i], epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, branchDecomposition_, useMinMaxPair_, - cleanTree_, treesNodeCorr_[i]); + cleanTree_, treesNodeCorr_[i],true,usePathMappings_); } printTreesStats(mTrees); } - if(usePathMappings_){ - treesNodeCorr_ = std::vector>(mTrees.size()); - printMsg("uses path mapping distance"); - for(unsigned int i = 0; i < mTrees.size(); ++i) { - ftm::FTMTree_MT *tree = &(mTrees[i].tree); - preprocessTree(tree, true); - - // - Delete null persistence pairs and persistence thresholding - persistenceThresholding(tree, persistenceThreshold_); - - // - Merge saddle points according epsilon - if(not isPersistenceDiagram_) { - if(epsilonTree2_ != 0){ - std::vector> treeNodeMerged( tree->getNumberOfNodes() ); - mergeSaddle(tree, epsilonTree2_, treeNodeMerged); - for(unsigned int j=0; jgetNode(j)->getOrigin(); - tree->getNode(k)->setOrigin(j); - tree->getNode(nodeToDelete)->setOrigin(-1); - } - } - ftm::cleanMergeTree(mTrees[i], treesNodeCorr_[i], true); - } - else{ - std::vector nodeCorri(tree->getNumberOfNodes()); - for(unsigned int j=0; j(tree, false); - } - } + // if(usePathMappings_){ + // treesNodeCorr_ = std::vector>(mTrees.size()); + // printMsg("uses path mapping distance"); + // for(unsigned int i = 0; i < mTrees.size(); ++i) { + // ftm::FTMTree_MT *tree = &(mTrees[i].tree); + // preprocessTree(tree, true); + + // // - Delete null persistence pairs and persistence thresholding + // persistenceThresholding(tree, persistenceThreshold_); + + // // - Merge saddle points according epsilon + // if(not isPersistenceDiagram_) { + // if(epsilonTree2_ != 0){ + // std::vector> treeNodeMerged( tree->getNumberOfNodes() ); + // mergeSaddle(tree, epsilonTree2_, treeNodeMerged); + // for(unsigned int j=0; jgetNode(j)->getOrigin(); + // tree->getNode(k)->setOrigin(j); + // tree->getNode(nodeToDelete)->setOrigin(-1); + // } + // } + // ftm::cleanMergeTree(mTrees[i], treesNodeCorr_[i], true); + // } + // else{ + // std::vector nodeCorri(tree->getNumberOfNodes()); + // for(unsigned int j=0; j(tree, false); + // } + // } // --- Execute std::vector> barycenters(mTrees.size()); diff --git a/core/base/mergeTreeTemporalReductionDecoding/MergeTreeTemporalReductionDecoding.h b/core/base/mergeTreeTemporalReductionDecoding/MergeTreeTemporalReductionDecoding.h index c207f87f84..0b0428ef21 100644 --- a/core/base/mergeTreeTemporalReductionDecoding/MergeTreeTemporalReductionDecoding.h +++ b/core/base/mergeTreeTemporalReductionDecoding/MergeTreeTemporalReductionDecoding.h @@ -171,50 +171,57 @@ namespace ttk { Timer t_tempSub; // --- Preprocessing - if(!usePathMappings_){ - treesNodeCorr_ = std::vector>(mTrees.size()); - for(unsigned int i = 0; i < mTrees.size(); ++i) { - preprocessingPipeline( - mTrees[i], epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, - branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[i]); - } - printTreesStats(mTrees); + // if(!usePathMappings_){ + // treesNodeCorr_ = std::vector>(mTrees.size()); + // for(unsigned int i = 0; i < mTrees.size(); ++i) { + // preprocessingPipeline( + // mTrees[i], epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, + // branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[i]); + // } + // printTreesStats(mTrees); + // } + treesNodeCorr_ = std::vector>(mTrees.size()); + for(unsigned int i = 0; i < mTrees.size(); ++i) { + preprocessingPipeline( + mTrees[i], epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, + branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[i],true,usePathMappings_); } + printTreesStats(mTrees); - if(usePathMappings_){ - treesNodeCorr_ = std::vector>(mTrees.size()); - printMsg("uses path mapping distance"); - for(unsigned int i = 0; i < mTrees.size(); ++i) { - ftm::FTMTree_MT *tree = &(mTrees[i].tree); - preprocessTree(tree, true); + // if(usePathMappings_){ + // treesNodeCorr_ = std::vector>(mTrees.size()); + // printMsg("uses path mapping distance"); + // for(unsigned int i = 0; i < mTrees.size(); ++i) { + // ftm::FTMTree_MT *tree = &(mTrees[i].tree); + // preprocessTree(tree, true); - // - Delete null persistence pairs and persistence thresholding - persistenceThresholding(tree, persistenceThreshold_); + // // - Delete null persistence pairs and persistence thresholding + // persistenceThresholding(tree, persistenceThreshold_); - // - Merge saddle points according epsilon - if(not isPersistenceDiagram_) { - if(epsilonTree2_ != 0){ - std::vector> treeNodeMerged( tree->getNumberOfNodes() ); - mergeSaddle(tree, epsilonTree2_, treeNodeMerged); - for(unsigned int j=0; jgetNode(j)->getOrigin(); - tree->getNode(k)->setOrigin(j); - tree->getNode(nodeToDelete)->setOrigin(-1); - } - } - ftm::cleanMergeTree(mTrees[i], treesNodeCorr_[i], true); - } - else{ - std::vector nodeCorri(tree->getNumberOfNodes()); - for(unsigned int j=0; j(tree, false); - } - } + // // - Merge saddle points according epsilon + // if(not isPersistenceDiagram_) { + // if(epsilonTree2_ != 0){ + // std::vector> treeNodeMerged( tree->getNumberOfNodes() ); + // mergeSaddle(tree, epsilonTree2_, treeNodeMerged); + // for(unsigned int j=0; jgetNode(j)->getOrigin(); + // tree->getNode(k)->setOrigin(j); + // tree->getNode(nodeToDelete)->setOrigin(-1); + // } + // } + // ftm::cleanMergeTree(mTrees[i], treesNodeCorr_[i], true); + // } + // else{ + // std::vector nodeCorri(tree->getNumberOfNodes()); + // for(unsigned int j=0; j(tree, false); + // } + // } // --- Execute distancesToKeyFrames_ = std::vector(coefs.size() * 2); diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index 402a6d7a61..357605d7b8 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -282,6 +282,7 @@ int ttkMergeTreeClustering::runCompute( branchDist.setAssignmentSolver(AssignmentSolver); branchDist.setSquared(false); branchDist.setComputeMapping(true); + branchDist.setPreprocess(true); // branchDist.setWriteBD(false); branchDist.setWriteBD(true); @@ -296,7 +297,7 @@ int ttkMergeTreeClustering::runCompute( branchDist.setDebugLevel(this->debugLevel_); distance = branchDist.editDistance_branch( - intermediateTrees[0], intermediateTrees[1], &outputMatching); + intermediateMTrees[0], intermediateMTrees[1], &outputMatching); std::vector nodeCorr1( intermediateTrees[0]->getNumberOfNodes()); @@ -328,7 +329,7 @@ int ttkMergeTreeClustering::runCompute( pathDist.setDebugLevel(this->debugLevel_); distance = pathDist.editDistance_path( - intermediateTrees[0], intermediateTrees[1], &outputMatching); + intermediateMTrees[0], intermediateMTrees[1], &outputMatching); trees1NodeCorrMesh = pathDist.getTreesNodeCorr(); // std::vector From 837f8814ca198df98ed5c4b11c13040cb40d43be Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Fri, 1 Mar 2024 16:27:54 +0100 Subject: [PATCH 47/72] path mapping preprocessing working for clustering with multiple clusters --- .../ttkMergeTreeClustering/ttkMergeTreeClustering.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index 357605d7b8..d3343d7c7e 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -220,6 +220,14 @@ int ttkMergeTreeClustering::runCompute( NormalizedWasserstein = false; KeepSubtree = true; ComputeBarycenter = false; + } else if(Backend == 3) { + BranchDecomposition = false; + NormalizedWasserstein = false; + KeepSubtree = false; + } else if(Backend == 4) { + BranchDecomposition = false; + NormalizedWasserstein = false; + KeepSubtree = false; } if(IsPersistenceDiagram) { BranchDecomposition = true; @@ -228,7 +236,8 @@ int ttkMergeTreeClustering::runCompute( if(not BranchDecomposition) printMsg("BranchDecomposition is set to true since the barycenter " "computation is asked."); - BranchDecomposition = true; + if(baseModule==0) + BranchDecomposition = true; if(KeepSubtree) printMsg("KeepSubtree is set to false since the barycenter computation " "is asked."); From 66622a3e00798ab83d149c9571b3cf2d92bed46c Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Thu, 11 Apr 2024 17:31:33 +0200 Subject: [PATCH 48/72] preprocessing working for single path/branch mapping distance --- core/base/mergeTreeClustering/BranchMappingDistance.h | 6 +++--- core/base/mergeTreeClustering/PathMappingDistance.h | 8 ++++---- .../vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp | 4 ++++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/core/base/mergeTreeClustering/BranchMappingDistance.h b/core/base/mergeTreeClustering/BranchMappingDistance.h index 1831404191..b20e826f1c 100644 --- a/core/base/mergeTreeClustering/BranchMappingDistance.h +++ b/core/base/mergeTreeClustering/BranchMappingDistance.h @@ -216,14 +216,14 @@ namespace ttk { std::vector> *outputMatching=nullptr) { // optional preprocessing - if(preprocess_ && !writeOptimalBranchDecomposition_){ + if(preprocess_){ treesNodeCorr_.resize(2); preprocessingPipeline( mTree1, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, - branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[0],true,true); + false, useMinMaxPair_, cleanTree_, treesNodeCorr_[0],true,true); preprocessingPipeline( mTree2, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, - branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[1],true,true); + false, useMinMaxPair_, cleanTree_, treesNodeCorr_[1],true,true); } ftm::FTMTree_MT *tree1 = (&mTree1.tree); diff --git a/core/base/mergeTreeClustering/PathMappingDistance.h b/core/base/mergeTreeClustering/PathMappingDistance.h index 59305f3f81..715da9ef48 100644 --- a/core/base/mergeTreeClustering/PathMappingDistance.h +++ b/core/base/mergeTreeClustering/PathMappingDistance.h @@ -753,10 +753,10 @@ namespace ttk { treesNodeCorr_.resize(2); preprocessingPipeline( mTree1, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, - branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[0],true,true); + false, useMinMaxPair_, cleanTree_, treesNodeCorr_[0],true,true); preprocessingPipeline( mTree2, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, - branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[1],true,true); + false, useMinMaxPair_, cleanTree_, treesNodeCorr_[1],true,true); } ftm::FTMTree_MT *tree1 = (&mTree1.tree); @@ -780,10 +780,10 @@ namespace ttk { treesNodeCorr_.resize(2); preprocessingPipeline( mTree1, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, - branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[0],true,true); + false, useMinMaxPair_, cleanTree_, treesNodeCorr_[0],true,true); preprocessingPipeline( mTree2, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, - branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[1],true,true); + false, useMinMaxPair_, cleanTree_, treesNodeCorr_[1],true,true); } ftm::FTMTree_MT *tree1 = (&mTree1.tree); diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index d3343d7c7e..bec50cd316 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -292,6 +292,7 @@ int ttkMergeTreeClustering::runCompute( branchDist.setSquared(false); branchDist.setComputeMapping(true); branchDist.setPreprocess(true); + branchDist.setBranchDecomposition(false); // branchDist.setWriteBD(false); branchDist.setWriteBD(true); @@ -299,6 +300,7 @@ int ttkMergeTreeClustering::runCompute( branchDist.setEpsilonTree2(EpsilonTree2); branchDist.setPersistenceThreshold(PersistenceThreshold); // branchDist.setUseMinMaxPair(UseMinMaxPair); + branchDist.setCleanTree(true); branchDist.setDeleteMultiPersPairs(DeleteMultiPersPairs); // branchDist.setEpsilon1UseFarthestSaddle(Epsilon1UseFarthestSaddle); branchDist.setPersistenceThreshold(PersistenceThreshold); @@ -326,11 +328,13 @@ int ttkMergeTreeClustering::runCompute( pathDist.setSquared(false); pathDist.setComputeMapping(true); pathDist.setPreprocess(true); + pathDist.setBranchDecomposition(false); pathDist.setEpsilonTree1(EpsilonTree1); pathDist.setEpsilonTree2(EpsilonTree2); pathDist.setPersistenceThreshold(PersistenceThreshold); // pathDist.setUseMinMaxPair(UseMinMaxPair); + pathDist.setCleanTree(true); pathDist.setDeleteMultiPersPairs(DeleteMultiPersPairs); // pathDist.setEpsilon1UseFarthestSaddle(Epsilon1UseFarthestSaddle); pathDist.setPersistenceThreshold(PersistenceThreshold); From 4ae6cf9ff4bc94b81be1a4d471895a8e7fe2fa1c Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Thu, 11 Apr 2024 18:03:34 +0200 Subject: [PATCH 49/72] renaming of path/branch mapping API --- .../BranchMappingDistance.h | 6 ++-- .../mergeTreeClustering/MergeTreeBarycenter.h | 4 +-- .../mergeTreeClustering/PathMappingDistance.h | 36 ++++++------------- .../MergeTreeDistanceMatrix.h | 4 +-- .../MergeTreeTemporalReduction.h | 2 +- .../MergeTreeTemporalReductionDecoding.h | 2 +- .../ttkMergeTreeClustering.cpp | 4 +-- 7 files changed, 22 insertions(+), 36 deletions(-) diff --git a/core/base/mergeTreeClustering/BranchMappingDistance.h b/core/base/mergeTreeClustering/BranchMappingDistance.h index b20e826f1c..4dc9b50a5b 100644 --- a/core/base/mergeTreeClustering/BranchMappingDistance.h +++ b/core/base/mergeTreeClustering/BranchMappingDistance.h @@ -211,7 +211,7 @@ namespace ttk { } template - dataType editDistance_branch(ftm::MergeTree &mTree1, + dataType execute(ftm::MergeTree &mTree1, ftm::MergeTree &mTree2, std::vector> *outputMatching=nullptr) { @@ -229,11 +229,11 @@ namespace ttk { ftm::FTMTree_MT *tree1 = (&mTree1.tree); ftm::FTMTree_MT *tree2 = (&mTree2.tree); - return editDistance_branch(tree1,tree2, outputMatching); + return computeDistance(tree1,tree2, outputMatching); } template - dataType editDistance_branch(ftm::FTMTree_MT *tree1, + dataType computeDistance(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2, std::vector> *outputMatching=nullptr) { diff --git a/core/base/mergeTreeClustering/MergeTreeBarycenter.h b/core/base/mergeTreeClustering/MergeTreeBarycenter.h index 04351b4725..ab71538e21 100644 --- a/core/base/mergeTreeClustering/MergeTreeBarycenter.h +++ b/core/base/mergeTreeClustering/MergeTreeBarycenter.h @@ -999,7 +999,7 @@ namespace ttk { pathDistance.setDistanceSquaredRoot(false); // squared root pathDistance.setComputeMapping(true); distance - = pathDistance.editDistance_path(baryTree, tree, &matching); + = pathDistance.computeDistance(baryTree, tree, &matching); } template @@ -1020,7 +1020,7 @@ namespace ttk { pathDistance.setDistanceSquaredRoot(false); // squared root pathDistance.setComputeMapping(false); distance - = pathDistance.editDistance_path(baryTree, tree); + = pathDistance.computeDistance(baryTree, tree); } else{ MergeTreeDistance mergeTreeDistance; diff --git a/core/base/mergeTreeClustering/PathMappingDistance.h b/core/base/mergeTreeClustering/PathMappingDistance.h index 715da9ef48..57a8260ba0 100644 --- a/core/base/mergeTreeClustering/PathMappingDistance.h +++ b/core/base/mergeTreeClustering/PathMappingDistance.h @@ -340,24 +340,10 @@ namespace ttk { } template - dataType editDistance_path(ftm::FTMTree_MT *tree1, + dataType computeDistance(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2, std::vector,std::pair>> *outputMatching) { - // // optional preprocessing - // if(preprocess_) { - // treesNodeCorr_.resize(2); - // preprocessingPipeline( - // mTree1, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, - // branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[0],true,true); - // preprocessingPipeline( - // mTree2, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, - // branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[1],true,true); - // } - - // ftm::FTMTree_MT *tree1 = (&mTree1.tree); - // ftm::FTMTree_MT *tree2 = (&mTree2.tree); - // compute preorder of both trees (necessary for bottom-up dynamic programming) std::vector> predecessors1(tree1->getNumberOfNodes()); @@ -701,7 +687,7 @@ namespace ttk { } template - dataType editDistance_path(ftm::MergeTree &mTree1, + dataType execute(ftm::MergeTree &mTree1, ftm::MergeTree &mTree2, std::vector,std::pair>> *outputMatching) { @@ -719,15 +705,15 @@ namespace ttk { ftm::FTMTree_MT *tree1 = (&mTree1.tree); ftm::FTMTree_MT *tree2 = (&mTree2.tree); - return editDistance_path(tree1,tree2,outputMatching); + return computeDistance(tree1,tree2,outputMatching); } template - dataType editDistance_path(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2, std::vector> *outputMatching){ + dataType computeDistance(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2, std::vector> *outputMatching){ std::vector matchedNodes(tree1->getNumberOfNodes(),-1); std::vector,std::pair>> mapping; - dataType res = editDistance_path(tree1,tree2,&mapping); + dataType res = computeDistance(tree1,tree2,&mapping); if(computeMapping_ && outputMatching){ outputMatching->clear(); for(auto m : mapping){ @@ -744,7 +730,7 @@ namespace ttk { } template - dataType editDistance_path(ftm::MergeTree &mTree1, + dataType execute(ftm::MergeTree &mTree1, ftm::MergeTree &mTree2, std::vector> *outputMatching){ @@ -762,17 +748,17 @@ namespace ttk { ftm::FTMTree_MT *tree1 = (&mTree1.tree); ftm::FTMTree_MT *tree2 = (&mTree2.tree); - return editDistance_path(tree1,tree2,outputMatching); + return computeDistance(tree1,tree2,outputMatching); } template - dataType editDistance_path(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2){ - return editDistance_path(tree1,tree2,(std::vector,std::pair>>*) nullptr); + dataType computeDistance(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2){ + return computeDistance(tree1,tree2,(std::vector,std::pair>>*) nullptr); } template - dataType editDistance_path(ftm::MergeTree &mTree1, + dataType execute(ftm::MergeTree &mTree1, ftm::MergeTree &mTree2){ // optional preprocessing @@ -789,7 +775,7 @@ namespace ttk { ftm::FTMTree_MT *tree1 = (&mTree1.tree); ftm::FTMTree_MT *tree2 = (&mTree2.tree); - return editDistance_path(tree1,tree2,(std::vector,std::pair>>*) nullptr); + return computeDistance(tree1,tree2,(std::vector,std::pair>>*) nullptr); } }; } // namespace ttk diff --git a/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h b/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h index 9ffd6ca5a7..80f61c3b79 100644 --- a/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h +++ b/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h @@ -104,11 +104,11 @@ namespace ttk { if(baseModule_ == 0) { distanceMatrix[i][j] = 0; } else if(baseModule_ == 1) { - dataType dist = branchDist.editDistance_branch( + dataType dist = branchDist.execute( ftmtrees[i], ftmtrees[j]); distanceMatrix[i][j] = static_cast(dist); } else if(baseModule_ == 2) { - dataType dist = pathDist.editDistance_path( + dataType dist = pathDist.execute( ftmtrees[i], ftmtrees[j]); distanceMatrix[i][j] = static_cast(dist); } diff --git a/core/base/mergeTreeTemporalReduction/MergeTreeTemporalReduction.h b/core/base/mergeTreeTemporalReduction/MergeTreeTemporalReduction.h index 518d663f55..81c0ea87f3 100644 --- a/core/base/mergeTreeTemporalReduction/MergeTreeTemporalReduction.h +++ b/core/base/mergeTreeTemporalReduction/MergeTreeTemporalReduction.h @@ -112,7 +112,7 @@ namespace ttk { ftm::FTMTree_MT* mt1 = &(mTree1.tree); ftm::FTMTree_MT* mt2 = &(mTree2.tree); - distance = mergeTreeDistance.editDistance_path(mt1, mt2); + distance = mergeTreeDistance.computeDistance(mt1, mt2); } else{ MergeTreeDistance mergeTreeDistance; diff --git a/core/base/mergeTreeTemporalReductionDecoding/MergeTreeTemporalReductionDecoding.h b/core/base/mergeTreeTemporalReductionDecoding/MergeTreeTemporalReductionDecoding.h index 0b0428ef21..573fbaa837 100644 --- a/core/base/mergeTreeTemporalReductionDecoding/MergeTreeTemporalReductionDecoding.h +++ b/core/base/mergeTreeTemporalReductionDecoding/MergeTreeTemporalReductionDecoding.h @@ -67,7 +67,7 @@ namespace ttk { ftm::FTMTree_MT* mt1 = &(mTree1.tree); ftm::FTMTree_MT* mt2 = &(mTree2.tree); dataType distance - = mergeTreeDistance.editDistance_path(mt1, mt2, &matching); + = mergeTreeDistance.computeDistance(mt1, mt2, &matching); return distance; } diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index bec50cd316..a32fb09794 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -307,7 +307,7 @@ int ttkMergeTreeClustering::runCompute( branchDist.setThreadNumber(this->threadNumber_); branchDist.setDebugLevel(this->debugLevel_); - distance = branchDist.editDistance_branch( + distance = branchDist.execute( intermediateMTrees[0], intermediateMTrees[1], &outputMatching); std::vector nodeCorr1( @@ -341,7 +341,7 @@ int ttkMergeTreeClustering::runCompute( pathDist.setThreadNumber(this->threadNumber_); pathDist.setDebugLevel(this->debugLevel_); - distance = pathDist.editDistance_path( + distance = pathDist.execute( intermediateMTrees[0], intermediateMTrees[1], &outputMatching); trees1NodeCorrMesh = pathDist.getTreesNodeCorr(); From e2d0a6bc7208c5f057f382bd72d936a8de131f33 Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Fri, 12 Apr 2024 13:16:33 +0200 Subject: [PATCH 50/72] preprocessing for path/branch mappings working in MergeTreeDistanceMatrix --- .../MergeTreeDistanceMatrix.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h b/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h index 80f61c3b79..cfc4b26d8c 100644 --- a/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h +++ b/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h @@ -91,11 +91,25 @@ namespace ttk { branchDist.setBaseMetric(branchMetric_); branchDist.setAssignmentSolver(assignmentSolverID_); branchDist.setSquared(not distanceSquaredRoot_); + branchDist.setEpsilonTree1(epsilonTree1_); + branchDist.setEpsilonTree2(epsilonTree2_); + branchDist.setEpsilon2Tree1(epsilon2Tree1_); + branchDist.setEpsilon2Tree2(epsilon2Tree2_); + branchDist.setEpsilon3Tree1(epsilon3Tree1_); + branchDist.setEpsilon3Tree2(epsilon3Tree2_); + branchDist.setPersistenceThreshold(persistenceThreshold_); PathMappingDistance pathDist; pathDist.setBaseMetric(pathMetric_); pathDist.setAssignmentSolver(assignmentSolverID_); pathDist.setSquared(not distanceSquaredRoot_); pathDist.setComputeMapping(true); + pathDist.setEpsilonTree1(epsilonTree1_); + pathDist.setEpsilonTree2(epsilonTree2_); + pathDist.setEpsilon2Tree1(epsilon2Tree1_); + pathDist.setEpsilon2Tree2(epsilon2Tree2_); + pathDist.setEpsilon3Tree1(epsilon3Tree1_); + pathDist.setEpsilon3Tree2(epsilon3Tree2_); + pathDist.setPersistenceThreshold(persistenceThreshold_); distanceMatrix[i][i] = 0.0; // compareTrees(trees[i],&(ftmtrees[i].tree)); From c32a75e28e4407e54e607166a8c7f38e182ec825 Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Fri, 12 Apr 2024 18:48:27 +0200 Subject: [PATCH 51/72] parallel computation for path/branch mapping distance in MergeTreeistanceMatrix --- .../BranchMappingDistance.h | 26 ++++-- .../mergeTreeClustering/PathMappingDistance.h | 64 ++++++++++--- .../MergeTreeDistanceMatrix.h | 90 +++++++------------ .../ttkMergeTreeDistanceMatrix.cpp | 5 +- 4 files changed, 106 insertions(+), 79 deletions(-) diff --git a/core/base/mergeTreeClustering/BranchMappingDistance.h b/core/base/mergeTreeClustering/BranchMappingDistance.h index 4dc9b50a5b..827d978506 100644 --- a/core/base/mergeTreeClustering/BranchMappingDistance.h +++ b/core/base/mergeTreeClustering/BranchMappingDistance.h @@ -47,6 +47,7 @@ namespace ttk { bool writeOptimalBranchDecomposition_ = false; bool preprocess_ = true; + bool saveTree_ = false; template inline dataType editCost_Wasserstein1(int n1, @@ -210,24 +211,39 @@ namespace ttk { preprocess_ = p; } + void setSaveTree(bool save) { + saveTree_ = save; + } + template dataType execute(ftm::MergeTree &mTree1, ftm::MergeTree &mTree2, std::vector> *outputMatching=nullptr) { + ftm::MergeTree mTree1Copy; + ftm::MergeTree mTree2Copy; + if(saveTree_) { + mTree1Copy = ftm::copyMergeTree(mTree1); + mTree2Copy = ftm::copyMergeTree(mTree2); + } + ftm::MergeTree &mTree1Int = (saveTree_ ? mTree1Copy : mTree1); + ftm::MergeTree &mTree2Int = (saveTree_ ? mTree2Copy : mTree2); + ftm::FTMTree_MT *tree1 = &(mTree1Int.tree); + ftm::FTMTree_MT *tree2 = &(mTree2Int.tree); + // optional preprocessing if(preprocess_){ treesNodeCorr_.resize(2); preprocessingPipeline( - mTree1, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, + mTree1Int, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, false, useMinMaxPair_, cleanTree_, treesNodeCorr_[0],true,true); preprocessingPipeline( - mTree2, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, + mTree2Int, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, false, useMinMaxPair_, cleanTree_, treesNodeCorr_[1],true,true); } - - ftm::FTMTree_MT *tree1 = (&mTree1.tree); - ftm::FTMTree_MT *tree2 = (&mTree2.tree); + + tree1 = &(mTree1Int.tree); + tree2 = &(mTree2Int.tree); return computeDistance(tree1,tree2, outputMatching); } diff --git a/core/base/mergeTreeClustering/PathMappingDistance.h b/core/base/mergeTreeClustering/PathMappingDistance.h index 57a8260ba0..c5f22cb96e 100644 --- a/core/base/mergeTreeClustering/PathMappingDistance.h +++ b/core/base/mergeTreeClustering/PathMappingDistance.h @@ -46,6 +46,7 @@ namespace ttk { bool computeMapping_ = false; bool preprocess_ = true; + bool saveTree_ = false; template inline dataType editCost_Persistence(int n1, @@ -339,6 +340,10 @@ namespace ttk { preprocess_ = p; } + void setSaveTree(bool save) { + saveTree_ = save; + } + template dataType computeDistance(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2, @@ -691,19 +696,30 @@ namespace ttk { ftm::MergeTree &mTree2, std::vector,std::pair>> *outputMatching) { + ftm::MergeTree mTree1Copy; + ftm::MergeTree mTree2Copy; + if(saveTree_) { + mTree1Copy = ftm::copyMergeTree(mTree1); + mTree2Copy = ftm::copyMergeTree(mTree2); + } + ftm::MergeTree &mTree1Int = (saveTree_ ? mTree1Copy : mTree1); + ftm::MergeTree &mTree2Int = (saveTree_ ? mTree2Copy : mTree2); + ftm::FTMTree_MT *tree1 = &(mTree1Int.tree); + ftm::FTMTree_MT *tree2 = &(mTree2Int.tree); + // optional preprocessing if(preprocess_) { treesNodeCorr_.resize(2); preprocessingPipeline( - mTree1, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, + mTree1Int, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[0],true,true); preprocessingPipeline( - mTree2, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, + mTree2Int, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[1],true,true); } - ftm::FTMTree_MT *tree1 = (&mTree1.tree); - ftm::FTMTree_MT *tree2 = (&mTree2.tree); + tree1 = &(mTree1Int.tree); + tree2 = &(mTree2Int.tree); return computeDistance(tree1,tree2,outputMatching); } @@ -734,19 +750,30 @@ namespace ttk { ftm::MergeTree &mTree2, std::vector> *outputMatching){ + ftm::MergeTree mTree1Copy; + ftm::MergeTree mTree2Copy; + if(saveTree_) { + mTree1Copy = ftm::copyMergeTree(mTree1); + mTree2Copy = ftm::copyMergeTree(mTree2); + } + ftm::MergeTree &mTree1Int = (saveTree_ ? mTree1Copy : mTree1); + ftm::MergeTree &mTree2Int = (saveTree_ ? mTree2Copy : mTree2); + ftm::FTMTree_MT *tree1 = &(mTree1Int.tree); + ftm::FTMTree_MT *tree2 = &(mTree2Int.tree); + // optional preprocessing if(preprocess_) { treesNodeCorr_.resize(2); preprocessingPipeline( - mTree1, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, + mTree1Int, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, false, useMinMaxPair_, cleanTree_, treesNodeCorr_[0],true,true); preprocessingPipeline( - mTree2, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, + mTree2Int, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, false, useMinMaxPair_, cleanTree_, treesNodeCorr_[1],true,true); } - ftm::FTMTree_MT *tree1 = (&mTree1.tree); - ftm::FTMTree_MT *tree2 = (&mTree2.tree); + tree1 = &(mTree1Int.tree); + tree2 = &(mTree2Int.tree); return computeDistance(tree1,tree2,outputMatching); @@ -760,20 +787,31 @@ namespace ttk { template dataType execute(ftm::MergeTree &mTree1, ftm::MergeTree &mTree2){ + + ftm::MergeTree mTree1Copy; + ftm::MergeTree mTree2Copy; + if(saveTree_) { + mTree1Copy = ftm::copyMergeTree(mTree1); + mTree2Copy = ftm::copyMergeTree(mTree2); + } + ftm::MergeTree &mTree1Int = (saveTree_ ? mTree1Copy : mTree1); + ftm::MergeTree &mTree2Int = (saveTree_ ? mTree2Copy : mTree2); + ftm::FTMTree_MT *tree1 = &(mTree1Int.tree); + ftm::FTMTree_MT *tree2 = &(mTree2Int.tree); // optional preprocessing if(preprocess_) { treesNodeCorr_.resize(2); preprocessingPipeline( - mTree1, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, + mTree1Int, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, false, useMinMaxPair_, cleanTree_, treesNodeCorr_[0],true,true); preprocessingPipeline( - mTree2, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, + mTree2Int, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, false, useMinMaxPair_, cleanTree_, treesNodeCorr_[1],true,true); } - - ftm::FTMTree_MT *tree1 = (&mTree1.tree); - ftm::FTMTree_MT *tree2 = (&mTree2.tree); + + tree1 = &(mTree1Int.tree); + tree2 = &(mTree2Int.tree); return computeDistance(tree1,tree2,(std::vector,std::pair>>*) nullptr); } diff --git a/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h b/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h index cfc4b26d8c..f286e42eb6 100644 --- a/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h +++ b/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h @@ -77,61 +77,6 @@ namespace ttk { } } - template - void execute(std::vector> &ftmtrees, - std::vector> &distanceMatrix) { - for(unsigned int i = 0; i < distanceMatrix.size(); ++i) { - if(i % std::max(int(distanceMatrix.size() / 10), 1) == 0) { - std::stringstream stream; - stream << i << " / " << distanceMatrix.size(); - printMsg(stream.str()); - } - - BranchMappingDistance branchDist; - branchDist.setBaseMetric(branchMetric_); - branchDist.setAssignmentSolver(assignmentSolverID_); - branchDist.setSquared(not distanceSquaredRoot_); - branchDist.setEpsilonTree1(epsilonTree1_); - branchDist.setEpsilonTree2(epsilonTree2_); - branchDist.setEpsilon2Tree1(epsilon2Tree1_); - branchDist.setEpsilon2Tree2(epsilon2Tree2_); - branchDist.setEpsilon3Tree1(epsilon3Tree1_); - branchDist.setEpsilon3Tree2(epsilon3Tree2_); - branchDist.setPersistenceThreshold(persistenceThreshold_); - PathMappingDistance pathDist; - pathDist.setBaseMetric(pathMetric_); - pathDist.setAssignmentSolver(assignmentSolverID_); - pathDist.setSquared(not distanceSquaredRoot_); - pathDist.setComputeMapping(true); - pathDist.setEpsilonTree1(epsilonTree1_); - pathDist.setEpsilonTree2(epsilonTree2_); - pathDist.setEpsilon2Tree1(epsilon2Tree1_); - pathDist.setEpsilon2Tree2(epsilon2Tree2_); - pathDist.setEpsilon3Tree1(epsilon3Tree1_); - pathDist.setEpsilon3Tree2(epsilon3Tree2_); - pathDist.setPersistenceThreshold(persistenceThreshold_); - - distanceMatrix[i][i] = 0.0; - // compareTrees(trees[i],&(ftmtrees[i].tree)); - for(unsigned int j = i + 1; j < distanceMatrix[0].size(); ++j) { - // Execute - if(baseModule_ == 0) { - distanceMatrix[i][j] = 0; - } else if(baseModule_ == 1) { - dataType dist = branchDist.execute( - ftmtrees[i], ftmtrees[j]); - distanceMatrix[i][j] = static_cast(dist); - } else if(baseModule_ == 2) { - dataType dist = pathDist.execute( - ftmtrees[i], ftmtrees[j]); - distanceMatrix[i][j] = static_cast(dist); - } - // distance matrix is symmetric - distanceMatrix[j][i] = distanceMatrix[i][j]; - } // end for j - } // end for i - } - template void executePara(std::vector> &trees, std::vector> &distanceMatrix, @@ -198,8 +143,39 @@ namespace ttk { std::vector> outputMatching; distanceMatrix[i][j] = mergeTreeDistance.execute( trees[i], trees[j], outputMatching); - } else { - distanceMatrix[i][j] = 0; + } else if(baseModule_ == 1) { + BranchMappingDistance branchDist; + branchDist.setBaseMetric(branchMetric_); + branchDist.setAssignmentSolver(assignmentSolverID_); + branchDist.setSquared(not distanceSquaredRoot_); + branchDist.setEpsilonTree1(epsilonTree1_); + branchDist.setEpsilonTree2(epsilonTree2_); + branchDist.setEpsilon2Tree1(epsilon2Tree1_); + branchDist.setEpsilon2Tree2(epsilon2Tree2_); + branchDist.setEpsilon3Tree1(epsilon3Tree1_); + branchDist.setEpsilon3Tree2(epsilon3Tree2_); + branchDist.setPersistenceThreshold(persistenceThreshold_); + branchDist.setSaveTree(true); + dataType dist = branchDist.execute( + trees[i], trees[j]); + distanceMatrix[i][j] = static_cast(dist); + } else if(baseModule_ == 2) { + PathMappingDistance pathDist; + pathDist.setBaseMetric(pathMetric_); + pathDist.setAssignmentSolver(assignmentSolverID_); + pathDist.setSquared(not distanceSquaredRoot_); + pathDist.setComputeMapping(true); + pathDist.setEpsilonTree1(epsilonTree1_); + pathDist.setEpsilonTree2(epsilonTree2_); + pathDist.setEpsilon2Tree1(epsilon2Tree1_); + pathDist.setEpsilon2Tree2(epsilon2Tree2_); + pathDist.setEpsilon3Tree1(epsilon3Tree1_); + pathDist.setEpsilon3Tree2(epsilon3Tree2_); + pathDist.setPersistenceThreshold(persistenceThreshold_); + pathDist.setSaveTree(true); + dataType dist = pathDist.execute( + trees[i], trees[j]); + distanceMatrix[i][j] = static_cast(dist); } // distance matrix is symmetric distanceMatrix[j][i] = distanceMatrix[i][j]; diff --git a/core/vtk/ttkMergeTreeDistanceMatrix/ttkMergeTreeDistanceMatrix.cpp b/core/vtk/ttkMergeTreeDistanceMatrix/ttkMergeTreeDistanceMatrix.cpp index 0411b3480b..a20a323cc6 100644 --- a/core/vtk/ttkMergeTreeDistanceMatrix/ttkMergeTreeDistanceMatrix.cpp +++ b/core/vtk/ttkMergeTreeDistanceMatrix/ttkMergeTreeDistanceMatrix.cpp @@ -188,10 +188,7 @@ int ttkMergeTreeDistanceMatrix::run( // --- Call base std::vector> treesDistMat( numInputs, std::vector(numInputs)); - if(baseModule_ == 0) - execute(intermediateTrees, intermediateTrees2, treesDistMat); - else - execute(intermediateTrees, treesDistMat); + execute(intermediateTrees, intermediateTrees2, treesDistMat); // --- Create output auto treesDistTable = vtkTable::GetData(outputVector); From ff08b2dfbc47780bd9e035e4640d72f39cc5ea5b Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Mon, 15 Apr 2024 16:24:37 +0200 Subject: [PATCH 52/72] Parallel assignment for path mapping distance in MergeTreeBarycenter --- .../mergeTreeClustering/MergeTreeBarycenter.h | 146 ++++++++++++------ .../mergeTreeClustering/MergeTreeClustering.h | 12 +- 2 files changed, 108 insertions(+), 50 deletions(-) diff --git a/core/base/mergeTreeClustering/MergeTreeBarycenter.h b/core/base/mergeTreeClustering/MergeTreeBarycenter.h index ab71538e21..bb8e2c9fa5 100644 --- a/core/base/mergeTreeClustering/MergeTreeBarycenter.h +++ b/core/base/mergeTreeClustering/MergeTreeBarycenter.h @@ -180,8 +180,9 @@ namespace ttk { for(unsigned int i = 0; i < trees.size(); ++i) for(unsigned int j = i + 1; j < trees.size(); ++j) { std::vector> matching; + std::vector,std::pair>> matching_path; dataType distance; - computeOneDistance(trees[i], trees2[j], matching, distance, + computeOneDistance(trees[i], trees2[j], matching, matching_path, distance, useDoubleInput, isFirstInput); distanceMatrix[i][j] = distance; distanceMatrix[j][i] = distance; @@ -984,29 +985,30 @@ namespace ttk { // ------------------------------------------------------------------------ // Assignment // ------------------------------------------------------------------------ - template - void computeOneDistance_pathMapping( - ftm::FTMTree_MT *tree, - ftm::FTMTree_MT *baryTree, - std::vector,std::pair>> &matching, - dataType &distance) { - // Timer t_distance; - PathMappingDistance pathDistance; - pathDistance.setDebugLevel(std::min(debugLevel_, 2)); - pathDistance.setPreprocess(false); - pathDistance.setAssignmentSolver(assignmentSolverID_); - pathDistance.setThreadNumber(this->threadNumber_); - pathDistance.setDistanceSquaredRoot(false); // squared root - pathDistance.setComputeMapping(true); - distance - = pathDistance.computeDistance(baryTree, tree, &matching); - } + // template + // void computeOneDistance_pathMapping( + // ftm::FTMTree_MT *tree, + // ftm::FTMTree_MT *baryTree, + // std::vector,std::pair>> &matching, + // dataType &distance) { + // // Timer t_distance; + // PathMappingDistance pathDistance; + // pathDistance.setDebugLevel(std::min(debugLevel_, 2)); + // pathDistance.setPreprocess(false); + // pathDistance.setAssignmentSolver(assignmentSolverID_); + // pathDistance.setThreadNumber(this->threadNumber_); + // pathDistance.setDistanceSquaredRoot(false); // squared root + // pathDistance.setComputeMapping(true); + // distance + // = pathDistance.computeDistance(baryTree, tree, &matching); + // } template void computeOneDistance( ftm::FTMTree_MT *tree, ftm::FTMTree_MT *baryTree, std::vector> &matching, + std::vector,std::pair>> &matching_path, dataType &distance, bool useDoubleInput = false, bool isFirstInput = true) { @@ -1018,9 +1020,9 @@ namespace ttk { pathDistance.setAssignmentSolver(assignmentSolverID_); pathDistance.setThreadNumber(this->threadNumber_); pathDistance.setDistanceSquaredRoot(false); // squared root - pathDistance.setComputeMapping(false); + pathDistance.setComputeMapping(true); distance - = pathDistance.computeDistance(baryTree, tree); + = pathDistance.computeDistance(baryTree, tree, &matching_path); } else{ MergeTreeDistance mergeTreeDistance; @@ -1061,10 +1063,11 @@ namespace ttk { ftm::FTMTree_MT *tree, ftm::MergeTree &baryMergeTree, std::vector> &matching, + std::vector,std::pair>> &matching_path, dataType &distance, bool useDoubleInput = false, bool isFirstInput = true) { - computeOneDistance(tree, &(baryMergeTree.tree), matching, + computeOneDistance(tree, &(baryMergeTree.tree), matching, matching_path, distance, useDoubleInput, isFirstInput); } @@ -1073,41 +1076,85 @@ namespace ttk { ftm::MergeTree &baryMergeTree, ftm::MergeTree &baryMergeTree2, std::vector> &matching, + std::vector,std::pair>> &matching_path, dataType &distance, bool useDoubleInput = false, bool isFirstInput = true) { computeOneDistance(&(baryMergeTree.tree), baryMergeTree2, - matching, distance, useDoubleInput, + matching, matching_path, distance, useDoubleInput, isFirstInput); } template - void assignment_path( - std::vector &trees, + void computeOneDistance( + ftm::FTMTree_MT *tree, + ftm::FTMTree_MT *baryTree, + std::vector> &matching, + dataType &distance, + bool useDoubleInput = false, + bool isFirstInput = true) { + std::vector,std::pair>> matching_path; + computeOneDistance(tree, baryTree, + matching, matching_path, distance, useDoubleInput, + isFirstInput); + } + + template + void computeOneDistance( + ftm::FTMTree_MT *tree, ftm::MergeTree &baryMergeTree, - std::vector,std::pair>>> - &matchings, - std::vector &distances) { - for(unsigned int i = 0; i < trees.size(); ++i){ - computeOneDistance_pathMapping(trees[i], &(baryMergeTree.tree), matchings[i], - distances[i]); - } + std::vector> &matching, + dataType &distance, + bool useDoubleInput = false, + bool isFirstInput = true) { + std::vector,std::pair>> matching_path; + computeOneDistance(tree, &(baryMergeTree.tree), matching, matching_path, + distance, useDoubleInput, isFirstInput); + } + + template + void computeOneDistance( + ftm::MergeTree &baryMergeTree, + ftm::MergeTree &baryMergeTree2, + std::vector> &matching, + dataType &distance, + bool useDoubleInput = false, + bool isFirstInput = true) { + std::vector,std::pair>> matching_path; + computeOneDistance(&(baryMergeTree.tree), baryMergeTree2, + matching, matching_path, distance, useDoubleInput, + isFirstInput); } + // template + // void assignment_path( + // std::vector &trees, + // ftm::MergeTree &baryMergeTree, + // std::vector,std::pair>>> + // &matchings, + // std::vector &distances) { + // for(unsigned int i = 0; i < trees.size(); ++i){ + // computeOneDistance_pathMapping(trees[i], &(baryMergeTree.tree), matchings[i], + // distances[i]); + // } + // } + template void assignment( std::vector &trees, ftm::MergeTree &baryMergeTree, std::vector>> &matchings, + std::vector,std::pair>>> + &matchings_path, std::vector &distances, bool useDoubleInput = false, bool isFirstInput = true) { if(not isCalled_) - assignmentPara(trees, baryMergeTree, matchings, distances, + assignmentPara(trees, baryMergeTree, matchings, matchings_path, distances, useDoubleInput, isFirstInput); else - assignmentTask(trees, baryMergeTree, matchings, distances, + assignmentTask(trees, baryMergeTree, matchings, matchings_path, distances, useDoubleInput, isFirstInput); } @@ -1117,6 +1164,8 @@ namespace ttk { ftm::MergeTree &baryMergeTree, std::vector>> &matchings, + std::vector,std::pair>>> + &matchings_path, std::vector &distances, bool useDoubleInput = false, bool isFirstInput = true) { @@ -1126,7 +1175,7 @@ namespace ttk { { #pragma omp single nowait #endif - assignmentTask(trees, baryMergeTree, matchings, distances, + assignmentTask(trees, baryMergeTree, matchings, matchings_path, distances, useDoubleInput, isFirstInput); #ifdef TTK_ENABLE_OPENMP4 } // pragma omp parallel @@ -1139,15 +1188,17 @@ namespace ttk { ftm::MergeTree &baryMergeTree, std::vector>> &matchings, + std::vector,std::pair>>> + &matchings_path, std::vector &distances, bool useDoubleInput = false, bool isFirstInput = true) { for(unsigned int i = 0; i < trees.size(); ++i) #ifdef TTK_ENABLE_OPENMP4 #pragma omp task firstprivate(i) UNTIED() \ - shared(baryMergeTree, matchings, distances) + shared(baryMergeTree, matchings, matchings_path, distances) #endif - computeOneDistance(trees[i], baryMergeTree, matchings[i], + computeOneDistance(trees[i], baryMergeTree, matchings[i],matchings_path[i], distances[i], useDoubleInput, isFirstInput); #ifdef TTK_ENABLE_OPENMP4 @@ -1284,12 +1335,13 @@ namespace ttk { matchings_path(trees.size()); std::vector distances(trees.size(), -1); Timer t_assignment; - if(baseModule_ == 2){ - assignment_path(trees, baryMergeTree, matchings_path, distances); - } - else{ - assignment(trees, baryMergeTree, matchings, distances); - } + // if(baseModule_ == 2){ + // assignment_path(trees, baryMergeTree, matchings_path, distances); + // } + // else{ + // assignment(trees, baryMergeTree, matchings, distances); + // } + assignment(trees, baryMergeTree, matchings, matchings_path, distances); Timer t_addDeletedNodes; if(progressiveBarycenter_) addScaledDeletedNodesCost( @@ -1369,7 +1421,10 @@ namespace ttk { if(baseModule_ == 2){ std::vector,std::pair>>> matchings_path(trees.size()); - assignment_path(trees, baryMergeTree, matchings_path, distances); + std::vector>> + matchings; + // assignment_path(trees, baryMergeTree, matchings_path, distances); + assignment(trees, baryMergeTree, matchings, matchings_path, distances); finalMatchings_path = matchings_path; for(unsigned int i=0; i(trees, baryMergeTree, finalMatchings, distances, + assignment(trees, baryMergeTree, finalMatchings, finalMatchings_path, distances, finalAsgnDoubleInput, finalAsgnFirstInput); } for(auto dist : distances) @@ -1654,8 +1709,9 @@ namespace ttk { &finalMatchings, std::vector distances) { std::vector> matching; + std::vector,std::pair>> matching_path; dataType distance; - computeOneDistance(trees[0], trees[1], matching, distance); + computeOneDistance(trees[0], trees[1], matching, matching_path, distance); if(distance != (distances[0] + distances[1])) { std::stringstream ss, ss2, ss3, ss4; ss << "distance T1 T2 : " << distance; diff --git a/core/base/mergeTreeClustering/MergeTreeClustering.h b/core/base/mergeTreeClustering/MergeTreeClustering.h index ab598f395a..ef05591a98 100644 --- a/core/base/mergeTreeClustering/MergeTreeClustering.h +++ b/core/base/mergeTreeClustering/MergeTreeClustering.h @@ -437,10 +437,12 @@ namespace ttk { std::vector distances(assignedTrees[i].size(), 0); std::vector distances2(assignedTrees[i].size(), 0); treesMatchingVector matching(trees.size()), matching2(trees2.size()); + std::vector,std::pair>>> matching_path(trees.size()); if(baseModule_ == 2){ - std::vector,std::pair>>> matching_path(trees.size()); - assignment_path( - assignedTrees[i], centroids[i], matching_path, distances); + // assignment_path( + // assignedTrees[i], centroids[i], matching_path, distances); + assignment( + assignedTrees[i], centroids[i], matching, matching_path, distances); for(unsigned int j=0; j matchedNodes(assignedTrees[i][j]->getNumberOfNodes(),-1); for(auto m : matching_path[j]){ @@ -455,10 +457,10 @@ namespace ttk { } else{ assignment( - assignedTrees[i], centroids[i], matching, distances, useDoubleInput_); + assignedTrees[i], centroids[i], matching, matching_path, distances, useDoubleInput_); matchingsC[i] = matching; if(trees2.size() != 0) { - assignment(assignedTrees2[i], centroids2[i], matching2, + assignment(assignedTrees2[i], centroids2[i], matching2, matching_path, distances2, useDoubleInput_, false); matchingsC2[i] = matching2; for(unsigned int j = 0; j < assignedTreesIndex[i].size(); ++j) From 8a8507bd8a2fdf421e2a5308c8a174b07be2bb42 Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Tue, 16 Apr 2024 16:49:06 +0200 Subject: [PATCH 53/72] added iteration limit for merge tree barycenter again --- core/base/mergeTreeClustering/MergeTreeBarycenter.h | 10 +++++----- .../ttkMergeTreeClustering.cpp | 2 +- .../ttkMergeTreeClustering/ttkMergeTreeClustering.h | 13 +++++++------ paraview/xmls/MergeTreeClustering.xml | 10 ++++++---- 4 files changed, 19 insertions(+), 16 deletions(-) diff --git a/core/base/mergeTreeClustering/MergeTreeBarycenter.h b/core/base/mergeTreeClustering/MergeTreeBarycenter.h index bb8e2c9fa5..65edf6230f 100644 --- a/core/base/mergeTreeClustering/MergeTreeBarycenter.h +++ b/core/base/mergeTreeClustering/MergeTreeBarycenter.h @@ -59,7 +59,7 @@ namespace ttk { bool useFixedInit_ = false; bool useEarlyOut_ = true; int fixedInitNumber_ = 0; - //int iterationLimit_ = 0; + int iterationLimit_ = 100; // Output std::vector finalDistances_; @@ -155,9 +155,9 @@ namespace ttk { fixedInitNumber_ = fixedInitNumber; } - // void setIterationLimit(int l) { - // iterationLimit_ = l; - // } + void setIterationLimit(int l) { + iterationLimit_ = l; + } /** * Implementation of the algorithm. @@ -1320,7 +1320,7 @@ namespace ttk { std::stringstream energySequence; int minBarySize = std::numeric_limits::max(); int maxBarySize = 0; - while(not converged && NoIteration<100){// && NoIterationpathMetric); mergeTreeBarycenter.setBranchDecomposition(false); diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h index e43a326cfc..bb79c36d9e 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h @@ -100,7 +100,7 @@ class TTKMERGETREECLUSTERING_EXPORT ttkMergeTreeClustering bool useFixedInit = false; int fixedInitNumber = 0; bool useEarlyOut = true; - // int iterationLimit = 0; + int iterationLimit = 100; double NonMatchingWeight = 1.0; // Output Options @@ -382,11 +382,12 @@ class TTKMERGETREECLUSTERING_EXPORT ttkMergeTreeClustering resetDataVisualization(); } - // void SetIterationLimit(int l) { - // iterationLimit = l; - // Modified(); - // resetDataVisualization(); - // } + void SetIterationLimit(int l) { + iterationLimit = l; + Modified(); + resetDataVisualization(); + } + void SetNonMatchingWeight(double weight) { NonMatchingWeight = weight; Modified(); diff --git a/paraview/xmls/MergeTreeClustering.xml b/paraview/xmls/MergeTreeClustering.xml index 725777c1e2..a78ae4a127 100644 --- a/paraview/xmls/MergeTreeClustering.xml +++ b/paraview/xmls/MergeTreeClustering.xml @@ -269,12 +269,13 @@ Online examples: - + > + panel_visibility="advanced"> + From 4205c37256188c4f0873247c1a754d9a6156b608 Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Thu, 18 Apr 2024 11:24:30 +0200 Subject: [PATCH 54/72] removed convergence flag in MergeTreeBarycenter and allowed unlimited iterations through negative iterationLimit flag --- .../base/mergeTreeClustering/MergeTreeBarycenter.h | 12 ++++++------ .../ttkMergeTreeClustering.cpp | 2 +- .../ttkMergeTreeClustering.h | 14 +++++++------- paraview/xmls/MergeTreeClustering.xml | 6 +++--- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/core/base/mergeTreeClustering/MergeTreeBarycenter.h b/core/base/mergeTreeClustering/MergeTreeBarycenter.h index 65edf6230f..f823e076a1 100644 --- a/core/base/mergeTreeClustering/MergeTreeBarycenter.h +++ b/core/base/mergeTreeClustering/MergeTreeBarycenter.h @@ -57,7 +57,7 @@ namespace ttk { int baseModule_ = 0; bool useMedianBarycenter_ = false; bool useFixedInit_ = false; - bool useEarlyOut_ = true; + // bool useEarlyOut_ = true; int fixedInitNumber_ = 0; int iterationLimit_ = 100; @@ -147,9 +147,9 @@ namespace ttk { useFixedInit_ = useFixedInit; } - void setUseEarlyOut(bool useEarlyOut) { - useEarlyOut_ = useEarlyOut; - } + // void setUseEarlyOut(bool useEarlyOut) { + // useEarlyOut_ = useEarlyOut; + // } void setFixedInitNumber(int fixedInitNumber) { fixedInitNumber_ = fixedInitNumber; @@ -1320,7 +1320,7 @@ namespace ttk { std::stringstream energySequence; int minBarySize = std::numeric_limits::max(); int maxBarySize = 0; - while(not converged && NoIteration= 10); } - if(!useEarlyOut_) converged = false; + // if(!useEarlyOut_) converged = false; // --- Persistence scaling if(progressiveBarycenter_) { diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index 30df653bea..87f31122bb 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -373,7 +373,7 @@ int ttkMergeTreeClustering::runCompute( mergeTreeBarycenter.setPersistenceThreshold(PersistenceThreshold); mergeTreeBarycenter.setUseFixedInit(useFixedInit); mergeTreeBarycenter.setFixedInitNumber(fixedInitNumber); - mergeTreeBarycenter.setUseEarlyOut(useEarlyOut); + // mergeTreeBarycenter.setUseEarlyOut(useEarlyOut); mergeTreeBarycenter.setIterationLimit(iterationLimit); if(baseModule == 2) { mergeTreeBarycenter.setPathMetric(this->pathMetric); diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h index bb79c36d9e..854dcc42ac 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h @@ -99,7 +99,7 @@ class TTKMERGETREECLUSTERING_EXPORT ttkMergeTreeClustering bool useMedianBarycenter = false; bool useFixedInit = false; int fixedInitNumber = 0; - bool useEarlyOut = true; + // bool useEarlyOut = true; int iterationLimit = 100; double NonMatchingWeight = 1.0; @@ -376,18 +376,18 @@ class TTKMERGETREECLUSTERING_EXPORT ttkMergeTreeClustering resetDataVisualization(); } - void SetUseEarlyOut(bool eo) { - useEarlyOut = eo; - Modified(); - resetDataVisualization(); - } + // void SetUseEarlyOut(bool eo) { + // useEarlyOut = eo; + // Modified(); + // resetDataVisualization(); + // } void SetIterationLimit(int l) { iterationLimit = l; Modified(); resetDataVisualization(); } - + void SetNonMatchingWeight(double weight) { NonMatchingWeight = weight; Modified(); diff --git a/paraview/xmls/MergeTreeClustering.xml b/paraview/xmls/MergeTreeClustering.xml index a78ae4a127..09336f003e 100644 --- a/paraview/xmls/MergeTreeClustering.xml +++ b/paraview/xmls/MergeTreeClustering.xml @@ -251,7 +251,7 @@ Online examples: - - + --> - + From 07838785afb1e28742969fe7540d6e27660fa82d Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Thu, 18 Apr 2024 14:11:22 +0200 Subject: [PATCH 55/72] improved preprocessing in MergeTreeDistanceMatrix --- .../MergeTreeDistanceMatrix.h | 26 ++++++++++++++++--- .../ttkMergeTreeDistanceMatrix.cpp | 6 +++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h b/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h index f286e42eb6..70762d21a6 100644 --- a/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h +++ b/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h @@ -67,8 +67,22 @@ namespace ttk { void execute(std::vector> &trees, std::vector> &trees2, std::vector> &distanceMatrix) { + treesNodeCorr_.resize(trees.size()); + for(unsigned int i = 0; i < trees.size(); ++i){ + preprocessingPipeline(trees[i], epsilonTree2_, + epsilon2Tree2_, epsilon3Tree2_, + baseModule_==0?branchDecomposition_:false, useMinMaxPair_, + true, treesNodeCorr_[i],true,baseModule_==2); + } executePara(trees, distanceMatrix); if(trees2.size() != 0) { + std::vector> trees2NodeCorr(trees2.size()); + for(unsigned int i = 0; i < trees.size(); ++i){ + preprocessingPipeline(trees2[i], epsilonTree2_, + epsilon2Tree2_, epsilon3Tree2_, + baseModule_==0?branchDecomposition_:false, useMinMaxPair_, + true, treesNodeCorr_[i],true,baseModule_==2); + } useDoubleInput_ = true; std::vector> distanceMatrix2( trees2.size(), std::vector(trees2.size())); @@ -129,7 +143,9 @@ namespace ttk { mergeTreeDistance.setKeepSubtree(keepSubtree_); mergeTreeDistance.setDistanceSquaredRoot(distanceSquaredRoot_); mergeTreeDistance.setUseMinMaxPair(useMinMaxPair_); - mergeTreeDistance.setSaveTree(true); + mergeTreeDistance.setPreprocess(false); + // mergeTreeDistance.setSaveTree(true); + mergeTreeDistance.setSaveTree(false); mergeTreeDistance.setCleanTree(true); mergeTreeDistance.setIsCalled(true); mergeTreeDistance.setPostprocess(false); @@ -155,7 +171,9 @@ namespace ttk { branchDist.setEpsilon3Tree1(epsilon3Tree1_); branchDist.setEpsilon3Tree2(epsilon3Tree2_); branchDist.setPersistenceThreshold(persistenceThreshold_); - branchDist.setSaveTree(true); + branchDist.setPreprocess(false); + // branchDist.setSaveTree(true); + branchDist.setSaveTree(false); dataType dist = branchDist.execute( trees[i], trees[j]); distanceMatrix[i][j] = static_cast(dist); @@ -172,7 +190,9 @@ namespace ttk { pathDist.setEpsilon3Tree1(epsilon3Tree1_); pathDist.setEpsilon3Tree2(epsilon3Tree2_); pathDist.setPersistenceThreshold(persistenceThreshold_); - pathDist.setSaveTree(true); + pathDist.setPreprocess(false); + // pathDist.setSaveTree(true); + pathDist.setSaveTree(false); dataType dist = pathDist.execute( trees[i], trees[j]); distanceMatrix[i][j] = static_cast(dist); diff --git a/core/vtk/ttkMergeTreeDistanceMatrix/ttkMergeTreeDistanceMatrix.cpp b/core/vtk/ttkMergeTreeDistanceMatrix/ttkMergeTreeDistanceMatrix.cpp index a20a323cc6..cd37569c36 100644 --- a/core/vtk/ttkMergeTreeDistanceMatrix/ttkMergeTreeDistanceMatrix.cpp +++ b/core/vtk/ttkMergeTreeDistanceMatrix/ttkMergeTreeDistanceMatrix.cpp @@ -173,6 +173,9 @@ int ttkMergeTreeDistanceMatrix::run( metric = "Shifting cost"; else return 1; + epsilonTree2_ = epsilonTree1_; + epsilon2Tree2_ = epsilon2Tree1_; + epsilon3Tree2_ = epsilon3Tree1_; printMsg("BranchMetric: " + metric); } if(baseModule_ == 2) { @@ -182,6 +185,9 @@ int ttkMergeTreeDistanceMatrix::run( metric = "Persistence difference"; else return 1; + epsilonTree2_ = epsilonTree1_; + epsilon2Tree2_ = epsilon2Tree1_; + epsilon3Tree2_ = epsilon3Tree1_; printMsg("PathMetric: " + metric); } From 0875770846aa057d9320c1f7965acda29cc24df6 Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Thu, 25 Apr 2024 15:48:12 +0200 Subject: [PATCH 56/72] updated authors and publications in all edit distance related modules --- .../mergeTreeClustering/MergeTreeBarycenter.h | 7 ++++++ .../mergeTreeClustering/MergeTreeClustering.h | 7 ++++++ .../mergeTreeClustering/MergeTreeDistance.h | 5 +++++ .../MergeTreeDistanceMatrix.h | 22 +++++++++++++++++++ .../MergeTreeTemporalReduction.h | 7 ++++++ .../MergeTreeTemporalReductionDecoding.h | 7 ++++++ .../ttkMergeTreeClustering.h | 7 ++++++ .../ttkMergeTreeDistanceMatrix.h | 22 +++++++++++++++++++ .../ttkMergeTreeTemporalReduction.h | 7 ++++++ .../ttkMergeTreeTemporalReductionDecoding.h | 7 ++++++ 10 files changed, 98 insertions(+) diff --git a/core/base/mergeTreeClustering/MergeTreeBarycenter.h b/core/base/mergeTreeClustering/MergeTreeBarycenter.h index f823e076a1..c77942c00c 100644 --- a/core/base/mergeTreeClustering/MergeTreeBarycenter.h +++ b/core/base/mergeTreeClustering/MergeTreeBarycenter.h @@ -1,6 +1,7 @@ /// \ingroup base /// \class MergeTreeBarycenter /// \author Mathieu Pont (mathieu.pont@lip6.fr) +/// \author Florian Wetzels (wetzels@cs.uni-kl.de) /// \date 2021. /// /// This module defines the %MergeTreeBarycenter class that computes @@ -12,6 +13,12 @@ /// Proc. of IEEE VIS 2021.\n /// IEEE Transactions on Visualization and Computer Graphics, 2021 +/// \b Related \b publication \n +/// "Merge Tree Geodesics and Barycenters with Path Mappings" \n +/// F. Wetzels, M. Pont, J. Tierny and C. Garth.\n +/// Proc. of IEEE VIS 2023.\n +/// IEEE Transactions on Visualization and Computer Graphics, 2024 + #pragma once #include diff --git a/core/base/mergeTreeClustering/MergeTreeClustering.h b/core/base/mergeTreeClustering/MergeTreeClustering.h index ef05591a98..2e468b4d55 100644 --- a/core/base/mergeTreeClustering/MergeTreeClustering.h +++ b/core/base/mergeTreeClustering/MergeTreeClustering.h @@ -1,6 +1,7 @@ /// \ingroup base /// \class MergeTreeClustering /// \author Mathieu Pont (mathieu.pont@lip6.fr) +/// \author Florian Wetzels (wetzels@cs.uni-kl.de) /// \date 2021. /// /// This module defines the %MergeTreeClustering class that computes @@ -13,6 +14,12 @@ /// Mathieu Pont, Jules Vidal, Julie Delon, Julien Tierny.\n /// Proc. of IEEE VIS 2021.\n /// IEEE Transactions on Visualization and Computer Graphics, 2021 + +/// \b Related \b publication \n +/// "Merge Tree Geodesics and Barycenters with Path Mappings" \n +/// F. Wetzels, M. Pont, J. Tierny and C. Garth.\n +/// Proc. of IEEE VIS 2023.\n +/// IEEE Transactions on Visualization and Computer Graphics, 2024 /// /// \b Online \b examples: \n /// - +/// \author Florian Wetzels (wetzels@cs.uni-kl.de) /// \date 2021. /// /// This VTK filter uses the ttk::MergeTreeDistanceMatrix module to compute the /// distance matrix of a group of merge trees. /// +/// \b Related \b publication \n +/// "Wasserstein Distances, Geodesics and Barycenters of Merge Trees" \n +/// Mathieu Pont, Jules Vidal, Julie Delon, Julien Tierny.\n +/// Proc. of IEEE VIS 2021.\n +/// IEEE Transactions on Visualization and Computer Graphics, 2021 +/// +/// \b Related \b publication \n +/// "Edit Distance between Merge Trees" \n +/// R. Sridharamurthy, T. B. Masood, A. Kamakshidasan and V. Natarajan. \n +/// IEEE Transactions on Visualization and Computer Graphics, 2020. +/// +/// \b Related \b publication \n +/// "Branch Decomposition-Independent Edit Distances for Merge Trees." \n +/// Florian Wetzels, Heike Leitte, and Christoph Garth. \n +/// Computer Graphics Forum, 2022. +/// +/// \b Related \b publication \n +/// "A Deformation-based Edit Distance for Merge Trees" \n +/// Florian Wetzels, Christoph Garth. \n +/// TopoInVis 2022. +/// /// \b Online \b examples: \n /// - Merge diff --git a/core/base/mergeTreeTemporalReduction/MergeTreeTemporalReduction.h b/core/base/mergeTreeTemporalReduction/MergeTreeTemporalReduction.h index 81c0ea87f3..9bc33ab2d4 100644 --- a/core/base/mergeTreeTemporalReduction/MergeTreeTemporalReduction.h +++ b/core/base/mergeTreeTemporalReduction/MergeTreeTemporalReduction.h @@ -1,6 +1,7 @@ /// \ingroup base /// \class ttk::MergeTreeTemporalReduction /// \author Mathieu Pont (mathieu.pont@lip6.fr) +/// \author Florian Wetzels (wetzels@cs.uni-kl.de) /// \date 2021. /// /// This module defines the %MergeTreeTemporalReduction class that @@ -11,6 +12,12 @@ /// Mathieu Pont, Jules Vidal, Julie Delon, Julien Tierny.\n /// Proc. of IEEE VIS 2021.\n /// IEEE Transactions on Visualization and Computer Graphics, 2021 + +/// \b Related \b publication \n +/// "Merge Tree Geodesics and Barycenters with Path Mappings" \n +/// F. Wetzels, M. Pont, J. Tierny and C. Garth.\n +/// Proc. of IEEE VIS 2023.\n +/// IEEE Transactions on Visualization and Computer Graphics, 2024 /// /// \b Online \b examples: \n /// - +/// \author Florian Wetzels (wetzels@cs.uni-kl.de) /// \date 2021. /// /// \brief TTK VTK-filter that wraps the ttk::MergeTreeDistanceMatrix module. @@ -17,6 +18,27 @@ /// See the related ParaView example state files for usage examples within a /// VTK pipeline. /// +/// \b Related \b publication \n +/// "Wasserstein Distances, Geodesics and Barycenters of Merge Trees" \n +/// Mathieu Pont, Jules Vidal, Julie Delon, Julien Tierny.\n +/// Proc. of IEEE VIS 2021.\n +/// IEEE Transactions on Visualization and Computer Graphics, 2021 +/// +/// \b Related \b publication \n +/// "Edit Distance between Merge Trees" \n +/// R. Sridharamurthy, T. B. Masood, A. Kamakshidasan and V. Natarajan. \n +/// IEEE Transactions on Visualization and Computer Graphics, 2020. +/// +/// \b Related \b publication \n +/// "Branch Decomposition-Independent Edit Distances for Merge Trees." \n +/// Florian Wetzels, Heike Leitte, and Christoph Garth. \n +/// Computer Graphics Forum, 2022. +/// +/// \b Related \b publication \n +/// "A Deformation-based Edit Distance for Merge Trees" \n +/// Florian Wetzels, Christoph Garth. \n +/// TopoInVis 2022. +/// /// \sa ttk::MergeTreeDistanceMatrix /// \sa ttkAlgorithm /// diff --git a/core/vtk/ttkMergeTreeTemporalReduction/ttkMergeTreeTemporalReduction.h b/core/vtk/ttkMergeTreeTemporalReduction/ttkMergeTreeTemporalReduction.h index 9145a4b1be..a6646c4dce 100644 --- a/core/vtk/ttkMergeTreeTemporalReduction/ttkMergeTreeTemporalReduction.h +++ b/core/vtk/ttkMergeTreeTemporalReduction/ttkMergeTreeTemporalReduction.h @@ -1,6 +1,7 @@ /// \ingroup vtk /// \class ttkMergeTreeTemporalReduction /// \author Mathieu Pont (mathieu.pont@lip6.fr) +/// \author Florian Wetzels (wetzels@cs.uni-kl.de) /// \date 2021. /// /// \brief TTK VTK-filter that wraps the ttk::MergeTreeTemporalReduction @@ -27,6 +28,12 @@ /// Mathieu Pont, Jules Vidal, Julie Delon, Julien Tierny.\n /// Proc. of IEEE VIS 2021.\n /// IEEE Transactions on Visualization and Computer Graphics, 2021 + +/// \b Related \b publication \n +/// "Merge Tree Geodesics and Barycenters with Path Mappings" \n +/// F. Wetzels, M. Pont, J. Tierny and C. Garth.\n +/// Proc. of IEEE VIS 2023.\n +/// IEEE Transactions on Visualization and Computer Graphics, 2024 /// /// \b Online \b examples: \n /// - Date: Thu, 25 Apr 2024 15:59:23 +0200 Subject: [PATCH 57/72] clang-format --- .../BranchMappingDistance.h | 293 ++++++----- .../mergeTreeClustering/MergeTreeBarycenter.h | 497 +++++++++++------- core/base/mergeTreeClustering/MergeTreeBase.h | 10 +- .../mergeTreeClustering/MergeTreeClustering.h | 72 +-- .../mergeTreeClustering/PathMappingDistance.h | 139 +++-- .../MergeTreeDistanceMatrix.h | 26 +- .../MergeTreeTemporalReduction.h | 44 +- .../MergeTreeTemporalReductionDecoding.h | 41 +- .../ttkMergeTreeClustering.cpp | 2 +- .../ttkMergeTreeVisualization.h | 6 +- 10 files changed, 645 insertions(+), 485 deletions(-) diff --git a/core/base/mergeTreeClustering/BranchMappingDistance.h b/core/base/mergeTreeClustering/BranchMappingDistance.h index 827d978506..e5174cf3dc 100644 --- a/core/base/mergeTreeClustering/BranchMappingDistance.h +++ b/core/base/mergeTreeClustering/BranchMappingDistance.h @@ -216,9 +216,11 @@ namespace ttk { } template - dataType execute(ftm::MergeTree &mTree1, - ftm::MergeTree &mTree2, - std::vector> *outputMatching=nullptr) { + dataType execute( + ftm::MergeTree &mTree1, + ftm::MergeTree &mTree2, + std::vector> *outputMatching + = nullptr) { ftm::MergeTree mTree1Copy; ftm::MergeTree mTree2Copy; @@ -232,42 +234,47 @@ namespace ttk { ftm::FTMTree_MT *tree2 = &(mTree2Int.tree); // optional preprocessing - if(preprocess_){ + if(preprocess_) { treesNodeCorr_.resize(2); preprocessingPipeline( - mTree1Int, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, - false, useMinMaxPair_, cleanTree_, treesNodeCorr_[0],true,true); + mTree1Int, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, false, + useMinMaxPair_, cleanTree_, treesNodeCorr_[0], true, true); preprocessingPipeline( - mTree2Int, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, - false, useMinMaxPair_, cleanTree_, treesNodeCorr_[1],true,true); + mTree2Int, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, false, + useMinMaxPair_, cleanTree_, treesNodeCorr_[1], true, true); } - + tree1 = &(mTree1Int.tree); tree2 = &(mTree2Int.tree); - return computeDistance(tree1,tree2, outputMatching); + return computeDistance(tree1, tree2, outputMatching); } template - dataType computeDistance(ftm::FTMTree_MT *tree1, - ftm::FTMTree_MT *tree2, - std::vector> *outputMatching=nullptr) { + dataType computeDistance( + ftm::FTMTree_MT *tree1, + ftm::FTMTree_MT *tree2, + std::vector> *outputMatching + = nullptr) { // // optional preprocessing // if(preprocess_ && !writeOptimalBranchDecomposition_){ // treesNodeCorr_.resize(2); // preprocessingPipeline( // mTree1, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, - // branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[0],true,true); + // branchDecomposition_, useMinMaxPair_, cleanTree_, + // treesNodeCorr_[0],true,true); // preprocessingPipeline( // mTree2, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, - // branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[1],true,true); + // branchDecomposition_, useMinMaxPair_, cleanTree_, + // treesNodeCorr_[1],true,true); // } // ftm::FTMTree_MT *tree1 = (&mTree1.tree); // ftm::FTMTree_MT *tree2 = (&mTree2.tree); - - // compute preorder of both trees (necessary for bottom-up dynamic programming) + + // compute preorder of both trees (necessary for bottom-up dynamic + // programming) std::vector> predecessors1(tree1->getNumberOfNodes()); std::vector> predecessors2(tree2->getNumberOfNodes()); @@ -624,47 +631,68 @@ namespace ttk { dataType res = memT[children1[0] + 1 * dim2 + children2[0] * dim3 + 1 * dim4]; - - if(computeMapping_ && outputMatching){ + + if(computeMapping_ && outputMatching) { outputMatching->clear(); - std::vector matchedNodes(tree1->getNumberOfNodes(),-1); - std::vector,std::pair>> mapping; - std::vector linkedNodes1(tree1->getNumberOfNodes(),-1); - std::vector linkedNodes2(tree2->getNumberOfNodes(),-1); - traceMapping_branch(tree1,tree2,children1[0],1,children2[0],1,predecessors1,predecessors2,depth1,depth2,memT,mapping); - //dataType cost_mapping = 0; - for(auto m : mapping){ - if(writeOptimalBranchDecomposition_ && m.first.first >=0 && m.first.second >=0){ + std::vector matchedNodes(tree1->getNumberOfNodes(), -1); + std::vector, std::pair>> + mapping; + std::vector linkedNodes1(tree1->getNumberOfNodes(), -1); + std::vector linkedNodes2(tree2->getNumberOfNodes(), -1); + traceMapping_branch(tree1, tree2, children1[0], 1, children2[0], 1, + predecessors1, predecessors2, depth1, depth2, memT, + mapping); + // dataType cost_mapping = 0; + for(auto m : mapping) { + if(writeOptimalBranchDecomposition_ && m.first.first >= 0 + && m.first.second >= 0) { tree1->getNode(m.first.first)->setOrigin(m.first.second); tree1->getNode(m.first.second)->setOrigin(m.first.first); linkedNodes1[m.first.first] = m.first.second; linkedNodes1[m.first.second] = m.first.first; } - if(writeOptimalBranchDecomposition_ && m.second.first >=0 && m.second.second >=0){ + if(writeOptimalBranchDecomposition_ && m.second.first >= 0 + && m.second.second >= 0) { tree2->getNode(m.second.first)->setOrigin(m.second.second); tree2->getNode(m.second.second)->setOrigin(m.second.first); linkedNodes2[m.second.first] = m.second.second; linkedNodes2[m.second.second] = m.second.first; } - // dataType cost = this->baseMetric_ == 0 ? editCost_Wasserstein1( - // m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2) - // : this->baseMetric_ == 1 ? editCost_Wasserstein2( - // m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2) + // dataType cost = this->baseMetric_ == 0 ? + // editCost_Wasserstein1( + // m.first.first, m.first.second, m.second.first, + // m.second.second, tree1, tree2) + // : this->baseMetric_ == 1 ? + // editCost_Wasserstein2( + // m.first.first, m.first.second, m.second.first, + // m.second.second, tree1, tree2) // : this->baseMetric_ == 2 // ? editCost_Persistence( - // m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2) + // m.first.first, m.first.second, m.second.first, + // m.second.second, tree1, tree2) // : editCost_Shifting( - // m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2); + // m.first.first, m.first.second, m.second.first, + // m.second.second, tree1, tree2); // dataType cost_ = editCost_Wasserstein1( - // m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2); + // m.first.first, m.first.second, m.second.first, + // m.second.second, tree1, tree2); // cost_mapping += cost_; - //std::cout << "(" << m.first.first << " " << m.first.second << ") - (" << m.second.first << " " << m.second.second << ") : " << cost << " " << cost_;// << std::endl; - //std::cout << "; (" << tree1->getValue(m.first.first) << " " << tree1->getValue(m.first.second) << ") - (" << tree2->getValue(m.second.first) << " " << tree2->getValue(m.second.second) << ")" << std::endl; - if(m.first.first == -1) continue; - if(m.first.second == -1) continue; - if(m.second.first == -1) continue; - if(m.second.second == -1) continue; + // std::cout << "(" << m.first.first << " " << m.first.second << ") - + // (" << m.second.first << " " << m.second.second << ") : " << cost << + // " " << cost_;// << std::endl; std::cout << "; (" << + // tree1->getValue(m.first.first) << " " << + // tree1->getValue(m.first.second) << ") - (" << + // tree2->getValue(m.second.first) << " " << + // tree2->getValue(m.second.second) << ")" << std::endl; + if(m.first.first == -1) + continue; + if(m.first.second == -1) + continue; + if(m.second.first == -1) + continue; + if(m.second.second == -1) + continue; matchedNodes[m.first.first] = m.second.first; matchedNodes[m.first.second] = m.second.second; } @@ -676,12 +704,13 @@ namespace ttk { // for(int i=0; i=0) outputMatching->emplace_back(std::make_tuple(i,matchedNodes[i], 0.0)); + for(ftm::idNode i = 0; i < matchedNodes.size(); i++) { + if(matchedNodes[i] >= 0) + outputMatching->emplace_back( + std::make_tuple(i, matchedNodes[i], 0.0)); } - //std::cout << res << " " << cost_mapping << std::endl; - + // std::cout << res << " " << cost_mapping << std::endl; } return squared_ ? std::sqrt(res) : res; @@ -700,8 +729,8 @@ namespace ttk { int depth1, int depth2, std::vector &memT, - std::vector, - std::pair>> &mapping) { + std::vector, std::pair>> + &mapping) { int nn1 = tree1->getNumberOfNodes(); int nn2 = tree2->getNumberOfNodes(); @@ -713,7 +742,7 @@ namespace ttk { //=============================================================================== // If second tree empty, track optimal branch decomposition of first tree - if(curr2 == nn2){ + if(curr2 == nn2) { std::vector children1; tree1->getChildren(curr1, children1); int parent1 = predecessors1[curr1][predecessors1[curr1].size() - l1]; @@ -737,7 +766,7 @@ namespace ttk { } c_ += memT[child1 + 1 * dim2 + nn2 * dim3 + 0 * dim4]; } - if(c_ == memT[curr1 + l1 * dim2 + nn2 * dim3 + 0 * dim4]){ + if(c_ == memT[curr1 + l1 * dim2 + nn2 * dim3 + 0 * dim4]) { traceMapping_branch(tree1, tree2, child1_mb, (l1 + 1), nn2, 0, predecessors1, predecessors2, depth1, depth2, memT, mapping); @@ -746,8 +775,8 @@ namespace ttk { continue; } traceMapping_branch(tree1, tree2, child1, 1, nn2, 0, - predecessors1, predecessors2, depth1, depth2, - memT, mapping); + predecessors1, predecessors2, depth1, + depth2, memT, mapping); } return; } @@ -759,7 +788,7 @@ namespace ttk { //=============================================================================== // If first tree empty, track optimal branch decomposition of second tree - if(curr1 == nn1){ + if(curr1 == nn1) { std::vector children2; tree2->getChildren(curr2, children2); int parent2 = predecessors2[curr2][predecessors2[curr2].size() - l2]; @@ -783,8 +812,8 @@ namespace ttk { } c_ += memT[nn1 + 0 * dim2 + child2 * dim3 + 1 * dim4]; } - if(c_ == memT[nn1 + 0 * dim2 + curr2 * dim3 + l2 * dim4]){ - traceMapping_branch(tree1, tree2, nn1, 0, child2_mb, (l2+1), + if(c_ == memT[nn1 + 0 * dim2 + curr2 * dim3 + l2 * dim4]) { + traceMapping_branch(tree1, tree2, nn1, 0, child2_mb, (l2 + 1), predecessors1, predecessors2, depth1, depth2, memT, mapping); for(auto child2 : children2) { @@ -792,8 +821,8 @@ namespace ttk { continue; } traceMapping_branch(tree1, tree2, nn1, 0, child2, 1, - predecessors1, predecessors2, depth1, depth2, - memT, mapping); + predecessors1, predecessors2, depth1, + depth2, memT, mapping); } return; } @@ -801,7 +830,7 @@ namespace ttk { this->printErr("Mapping traceback not correct."); } } - + std::vector children1; tree1->getChildren(curr1, children1); std::vector children2; @@ -816,7 +845,7 @@ namespace ttk { // If both trees only have one branch, return edit cost between // the two branches if(tree1->getNumberOfChildren(curr1) == 0 - and tree2->getNumberOfChildren(curr2) == 0) { + and tree2->getNumberOfChildren(curr2) == 0) { mapping.emplace_back(std::make_pair( std::make_pair(curr1, parent1), std::make_pair(curr2, parent2))); return; @@ -826,16 +855,16 @@ namespace ttk { // second tree else if(children1.size() == 0) { for(auto child2_mb : children2) { - dataType d_ = memT[curr1 + l1 * dim2 + child2_mb * dim3 - + (l2 + 1) * dim4]; + dataType d_ + = memT[curr1 + l1 * dim2 + child2_mb * dim3 + (l2 + 1) * dim4]; for(auto child2 : children2) { if(child2 == child2_mb) { continue; } d_ += memT[nn1 + 0 * dim2 + child2 * dim3 + 1 * dim4]; } - if(d_ == memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4]){ - traceMapping_branch(tree1, tree2, curr1, l1, child2_mb, (l2+1), + if(d_ == memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4]) { + traceMapping_branch(tree1, tree2, curr1, l1, child2_mb, (l2 + 1), predecessors1, predecessors2, depth1, depth2, memT, mapping); for(auto child2 : children2) { @@ -855,15 +884,15 @@ namespace ttk { // first tree else if(children2.size() == 0) { for(auto child1_mb : children1) { - dataType d_ = memT[child1_mb + (l1 + 1) * dim2 + curr2 * dim3 - + l2 * dim4]; + dataType d_ + = memT[child1_mb + (l1 + 1) * dim2 + curr2 * dim3 + l2 * dim4]; for(auto child1 : children1) { if(child1 == child1_mb) { continue; } d_ += memT[child1 + 1 * dim2 + nn2 * dim3 + 0 * dim4]; } - if(d_ == memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4]){ + if(d_ == memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4]) { traceMapping_branch(tree1, tree2, child1_mb, (l1 + 1), curr2, l2, predecessors1, predecessors2, depth1, depth2, memT, mapping); @@ -892,75 +921,73 @@ namespace ttk { int child12 = children1[1]; int child21 = children2[0]; int child22 = children2[1]; - if(memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4] == - memT[child11 + (l1 + 1) * dim2 + child21 * dim3 + (l2 + 1) * dim4] - + memT[child12 + 1 * dim2 + child22 * dim3 + 1 * dim4]){ - - traceMapping_branch(tree1, tree2, child11, (l1 + 1), child21, (l2+1), - predecessors1, predecessors2, depth1, depth2, - memT, mapping); + if(memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4] + == memT[child11 + (l1 + 1) * dim2 + child21 * dim3 + + (l2 + 1) * dim4] + + memT[child12 + 1 * dim2 + child22 * dim3 + 1 * dim4]) { + + traceMapping_branch(tree1, tree2, child11, (l1 + 1), child21, + (l2 + 1), predecessors1, predecessors2, depth1, + depth2, memT, mapping); traceMapping_branch(tree1, tree2, child12, 1, child22, 1, predecessors1, predecessors2, depth1, depth2, memT, mapping); - + return; } - if(memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4] == - memT[child12 + (l1 + 1) * dim2 + child22 * dim3 + (l2 + 1) * dim4] - + memT[child11 + 1 * dim2 + child21 * dim3 + 1 * dim4]){ - - traceMapping_branch(tree1, tree2, child12, (l1 + 1), child22, (l2+1), - predecessors1, predecessors2, depth1, depth2, - memT, mapping); + if(memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4] + == memT[child12 + (l1 + 1) * dim2 + child22 * dim3 + + (l2 + 1) * dim4] + + memT[child11 + 1 * dim2 + child21 * dim3 + 1 * dim4]) { + + traceMapping_branch(tree1, tree2, child12, (l1 + 1), child22, + (l2 + 1), predecessors1, predecessors2, depth1, + depth2, memT, mapping); traceMapping_branch(tree1, tree2, child11, 1, child21, 1, predecessors1, predecessors2, depth1, depth2, memT, mapping); - - return; + return; } - if(memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4] == - memT[child11 + (l1 + 1) * dim2 + child22 * dim3 + (l2 + 1) * dim4] - + memT[child12 + 1 * dim2 + child21 * dim3 + 1 * dim4]){ - - traceMapping_branch(tree1, tree2, child11, (l1 + 1), child22, (l2+1), - predecessors1, predecessors2, depth1, depth2, - memT, mapping); + if(memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4] + == memT[child11 + (l1 + 1) * dim2 + child22 * dim3 + + (l2 + 1) * dim4] + + memT[child12 + 1 * dim2 + child21 * dim3 + 1 * dim4]) { + + traceMapping_branch(tree1, tree2, child11, (l1 + 1), child22, + (l2 + 1), predecessors1, predecessors2, depth1, + depth2, memT, mapping); traceMapping_branch(tree1, tree2, child12, 1, child21, 1, predecessors1, predecessors2, depth1, depth2, memT, mapping); - - return; + return; } - if(memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4] == - memT[child12 + (l1 + 1) * dim2 + child21 * dim3 + (l2 + 1) * dim4] - + memT[child11 + 1 * dim2 + child22 * dim3 + 1 * dim4]){ - - traceMapping_branch(tree1, tree2, child12, (l1 + 1), child21, (l2+1), - predecessors1, predecessors2, depth1, depth2, - memT, mapping); + if(memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4] + == memT[child12 + (l1 + 1) * dim2 + child21 * dim3 + + (l2 + 1) * dim4] + + memT[child11 + 1 * dim2 + child22 * dim3 + 1 * dim4]) { + + traceMapping_branch(tree1, tree2, child12, (l1 + 1), child21, + (l2 + 1), predecessors1, predecessors2, depth1, + depth2, memT, mapping); traceMapping_branch(tree1, tree2, child11, 1, child22, 1, predecessors1, predecessors2, depth1, depth2, memT, mapping); - - return; + return; } - } - else { + } else { for(auto child1_mb : children1) { std::vector topo1_; tree1->getChildren(curr1, topo1_); - topo1_.erase( - std::remove(topo1_.begin(), topo1_.end(), child1_mb), - topo1_.end()); + topo1_.erase(std::remove(topo1_.begin(), topo1_.end(), child1_mb), + topo1_.end()); for(auto child2_mb : children2) { std::vector topo2_; tree2->getChildren(curr2, topo2_); - topo2_.erase( - std::remove(topo2_.begin(), topo2_.end(), child2_mb), - topo2_.end()); + topo2_.erase(std::remove(topo2_.begin(), topo2_.end(), child2_mb), + topo2_.end()); auto f = [&](unsigned r, unsigned c) { int c1 = r < topo1_.size() ? topo1_[r] : -1; @@ -998,34 +1025,34 @@ namespace ttk { assignmentSolver->setInput(costMatrix); assignmentSolver->setBalanced(true); assignmentSolver->run(matching); - dataType d_ = memT[child1_mb + (l1 + 1) * dim2 - + child2_mb * dim3 + (l2 + 1) * dim4]; + dataType d_ = memT[child1_mb + (l1 + 1) * dim2 + child2_mb * dim3 + + (l2 + 1) * dim4]; for(auto m : matching) d_ += std::get<2>(m); - - if(d_ == memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4]){ - traceMapping_branch(tree1, tree2, child1_mb, (l1 + 1), child2_mb, (l2 + 1), - predecessors1, predecessors2, depth1, depth2, - memT, mapping); - for(auto m : matching){ + + if(d_ == memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4]) { + traceMapping_branch( + tree1, tree2, child1_mb, (l1 + 1), child2_mb, (l2 + 1), + predecessors1, predecessors2, depth1, depth2, memT, mapping); + for(auto m : matching) { int n1 = std::get<0>(m) < static_cast(topo1_.size()) - ? topo1_[std::get<0>(m)] - : -1; + ? topo1_[std::get<0>(m)] + : -1; int n2 = std::get<1>(m) < static_cast(topo2_.size()) - ? topo2_[std::get<1>(m)] - : -1; + ? topo2_[std::get<1>(m)] + : -1; if(n1 >= 0 && n2 >= 0) traceMapping_branch(tree1, tree2, n1, 1, n2, 1, - predecessors1, predecessors2, depth1, depth2, - memT, mapping); + predecessors1, predecessors2, depth1, + depth2, memT, mapping); else if(n1 >= 0) traceMapping_branch(tree1, tree2, n1, 1, nn2, 0, - predecessors1, predecessors2, depth1, depth2, - memT, mapping); + predecessors1, predecessors2, depth1, + depth2, memT, mapping); else if(n2 >= 0) traceMapping_branch(tree1, tree2, nn1, 0, n2, 1, - predecessors1, predecessors2, depth1, depth2, - memT, mapping); + predecessors1, predecessors2, depth1, + depth2, memT, mapping); } return; } @@ -1037,15 +1064,15 @@ namespace ttk { // delete all other subtrees Then match continued branch to // current branch in second tree for(auto child1_mb : children1) { - dataType d_ = memT[child1_mb + (l1 + 1) * dim2 + curr2 * dim3 - + l2 * dim4]; + dataType d_ + = memT[child1_mb + (l1 + 1) * dim2 + curr2 * dim3 + l2 * dim4]; for(auto child1 : children1) { if(child1 == child1_mb) { continue; } d_ += memT[child1 + 1 * dim2 + nn2 * dim3 + 0 * dim4]; } - if(memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4] == d_){ + if(memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4] == d_) { traceMapping_branch(tree1, tree2, child1_mb, (l1 + 1), curr2, l2, predecessors1, predecessors2, depth1, depth2, memT, mapping); @@ -1065,16 +1092,16 @@ namespace ttk { // delete all other subtrees Then match continued branch to // current branch in first tree for(auto child2_mb : children2) { - dataType d_ = memT[curr1 + l1 * dim2 + child2_mb * dim3 - + (l2 + 1) * dim4]; + dataType d_ + = memT[curr1 + l1 * dim2 + child2_mb * dim3 + (l2 + 1) * dim4]; for(auto child2 : children2) { if(child2 == child2_mb) { continue; } d_ += memT[nn1 + 0 * dim2 + child2 * dim3 + 1 * dim4]; } - if(memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4] == d_){ - traceMapping_branch(tree1, tree2, curr1, l1, child2_mb, (l2+1), + if(memT[curr1 + l1 * dim2 + curr2 * dim3 + l2 * dim4] == d_) { + traceMapping_branch(tree1, tree2, curr1, l1, child2_mb, (l2 + 1), predecessors1, predecessors2, depth1, depth2, memT, mapping); for(auto child2 : children2) { diff --git a/core/base/mergeTreeClustering/MergeTreeBarycenter.h b/core/base/mergeTreeClustering/MergeTreeBarycenter.h index c77942c00c..15ff980ce4 100644 --- a/core/base/mergeTreeClustering/MergeTreeBarycenter.h +++ b/core/base/mergeTreeClustering/MergeTreeBarycenter.h @@ -59,7 +59,7 @@ namespace ttk { bool preprocess_ = true; bool postprocess_ = true; - + int pathMetric_ = 0; int baseModule_ = 0; bool useMedianBarycenter_ = false; @@ -187,10 +187,13 @@ namespace ttk { for(unsigned int i = 0; i < trees.size(); ++i) for(unsigned int j = i + 1; j < trees.size(); ++j) { std::vector> matching; - std::vector,std::pair>> matching_path; + std::vector, + std::pair>> + matching_path; dataType distance; - computeOneDistance(trees[i], trees2[j], matching, matching_path, distance, - useDoubleInput, isFirstInput); + computeOneDistance(trees[i], trees2[j], matching, + matching_path, distance, useDoubleInput, + isFirstInput); distanceMatrix[i][j] = distance; distanceMatrix[j][i] = distance; } @@ -322,14 +325,17 @@ namespace ttk { ftm::MergeTree &baryTree, bool distMinimizer = true) { int bestIndex; - if(useFixedInit_){ - if(fixedInitNumber_ >= 0 && fixedInitNumber_ < (int) trees.size()) bestIndex = fixedInitNumber_; - else bestIndex = 0; - } - else bestIndex = getBestInitTreeIndex(trees, distMinimizer); + if(useFixedInit_) { + if(fixedInitNumber_ >= 0 && fixedInitNumber_ < (int)trees.size()) + bestIndex = fixedInitNumber_; + else + bestIndex = 0; + } else + bestIndex = getBestInitTreeIndex(trees, distMinimizer); // bestIndex = 10; - //baryTree = ftm::copyMergeTree(trees[bestIndex], true); - baryTree = ftm::copyMergeTree(trees[bestIndex], baseModule_!=2); + // baryTree = ftm::copyMergeTree(trees[bestIndex], true); + baryTree + = ftm::copyMergeTree(trees[bestIndex], baseModule_ != 2); // ftm::FTMTree_MT* bt = &(baryTree.tree); limitSizeBarycenter(baryTree, trees); } @@ -741,9 +747,10 @@ namespace ttk { std::vector &trees, ftm::MergeTree &baryMergeTree, std::vector &alphas, - std::vector,std::pair>>> + std::vector, + std::pair>>> &matchings) { - ftm::FTMTree_MT* baryTree = &(baryMergeTree.tree); + ftm::FTMTree_MT *baryTree = &(baryMergeTree.tree); double alphaSum = 0; for(unsigned int i = 0; i < trees.size(); ++i) alphaSum += alphas[i]; @@ -751,12 +758,13 @@ namespace ttk { int oldSize = baryTree->getNumberOfNodes(); // compute matched and unmatched nodes for all trees and barycenter - std::vector baryNodesMatched(baryTree->getNumberOfNodes(),false); + std::vector baryNodesMatched(baryTree->getNumberOfNodes(), false); std::vector> treeNodesMatched(trees.size()); - for(unsigned int i=0; igetNumberOfNodes(),false); - for(auto match : matchings[i]){ + for(unsigned int i = 0; i < trees.size(); i++) { + if(alphas[i] == 0) + continue; + treeNodesMatched[i].resize(trees[i]->getNumberOfNodes(), false); + for(auto match : matchings[i]) { baryNodesMatched[match.first.first] = true; baryNodesMatched[match.first.second] = true; treeNodesMatched[i][match.second.first] = true; @@ -765,37 +773,41 @@ namespace ttk { } // compute size of new barycenter tree int newSize = oldSize; - for(unsigned int i=0; i baryMergeTreeNew = ftm::createEmptyMergeTree(newSize); - //newScalars.resize(newSize); - //ftm::setTreeScalars(baryMergeTreeNew, newScalars); + // newScalars.resize(newSize); + // ftm::setTreeScalars(baryMergeTreeNew, newScalars); ftm::FTMTree_MT *baryTreeNew = &(baryMergeTreeNew.tree); // Copy the old tree structure baryTreeNew->copyMergeTreeStructure(baryTree); // delete not-matched nodes in barycenter - for(ftm::idNode i=0; igetNumberOfNodes(); i++){ - if(not baryNodesMatched[i]){ + for(ftm::idNode i = 0; i < baryTree->getNumberOfNodes(); i++) { + if(not baryNodesMatched[i]) { baryTreeNew->getNode(i)->setOrigin(-1); baryTreeNew->deleteNode(i); } } // relabel paths - std::vector> parentEdgeLengths(baryTree->getNumberOfNodes()); - for(unsigned int i=0; i> parentEdgeLengths( + baryTree->getNumberOfNodes()); + for(unsigned int i = 0; i < trees.size(); i++) { + if(alphas[i] == 0) + continue; auto tree = trees[i]; - for(auto match : matchings[i]){ + for(auto match : matchings[i]) { dataType bv1 = baryTree->getValue(match.first.first); dataType bv2 = baryTree->getValue(match.first.second); dataType tv1 = tree->getValue(match.second.first); @@ -804,13 +816,19 @@ namespace ttk { dataType pathRangeT = tv1 > tv2 ? tv1 - tv2 : tv2 - tv1; ftm::idNode currB = baryTreeNew->getParentSafe(match.first.first); ftm::idNode lastB = match.first.first; - while(lastB != match.first.second){ + while(lastB != match.first.second) { dataType currValueB = baryTree->getValue(currB); dataType lastValueB = baryTree->getValue(lastB); - dataType relativeValueB = lastValueB > currValueB ? lastValueB - currValueB : currValueB - lastValueB; - relativeValueB = relativeValueB/pathRangeB; - if(useMedianBarycenter_) parentEdgeLengths[lastB].emplace_back(relativeValueB * pathRangeT); - else parentEdgeLengths[lastB].emplace_back(relativeValueB * pathRangeT * alphas[i]); + dataType relativeValueB = lastValueB > currValueB + ? lastValueB - currValueB + : currValueB - lastValueB; + relativeValueB = relativeValueB / pathRangeB; + if(useMedianBarycenter_) + parentEdgeLengths[lastB].emplace_back(relativeValueB + * pathRangeT); + else + parentEdgeLengths[lastB].emplace_back(relativeValueB * pathRangeT + * alphas[i]); // continue iteration lastB = currB; currB = baryTreeNew->getParentSafe(currB); @@ -819,42 +837,50 @@ namespace ttk { } std::queue q; q.push(baryTreeNew->getRoot()); - //std::vector newScalars(baryTree->getNumberOfNodes(),0); - std::vector newScalars(newSize,0); - newScalars[baryTreeNew->getRoot()] = baryTree->getValue(baryTree->getRoot()); - while(!q.empty()){ + // std::vector newScalars(baryTree->getNumberOfNodes(),0); + std::vector newScalars(newSize, 0); + newScalars[baryTreeNew->getRoot()] + = baryTree->getValue(baryTree->getRoot()); + while(!q.empty()) { auto curr = q.front(); q.pop(); std::vector children; - baryTreeNew->getChildren(curr,children); - for(auto child : children){ + baryTreeNew->getChildren(curr, children); + for(auto child : children) { q.emplace(child); - if(useMedianBarycenter_){ - auto m = parentEdgeLengths[child].begin() + parentEdgeLengths[child].size()/2; - std::nth_element(parentEdgeLengths[child].begin(), m, parentEdgeLengths[child].end()); - auto medianEdgeLength = parentEdgeLengths[child][parentEdgeLengths[child].size()/2]; - newScalars[child] = newScalars[curr] + (joinTrees ? - medianEdgeLength : medianEdgeLength); - } - else{ + if(useMedianBarycenter_) { + auto m = parentEdgeLengths[child].begin() + + parentEdgeLengths[child].size() / 2; + std::nth_element(parentEdgeLengths[child].begin(), m, + parentEdgeLengths[child].end()); + auto medianEdgeLength + = parentEdgeLengths[child][parentEdgeLengths[child].size() / 2]; + newScalars[child] + = newScalars[curr] + + (joinTrees ? -medianEdgeLength : medianEdgeLength); + } else { dataType avgEdgeLength = 0; - for(auto l : parentEdgeLengths[child]){ + for(auto l : parentEdgeLengths[child]) { avgEdgeLength += l; } - //avgEdgeLength = avgEdgeLength/static_cast(trees.size()); - avgEdgeLength = avgEdgeLength/alphaSum; - newScalars[child] = newScalars[curr] + (joinTrees ? - avgEdgeLength : avgEdgeLength); + // avgEdgeLength = + // avgEdgeLength/static_cast(trees.size()); + avgEdgeLength = avgEdgeLength / alphaSum; + newScalars[child] + = newScalars[curr] + (joinTrees ? -avgEdgeLength : avgEdgeLength); } } } setTreeScalars(baryMergeTreeNew, newScalars); - + // insert new nodes int currSize = oldSize; - for(unsigned int i=0; i newIndices(tree->getNumberOfNodes(),-1); - for(auto match : matchings[i]){ + std::vector newIndices(tree->getNumberOfNodes(), -1); + for(auto match : matchings[i]) { dataType bv1 = baryTreeNew->getValue(match.first.first); dataType bv2 = baryTreeNew->getValue(match.first.second); dataType tv1 = tree->getValue(match.second.first); @@ -866,100 +892,128 @@ namespace ttk { ftm::idNode lastB = match.first.first; ftm::idNode lastT = match.second.first; ftm::idNode lastNode = lastB; - while(currB != match.first.second || currT != match.second.second){ + while(currB != match.first.second || currT != match.second.second) { dataType currValueB = baryTreeNew->getValue(currB); dataType currValueT = tree->getValue(currT); - dataType relativeValueB = bv1 > bv2 ? bv1 - currValueB : currValueB - bv1; - dataType relativeValueT = tv1 > tv2 ? tv1 - currValueT : currValueT - tv1; - relativeValueB = relativeValueB/pathRangeB; - relativeValueT = relativeValueT/pathRangeT; + dataType relativeValueB + = bv1 > bv2 ? bv1 - currValueB : currValueB - bv1; + dataType relativeValueT + = tv1 > tv2 ? tv1 - currValueT : currValueT - tv1; + relativeValueB = relativeValueB / pathRangeB; + relativeValueT = relativeValueT / pathRangeT; // if next node in barycenter, ignore - if(relativeValueB < relativeValueT){ + if(relativeValueB < relativeValueT) { // continue iteration lastB = currB; currB = baryTreeNew->getParentSafe(currB); lastNode = lastB; } // if next node in tree, add nodes - else if(relativeValueB > relativeValueT){ + else if(relativeValueB > relativeValueT) { q = std::queue(); std::vector currChildren; - tree->getChildren(currT,currChildren); - newIndices[currT] = currSize;//newScalars.size(); + tree->getChildren(currT, currChildren); + newIndices[currT] = currSize; // newScalars.size(); currSize++; ftm::idNode nI = newIndices[currT]; - //newScalars.emplace_back(tree->getValue(currT)); - //newScalars.emplace_back(bv1 + (joinTrees ? relativeValueT * pathRangeB : - relativeValueT * pathRangeB)); - newScalars[nI] = bv1 + (joinTrees ? relativeValueT * pathRangeB : - relativeValueT * pathRangeB); + // newScalars.emplace_back(tree->getValue(currT)); + // newScalars.emplace_back(bv1 + (joinTrees ? relativeValueT * + // pathRangeB : - relativeValueT * pathRangeB)); + newScalars[nI] = bv1 + + (joinTrees ? relativeValueT * pathRangeB + : -relativeValueT * pathRangeB); baryTreeNew->makeNode(nI); baryTreeNew->setParent(nI, currB); baryTreeNew->deleteParent(lastNode); baryTreeNew->setParent(lastNode, nI); baryTreeNew->getNode(nI)->setOrigin(-1); std::vector nodesWithoutLink; - //baryTreeNew->getNode(nI)->setOrigin(newIndices[tree->getNode(currT)->getOrigin()]); + // baryTreeNew->getNode(nI)->setOrigin(newIndices[tree->getNode(currT)->getOrigin()]); lastNode = newIndices[currT]; - for(auto child : currChildren){ - if(child==lastT) continue; + for(auto child : currChildren) { + if(child == lastT) + continue; q.emplace(child); - newIndices[child] = currSize;//newScalars.size(); + newIndices[child] = currSize; // newScalars.size(); currSize++; nI = newIndices[child]; - //newScalars.emplace_back(tree->getValue(child)); - dataType edgeLength = (joinTrees ? tree->getValue(currT) - tree->getValue(child) : tree->getValue(child) - tree->getValue(currT)); - //newScalars.emplace_back(newScalars[newIndices[currT]] + (joinTrees ? - edgeLength * (alphas[i]/alphaSum) : edgeLength * (alphas[i]/alphaSum))); - newScalars[nI] = newScalars[newIndices[currT]] + (joinTrees ? - edgeLength * (alphas[i]/alphaSum) : edgeLength * (alphas[i]/alphaSum)); + // newScalars.emplace_back(tree->getValue(child)); + dataType edgeLength + = (joinTrees ? tree->getValue(currT) + - tree->getValue(child) + : tree->getValue(child) + - tree->getValue(currT)); + // newScalars.emplace_back(newScalars[newIndices[currT]] + + // (joinTrees ? - edgeLength * (alphas[i]/alphaSum) : edgeLength + // * (alphas[i]/alphaSum))); + newScalars[nI] + = newScalars[newIndices[currT]] + + (joinTrees ? -edgeLength * (alphas[i] / alphaSum) + : edgeLength * (alphas[i] / alphaSum)); baryTreeNew->makeNode(nI); baryTreeNew->setParent(nI, newIndices[currT]); baryTreeNew->getNode(nI)->setOrigin(-1); - if(tree->getNumberOfChildren(child) == 0 && newIndices[tree->getNode(child)->getOrigin()] >= 0){ - ftm::idNode ln = newIndices[tree->getNode(child)->getOrigin()]; + if(tree->getNumberOfChildren(child) == 0 + && newIndices[tree->getNode(child)->getOrigin()] >= 0) { + ftm::idNode ln + = newIndices[tree->getNode(child)->getOrigin()]; baryTreeNew->getNode(nI)->setOrigin(ln); baryTreeNew->getNode(ln)->setOrigin(nI); - } - else{ + } else { nodesWithoutLink.push_back(nI); } } - while(!q.empty()){ + while(!q.empty()) { auto currNode = q.front(); q.pop(); currChildren.clear(); - tree->getChildren(currNode,currChildren); - for(auto child : currChildren){ + tree->getChildren(currNode, currChildren); + for(auto child : currChildren) { q.emplace(child); - newIndices[child] = currSize;//newScalars.size(); + newIndices[child] = currSize; // newScalars.size(); currSize++; nI = newIndices[child]; - //newScalars.emplace_back(tree->getValue(child)); - dataType edgeLength = (joinTrees ? tree->getValue(currNode) - tree->getValue(child) : tree->getValue(child) - tree->getValue(currNode)); - //newScalars.emplace_back(newScalars[newIndices[currNode]] + (joinTrees ? - edgeLength * (alphas[i]/alphaSum) : edgeLength * (alphas[i]/alphaSum))); - newScalars[nI] = newScalars[newIndices[currNode]] + (joinTrees ? - edgeLength * (alphas[i]/alphaSum) : edgeLength * (alphas[i]/alphaSum)); + // newScalars.emplace_back(tree->getValue(child)); + dataType edgeLength + = (joinTrees ? tree->getValue(currNode) + - tree->getValue(child) + : tree->getValue(child) + - tree->getValue(currNode)); + // newScalars.emplace_back(newScalars[newIndices[currNode]] + + // (joinTrees ? - edgeLength * (alphas[i]/alphaSum) : + // edgeLength * (alphas[i]/alphaSum))); + newScalars[nI] + = newScalars[newIndices[currNode]] + + (joinTrees ? -edgeLength * (alphas[i] / alphaSum) + : edgeLength * (alphas[i] / alphaSum)); baryTreeNew->makeNode(nI); baryTreeNew->getNode(nI)->setOrigin(-1); baryTreeNew->setParent(nI, newIndices[currNode]); - if(tree->getNumberOfChildren(child) == 0 && newIndices[tree->getNode(child)->getOrigin()] >= 0){ - ftm::idNode ln = newIndices[tree->getNode(child)->getOrigin()]; + if(tree->getNumberOfChildren(child) == 0 + && newIndices[tree->getNode(child)->getOrigin()] >= 0) { + ftm::idNode ln + = newIndices[tree->getNode(child)->getOrigin()]; baryTreeNew->getNode(nI)->setOrigin(ln); baryTreeNew->getNode(ln)->setOrigin(nI); - } - else{ + } else { nodesWithoutLink.push_back(nI); } } } - //std::cout << baryTreeNew->getNode(newIndices[currT])->getOrigin() << " " << nodesWithoutLink.size() << std::endl; - if(baryTreeNew->getNode(newIndices[currT])->getOrigin() < 0){ - baryTreeNew->getNode(newIndices[currT])->setOrigin(nodesWithoutLink[0]); + // std::cout << + // baryTreeNew->getNode(newIndices[currT])->getOrigin() << " " << + // nodesWithoutLink.size() << std::endl; + if(baryTreeNew->getNode(newIndices[currT])->getOrigin() < 0) { + baryTreeNew->getNode(newIndices[currT]) + ->setOrigin(nodesWithoutLink[0]); } - for(ftm::idNode n : nodesWithoutLink){ + for(ftm::idNode n : nodesWithoutLink) { baryTreeNew->getNode(n)->setOrigin(newIndices[currT]); } // continue iteration lastT = currT; currT = tree->getParentSafe(currT); - } - else{ + } else { // this should not happen printErr("Impossible Matching behaviour."); lastB = currB; @@ -969,10 +1023,10 @@ namespace ttk { } } } - setTreeScalars(baryMergeTreeNew,newScalars); + setTreeScalars(baryMergeTreeNew, newScalars); } - ftm::cleanMergeTree(baryMergeTreeNew,true); + ftm::cleanMergeTree(baryMergeTreeNew, true); baryMergeTree = baryMergeTreeNew; } @@ -996,8 +1050,9 @@ namespace ttk { // void computeOneDistance_pathMapping( // ftm::FTMTree_MT *tree, // ftm::FTMTree_MT *baryTree, - // std::vector,std::pair>> &matching, - // dataType &distance) { + // std::vector,std::pair>> &matching, dataType + // &distance) { // // Timer t_distance; // PathMappingDistance pathDistance; // pathDistance.setDebugLevel(std::min(debugLevel_, 2)); @@ -1015,12 +1070,14 @@ namespace ttk { ftm::FTMTree_MT *tree, ftm::FTMTree_MT *baryTree, std::vector> &matching, - std::vector,std::pair>> &matching_path, + std::vector, + std::pair>> + &matching_path, dataType &distance, bool useDoubleInput = false, bool isFirstInput = true) { // Timer t_distance; - if(baseModule_ == 2){ + if(baseModule_ == 2) { PathMappingDistance pathDistance; pathDistance.setDebugLevel(std::min(debugLevel_, 2)); pathDistance.setPreprocess(false); @@ -1028,10 +1085,9 @@ namespace ttk { pathDistance.setThreadNumber(this->threadNumber_); pathDistance.setDistanceSquaredRoot(false); // squared root pathDistance.setComputeMapping(true); - distance - = pathDistance.computeDistance(baryTree, tree, &matching_path); - } - else{ + distance = pathDistance.computeDistance( + baryTree, tree, &matching_path); + } else { MergeTreeDistance mergeTreeDistance; mergeTreeDistance.setDebugLevel(std::min(debugLevel_, 2)); mergeTreeDistance.setPreprocess(false); @@ -1052,8 +1108,8 @@ namespace ttk { mergeTreeDistance.setAuctionNoRounds(1); mergeTreeDistance.setAuctionEpsilonDiviser(NoIteration-1); }*/ - distance - = mergeTreeDistance.computeDistance(baryTree, tree, matching); + distance = mergeTreeDistance.computeDistance( + baryTree, tree, matching); } std::stringstream ss, ss2; ss << "distance tree : " << distance; @@ -1070,12 +1126,15 @@ namespace ttk { ftm::FTMTree_MT *tree, ftm::MergeTree &baryMergeTree, std::vector> &matching, - std::vector,std::pair>> &matching_path, + std::vector, + std::pair>> + &matching_path, dataType &distance, bool useDoubleInput = false, bool isFirstInput = true) { - computeOneDistance(tree, &(baryMergeTree.tree), matching, matching_path, - distance, useDoubleInput, isFirstInput); + computeOneDistance(tree, &(baryMergeTree.tree), matching, + matching_path, distance, useDoubleInput, + isFirstInput); } template @@ -1083,13 +1142,15 @@ namespace ttk { ftm::MergeTree &baryMergeTree, ftm::MergeTree &baryMergeTree2, std::vector> &matching, - std::vector,std::pair>> &matching_path, + std::vector, + std::pair>> + &matching_path, dataType &distance, bool useDoubleInput = false, bool isFirstInput = true) { computeOneDistance(&(baryMergeTree.tree), baryMergeTree2, - matching, matching_path, distance, useDoubleInput, - isFirstInput); + matching, matching_path, distance, + useDoubleInput, isFirstInput); } template @@ -1100,10 +1161,11 @@ namespace ttk { dataType &distance, bool useDoubleInput = false, bool isFirstInput = true) { - std::vector,std::pair>> matching_path; - computeOneDistance(tree, baryTree, - matching, matching_path, distance, useDoubleInput, - isFirstInput); + std::vector, + std::pair>> + matching_path; + computeOneDistance(tree, baryTree, matching, matching_path, + distance, useDoubleInput, isFirstInput); } template @@ -1114,9 +1176,12 @@ namespace ttk { dataType &distance, bool useDoubleInput = false, bool isFirstInput = true) { - std::vector,std::pair>> matching_path; - computeOneDistance(tree, &(baryMergeTree.tree), matching, matching_path, - distance, useDoubleInput, isFirstInput); + std::vector, + std::pair>> + matching_path; + computeOneDistance(tree, &(baryMergeTree.tree), matching, + matching_path, distance, useDoubleInput, + isFirstInput); } template @@ -1127,21 +1192,25 @@ namespace ttk { dataType &distance, bool useDoubleInput = false, bool isFirstInput = true) { - std::vector,std::pair>> matching_path; + std::vector, + std::pair>> + matching_path; computeOneDistance(&(baryMergeTree.tree), baryMergeTree2, - matching, matching_path, distance, useDoubleInput, - isFirstInput); + matching, matching_path, distance, + useDoubleInput, isFirstInput); } // template // void assignment_path( // std::vector &trees, // ftm::MergeTree &baryMergeTree, - // std::vector,std::pair>>> + // std::vector,std::pair>>> // &matchings, // std::vector &distances) { // for(unsigned int i = 0; i < trees.size(); ++i){ - // computeOneDistance_pathMapping(trees[i], &(baryMergeTree.tree), matchings[i], + // computeOneDistance_pathMapping(trees[i], + // &(baryMergeTree.tree), matchings[i], // distances[i]); // } // } @@ -1152,17 +1221,18 @@ namespace ttk { ftm::MergeTree &baryMergeTree, std::vector>> &matchings, - std::vector,std::pair>>> + std::vector, + std::pair>>> &matchings_path, std::vector &distances, bool useDoubleInput = false, bool isFirstInput = true) { if(not isCalled_) - assignmentPara(trees, baryMergeTree, matchings, matchings_path, distances, - useDoubleInput, isFirstInput); + assignmentPara(trees, baryMergeTree, matchings, matchings_path, + distances, useDoubleInput, isFirstInput); else - assignmentTask(trees, baryMergeTree, matchings, matchings_path, distances, - useDoubleInput, isFirstInput); + assignmentTask(trees, baryMergeTree, matchings, matchings_path, + distances, useDoubleInput, isFirstInput); } template @@ -1171,7 +1241,8 @@ namespace ttk { ftm::MergeTree &baryMergeTree, std::vector>> &matchings, - std::vector,std::pair>>> + std::vector, + std::pair>>> &matchings_path, std::vector &distances, bool useDoubleInput = false, @@ -1182,8 +1253,8 @@ namespace ttk { { #pragma omp single nowait #endif - assignmentTask(trees, baryMergeTree, matchings, matchings_path, distances, - useDoubleInput, isFirstInput); + assignmentTask(trees, baryMergeTree, matchings, matchings_path, + distances, useDoubleInput, isFirstInput); #ifdef TTK_ENABLE_OPENMP4 } // pragma omp parallel #endif @@ -1195,7 +1266,8 @@ namespace ttk { ftm::MergeTree &baryMergeTree, std::vector>> &matchings, - std::vector,std::pair>>> + std::vector, + std::pair>>> &matchings_path, std::vector &distances, bool useDoubleInput = false, @@ -1205,9 +1277,9 @@ namespace ttk { #pragma omp task firstprivate(i) UNTIED() \ shared(baryMergeTree, matchings, matchings_path, distances) #endif - computeOneDistance(trees[i], baryMergeTree, matchings[i],matchings_path[i], - distances[i], useDoubleInput, - isFirstInput); + computeOneDistance(trees[i], baryMergeTree, matchings[i], + matchings_path[i], distances[i], + useDoubleInput, isFirstInput); #ifdef TTK_ENABLE_OPENMP4 #pragma omp taskwait #endif @@ -1294,7 +1366,8 @@ namespace ttk { std::vector &alphas, std::vector>> &finalMatchings, - std::vector,std::pair>>> + std::vector, + std::pair>>> &finalMatchings_path, bool finalAsgnDoubleInput = false, bool finalAsgnFirstInput = true) { @@ -1327,7 +1400,8 @@ namespace ttk { std::stringstream energySequence; int minBarySize = std::numeric_limits::max(); int maxBarySize = 0; - while(not converged && (iterationLimit_<0 || NoIteration>> matchings(trees.size()); - std::vector,std::pair>>> + std::vector, + std::pair>>> matchings_path(trees.size()); std::vector distances(trees.size(), -1); Timer t_assignment; // if(baseModule_ == 2){ - // assignment_path(trees, baryMergeTree, matchings_path, distances); + // assignment_path(trees, baryMergeTree, matchings_path, + // distances); // } // else{ // assignment(trees, baryMergeTree, matchings, distances); // } - assignment(trees, baryMergeTree, matchings, matchings_path, distances); + assignment( + trees, baryMergeTree, matchings, matchings_path, distances); Timer t_addDeletedNodes; if(progressiveBarycenter_) addScaledDeletedNodesCost( @@ -1361,11 +1438,12 @@ namespace ttk { // --- Update Timer t_update; - if(baseModule_ == 2){ - updateBarycenterTree_path(trees, baryMergeTree, alphas, matchings_path); - } - else{ - updateBarycenterTree(trees, baryMergeTree, alphas, matchings); + if(baseModule_ == 2) { + updateBarycenterTree_path( + trees, baryMergeTree, alphas, matchings_path); + } else { + updateBarycenterTree( + trees, baryMergeTree, alphas, matchings); } auto t_update_time = t_update.getElapsedTime(); baryTree = &(baryMergeTree.tree); @@ -1375,7 +1453,7 @@ namespace ttk { // --- Check convergence dataType currentFrechetEnergy = 0; dataType currentFrechetEnergy2 = 0; - for(unsigned int i = 0; i < trees.size(); ++i){ + for(unsigned int i = 0; i < trees.size(); ++i) { currentFrechetEnergy2 += alphas[i] * distances[i]; currentFrechetEnergy += alphas[i] * distances[i] * distances[i]; } @@ -1391,14 +1469,16 @@ namespace ttk { auto barycenterTime = t_bary.getElapsedTime() - addDeletedNodesTime_; printMsg("Total", 1, barycenterTime, this->threadNumber_, debug::LineMode::NEW, debug::Priority::INFO); - printBaryStats(baryTree,debug::Priority::INFO); + printBaryStats(baryTree, debug::Priority::INFO); ss4 << "Frechet energy : " << frechetEnergy; ss5 << "Frechet energy non-squared: " << currentFrechetEnergy2; printMsg(ss4.str()); printMsg(ss5.str()); - if((int) baryTree->getNumberOfNodes() > maxBarySize) maxBarySize = baryTree->getNumberOfNodes(); - if((int)baryTree->getNumberOfNodes() < minBarySize) minBarySize = baryTree->getNumberOfNodes(); + if((int)baryTree->getNumberOfNodes() > maxBarySize) + maxBarySize = baryTree->getNumberOfNodes(); + if((int)baryTree->getNumberOfNodes() < minBarySize) + minBarySize = baryTree->getNumberOfNodes(); minFrechet = std::min(minFrechet, frechetEnergy); if(not converged and (not progressiveBarycenter_ or treesUnscaled)) { @@ -1425,37 +1505,42 @@ namespace ttk { printMsg("Final assignment"); std::vector distances(trees.size(), -1); - if(baseModule_ == 2){ - std::vector,std::pair>>> + if(baseModule_ == 2) { + std::vector, + std::pair>>> matchings_path(trees.size()); std::vector>> matchings; - // assignment_path(trees, baryMergeTree, matchings_path, distances); - assignment(trees, baryMergeTree, matchings, matchings_path, distances); + // assignment_path(trees, baryMergeTree, matchings_path, + // distances); + assignment( + trees, baryMergeTree, matchings, matchings_path, distances); finalMatchings_path = matchings_path; - for(unsigned int i=0; i matchedNodes(trees[i]->getNumberOfNodes(),-1); - for(auto m : matchings_path[i]){ + std::vector matchedNodes(trees[i]->getNumberOfNodes(), -1); + for(auto m : matchings_path[i]) { matchedNodes[m.second.first] = m.first.first; matchedNodes[m.second.second] = m.first.second; } - for(ftm::idNode j=0; j=0) finalMatchings[i].emplace_back(std::make_tuple(matchedNodes[j],j, 0.0)); + for(ftm::idNode j = 0; j < matchedNodes.size(); j++) { + if(matchedNodes[j] >= 0) + finalMatchings[i].emplace_back( + std::make_tuple(matchedNodes[j], j, 0.0)); } } - } - else{ - assignment(trees, baryMergeTree, finalMatchings, finalMatchings_path, distances, + } else { + assignment(trees, baryMergeTree, finalMatchings, + finalMatchings_path, distances, finalAsgnDoubleInput, finalAsgnFirstInput); } for(auto dist : distances) finalDistances_.push_back(dist); dataType currentFrechetEnergy = 0; dataType currentFrechetEnergy2 = 0; - for(unsigned int i = 0; i < trees.size(); ++i){ - currentFrechetEnergy2 += alphas[i] * distances[i]; - currentFrechetEnergy += alphas[i] * distances[i] * distances[i]; + for(unsigned int i = 0; i < trees.size(); ++i) { + currentFrechetEnergy2 += alphas[i] * distances[i]; + currentFrechetEnergy += alphas[i] * distances[i] * distances[i]; } auto barycenterTime = t_bary.getElapsedTime() - addDeletedNodesTime_; @@ -1470,15 +1555,15 @@ namespace ttk { std::stringstream ssIt; ssIt << "Number of iterations: " << NoIteration; - printMsg(ssIt.str(),debug::Priority::PERFORMANCE); + printMsg(ssIt.str(), debug::Priority::PERFORMANCE); std::stringstream ssMin; ssMin << "Min barycenter bize: " << minBarySize; - printMsg(ssMin.str(),debug::Priority::PERFORMANCE); + printMsg(ssMin.str(), debug::Priority::PERFORMANCE); std::stringstream ssMax; ssMax << "Max barycenter bize: " << maxBarySize; - printMsg(ssMax.str(),debug::Priority::PERFORMANCE); + printMsg(ssMax.str(), debug::Priority::PERFORMANCE); - if(trees.size() == 2 and not isCalled_ && baseModule_!=2) + if(trees.size() == 2 and not isCalled_ && baseModule_ != 2) verifyBarycenterTwoTrees( trees, baryMergeTree, finalMatchings, distances); @@ -1496,7 +1581,8 @@ namespace ttk { std::vector &alphas, std::vector>> &finalMatchings, - std::vector,std::pair>>> + std::vector, + std::pair>>> &finalMatchings_path, ftm::MergeTree &baryMergeTree, bool finalAsgnDoubleInput = false, @@ -1504,11 +1590,11 @@ namespace ttk { // --- Preprocessing if(preprocess_) { treesNodeCorr_.resize(trees.size()); - for(unsigned int i = 0; i < trees.size(); ++i){ - preprocessingPipeline(trees[i], epsilonTree2_, - epsilon2Tree2_, epsilon3Tree2_, - branchDecomposition_, useMinMaxPair_, - cleanTree_, treesNodeCorr_[i], true, baseModule_==2); + for(unsigned int i = 0; i < trees.size(); ++i) { + preprocessingPipeline( + trees[i], epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, + branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[i], + true, baseModule_ == 2); } printTreesStats(trees); } @@ -1519,15 +1605,16 @@ namespace ttk { initBarycenterTree(treesT, baryMergeTree); // --- Execute - computeBarycenter(treesT, baryMergeTree, alphas, finalMatchings, finalMatchings_path, - finalAsgnDoubleInput, finalAsgnFirstInput); - - if(baseModule_==2){ - ftm::FTMTree_MT* baryTree = &(baryMergeTree.tree); - for(ftm::idNode node=0; nodegetNumberOfNodes(); node++){ + computeBarycenter(treesT, baryMergeTree, alphas, finalMatchings, + finalMatchings_path, finalAsgnDoubleInput, + finalAsgnFirstInput); + + if(baseModule_ == 2) { + ftm::FTMTree_MT *baryTree = &(baryMergeTree.tree); + for(ftm::idNode node = 0; node < baryTree->getNumberOfNodes(); node++) { baryTree->getNode(node)->setOrigin(-1); } - preprocessTree(baryTree,false); + preprocessTree(baryTree, false); } // --- Postprocessing @@ -1555,17 +1642,13 @@ namespace ttk { ftm::MergeTree &baryMergeTree, bool finalAsgnDoubleInput = false, bool finalAsgnFirstInput = true) { - - std::vector,std::pair>>> - finalMatchings_path; - execute(trees, - alphas, - finalMatchings, - finalMatchings_path, - baryMergeTree, - finalAsgnDoubleInput, - finalAsgnFirstInput); + std::vector, + std::pair>>> + finalMatchings_path; + execute(trees, alphas, finalMatchings, finalMatchings_path, + baryMergeTree, finalAsgnDoubleInput, + finalAsgnFirstInput); } template @@ -1573,7 +1656,8 @@ namespace ttk { std::vector> &trees, std::vector>> &finalMatchings, - std::vector,std::pair>>> + std::vector, + std::pair>>> &finalMatchings_path, ftm::MergeTree &baryMergeTree, bool finalAsgnDoubleInput = false, @@ -1587,8 +1671,9 @@ namespace ttk { alphas.push_back(1 - alpha_); } - execute(trees, alphas, finalMatchings, finalMatchings_path, baryMergeTree, - finalAsgnDoubleInput, finalAsgnFirstInput); + execute(trees, alphas, finalMatchings, finalMatchings_path, + baryMergeTree, finalAsgnDoubleInput, + finalAsgnFirstInput); } template @@ -1608,11 +1693,13 @@ namespace ttk { alphas.push_back(1 - alpha_); } - std::vector,std::pair>>> + std::vector, + std::pair>>> finalMatchings_path; - execute(trees, alphas, finalMatchings, finalMatchings_path, baryMergeTree, - finalAsgnDoubleInput, finalAsgnFirstInput); + execute(trees, alphas, finalMatchings, finalMatchings_path, + baryMergeTree, finalAsgnDoubleInput, + finalAsgnFirstInput); } // ------------------------------------------------------------------------ @@ -1716,7 +1803,9 @@ namespace ttk { &finalMatchings, std::vector distances) { std::vector> matching; - std::vector,std::pair>> matching_path; + std::vector, + std::pair>> + matching_path; dataType distance; computeOneDistance(trees[0], trees[1], matching, matching_path, distance); if(distance != (distances[0] + distances[1])) { diff --git a/core/base/mergeTreeClustering/MergeTreeBase.h b/core/base/mergeTreeClustering/MergeTreeBase.h index abadbe704d..d13463307a 100644 --- a/core/base/mergeTreeClustering/MergeTreeBase.h +++ b/core/base/mergeTreeClustering/MergeTreeBase.h @@ -651,11 +651,11 @@ namespace ttk { std::vector> treeNodeMerged( tree->getNumberOfNodes()); if(not isPersistenceDiagram_ or convertToDiagram_) { - if(epsilonTree != 0){ + if(epsilonTree != 0) { mergeSaddle(tree, epsilonTree, treeNodeMerged); - if(removeMergedSaddles){ - for(unsigned int j=0; jgetNode(k)->getOrigin(); tree->getNode(k)->setOrigin(j); tree->getNode(nodeToDelete)->setOrigin(-1); @@ -1305,7 +1305,7 @@ namespace ttk { std::stringstream ss; ss << trees.size() << " trees average [node: " << avgNodes << " / " << avgNodesT << ", depth: " << avgDepth << "]"; - printMsg(ss.str(),debug::Priority::PERFORMANCE); + printMsg(ss.str(), debug::Priority::PERFORMANCE); } template diff --git a/core/base/mergeTreeClustering/MergeTreeClustering.h b/core/base/mergeTreeClustering/MergeTreeClustering.h index 2e468b4d55..caeb0ffab4 100644 --- a/core/base/mergeTreeClustering/MergeTreeClustering.h +++ b/core/base/mergeTreeClustering/MergeTreeClustering.h @@ -158,12 +158,12 @@ namespace ttk { "Init index : " + std::to_string(bestIndex), debug::Priority::DETAIL); // Create new centroid allCentroids[0][i] - = ftm::copyMergeTree(trees[bestIndex], baseModule_!=2); + = ftm::copyMergeTree(trees[bestIndex], baseModule_ != 2); limitSizeBarycenter(allCentroids[0][i], trees, limitPercent); ftm::cleanMergeTree(allCentroids[0][i]); if(trees2.size() != 0) { allCentroids[1][i] - = ftm::copyMergeTree(trees2[bestIndex], baseModule_!=2); + = ftm::copyMergeTree(trees2[bestIndex], baseModule_ != 2); limitSizeBarycenter(allCentroids[1][i], trees2, limitPercent); ftm::cleanMergeTree(allCentroids[1][i]); } @@ -205,7 +205,8 @@ namespace ttk { distancesAndIndexes[i] = std::make_tuple(-bestDistance_[i], i); std::sort(distancesAndIndexes.begin(), distancesAndIndexes.end()); int const bestIndex = std::get<1>(distancesAndIndexes[noNewCentroid]); - centroid = ftm::copyMergeTree(trees[bestIndex], baseModule_!=2); + centroid + = ftm::copyMergeTree(trees[bestIndex], baseModule_ != 2); limitSizeBarycenter(centroid, trees); ftm::cleanMergeTree(centroid); } @@ -444,34 +445,40 @@ namespace ttk { std::vector distances(assignedTrees[i].size(), 0); std::vector distances2(assignedTrees[i].size(), 0); treesMatchingVector matching(trees.size()), matching2(trees2.size()); - std::vector,std::pair>>> matching_path(trees.size()); - if(baseModule_ == 2){ + std::vector, + std::pair>>> + matching_path(trees.size()); + if(baseModule_ == 2) { // assignment_path( // assignedTrees[i], centroids[i], matching_path, distances); assignment( assignedTrees[i], centroids[i], matching, matching_path, distances); - for(unsigned int j=0; j matchedNodes(assignedTrees[i][j]->getNumberOfNodes(),-1); - for(auto m : matching_path[j]){ + for(unsigned int j = 0; j < assignedTrees[i].size(); j++) { + std::vector matchedNodes( + assignedTrees[i][j]->getNumberOfNodes(), -1); + for(auto m : matching_path[j]) { matchedNodes[m.second.first] = m.first.first; matchedNodes[m.second.second] = m.first.second; } - for(ftm::idNode k=0; k=0) matching[j].emplace_back(std::make_tuple(matchedNodes[k],k, 0.0)); + for(ftm::idNode k = 0; k < matchedNodes.size(); k++) { + if(matchedNodes[k] >= 0) + matching[j].emplace_back( + std::make_tuple(matchedNodes[k], k, 0.0)); } } matchingsC[i] = matching; - } - else{ - assignment( - assignedTrees[i], centroids[i], matching, matching_path, distances, useDoubleInput_); + } else { + assignment(assignedTrees[i], centroids[i], matching, + matching_path, distances, useDoubleInput_); matchingsC[i] = matching; if(trees2.size() != 0) { - assignment(assignedTrees2[i], centroids2[i], matching2, matching_path, - distances2, useDoubleInput_, false); + assignment(assignedTrees2[i], centroids2[i], matching2, + matching_path, distances2, useDoubleInput_, + false); matchingsC2[i] = matching2; for(unsigned int j = 0; j < assignedTreesIndex[i].size(); ++j) - distances[j] = mixDistances(distances[j], distances2[j]); + distances[j] + = mixDistances(distances[j], distances2[j]); } } for(unsigned int j = 0; j < assignedTreesIndex[i].size(); ++j) { @@ -601,8 +608,8 @@ namespace ttk { for(unsigned int t = 0; t < trees.size(); ++t) lowerBound_[t][i] = 0; } else if(assignedTrees[i].size() == 1) { - centroids[i] - = ftm::copyMergeTree(assignedTrees[i][0], baseModule_!=2); + centroids[i] = ftm::copyMergeTree( + assignedTrees[i][0], baseModule_ != 2); limitSizeBarycenter(centroids[i], assignedTrees[i]); ftm::cleanMergeTree(centroids[i]); } else if(not samePreviousAssignment(i)) { @@ -656,7 +663,7 @@ namespace ttk { barycenterMaximumNumberOfPairs_); mergeTreeBary.setBarycenterSizeLimitPercent(barycenterSizeLimitPercent_); - if(baseModule_==2){ + if(baseModule_ == 2) { mergeTreeBary.setPathMetric(this->pathMetric_); mergeTreeBary.setBranchDecomposition(false); mergeTreeBary.setNormalizedWasserstein(false); @@ -664,8 +671,7 @@ namespace ttk { // mergeTreeBary.setUseMinMaxPair(true); mergeTreeBary.setAddNodes(false); mergeTreeBary.setPostprocess(false); - } - else{ + } else { mergeTreeBary.setBranchDecomposition(true); mergeTreeBary.setNormalizedWasserstein(normalizedWasserstein_); // mergeTreeBary.setNormalizedWassersteinReg(normalizedWassersteinReg_); @@ -674,19 +680,20 @@ namespace ttk { mergeTreeBary.setProgressiveBarycenter(progressiveBarycenter_); } - std::vector,std::pair>>> + std::vector, + std::pair>>> finalMatchings_path; mergeTreeBary.computeBarycenter( trees, baryMergeTree, alphas, finalMatchings, finalMatchings_path); addDeletedNodesTime_ += mergeTreeBary.getAddDeletedNodesTime(); - - if(baseModule_==2){ - ftm::FTMTree_MT* baryTree = &(baryMergeTree.tree); - for(ftm::idNode node=0; nodegetNumberOfNodes(); node++){ + + if(baseModule_ == 2) { + ftm::FTMTree_MT *baryTree = &(baryMergeTree.tree); + for(ftm::idNode node = 0; node < baryTree->getNumberOfNodes(); node++) { baryTree->getNode(node)->setOrigin(-1); } - preprocessTree(baryTree,false); + preprocessTree(baryTree, false); } } @@ -852,7 +859,7 @@ namespace ttk { outputMatching2); // --- Postprocessing - if(baseModule_==0 && postprocess_) { + if(baseModule_ == 0 && postprocess_) { // fixMergedRootOriginClustering(centroids); postprocessingClustering( trees, centroids, outputMatching, clusteringAssignment); @@ -902,9 +909,10 @@ namespace ttk { std::vector> &nodeCorr, bool useMinMaxPairT = true) { for(unsigned int i = 0; i < trees.size(); ++i) { - preprocessingPipeline( - trees[i], epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, - branchDecomposition_, useMinMaxPairT, cleanTree_, nodeCorr[i],true,baseModule_==2); + preprocessingPipeline(trees[i], epsilonTree2_, epsilon2Tree2_, + epsilon3Tree2_, branchDecomposition_, + useMinMaxPairT, cleanTree_, nodeCorr[i], + true, baseModule_ == 2); if(trees.size() < 40) printTreeStats(trees[i]); } diff --git a/core/base/mergeTreeClustering/PathMappingDistance.h b/core/base/mergeTreeClustering/PathMappingDistance.h index c5f22cb96e..878cb57f4f 100644 --- a/core/base/mergeTreeClustering/PathMappingDistance.h +++ b/core/base/mergeTreeClustering/PathMappingDistance.h @@ -345,11 +345,15 @@ namespace ttk { } template - dataType computeDistance(ftm::FTMTree_MT *tree1, - ftm::FTMTree_MT *tree2, - std::vector,std::pair>> *outputMatching) { + dataType computeDistance( + ftm::FTMTree_MT *tree1, + ftm::FTMTree_MT *tree2, + std::vector, + std::pair>> + *outputMatching) { - // compute preorder of both trees (necessary for bottom-up dynamic programming) + // compute preorder of both trees (necessary for bottom-up dynamic + // programming) std::vector> predecessors1(tree1->getNumberOfNodes()); std::vector> predecessors2(tree2->getNumberOfNodes()); @@ -409,7 +413,8 @@ namespace ttk { size_t const dim3 = (depth1 + 1) * dim2; size_t const dim4 = (nn2 + 1) * dim3; - //std::cout << (nn1 + 1) * (depth1 + 1) * (nn2 + 1) * (depth2 + 1) * sizeof(dataType) << std::endl; + // std::cout << (nn1 + 1) * (depth1 + 1) * (nn2 + 1) * (depth2 + 1) * + // sizeof(dataType) << std::endl; std::vector memT((nn1 + 1) * (depth1 + 1) * (nn2 + 1) * (depth2 + 1)); @@ -639,10 +644,12 @@ namespace ttk { dataType res = memT[children1[0] + 1 * dim2 + children2[0] * dim3 + 1 * dim4]; - if(computeMapping_ && outputMatching){ + if(computeMapping_ && outputMatching) { outputMatching->clear(); - traceMapping_path(tree1,tree2,children1[0],1,children2[0],1,predecessors1,predecessors2,depth1,depth2,memT,*outputMatching); + traceMapping_path(tree1, tree2, children1[0], 1, children2[0], 1, + predecessors1, predecessors2, depth1, depth2, memT, + *outputMatching); // dataType cost_mapping = 0; // dataType cost_ins = 0; @@ -665,27 +672,34 @@ namespace ttk { // cn = tree2->getParentSafe(cn); // } // dataType cost = editCost_Persistence( - // m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2); + // m.first.first, m.first.second, m.second.first, + // m.second.second, tree1, tree2); // cost_mapping += cost; - // // std::cout << " (" << m.first.first << " " << m.first.second << ") - (" << m.second.first << " " << m.second.second << ") : " << cost << "\n"; + // // std::cout << " (" << m.first.first << " " << m.first.second << + // ") - (" << m.second.first << " " << m.second.second << ") : " << + // cost << "\n"; // } // for(ftm::idNode i=0; igetNumberOfNodes(); i++){ // if(!matchedNodes1[i]){ - // dataType cost = editCost_Persistence(i, tree1->getParentSafe(i), -1, -1, tree1, tree2); - // // std::cout << " (" << i << " " << tree1->getParentSafe(i) << ") - (" << -1 << " " << -1 << ") : " << cost << "\n"; - // cost_del += cost; + // dataType cost = editCost_Persistence(i, + // tree1->getParentSafe(i), -1, -1, tree1, tree2); + // // std::cout << " (" << i << " " << tree1->getParentSafe(i) << + // ") - (" << -1 << " " << -1 << ") : " << cost << "\n"; cost_del += + // cost; // } // } // for(ftm::idNode i=0; igetNumberOfNodes(); i++){ // if(!matchedNodes2[i]){ - // dataType cost = editCost_Persistence(-1, -1, i, tree2->getParentSafe(i), tree1, tree2); - // // std::cout << " (" << -1 << " " << -1 << ") - (" << i << " " << tree2->getParentSafe(i) << ") : " << cost << "\n"; - // cost_ins += cost; + // dataType cost = editCost_Persistence(-1, -1, i, + // tree2->getParentSafe(i), tree1, tree2); + // // std::cout << " (" << -1 << " " << -1 << ") - (" << i << " " + // << tree2->getParentSafe(i) << ") : " << cost << "\n"; cost_ins += + // cost; // } // } - // // std::cout << res << " " << cost_mapping+cost_ins+cost_del << std::endl; + // // std::cout << res << " " << cost_mapping+cost_ins+cost_del << + // std::endl; // // std::cout << res << " " << cost_mapping << std::endl; - } return squared_ ? std::sqrt(res) : res; @@ -693,9 +707,11 @@ namespace ttk { template dataType execute(ftm::MergeTree &mTree1, - ftm::MergeTree &mTree2, - std::vector,std::pair>> *outputMatching) { - + ftm::MergeTree &mTree2, + std::vector, + std::pair>> + *outputMatching) { + ftm::MergeTree mTree1Copy; ftm::MergeTree mTree2Copy; if(saveTree_) { @@ -706,50 +722,60 @@ namespace ttk { ftm::MergeTree &mTree2Int = (saveTree_ ? mTree2Copy : mTree2); ftm::FTMTree_MT *tree1 = &(mTree1Int.tree); ftm::FTMTree_MT *tree2 = &(mTree2Int.tree); - + // optional preprocessing if(preprocess_) { treesNodeCorr_.resize(2); preprocessingPipeline( mTree1Int, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, - branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[0],true,true); + branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[0], + true, true); preprocessingPipeline( mTree2Int, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, - branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[1],true,true); + branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[1], + true, true); } tree1 = &(mTree1Int.tree); tree2 = &(mTree2Int.tree); - return computeDistance(tree1,tree2,outputMatching); + return computeDistance(tree1, tree2, outputMatching); } template - dataType computeDistance(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2, std::vector> *outputMatching){ - - std::vector matchedNodes(tree1->getNumberOfNodes(),-1); - std::vector,std::pair>> mapping; - dataType res = computeDistance(tree1,tree2,&mapping); - if(computeMapping_ && outputMatching){ + dataType + computeDistance(ftm::FTMTree_MT *tree1, + ftm::FTMTree_MT *tree2, + std::vector> + *outputMatching) { + + std::vector matchedNodes(tree1->getNumberOfNodes(), -1); + std::vector, + std::pair>> + mapping; + dataType res = computeDistance(tree1, tree2, &mapping); + if(computeMapping_ && outputMatching) { outputMatching->clear(); - for(auto m : mapping){ + for(auto m : mapping) { matchedNodes[m.first.first] = m.second.first; matchedNodes[m.first.second] = m.second.second; } - for(ftm::idNode i=0; i=0) outputMatching->emplace_back(std::make_tuple(i,matchedNodes[i], 0.0)); + for(ftm::idNode i = 0; i < matchedNodes.size(); i++) { + if(matchedNodes[i] >= 0) + outputMatching->emplace_back( + std::make_tuple(i, matchedNodes[i], 0.0)); } } return res; - } template dataType execute(ftm::MergeTree &mTree1, - ftm::MergeTree &mTree2, - std::vector> *outputMatching){ - + ftm::MergeTree &mTree2, + std::vector> + *outputMatching) { + ftm::MergeTree mTree1Copy; ftm::MergeTree mTree2Copy; if(saveTree_) { @@ -760,33 +786,35 @@ namespace ttk { ftm::MergeTree &mTree2Int = (saveTree_ ? mTree2Copy : mTree2); ftm::FTMTree_MT *tree1 = &(mTree1Int.tree); ftm::FTMTree_MT *tree2 = &(mTree2Int.tree); - + // optional preprocessing if(preprocess_) { treesNodeCorr_.resize(2); preprocessingPipeline( - mTree1Int, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, - false, useMinMaxPair_, cleanTree_, treesNodeCorr_[0],true,true); + mTree1Int, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, false, + useMinMaxPair_, cleanTree_, treesNodeCorr_[0], true, true); preprocessingPipeline( - mTree2Int, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, - false, useMinMaxPair_, cleanTree_, treesNodeCorr_[1],true,true); + mTree2Int, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, false, + useMinMaxPair_, cleanTree_, treesNodeCorr_[1], true, true); } tree1 = &(mTree1Int.tree); tree2 = &(mTree2Int.tree); - return computeDistance(tree1,tree2,outputMatching); - + return computeDistance(tree1, tree2, outputMatching); } template - dataType computeDistance(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2){ - return computeDistance(tree1,tree2,(std::vector,std::pair>>*) nullptr); + dataType computeDistance(ftm::FTMTree_MT *tree1, ftm::FTMTree_MT *tree2) { + return computeDistance( + tree1, tree2, + (std::vector, + std::pair>> *)nullptr); } template dataType execute(ftm::MergeTree &mTree1, - ftm::MergeTree &mTree2){ + ftm::MergeTree &mTree2) { ftm::MergeTree mTree1Copy; ftm::MergeTree mTree2Copy; @@ -798,22 +826,25 @@ namespace ttk { ftm::MergeTree &mTree2Int = (saveTree_ ? mTree2Copy : mTree2); ftm::FTMTree_MT *tree1 = &(mTree1Int.tree); ftm::FTMTree_MT *tree2 = &(mTree2Int.tree); - + // optional preprocessing if(preprocess_) { treesNodeCorr_.resize(2); preprocessingPipeline( - mTree1Int, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, - false, useMinMaxPair_, cleanTree_, treesNodeCorr_[0],true,true); + mTree1Int, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, false, + useMinMaxPair_, cleanTree_, treesNodeCorr_[0], true, true); preprocessingPipeline( - mTree2Int, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, - false, useMinMaxPair_, cleanTree_, treesNodeCorr_[1],true,true); + mTree2Int, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, false, + useMinMaxPair_, cleanTree_, treesNodeCorr_[1], true, true); } - + tree1 = &(mTree1Int.tree); tree2 = &(mTree2Int.tree); - return computeDistance(tree1,tree2,(std::vector,std::pair>>*) nullptr); + return computeDistance( + tree1, tree2, + (std::vector, + std::pair>> *)nullptr); } }; } // namespace ttk diff --git a/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h b/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h index 4a98844320..a9552c5adb 100644 --- a/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h +++ b/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h @@ -90,20 +90,20 @@ namespace ttk { std::vector> &trees2, std::vector> &distanceMatrix) { treesNodeCorr_.resize(trees.size()); - for(unsigned int i = 0; i < trees.size(); ++i){ - preprocessingPipeline(trees[i], epsilonTree2_, - epsilon2Tree2_, epsilon3Tree2_, - baseModule_==0?branchDecomposition_:false, useMinMaxPair_, - true, treesNodeCorr_[i],true,baseModule_==2); + for(unsigned int i = 0; i < trees.size(); ++i) { + preprocessingPipeline( + trees[i], epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, + baseModule_ == 0 ? branchDecomposition_ : false, useMinMaxPair_, true, + treesNodeCorr_[i], true, baseModule_ == 2); } executePara(trees, distanceMatrix); if(trees2.size() != 0) { std::vector> trees2NodeCorr(trees2.size()); - for(unsigned int i = 0; i < trees.size(); ++i){ - preprocessingPipeline(trees2[i], epsilonTree2_, - epsilon2Tree2_, epsilon3Tree2_, - baseModule_==0?branchDecomposition_:false, useMinMaxPair_, - true, treesNodeCorr_[i],true,baseModule_==2); + for(unsigned int i = 0; i < trees.size(); ++i) { + preprocessingPipeline( + trees2[i], epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, + baseModule_ == 0 ? branchDecomposition_ : false, useMinMaxPair_, + true, treesNodeCorr_[i], true, baseModule_ == 2); } useDoubleInput_ = true; std::vector> distanceMatrix2( @@ -196,8 +196,7 @@ namespace ttk { branchDist.setPreprocess(false); // branchDist.setSaveTree(true); branchDist.setSaveTree(false); - dataType dist = branchDist.execute( - trees[i], trees[j]); + dataType dist = branchDist.execute(trees[i], trees[j]); distanceMatrix[i][j] = static_cast(dist); } else if(baseModule_ == 2) { PathMappingDistance pathDist; @@ -215,8 +214,7 @@ namespace ttk { pathDist.setPreprocess(false); // pathDist.setSaveTree(true); pathDist.setSaveTree(false); - dataType dist = pathDist.execute( - trees[i], trees[j]); + dataType dist = pathDist.execute(trees[i], trees[j]); distanceMatrix[i][j] = static_cast(dist); } // distance matrix is symmetric diff --git a/core/base/mergeTreeTemporalReduction/MergeTreeTemporalReduction.h b/core/base/mergeTreeTemporalReduction/MergeTreeTemporalReduction.h index 9bc33ab2d4..1e60f66c37 100644 --- a/core/base/mergeTreeTemporalReduction/MergeTreeTemporalReduction.h +++ b/core/base/mergeTreeTemporalReduction/MergeTreeTemporalReduction.h @@ -105,7 +105,7 @@ namespace ttk { ftm::MergeTree &mTree2, bool emptyTreeDistance = false) { dataType distance; - if(usePathMappings_){ + if(usePathMappings_) { PathMappingDistance mergeTreeDistance; mergeTreeDistance.setAssignmentSolver(assignmentSolverID_); mergeTreeDistance.setEpsilonTree1(epsilonTree1_); @@ -117,11 +117,10 @@ namespace ttk { mergeTreeDistance.setPreprocess(false); mergeTreeDistance.setComputeMapping(false); - ftm::FTMTree_MT* mt1 = &(mTree1.tree); - ftm::FTMTree_MT* mt2 = &(mTree2.tree); + ftm::FTMTree_MT *mt1 = &(mTree1.tree); + ftm::FTMTree_MT *mt2 = &(mTree2.tree); distance = mergeTreeDistance.computeDistance(mt1, mt2); - } - else{ + } else { MergeTreeDistance mergeTreeDistance; mergeTreeDistance.setAssignmentSolver(assignmentSolverID_); mergeTreeDistance.setEpsilonTree1(epsilonTree1_); @@ -145,7 +144,8 @@ namespace ttk { mergeTreeDistance.setOnlyEmptyTreeDistance(emptyTreeDistance); std::vector> matching; - distance = mergeTreeDistance.execute(mTree1, mTree2, matching); + distance + = mergeTreeDistance.execute(mTree1, mTree2, matching); } return distance; @@ -175,7 +175,7 @@ namespace ttk { mergeTreeBarycenter.setPostprocess(false); // mergeTreeBarycenter.setIsCalled(true); - if(usePathMappings_){ + if(usePathMappings_) { mergeTreeBarycenter.setBaseModule(2); mergeTreeBarycenter.setBranchDecomposition(false); mergeTreeBarycenter.setNormalizedWasserstein(false); @@ -183,8 +183,7 @@ namespace ttk { mergeTreeBarycenter.setUseMinMaxPair(false); mergeTreeBarycenter.setAddNodes(false); mergeTreeBarycenter.setPostprocess(false); - } - else{ + } else { mergeTreeBarycenter.setBranchDecomposition(true); mergeTreeBarycenter.setNormalizedWasserstein(normalizedWasserstein_); // mergeTreeBarycenter.setNormalizedWassersteinReg(normalizedWassersteinReg_); @@ -358,13 +357,13 @@ namespace ttk { Timer t_tempSub; // --- Preprocessing - if(not useL2Distance_){//} && not usePathMappings_) { + if(not useL2Distance_) { //} && not usePathMappings_) { treesNodeCorr_ = std::vector>(mTrees.size()); for(unsigned int i = 0; i < mTrees.size(); ++i) { - preprocessingPipeline(mTrees[i], epsilonTree2_, - epsilon2Tree2_, epsilon3Tree2_, - branchDecomposition_, useMinMaxPair_, - cleanTree_, treesNodeCorr_[i],true,usePathMappings_); + preprocessingPipeline( + mTrees[i], epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, + branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[i], + true, usePathMappings_); } printTreesStats(mTrees); } @@ -381,21 +380,24 @@ namespace ttk { // // - Merge saddle points according epsilon // if(not isPersistenceDiagram_) { // if(epsilonTree2_ != 0){ - // std::vector> treeNodeMerged( tree->getNumberOfNodes() ); - // mergeSaddle(tree, epsilonTree2_, treeNodeMerged); - // for(unsigned int j=0; j> treeNodeMerged( + // tree->getNumberOfNodes() ); mergeSaddle(tree, + // epsilonTree2_, treeNodeMerged); for(unsigned int j=0; + // jgetNode(j)->getOrigin(); // tree->getNode(k)->setOrigin(j); // tree->getNode(nodeToDelete)->setOrigin(-1); // } // } - // ftm::cleanMergeTree(mTrees[i], treesNodeCorr_[i], true); + // ftm::cleanMergeTree(mTrees[i], treesNodeCorr_[i], + // true); // } // else{ - // std::vector nodeCorri(tree->getNumberOfNodes()); - // for(unsigned int j=0; j + // nodeCorri(tree->getNumberOfNodes()); for(unsigned int j=0; + // j &mTree1, ftm::MergeTree &mTree2, std::vector> &matching) { - - if(usePathMappings_){ + + if(usePathMappings_) { PathMappingDistance mergeTreeDistance; mergeTreeDistance.setAssignmentSolver(assignmentSolverID_); mergeTreeDistance.setEpsilonTree1(epsilonTree1_); @@ -71,14 +71,13 @@ namespace ttk { mergeTreeDistance.setPreprocess(false); mergeTreeDistance.setComputeMapping(true); - ftm::FTMTree_MT* mt1 = &(mTree1.tree); - ftm::FTMTree_MT* mt2 = &(mTree2.tree); + ftm::FTMTree_MT *mt1 = &(mTree1.tree); + ftm::FTMTree_MT *mt2 = &(mTree2.tree); dataType distance = mergeTreeDistance.computeDistance(mt1, mt2, &matching); return distance; - } - else{ + } else { MergeTreeDistance mergeTreeDistance; mergeTreeDistance.setAssignmentSolver(assignmentSolverID_); mergeTreeDistance.setEpsilonTree1(epsilonTree1_); @@ -141,7 +140,7 @@ namespace ttk { mergeTreeBarycenter.setPostprocess(false); // mergeTreeBarycenter.setIsCalled(true); - if(usePathMappings_){ + if(usePathMappings_) { mergeTreeBarycenter.setBaseModule(2); mergeTreeBarycenter.setBranchDecomposition(false); mergeTreeBarycenter.setNormalizedWasserstein(false); @@ -149,8 +148,7 @@ namespace ttk { mergeTreeBarycenter.setUseMinMaxPair(false); mergeTreeBarycenter.setAddNodes(false); mergeTreeBarycenter.setPostprocess(false); - } - else{ + } else { mergeTreeBarycenter.setBranchDecomposition(true); mergeTreeBarycenter.setNormalizedWasserstein(normalizedWasserstein_); // mergeTreeBarycenter.setNormalizedWassersteinReg(normalizedWassersteinReg_); @@ -183,7 +181,8 @@ namespace ttk { // for(unsigned int i = 0; i < mTrees.size(); ++i) { // preprocessingPipeline( // mTrees[i], epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, - // branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[i]); + // branchDecomposition_, useMinMaxPair_, cleanTree_, + // treesNodeCorr_[i]); // } // printTreesStats(mTrees); // } @@ -191,7 +190,8 @@ namespace ttk { for(unsigned int i = 0; i < mTrees.size(); ++i) { preprocessingPipeline( mTrees[i], epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, - branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[i],true,usePathMappings_); + branchDecomposition_, useMinMaxPair_, cleanTree_, treesNodeCorr_[i], + true, usePathMappings_); } printTreesStats(mTrees); @@ -208,21 +208,24 @@ namespace ttk { // // - Merge saddle points according epsilon // if(not isPersistenceDiagram_) { // if(epsilonTree2_ != 0){ - // std::vector> treeNodeMerged( tree->getNumberOfNodes() ); - // mergeSaddle(tree, epsilonTree2_, treeNodeMerged); - // for(unsigned int j=0; j> treeNodeMerged( + // tree->getNumberOfNodes() ); mergeSaddle(tree, + // epsilonTree2_, treeNodeMerged); for(unsigned int j=0; + // jgetNode(j)->getOrigin(); // tree->getNode(k)->setOrigin(j); // tree->getNode(nodeToDelete)->setOrigin(-1); // } // } - // ftm::cleanMergeTree(mTrees[i], treesNodeCorr_[i], true); + // ftm::cleanMergeTree(mTrees[i], treesNodeCorr_[i], + // true); // } // else{ - // std::vector nodeCorri(tree->getNumberOfNodes()); - // for(unsigned int j=0; j + // nodeCorri(tree->getNumberOfNodes()); for(unsigned int j=0; + // j(allMT[i], allMT[i + 1], allMatching[i]); // --- Postprocessing - if(!usePathMappings_){ + if(!usePathMappings_) { for(unsigned int i = 0; i < allMT.size(); ++i) postprocessingPipeline(&(allMT[i].tree)); for(unsigned int i = 0; i < mTrees.size(); ++i) diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index 87f31122bb..007727602a 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -236,7 +236,7 @@ int ttkMergeTreeClustering::runCompute( if(not BranchDecomposition) printMsg("BranchDecomposition is set to true since the barycenter " "computation is asked."); - if(baseModule==0) + if(baseModule == 0) BranchDecomposition = true; if(KeepSubtree) printMsg("KeepSubtree is set to false since the barycenter computation " diff --git a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h index 4028bfa7ae..0c4b9adee0 100644 --- a/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h +++ b/core/vtk/ttkPlanarGraphLayout/ttkMergeTreeVisualization.h @@ -564,8 +564,10 @@ class ttkMergeTreeVisualization : public ttk::MergeTreeVisualization { : nodeCorr1[0][tree1NodeId]; double *point1 = vtkOutputNode2->GetPoints()->GetPoint(pointToGet1); const SimplexId nextPointId1 = pointsM->InsertNextPoint(point1); - if(not clusteringOutput) isBarycenterNodeField->InsertNextTuple1(0); - else isBarycenterNodeField->InsertNextTuple1(1); + if(not clusteringOutput) + isBarycenterNodeField->InsertNextTuple1(0); + else + isBarycenterNodeField->InsertNextTuple1(1); pointIds[0] = nextPointId1; // Get second point From 1abf1e1932977e93e74e9c53c9e50c42479715ee Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Mon, 29 Apr 2024 12:16:52 +0200 Subject: [PATCH 58/72] compiler warnings --- core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index 007727602a..de9f9fa5f8 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -318,8 +318,7 @@ int ttkMergeTreeClustering::runCompute( nodeCorr1[i] = i; for(unsigned int i = 0; i < nodeCorr2.size(); i++) nodeCorr2[i] = i; - trees1NodeCorrMesh - = std::vector>{nodeCorr1, nodeCorr2}; + trees1NodeCorrMesh = branchDist.getTreesNodeCorr(); finalDistances = std::vector{distance}; } else { PathMappingDistance pathDist; From 9cccc2387cc124035baa26cff41baaad362a9092 Mon Sep 17 00:00:00 2001 From: MatPont Date: Thu, 2 May 2024 17:27:37 +0200 Subject: [PATCH 59/72] [MergeTreeClustering] filter backends and options --- .../ttkMergeTreeClustering.cpp | 49 ++++++++++++------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index de9f9fa5f8..1520e7f404 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -130,11 +130,39 @@ int ttkMergeTreeClustering::RequestData(vtkInformation *ttkNotUsed(request), baseModule = 0; } - // filter out new backends (not yet supported) + // filter out backends (not yet supported) if(baseModule == 1 && ComputeBarycenter) { printErr("Invalid Backend chosen. Branch Mapping Distance not yet " "supported for Barycenter computation. Canceling computation."); - return 1; + return -1; + } + if(Backend == 1 && ComputeBarycenter) { + printErr("Invalid Backend chosen. Edit Distance is not yet supported for " + "Barycenter computation. Canceling computation."); + return -1; + } + if(Backend == 2) { + if(ComputeBarycenter) { + if(not BranchDecomposition) { + printErr( + "Invalid Backend chosen. Custom Backend without Branch " + "Decomposition is not yet supported for Barycenter computation. " + "Canceling computation."); + return -1; + } + if(KeepSubtree) { + printErr( + "Invalid Backend chosen. Custom Backend with Keep Subtree is not yet " + "supported for Barycenter computation. Canceling computation."); + return -1; + } + } + if(not BranchDecomposition and NormalizedWasserstein) { + printErr( + "Invalid Backend chosen. Custom Backend with Normalized Wasserstein " + "and without Branch Decomposition is not yet. Canceling computation."); + return -1; + } } // ------------------------------------------------------------------------------------ @@ -232,23 +260,6 @@ int ttkMergeTreeClustering::runCompute( if(IsPersistenceDiagram) { BranchDecomposition = true; } - if(ComputeBarycenter) { - if(not BranchDecomposition) - printMsg("BranchDecomposition is set to true since the barycenter " - "computation is asked."); - if(baseModule == 0) - BranchDecomposition = true; - if(KeepSubtree) - printMsg("KeepSubtree is set to false since the barycenter computation " - "is asked."); - KeepSubtree = false; - } - if(not BranchDecomposition) { - if(NormalizedWasserstein) - printMsg("NormalizedWasserstein is set to false since branch " - "decomposition is not asked."); - NormalizedWasserstein = false; - } EpsilonTree2 = EpsilonTree1; Epsilon2Tree2 = Epsilon2Tree1; Epsilon3Tree2 = Epsilon3Tree1; From 70547bedea19baeb4638eec74ef1110242ce22c7 Mon Sep 17 00:00:00 2001 From: MatPont Date: Thu, 2 May 2024 17:33:37 +0200 Subject: [PATCH 60/72] [MergeTreeClustering] fix compute barycenter option caching with edit distance --- core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index 1520e7f404..771c9415c5 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -247,7 +247,6 @@ int ttkMergeTreeClustering::runCompute( BranchDecomposition = false; NormalizedWasserstein = false; KeepSubtree = true; - ComputeBarycenter = false; } else if(Backend == 3) { BranchDecomposition = false; NormalizedWasserstein = false; From 2c63c97b2c6aceffa9c091ff306b9160dc7f09e1 Mon Sep 17 00:00:00 2001 From: MatPont Date: Thu, 2 May 2024 17:52:30 +0200 Subject: [PATCH 61/72] [MergeTreeClustering] fix barycenter dbug level when called in clustering --- core/base/mergeTreeClustering/MergeTreeClustering.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/base/mergeTreeClustering/MergeTreeClustering.h b/core/base/mergeTreeClustering/MergeTreeClustering.h index caeb0ffab4..1ca23609cb 100644 --- a/core/base/mergeTreeClustering/MergeTreeClustering.h +++ b/core/base/mergeTreeClustering/MergeTreeClustering.h @@ -650,7 +650,7 @@ namespace ttk { &finalMatchings) { MergeTreeBarycenter mergeTreeBary; - mergeTreeBary.setDebugLevel(std::min(debugLevel_, 2)); + mergeTreeBary.setDebugLevel(std::min(debugLevel_, 1)); mergeTreeBary.setBaseModule(this->baseModule_); // mergeTreeBary.setProgressiveComputation(false); mergeTreeBary.setAssignmentSolver(assignmentSolverID_); From a3c1515f8d50ac13a68cad0808f858fc27d40178 Mon Sep 17 00:00:00 2001 From: MatPont Date: Thu, 2 May 2024 17:53:45 +0200 Subject: [PATCH 62/72] [MergeTreeClustering] fix xml conditions for barycenter options --- paraview/xmls/MergeTreeClustering.xml | 140 +++++++++++++++++++------- 1 file changed, 106 insertions(+), 34 deletions(-) diff --git a/paraview/xmls/MergeTreeClustering.xml b/paraview/xmls/MergeTreeClustering.xml index 09336f003e..9153ac9a31 100644 --- a/paraview/xmls/MergeTreeClustering.xml +++ b/paraview/xmls/MergeTreeClustering.xml @@ -108,26 +108,28 @@ Online examples: - + + + + + - + property="KeepSubtree" + value="0" /> - - - + + - + - + + + + + + + + + + + + + + + + + Use fixed member for initial barycenter candidate. @@ -241,10 +275,48 @@ Online examples: number_of_elements="1" default_values="0"> - + + + + + + + + + + + + + + + + + + + + + Member index for initial barycenter candidate. @@ -280,8 +352,8 @@ Online examples: - - + + - + - - + + + mode="visibility" + property="Backend" + value="4" /> Date: Tue, 23 Jul 2024 17:37:10 +0200 Subject: [PATCH 63/72] fixed inverted squared-parameter in MergeTreeDistanceMatrix --- core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h b/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h index a9552c5adb..ab71cfb623 100644 --- a/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h +++ b/core/base/mergeTreeDistanceMatrix/MergeTreeDistanceMatrix.h @@ -185,7 +185,7 @@ namespace ttk { BranchMappingDistance branchDist; branchDist.setBaseMetric(branchMetric_); branchDist.setAssignmentSolver(assignmentSolverID_); - branchDist.setSquared(not distanceSquaredRoot_); + branchDist.setSquared(distanceSquaredRoot_); branchDist.setEpsilonTree1(epsilonTree1_); branchDist.setEpsilonTree2(epsilonTree2_); branchDist.setEpsilon2Tree1(epsilon2Tree1_); @@ -202,7 +202,7 @@ namespace ttk { PathMappingDistance pathDist; pathDist.setBaseMetric(pathMetric_); pathDist.setAssignmentSolver(assignmentSolverID_); - pathDist.setSquared(not distanceSquaredRoot_); + pathDist.setSquared(distanceSquaredRoot_); pathDist.setComputeMapping(true); pathDist.setEpsilonTree1(epsilonTree1_); pathDist.setEpsilonTree2(epsilonTree2_); From 85142bc70803aaaa31005322fc034f2b2b645da9 Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Wed, 24 Jul 2024 15:14:38 +0200 Subject: [PATCH 64/72] fixed cost array in matching output of MergeTreeClustering when using the path mapping distance --- .../mergeTreeClustering/MergeTreeBarycenter.h | 51 +++++++++++-------- .../mergeTreeClustering/MergeTreeClustering.h | 28 +++++----- .../mergeTreeClustering/PathMappingDistance.h | 48 ++++++++++++++++- .../ttkMergeTreeClustering.h | 10 +++- 4 files changed, 98 insertions(+), 39 deletions(-) diff --git a/core/base/mergeTreeClustering/MergeTreeBarycenter.h b/core/base/mergeTreeClustering/MergeTreeBarycenter.h index 15ff980ce4..67fd029952 100644 --- a/core/base/mergeTreeClustering/MergeTreeBarycenter.h +++ b/core/base/mergeTreeClustering/MergeTreeBarycenter.h @@ -1085,8 +1085,12 @@ namespace ttk { pathDistance.setThreadNumber(this->threadNumber_); pathDistance.setDistanceSquaredRoot(false); // squared root pathDistance.setComputeMapping(true); + // distance = pathDistance.computeDistance( + // baryTree, tree, &matching_path); + // distance = pathDistance.computeDistance( + // baryTree, tree, &matching); distance = pathDistance.computeDistance( - baryTree, tree, &matching_path); + baryTree, tree, &matching, &matching_path); } else { MergeTreeDistance mergeTreeDistance; mergeTreeDistance.setDebugLevel(std::min(debugLevel_, 2)); @@ -1506,29 +1510,34 @@ namespace ttk { std::vector distances(trees.size(), -1); if(baseModule_ == 2) { - std::vector, - std::pair>>> - matchings_path(trees.size()); - std::vector>> - matchings; + // std::vector, + // std::pair>>> + // matchings_path(trees.size()); + // std::vector>> + // matchings(trees.size()); // assignment_path(trees, baryMergeTree, matchings_path, // distances); assignment( - trees, baryMergeTree, matchings, matchings_path, distances); - finalMatchings_path = matchings_path; - for(unsigned int i = 0; i < matchings_path.size(); i++) { - finalMatchings[i].clear(); - std::vector matchedNodes(trees[i]->getNumberOfNodes(), -1); - for(auto m : matchings_path[i]) { - matchedNodes[m.second.first] = m.first.first; - matchedNodes[m.second.second] = m.first.second; - } - for(ftm::idNode j = 0; j < matchedNodes.size(); j++) { - if(matchedNodes[j] >= 0) - finalMatchings[i].emplace_back( - std::make_tuple(matchedNodes[j], j, 0.0)); - } - } + trees, baryMergeTree, finalMatchings, finalMatchings_path, distances); + // finalMatchings_path = matchings_path; + // for(unsigned int i = 0; i < matchings_path.size(); i++) { + // finalMatchings[i].clear(); + // std::vector matchedNodes(trees[i]->getNumberOfNodes(), -1); + // std::vector matchedCost(trees[i]->getNumberOfNodes(), -1); + // for(auto m : matchings_path[i]) { + // matchedNodes[m.second.first] = m.first.first; + // matchedNodes[m.second.second] = m.first.second; + // // matchedCost[m.first.first] = PathMappingDistance::editCost_Persistence(m.first.first,m.first.second,m.second.first,m.second.second,trees[i],&(baryMergeTree.tree); + // if(m.first.second == trees[i]->getRoot()){ + // matchedCost[m.first.second] = matchedCost[m.first.first]; + // } + // } + // for(ftm::idNode j = 0; j < matchedNodes.size(); j++) { + // if(matchedNodes[j] >= 0) + // finalMatchings[i].emplace_back( + // std::make_tuple(matchedNodes[j], j, matchedCost[i])); + // } + // } } else { assignment(trees, baryMergeTree, finalMatchings, finalMatchings_path, distances, diff --git a/core/base/mergeTreeClustering/MergeTreeClustering.h b/core/base/mergeTreeClustering/MergeTreeClustering.h index 1ca23609cb..741b19d494 100644 --- a/core/base/mergeTreeClustering/MergeTreeClustering.h +++ b/core/base/mergeTreeClustering/MergeTreeClustering.h @@ -453,19 +453,19 @@ namespace ttk { // assignedTrees[i], centroids[i], matching_path, distances); assignment( assignedTrees[i], centroids[i], matching, matching_path, distances); - for(unsigned int j = 0; j < assignedTrees[i].size(); j++) { - std::vector matchedNodes( - assignedTrees[i][j]->getNumberOfNodes(), -1); - for(auto m : matching_path[j]) { - matchedNodes[m.second.first] = m.first.first; - matchedNodes[m.second.second] = m.first.second; - } - for(ftm::idNode k = 0; k < matchedNodes.size(); k++) { - if(matchedNodes[k] >= 0) - matching[j].emplace_back( - std::make_tuple(matchedNodes[k], k, 0.0)); - } - } + // for(unsigned int j = 0; j < assignedTrees[i].size(); j++) { + // std::vector matchedNodes( + // assignedTrees[i][j]->getNumberOfNodes(), -1); + // for(auto m : matching_path[j]) { + // matchedNodes[m.second.first] = m.first.first; + // matchedNodes[m.second.second] = m.first.second; + // } + // for(ftm::idNode k = 0; k < matchedNodes.size(); k++) { + // if(matchedNodes[k] >= 0) + // matching[j].emplace_back( + // std::make_tuple(matchedNodes[k], k, 0.0)); + // } + // } matchingsC[i] = matching; } else { assignment(assignedTrees[i], centroids[i], matching, @@ -682,7 +682,7 @@ namespace ttk { std::vector, std::pair>>> - finalMatchings_path; + finalMatchings_path(trees.size()); mergeTreeBary.computeBarycenter( trees, baryMergeTree, alphas, finalMatchings, finalMatchings_path); diff --git a/core/base/mergeTreeClustering/PathMappingDistance.h b/core/base/mergeTreeClustering/PathMappingDistance.h index 878cb57f4f..d8619dd5b3 100644 --- a/core/base/mergeTreeClustering/PathMappingDistance.h +++ b/core/base/mergeTreeClustering/PathMappingDistance.h @@ -750,6 +750,7 @@ namespace ttk { *outputMatching) { std::vector matchedNodes(tree1->getNumberOfNodes(), -1); + std::vector matchedCost(tree1->getNumberOfNodes(), -1); std::vector, std::pair>> mapping; @@ -759,11 +760,54 @@ namespace ttk { for(auto m : mapping) { matchedNodes[m.first.first] = m.second.first; matchedNodes[m.first.second] = m.second.second; + matchedCost[m.first.first] = editCost_Persistence(m.first.first,m.first.second,m.second.first,m.second.second,tree1,tree2); + if(m.first.second == tree1->getRoot()){ + matchedCost[m.first.second] = matchedCost[m.first.first]; + } } for(ftm::idNode i = 0; i < matchedNodes.size(); i++) { - if(matchedNodes[i] >= 0) + if(matchedNodes[i] >= 0){ outputMatching->emplace_back( - std::make_tuple(i, matchedNodes[i], 0.0)); + std::make_tuple(i, matchedNodes[i], matchedCost[i])); + } + } + } + + return res; + } + + template + dataType + computeDistance(ftm::FTMTree_MT *tree1, + ftm::FTMTree_MT *tree2, + std::vector> + *outputMatching, + std::vector, + std::pair>> + *outputMatching_path) { + + std::vector matchedNodes(tree1->getNumberOfNodes(), -1); + std::vector matchedCost(tree1->getNumberOfNodes(), -1); + // std::vector, + // std::pair>> + // mapping; + dataType res = computeDistance(tree1, tree2, outputMatching_path); + // *outputMatching_path = mapping; + if(computeMapping_ && outputMatching) { + outputMatching->clear(); + for(auto m : *outputMatching_path) { + matchedNodes[m.first.first] = m.second.first; + matchedNodes[m.first.second] = m.second.second; + matchedCost[m.first.first] = editCost_Persistence(m.first.first,m.first.second,m.second.first,m.second.second,tree1,tree2); + if(m.first.second == tree1->getRoot()){ + matchedCost[m.first.second] = matchedCost[m.first.first]; + } + } + for(ftm::idNode i = 0; i < matchedNodes.size(); i++) { + if(matchedNodes[i] >= 0){ + outputMatching->emplace_back( + std::make_tuple(i, matchedNodes[i], matchedCost[i])); + } } } diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h index d77cb14654..e00829f15c 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h @@ -188,8 +188,14 @@ class TTKMERGETREECLUSTERING_EXPORT ttkMergeTreeClustering std::vector< std::vector>>( numInputs2)); - outputMatchings_path.clear(); - outputMatchings_path.resize(NumberOfBarycenters); + outputMatchings_path = std::vector, + std::pair>>>>( + NumberOfBarycenters, + std::vector< + std::vector, + std::pair>>>( + numInputs)); // Barycenter barycentersS From 18d6307f882ecfa2ad4d8071cb65842535736d8c Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Wed, 24 Jul 2024 15:44:10 +0200 Subject: [PATCH 65/72] fixed cost array in mapping output for branch mapping distance --- .../mergeTreeClustering/BranchMappingDistance.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/core/base/mergeTreeClustering/BranchMappingDistance.h b/core/base/mergeTreeClustering/BranchMappingDistance.h index e5174cf3dc..b76f68706f 100644 --- a/core/base/mergeTreeClustering/BranchMappingDistance.h +++ b/core/base/mergeTreeClustering/BranchMappingDistance.h @@ -636,6 +636,7 @@ namespace ttk { outputMatching->clear(); std::vector matchedNodes(tree1->getNumberOfNodes(), -1); + std::vector matchedCost(tree1->getNumberOfNodes(), -1); std::vector, std::pair>> mapping; std::vector linkedNodes1(tree1->getNumberOfNodes(), -1); @@ -695,6 +696,18 @@ namespace ttk { continue; matchedNodes[m.first.first] = m.second.first; matchedNodes[m.first.second] = m.second.second; + matchedCost[m.first.first] = this->baseMetric_ == 0 ? editCost_Wasserstein1( + m.first.first,m.first.second,m.second.first,m.second.second,tree1,tree2) + : this->baseMetric_ == 1 ? editCost_Wasserstein2( + m.first.first,m.first.second,m.second.first,m.second.second,tree1,tree2) + : this->baseMetric_ == 2 + ? editCost_Persistence( + m.first.first,m.first.second,m.second.first,m.second.second,tree1,tree2) + : editCost_Shifting( + m.first.first,m.first.second,m.second.first,m.second.second,tree1,tree2); + if(m.first.second == tree1->getRoot()){ + matchedCost[m.first.second] = matchedCost[m.first.first]; + } } // std::cout << "Pairs Tree 1:\n"; // for(int i=0; i= 0) outputMatching->emplace_back( - std::make_tuple(i, matchedNodes[i], 0.0)); + std::make_tuple(i, matchedNodes[i], matchedCost[i])); } // std::cout << res << " " << cost_mapping << std::endl; From 225e6e9340cb7606d36b535ed77d9b7239491d9d Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Wed, 24 Jul 2024 16:02:25 +0200 Subject: [PATCH 66/72] clang format --- .../BranchMappingDistance.h | 25 ++++++++------ .../mergeTreeClustering/MergeTreeBarycenter.h | 12 ++++--- .../mergeTreeClustering/PathMappingDistance.h | 34 +++++++++++-------- 3 files changed, 42 insertions(+), 29 deletions(-) diff --git a/core/base/mergeTreeClustering/BranchMappingDistance.h b/core/base/mergeTreeClustering/BranchMappingDistance.h index b76f68706f..2e0246a13c 100644 --- a/core/base/mergeTreeClustering/BranchMappingDistance.h +++ b/core/base/mergeTreeClustering/BranchMappingDistance.h @@ -696,16 +696,21 @@ namespace ttk { continue; matchedNodes[m.first.first] = m.second.first; matchedNodes[m.first.second] = m.second.second; - matchedCost[m.first.first] = this->baseMetric_ == 0 ? editCost_Wasserstein1( - m.first.first,m.first.second,m.second.first,m.second.second,tree1,tree2) - : this->baseMetric_ == 1 ? editCost_Wasserstein2( - m.first.first,m.first.second,m.second.first,m.second.second,tree1,tree2) - : this->baseMetric_ == 2 - ? editCost_Persistence( - m.first.first,m.first.second,m.second.first,m.second.second,tree1,tree2) - : editCost_Shifting( - m.first.first,m.first.second,m.second.first,m.second.second,tree1,tree2); - if(m.first.second == tree1->getRoot()){ + matchedCost[m.first.first] + = this->baseMetric_ == 0 ? editCost_Wasserstein1( + m.first.first, m.first.second, m.second.first, m.second.second, + tree1, tree2) + : this->baseMetric_ == 1 ? editCost_Wasserstein2( + m.first.first, m.first.second, m.second.first, + m.second.second, tree1, tree2) + : this->baseMetric_ == 2 + ? editCost_Persistence(m.first.first, m.first.second, + m.second.first, + m.second.second, tree1, tree2) + : editCost_Shifting(m.first.first, m.first.second, + m.second.first, m.second.second, + tree1, tree2); + if(m.first.second == tree1->getRoot()) { matchedCost[m.first.second] = matchedCost[m.first.first]; } } diff --git a/core/base/mergeTreeClustering/MergeTreeBarycenter.h b/core/base/mergeTreeClustering/MergeTreeBarycenter.h index 67fd029952..3d5be4ae8c 100644 --- a/core/base/mergeTreeClustering/MergeTreeBarycenter.h +++ b/core/base/mergeTreeClustering/MergeTreeBarycenter.h @@ -1510,10 +1510,13 @@ namespace ttk { std::vector distances(trees.size(), -1); if(baseModule_ == 2) { - // std::vector, - // std::pair>>> + // std::vector, + // std::pair>>> // matchings_path(trees.size()); - // std::vector>> + // std::vector>> // matchings(trees.size()); // assignment_path(trees, baryMergeTree, matchings_path, // distances); @@ -1527,7 +1530,8 @@ namespace ttk { // for(auto m : matchings_path[i]) { // matchedNodes[m.second.first] = m.first.first; // matchedNodes[m.second.second] = m.first.second; - // // matchedCost[m.first.first] = PathMappingDistance::editCost_Persistence(m.first.first,m.first.second,m.second.first,m.second.second,trees[i],&(baryMergeTree.tree); + // // matchedCost[m.first.first] = + // PathMappingDistance::editCost_Persistence(m.first.first,m.first.second,m.second.first,m.second.second,trees[i],&(baryMergeTree.tree); // if(m.first.second == trees[i]->getRoot()){ // matchedCost[m.first.second] = matchedCost[m.first.first]; // } diff --git a/core/base/mergeTreeClustering/PathMappingDistance.h b/core/base/mergeTreeClustering/PathMappingDistance.h index d8619dd5b3..8b8114178a 100644 --- a/core/base/mergeTreeClustering/PathMappingDistance.h +++ b/core/base/mergeTreeClustering/PathMappingDistance.h @@ -760,13 +760,15 @@ namespace ttk { for(auto m : mapping) { matchedNodes[m.first.first] = m.second.first; matchedNodes[m.first.second] = m.second.second; - matchedCost[m.first.first] = editCost_Persistence(m.first.first,m.first.second,m.second.first,m.second.second,tree1,tree2); - if(m.first.second == tree1->getRoot()){ + matchedCost[m.first.first] = editCost_Persistence( + m.first.first, m.first.second, m.second.first, m.second.second, + tree1, tree2); + if(m.first.second == tree1->getRoot()) { matchedCost[m.first.second] = matchedCost[m.first.first]; } } for(ftm::idNode i = 0; i < matchedNodes.size(); i++) { - if(matchedNodes[i] >= 0){ + if(matchedNodes[i] >= 0) { outputMatching->emplace_back( std::make_tuple(i, matchedNodes[i], matchedCost[i])); } @@ -777,34 +779,36 @@ namespace ttk { } template - dataType - computeDistance(ftm::FTMTree_MT *tree1, - ftm::FTMTree_MT *tree2, - std::vector> - *outputMatching, - std::vector, - std::pair>> - *outputMatching_path) { + dataType computeDistance( + ftm::FTMTree_MT *tree1, + ftm::FTMTree_MT *tree2, + std::vector> *outputMatching, + std::vector, + std::pair>> + *outputMatching_path) { std::vector matchedNodes(tree1->getNumberOfNodes(), -1); std::vector matchedCost(tree1->getNumberOfNodes(), -1); // std::vector, // std::pair>> // mapping; - dataType res = computeDistance(tree1, tree2, outputMatching_path); + dataType res + = computeDistance(tree1, tree2, outputMatching_path); // *outputMatching_path = mapping; if(computeMapping_ && outputMatching) { outputMatching->clear(); for(auto m : *outputMatching_path) { matchedNodes[m.first.first] = m.second.first; matchedNodes[m.first.second] = m.second.second; - matchedCost[m.first.first] = editCost_Persistence(m.first.first,m.first.second,m.second.first,m.second.second,tree1,tree2); - if(m.first.second == tree1->getRoot()){ + matchedCost[m.first.first] = editCost_Persistence( + m.first.first, m.first.second, m.second.first, m.second.second, + tree1, tree2); + if(m.first.second == tree1->getRoot()) { matchedCost[m.first.second] = matchedCost[m.first.first]; } } for(ftm::idNode i = 0; i < matchedNodes.size(); i++) { - if(matchedNodes[i] >= 0){ + if(matchedNodes[i] >= 0) { outputMatching->emplace_back( std::make_tuple(i, matchedNodes[i], matchedCost[i])); } From b83a149f21a772ad81d0ebc973412411e20f3d96 Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Wed, 24 Jul 2024 16:21:18 +0200 Subject: [PATCH 67/72] removed old code and fixed some warnings --- .../BranchMappingDistance.h | 54 +------------- .../mergeTreeClustering/MergeTreeBarycenter.h | 74 ------------------- .../mergeTreeClustering/MergeTreeClustering.h | 15 ---- .../mergeTreeClustering/PathMappingDistance.h | 54 -------------- .../ttkMergeTreeClustering.cpp | 11 --- 5 files changed, 1 insertion(+), 207 deletions(-) diff --git a/core/base/mergeTreeClustering/BranchMappingDistance.h b/core/base/mergeTreeClustering/BranchMappingDistance.h index 2e0246a13c..ce54a5bd2b 100644 --- a/core/base/mergeTreeClustering/BranchMappingDistance.h +++ b/core/base/mergeTreeClustering/BranchMappingDistance.h @@ -257,22 +257,6 @@ namespace ttk { std::vector> *outputMatching = nullptr) { - // // optional preprocessing - // if(preprocess_ && !writeOptimalBranchDecomposition_){ - // treesNodeCorr_.resize(2); - // preprocessingPipeline( - // mTree1, epsilonTree1_, epsilon2Tree1_, epsilon3Tree1_, - // branchDecomposition_, useMinMaxPair_, cleanTree_, - // treesNodeCorr_[0],true,true); - // preprocessingPipeline( - // mTree2, epsilonTree2_, epsilon2Tree2_, epsilon3Tree2_, - // branchDecomposition_, useMinMaxPair_, cleanTree_, - // treesNodeCorr_[1],true,true); - // } - - // ftm::FTMTree_MT *tree1 = (&mTree1.tree); - // ftm::FTMTree_MT *tree2 = (&mTree2.tree); - // compute preorder of both trees (necessary for bottom-up dynamic // programming) @@ -660,32 +644,6 @@ namespace ttk { linkedNodes2[m.second.first] = m.second.second; linkedNodes2[m.second.second] = m.second.first; } - // dataType cost = this->baseMetric_ == 0 ? - // editCost_Wasserstein1( - // m.first.first, m.first.second, m.second.first, - // m.second.second, tree1, tree2) - // : this->baseMetric_ == 1 ? - // editCost_Wasserstein2( - // m.first.first, m.first.second, m.second.first, - // m.second.second, tree1, tree2) - // : this->baseMetric_ == 2 - // ? editCost_Persistence( - // m.first.first, m.first.second, m.second.first, - // m.second.second, tree1, tree2) - // : editCost_Shifting( - // m.first.first, m.first.second, m.second.first, - // m.second.second, tree1, tree2); - // dataType cost_ = editCost_Wasserstein1( - // m.first.first, m.first.second, m.second.first, - // m.second.second, tree1, tree2); - // cost_mapping += cost_; - // std::cout << "(" << m.first.first << " " << m.first.second << ") - - // (" << m.second.first << " " << m.second.second << ") : " << cost << - // " " << cost_;// << std::endl; std::cout << "; (" << - // tree1->getValue(m.first.first) << " " << - // tree1->getValue(m.first.second) << ") - (" << - // tree2->getValue(m.second.first) << " " << - // tree2->getValue(m.second.second) << ")" << std::endl; if(m.first.first == -1) continue; if(m.first.second == -1) @@ -710,25 +668,15 @@ namespace ttk { : editCost_Shifting(m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2); - if(m.first.second == tree1->getRoot()) { + if(m.first.second == (int)tree1->getRoot()) { matchedCost[m.first.second] = matchedCost[m.first.first]; } } - // std::cout << "Pairs Tree 1:\n"; - // for(int i=0; i= 0) outputMatching->emplace_back( std::make_tuple(i, matchedNodes[i], matchedCost[i])); } - - // std::cout << res << " " << cost_mapping << std::endl; } return squared_ ? std::sqrt(res) : res; diff --git a/core/base/mergeTreeClustering/MergeTreeBarycenter.h b/core/base/mergeTreeClustering/MergeTreeBarycenter.h index 3d5be4ae8c..d9ac1f7263 100644 --- a/core/base/mergeTreeClustering/MergeTreeBarycenter.h +++ b/core/base/mergeTreeClustering/MergeTreeBarycenter.h @@ -1046,24 +1046,6 @@ namespace ttk { // ------------------------------------------------------------------------ // Assignment // ------------------------------------------------------------------------ - // template - // void computeOneDistance_pathMapping( - // ftm::FTMTree_MT *tree, - // ftm::FTMTree_MT *baryTree, - // std::vector,std::pair>> &matching, dataType - // &distance) { - // // Timer t_distance; - // PathMappingDistance pathDistance; - // pathDistance.setDebugLevel(std::min(debugLevel_, 2)); - // pathDistance.setPreprocess(false); - // pathDistance.setAssignmentSolver(assignmentSolverID_); - // pathDistance.setThreadNumber(this->threadNumber_); - // pathDistance.setDistanceSquaredRoot(false); // squared root - // pathDistance.setComputeMapping(true); - // distance - // = pathDistance.computeDistance(baryTree, tree, &matching); - // } template void computeOneDistance( @@ -1085,10 +1067,6 @@ namespace ttk { pathDistance.setThreadNumber(this->threadNumber_); pathDistance.setDistanceSquaredRoot(false); // squared root pathDistance.setComputeMapping(true); - // distance = pathDistance.computeDistance( - // baryTree, tree, &matching_path); - // distance = pathDistance.computeDistance( - // baryTree, tree, &matching); distance = pathDistance.computeDistance( baryTree, tree, &matching, &matching_path); } else { @@ -1204,21 +1182,6 @@ namespace ttk { useDoubleInput, isFirstInput); } - // template - // void assignment_path( - // std::vector &trees, - // ftm::MergeTree &baryMergeTree, - // std::vector,std::pair>>> - // &matchings, - // std::vector &distances) { - // for(unsigned int i = 0; i < trees.size(); ++i){ - // computeOneDistance_pathMapping(trees[i], - // &(baryMergeTree.tree), matchings[i], - // distances[i]); - // } - // } - template void assignment( std::vector &trees, @@ -1421,13 +1384,6 @@ namespace ttk { matchings_path(trees.size()); std::vector distances(trees.size(), -1); Timer t_assignment; - // if(baseModule_ == 2){ - // assignment_path(trees, baryMergeTree, matchings_path, - // distances); - // } - // else{ - // assignment(trees, baryMergeTree, matchings, distances); - // } assignment( trees, baryMergeTree, matchings, matchings_path, distances); Timer t_addDeletedNodes; @@ -1510,38 +1466,8 @@ namespace ttk { std::vector distances(trees.size(), -1); if(baseModule_ == 2) { - // std::vector, - // std::pair>>> - // matchings_path(trees.size()); - // std::vector>> - // matchings(trees.size()); - // assignment_path(trees, baryMergeTree, matchings_path, - // distances); assignment( trees, baryMergeTree, finalMatchings, finalMatchings_path, distances); - // finalMatchings_path = matchings_path; - // for(unsigned int i = 0; i < matchings_path.size(); i++) { - // finalMatchings[i].clear(); - // std::vector matchedNodes(trees[i]->getNumberOfNodes(), -1); - // std::vector matchedCost(trees[i]->getNumberOfNodes(), -1); - // for(auto m : matchings_path[i]) { - // matchedNodes[m.second.first] = m.first.first; - // matchedNodes[m.second.second] = m.first.second; - // // matchedCost[m.first.first] = - // PathMappingDistance::editCost_Persistence(m.first.first,m.first.second,m.second.first,m.second.second,trees[i],&(baryMergeTree.tree); - // if(m.first.second == trees[i]->getRoot()){ - // matchedCost[m.first.second] = matchedCost[m.first.first]; - // } - // } - // for(ftm::idNode j = 0; j < matchedNodes.size(); j++) { - // if(matchedNodes[j] >= 0) - // finalMatchings[i].emplace_back( - // std::make_tuple(matchedNodes[j], j, matchedCost[i])); - // } - // } } else { assignment(trees, baryMergeTree, finalMatchings, finalMatchings_path, distances, diff --git a/core/base/mergeTreeClustering/MergeTreeClustering.h b/core/base/mergeTreeClustering/MergeTreeClustering.h index 741b19d494..1d81c6b76d 100644 --- a/core/base/mergeTreeClustering/MergeTreeClustering.h +++ b/core/base/mergeTreeClustering/MergeTreeClustering.h @@ -449,23 +449,8 @@ namespace ttk { std::pair>>> matching_path(trees.size()); if(baseModule_ == 2) { - // assignment_path( - // assignedTrees[i], centroids[i], matching_path, distances); assignment( assignedTrees[i], centroids[i], matching, matching_path, distances); - // for(unsigned int j = 0; j < assignedTrees[i].size(); j++) { - // std::vector matchedNodes( - // assignedTrees[i][j]->getNumberOfNodes(), -1); - // for(auto m : matching_path[j]) { - // matchedNodes[m.second.first] = m.first.first; - // matchedNodes[m.second.second] = m.first.second; - // } - // for(ftm::idNode k = 0; k < matchedNodes.size(); k++) { - // if(matchedNodes[k] >= 0) - // matching[j].emplace_back( - // std::make_tuple(matchedNodes[k], k, 0.0)); - // } - // } matchingsC[i] = matching; } else { assignment(assignedTrees[i], centroids[i], matching, diff --git a/core/base/mergeTreeClustering/PathMappingDistance.h b/core/base/mergeTreeClustering/PathMappingDistance.h index 8b8114178a..e43cb17afa 100644 --- a/core/base/mergeTreeClustering/PathMappingDistance.h +++ b/core/base/mergeTreeClustering/PathMappingDistance.h @@ -650,56 +650,6 @@ namespace ttk { traceMapping_path(tree1, tree2, children1[0], 1, children2[0], 1, predecessors1, predecessors2, depth1, depth2, memT, *outputMatching); - - // dataType cost_mapping = 0; - // dataType cost_ins = 0; - // dataType cost_del = 0; - // std::vector matchedNodes1(tree1->getNumberOfNodes(),false); - // std::vector matchedNodes2(tree2->getNumberOfNodes(),false); - // for(auto m : *outputMatching){ - // matchedNodes1[m.first.first] = true; - // matchedNodes1[m.first.second] = true; - // matchedNodes2[m.second.first] = true; - // matchedNodes2[m.second.second] = true; - // ftm::idNode cn = tree1->getParentSafe(m.first.first); - // while(cn!=m.first.second){ - // matchedNodes1[cn] = true; - // cn = tree1->getParentSafe(cn); - // } - // cn = tree2->getParentSafe(m.second.first); - // while(cn!=m.second.second){ - // matchedNodes2[cn] = true; - // cn = tree2->getParentSafe(cn); - // } - // dataType cost = editCost_Persistence( - // m.first.first, m.first.second, m.second.first, - // m.second.second, tree1, tree2); - // cost_mapping += cost; - // // std::cout << " (" << m.first.first << " " << m.first.second << - // ") - (" << m.second.first << " " << m.second.second << ") : " << - // cost << "\n"; - // } - // for(ftm::idNode i=0; igetNumberOfNodes(); i++){ - // if(!matchedNodes1[i]){ - // dataType cost = editCost_Persistence(i, - // tree1->getParentSafe(i), -1, -1, tree1, tree2); - // // std::cout << " (" << i << " " << tree1->getParentSafe(i) << - // ") - (" << -1 << " " << -1 << ") : " << cost << "\n"; cost_del += - // cost; - // } - // } - // for(ftm::idNode i=0; igetNumberOfNodes(); i++){ - // if(!matchedNodes2[i]){ - // dataType cost = editCost_Persistence(-1, -1, i, - // tree2->getParentSafe(i), tree1, tree2); - // // std::cout << " (" << -1 << " " << -1 << ") - (" << i << " " - // << tree2->getParentSafe(i) << ") : " << cost << "\n"; cost_ins += - // cost; - // } - // } - // // std::cout << res << " " << cost_mapping+cost_ins+cost_del << - // std::endl; - // // std::cout << res << " " << cost_mapping << std::endl; } return squared_ ? std::sqrt(res) : res; @@ -789,12 +739,8 @@ namespace ttk { std::vector matchedNodes(tree1->getNumberOfNodes(), -1); std::vector matchedCost(tree1->getNumberOfNodes(), -1); - // std::vector, - // std::pair>> - // mapping; dataType res = computeDistance(tree1, tree2, outputMatching_path); - // *outputMatching_path = mapping; if(computeMapping_ && outputMatching) { outputMatching->clear(); for(auto m : *outputMatching_path) { diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp index 771c9415c5..c268bab645 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.cpp @@ -413,17 +413,6 @@ int ttkMergeTreeClustering::runCompute( trees1NodeCorrMesh = mergeTreeBarycenter.getTreesNodeCorr(); finalDistances = mergeTreeBarycenter.getFinalDistances(); - /*std::cout << "Path Mappings:\n"; - for(auto matching : outputMatchings_path[0]) { - std::cout << "---------------------------\n"; - std::cout << intermediateMTrees[i]->printTree().str() << std::: - for(auto m : matching) { - std::cout << "(" << m.first.first << "," << m.first.second << ") - "; - std::cout << "(" << m.second.first << "," << m.second.second << ")" - << std::endl; - } - std::cout << "---------------------------\n"; - }*/ } else { MergeTreeClustering mergeTreeClustering; mergeTreeClustering.setAssignmentSolver(AssignmentSolver); From 13ee09f13be7a894d4c70a811b7a0dd6c0e1fb60 Mon Sep 17 00:00:00 2001 From: MatPont Date: Mon, 26 Aug 2024 18:20:49 +0200 Subject: [PATCH 68/72] [MergeTreeClustering] compute barycenter option caching --- core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h index e00829f15c..8cd0717752 100644 --- a/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h +++ b/core/vtk/ttkMergeTreeClustering/ttkMergeTreeClustering.h @@ -97,6 +97,7 @@ class TTKMERGETREECLUSTERING_EXPORT ttkMergeTreeClustering bool oldKS = KeepSubtree; double JoinSplitMixtureCoefficient = 0.5; bool ComputeBarycenter = false; + bool oldComputeBarycenter = ComputeBarycenter; unsigned int NumberOfBarycenters = 1; double BarycenterSizeLimitPercent = 0.0; bool Deterministic = false; @@ -281,6 +282,12 @@ class TTKMERGETREECLUSTERING_EXPORT ttkMergeTreeClustering NormalizedWasserstein = oldNW; KeepSubtree = oldKS; } + if(Backend == 1 or Backend == 3) // edit distance or branch mapping + ComputeBarycenter = oldComputeBarycenter; + if(newBackend == 1 or newBackend == 3) { + oldComputeBarycenter = ComputeBarycenter; + ComputeBarycenter = false; + } Backend = newBackend; Modified(); resetDataVisualization(); From 74764b140638380a6acbc2097f6abf5ec29f168d Mon Sep 17 00:00:00 2001 From: MatPont Date: Wed, 28 Aug 2024 16:45:21 +0200 Subject: [PATCH 69/72] [MergeTree] xml doc --- paraview/xmls/MergeTreeClustering.xml | 29 +++++++++++++++---- paraview/xmls/MergeTreeDistanceMatrix.xml | 29 +++++++++++++++++++ paraview/xmls/MergeTreeTemporalReduction.xml | 5 ++++ .../MergeTreeTemporalReductionDecoding.xml | 5 ++++ 4 files changed, 63 insertions(+), 5 deletions(-) diff --git a/paraview/xmls/MergeTreeClustering.xml b/paraview/xmls/MergeTreeClustering.xml index 9153ac9a31..b461ce8934 100644 --- a/paraview/xmls/MergeTreeClustering.xml +++ b/paraview/xmls/MergeTreeClustering.xml @@ -15,23 +15,42 @@ short_help="TTK MergeTreeClustering plugin that compute distance, geodesics and barycenters between merge trees."> This filter allows to compute distances, geodesics, barycenters and clusters of merge trees. -Two backends are available: +Four backends are available: -- The Wasserstein Distance: +- The Wasserstein Distance. Related publication: 'Wasserstein Distances, Geodesics and Barycenters of Merge Trees' Mathieu Pont, Jules Vidal, Julie Delon, Julien Tierny. Proc. of IEEE VIS 2021. IEEE Transactions on Visualization and Computer Graphics, 2021 -- The Edit Distance: +- The Edit Distance. Related publication: 'Edit distance between merge trees.' R. Sridharamurthy, T. B. Masood, A. Kamakshidasan, and V. Natarajan. IEEE Transactions on Visualization and Computer Graphics, 2018. -Only the first backend allows to compute geodesics, barycenters and clusters of merge trees. The second one can only compute distances. -These backends are different through 3 parameters: +- The Branch-Decomposition Edit Distance. +Related publication: +"Branch Decomposition-Independent Edit Distances for Merge Trees." +Florian Wetzels, Heike Leitte, and Christoph Garth. +Computer Graphics Forum, 2022. + +- The Path-Mapping Distance. +Related publications: +"A Deformation-based Edit Distance for Merge Trees" +Florian Wetzels, Christoph Garth. +TopoInVis 2022. +and +'Merge Tree Geodesics and Barycenters with Path Mappings' +F. Wetzels, M. Pont, J. Tierny and C. Garth. +Proc. of IEEE VIS 2023. +IEEE Transactions on Visualization and Computer Graphics, 2024 + +Only the first and last backend allows to compute geodesics, barycenters and clusters of merge trees. +The other ones can only compute distances, therefore, the "ComputeBarycenter" will always be false for these backends, whatever its old value. + +The first two backends are different through 3 parameters: Parameters | Wasserstein | Edit | --------------------------|-------------|-------| diff --git a/paraview/xmls/MergeTreeDistanceMatrix.xml b/paraview/xmls/MergeTreeDistanceMatrix.xml index 27c2cccf1d..24fc2474fb 100644 --- a/paraview/xmls/MergeTreeDistanceMatrix.xml +++ b/paraview/xmls/MergeTreeDistanceMatrix.xml @@ -8,6 +8,35 @@ +This filter allows to compute a distance matrix of a set of merge trees. + +Four backends are available: + +- The Wasserstein Distance. +Related publication: +'Wasserstein Distances, Geodesics and Barycenters of Merge Trees' +Mathieu Pont, Jules Vidal, Julie Delon, Julien Tierny. +Proc. of IEEE VIS 2021. +IEEE Transactions on Visualization and Computer Graphics, 2021 + +- The Edit Distance. +Related publication: +'Edit distance between merge trees.' +R. Sridharamurthy, T. B. Masood, A. Kamakshidasan, and V. Natarajan. +IEEE Transactions on Visualization and Computer Graphics, 2018. + +- The Branch-Decomposition Edit Distance. +Related publication: +"Branch Decomposition-Independent Edit Distances for Merge Trees." +Florian Wetzels, Heike Leitte, and Christoph Garth. +Computer Graphics Forum, 2022. + +- The Path-Mapping Distance. +Related publications: +"A Deformation-based Edit Distance for Merge Trees" +Florian Wetzels, Christoph Garth. +TopoInVis 2022. + Online examples: - https://topology-tool-kit.github.io/examples/mergeTreeClustering/ diff --git a/paraview/xmls/MergeTreeTemporalReduction.xml b/paraview/xmls/MergeTreeTemporalReduction.xml index 55c8382a76..13a1c25497 100644 --- a/paraview/xmls/MergeTreeTemporalReduction.xml +++ b/paraview/xmls/MergeTreeTemporalReduction.xml @@ -21,6 +21,11 @@ Mathieu Pont, Jules Vidal, Julie Delon, Julien Tierny. Proc. of IEEE VIS 2021. IEEE Transactions on Visualization and Computer Graphics, 2021 +'Merge Tree Geodesics and Barycenters with Path Mappings' +F. Wetzels, M. Pont, J. Tierny and C. Garth. +Proc. of IEEE VIS 2023. +IEEE Transactions on Visualization and Computer Graphics, 2024 + Online examples: - https://topology-tool-kit.github.io/examples/mergeTreeTemporalReduction/ diff --git a/paraview/xmls/MergeTreeTemporalReductionDecoding.xml b/paraview/xmls/MergeTreeTemporalReductionDecoding.xml index 5a1206ff99..6521a8f36f 100644 --- a/paraview/xmls/MergeTreeTemporalReductionDecoding.xml +++ b/paraview/xmls/MergeTreeTemporalReductionDecoding.xml @@ -19,6 +19,11 @@ Mathieu Pont, Jules Vidal, Julie Delon, Julien Tierny. Proc. of IEEE VIS 2021. IEEE Transactions on Visualization and Computer Graphics, 2021 +'Merge Tree Geodesics and Barycenters with Path Mappings' +F. Wetzels, M. Pont, J. Tierny and C. Garth. +Proc. of IEEE VIS 2023. +IEEE Transactions on Visualization and Computer Graphics, 2024 + Online examples: - https://topology-tool-kit.github.io/examples/mergeTreeTemporalReduction/ From da70930123a79db84eaa054aa788869dbd210a80 Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Thu, 19 Dec 2024 14:29:15 +0100 Subject: [PATCH 70/72] [BranchMappingDistance] fixed type of cost array --- core/base/mergeTreeClustering/BranchMappingDistance.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/base/mergeTreeClustering/BranchMappingDistance.h b/core/base/mergeTreeClustering/BranchMappingDistance.h index ce54a5bd2b..694ffbaffd 100644 --- a/core/base/mergeTreeClustering/BranchMappingDistance.h +++ b/core/base/mergeTreeClustering/BranchMappingDistance.h @@ -620,7 +620,7 @@ namespace ttk { outputMatching->clear(); std::vector matchedNodes(tree1->getNumberOfNodes(), -1); - std::vector matchedCost(tree1->getNumberOfNodes(), -1); + std::vector matchedCost(tree1->getNumberOfNodes(), -1); std::vector, std::pair>> mapping; std::vector linkedNodes1(tree1->getNumberOfNodes(), -1); From ebc62eca9f1b7aeee7620c1783d20eba83f8d37a Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Thu, 19 Dec 2024 15:14:41 +0100 Subject: [PATCH 71/72] [BranchMappingDistance] fixed missing entries in cost array --- core/base/mergeTreeClustering/BranchMappingDistance.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/core/base/mergeTreeClustering/BranchMappingDistance.h b/core/base/mergeTreeClustering/BranchMappingDistance.h index 694ffbaffd..b0b5b393d1 100644 --- a/core/base/mergeTreeClustering/BranchMappingDistance.h +++ b/core/base/mergeTreeClustering/BranchMappingDistance.h @@ -668,9 +668,10 @@ namespace ttk { : editCost_Shifting(m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2); - if(m.first.second == (int)tree1->getRoot()) { - matchedCost[m.first.second] = matchedCost[m.first.first]; - } + // if(m.first.second == (int)tree1->getRoot()) { + // matchedCost[m.first.second] = matchedCost[m.first.first]; + // } + matchedCost[m.first.second] = matchedCost[m.first.first]; } for(ftm::idNode i = 0; i < matchedNodes.size(); i++) { if(matchedNodes[i] >= 0) From 807dc364282d5ad57852c9ef63018464086d5306 Mon Sep 17 00:00:00 2001 From: Florian Wetzels Date: Thu, 19 Dec 2024 16:13:58 +0100 Subject: [PATCH 72/72] [BranchMappingDistance] removed outcommented code --- core/base/mergeTreeClustering/BranchMappingDistance.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/base/mergeTreeClustering/BranchMappingDistance.h b/core/base/mergeTreeClustering/BranchMappingDistance.h index b0b5b393d1..de3e47c835 100644 --- a/core/base/mergeTreeClustering/BranchMappingDistance.h +++ b/core/base/mergeTreeClustering/BranchMappingDistance.h @@ -668,9 +668,6 @@ namespace ttk { : editCost_Shifting(m.first.first, m.first.second, m.second.first, m.second.second, tree1, tree2); - // if(m.first.second == (int)tree1->getRoot()) { - // matchedCost[m.first.second] = matchedCost[m.first.first]; - // } matchedCost[m.first.second] = matchedCost[m.first.first]; } for(ftm::idNode i = 0; i < matchedNodes.size(); i++) {