254 template <
class scalarType>
255 int execute(
const std::vector<void *> &scalarsVP,
256 const std::vector<int *> ®ionSizes,
257 const std::vector<int *> &segmentationIds,
258 const std::vector<long long *> &topologies,
259 const std::vector<size_t> &nVertices,
260 const std::vector<size_t> &nEdges,
261 const std::vector<int *> &segmentations,
262 const std::vector<size_t> &segsizes,
264 std::vector<float> &outputVertices,
265 std::vector<long long> &outputFrequencies,
266 std::vector<long long> &outputVertexIds,
267 std::vector<long long> &outputBranchIds,
268 std::vector<long long> &outputSegmentationIds,
269 std::vector<long long> &outputArcIds,
270 std::vector<int> &outputEdges,
279 bool alignTree(
const std::shared_ptr<ContourTree> &t);
284 bool initialize(
const std::shared_ptr<ContourTree> &t);
300 std::vector<std::pair<std::vector<std::shared_ptr<ttk::cta::CTNode>>,
301 std::vector<std::shared_ptr<ttk::cta::CTEdge>>>>
310 std::pair<std::vector<std::shared_ptr<ttk::cta::AlignmentNode>>,
311 std::vector<std::shared_ptr<ttk::cta::AlignmentEdge>>>
326 std::pair<float, std::shared_ptr<ttk::cta::AlignmentTree>>
328 const std::shared_ptr<ttk::cta::BinaryTree> &t2);
343 std::vector<std::shared_ptr<ttk::cta::AlignmentNode>>
nodes;
344 std::vector<std::shared_ptr<ttk::cta::AlignmentEdge>>
arcs;
356 const std::shared_ptr<ttk::cta::BinaryTree> &t2,
357 std::vector<std::vector<float>> &memT,
358 std::vector<std::vector<float>> &memF);
360 const std::shared_ptr<ttk::cta::BinaryTree> &t2,
361 std::vector<std::vector<float>> &memT,
362 std::vector<std::vector<float>> &memF);
366 std::shared_ptr<ttk::cta::AlignmentTree>
368 const std::shared_ptr<ttk::cta::BinaryTree> &t2,
369 std::vector<std::vector<float>> &memT,
370 std::vector<std::vector<float>> &memF);
371 std::vector<std::shared_ptr<ttk::cta::AlignmentTree>>
373 const std::shared_ptr<ttk::cta::BinaryTree> &t2,
374 std::vector<std::vector<float>> &memT,
375 std::vector<std::vector<float>> &memF);
376 std::shared_ptr<ttk::cta::AlignmentTree>
381 float editCost(
const std::shared_ptr<ttk::cta::BinaryTree> &t1,
382 const std::shared_ptr<ttk::cta::BinaryTree> &t2);
385 bool isBinary(
const std::shared_ptr<ttk::cta::Tree> &t);
386 std::shared_ptr<ttk::cta::BinaryTree>
387 rootAtNode(
const std::shared_ptr<ttk::cta::AlignmentNode> &root);
388 std::shared_ptr<ttk::cta::BinaryTree>
390 const std::shared_ptr<ttk::cta::AlignmentEdge> &parent,
392 std::shared_ptr<ttk::cta::BinaryTree>
397 const std::shared_ptr<ttk::cta::AlignmentTree> &res);
400 std::pair<float, std::vector<std::shared_ptr<ttk::cta::AlignmentNode>>>
401 pathToMax(
const std::shared_ptr<ttk::cta::AlignmentNode> &root,
402 const std::shared_ptr<ttk::cta::AlignmentNode> &parent);
403 std::pair<float, std::vector<std::shared_ptr<ttk::cta::AlignmentNode>>>
404 pathToMin(
const std::shared_ptr<ttk::cta::AlignmentNode> &root,
405 const std::shared_ptr<ttk::cta::AlignmentNode> &parent);
411 const std::vector<void *> &scalarsVP,
412 const std::vector<int *> ®ionSizes,
413 const std::vector<int *> &segmentationIds,
414 const std::vector<long long *> &topologies,
415 const std::vector<size_t> &nVertices,
416 const std::vector<size_t> &nEdges,
417 const std::vector<int *> &segmentations,
418 const std::vector<size_t> &segsizes,
419 std::vector<float> &outputVertices,
420 std::vector<long long> &outputFrequencies,
421 std::vector<long long> &outputVertexIds,
422 std::vector<long long> &outputBranchIds,
423 std::vector<long long> &outputSegmentationIds,
424 std::vector<long long> &outputArcIds,
425 std::vector<int> &outputEdges,
430 const size_t nTrees = nVertices.size();
432 std::vector<float *> scalars(nTrees);
433 for(
size_t t = 0; t < nTrees; t++) {
434 scalars[t] = (
float *)((scalarType *)scalarsVP[t]);
440 this->
printMsg(
"Execute base layer");
441 this->
printMsg(
"Computing Alignment for " + std::to_string(nTrees)
445 for(
size_t t = 0; t < nTrees; t++) {
447 this->
printMsg(
"Input Tree " + std::to_string(t) +
" topology:",
450 std::vector<std::vector<std::string>> tableLines;
451 tableLines.push_back(
452 {
"cellId",
"vId0",
"vId1",
"scalar0",
"scalar1",
"region",
"segId"});
453 for(
size_t i = 0; i < nEdges[t]; i++) {
454 const long long vertexId0 = topologies[t][i * 2 + 0];
455 const long long vertexId1 = topologies[t][i * 2 + 1];
456 const int regionSize = regionSizes[t][i];
457 const int segmentationId = segmentationIds[t][i];
458 scalarType scalarOfVertexId0 = scalars[t][vertexId0];
459 scalarType scalarOfVertexId1 = scalars[t][vertexId1];
461 std::vector<std::string> tableLine;
462 tableLine.push_back(std::to_string(i));
463 tableLine.push_back(std::to_string(vertexId0));
464 tableLine.push_back(std::to_string(vertexId1));
465 tableLine.push_back(std::to_string(scalarOfVertexId0));
466 tableLine.push_back(std::to_string(scalarOfVertexId1));
467 tableLine.push_back(std::to_string(regionSize));
468 tableLine.push_back(std::to_string(segmentationId));
470 tableLines.push_back(tableLine);
475 std::vector<std::vector<std::vector<int>>> segRegions;
476 if(!segsizes.empty()) {
477 for(
size_t i = 0; i < nTrees; i++) {
479 std::vector<int> seg(segsizes[i]);
480 for(
size_t j = 0; j < segsizes[i]; j++) {
481 maxSegId = std::max(maxSegId, segmentations[i][j]);
482 seg[j] = segmentations[i][j];
484 std::vector<std::vector<int>> reg(maxSegId + 1);
485 for(
size_t j = 0; j < segsizes[i]; j++) {
486 reg[segmentations[i][j]].push_back(j);
488 segRegions.push_back(reg);
490 for(
size_t i = 0; i < nTrees; i++) {
492 for(
const auto &seg : segRegions[i]) {
495 this->
printMsg(
"Tree " + std::to_string(i)
496 +
", sum of segment sizes: " + std::to_string(sum));
498 for(
size_t j = 0; j < nEdges[i]; j++) {
499 sum += regionSizes[i][j];
501 this->
printMsg(
"Tree " + std::to_string(i)
502 +
", sum of region sizes: " + std::to_string(sum));
507 contourtrees = std::vector<std::shared_ptr<ContourTree>>();
508 nodes = std::vector<std::shared_ptr<ttk::cta::AlignmentNode>>();
509 arcs = std::vector<std::shared_ptr<ttk::cta::AlignmentEdge>>();
513 this->
printMsg(
"Shuffling input trees. Used seed: " + std::to_string(seed), 0,
518 for(
size_t i = 0; i < nTrees; i++) {
523 std::mt19937 random_engine{};
524 random_engine.seed(seed);
532 "Shuffling input trees. Used seed: " + std::to_string(seed), 1);
536 std::string permutationString =
"";
538 permutationString += std::to_string(
permutation[i])
545 this->
printMsg(
"Starting alignment heuristic.");
547 std::tuple<std::vector<std::shared_ptr<ttk::cta::AlignmentNode>>,
548 std::vector<std::shared_ptr<ttk::cta::AlignmentEdge>>,
549 std::vector<std::shared_ptr<ContourTree>>>
551 float bestAlignmentValue = FLT_MAX;
556 std::vector<std::shared_ptr<ContourTree>> contourtreesToAlign;
557 for(
size_t i = 0; i < nTrees; i++) {
558 auto ct = std::make_shared<ContourTree>(
562 segRegions.empty() ? std::vector<std::vector<int>>() : segRegions[i]);
564 contourtreesToAlign.push_back(ct);
567 +
" not binary. Will not be aligned.");
569 printMsg(
"Filtering input contour trees (" + std::to_string(i) +
"/"
570 + std::to_string(nTrees) +
")",
573 if(contourtreesToAlign.empty()) {
580 printMsg(
"Filtering input contour trees", 1);
582 for(
size_t rootIdx = 0;
583 rootIdx < contourtreesToAlign[0]->getGraph().first.size(); rootIdx++) {
591 this->
printMsg(
"Starting alignment computation with root "
592 + std::to_string(rootIdx));
598 "Initializing alignment with tree " + std::to_string(
permutation[i]), 0,
602 "Initializing alignment with tree " + std::to_string(
permutation[i]), 1,
607 this->
printMsg(
"Initialized root is saddle, alignment aborted.");
615 while(i < contourtreesToAlign.size()) {
626 this->
printMsg(
"All trees aligned. Total alignment value: "
633 bestRootIdx = rootIdx;
637 nodes = std::get<0>(bestAlignment);
638 arcs = std::get<1>(bestAlignment);
642 this->
printMsg(
"Alignment iteration complete.");
643 this->
printMsg(
"Root of optimal alignment: " + std::to_string(bestRootIdx)
646 "Value of optimal alignment: " + std::to_string(bestAlignmentValue) +
".");
658 for(
const auto &node :
nodes) {
660 outputVertices.push_back(node->scalarValue);
661 outputFrequencies.push_back(node->freq);
662 outputBranchIds.push_back(node->branchID);
663 std::vector<long long> refs(nTrees, -1);
664 std::vector<long long> segRefs(nTrees, -1);
665 for(
auto ref : node->nodeRefs) {
668 =
contourtrees[ref.first]->getGraph().first[ref.second]->edgeList[0];
670 =
contourtrees[ref.first]->getGraph().second[eId]->segId;
672 for(
int ref : refs) {
673 outputVertexIds.push_back(ref);
675 for(
int segRef : segRefs) {
676 outputSegmentationIds.push_back(segRef);
680 for(
const auto &edge :
arcs) {
683 for(
const auto &node :
nodes) {
685 if(node == edge->node1.lock()) {
686 outputEdges.push_back(i);
689 if(node == edge->node2.lock()) {
690 outputEdges.push_back(i);
696 std::vector<long long> arcRefs(nTrees, -1);
697 for(
auto ref : edge->arcRefs) {
700 for(
int ref : arcRefs) {
701 outputArcIds.push_back(ref);
709 this->
printMsg(
"Alignment computed in "
712 this->
printMsg(
"Number of nodes in alignment: "
713 + std::to_string(
nodes.size()));
int execute(const std::vector< void * > &scalarsVP, const std::vector< int * > ®ionSizes, const std::vector< int * > &segmentationIds, const std::vector< long long * > &topologies, const std::vector< size_t > &nVertices, const std::vector< size_t > &nEdges, const std::vector< int * > &segmentations, const std::vector< size_t > &segsizes, std::vector< float > &outputVertices, std::vector< long long > &outputFrequencies, std::vector< long long > &outputVertexIds, std::vector< long long > &outputBranchIds, std::vector< long long > &outputSegmentationIds, std::vector< long long > &outputArcIds, std::vector< int > &outputEdges, int seed)