279 const std::shared_ptr<ContourTree> &ct,
int rootIdx) {
285 contourtrees.push_back(ct);
289 const std::shared_ptr<ttk::cta::BinaryTree> t = ct->rootAtMax();
291 std::queue<std::pair<std::shared_ptr<ttk::cta::BinaryTree>,
292 std::shared_ptr<ttk::cta::AlignmentNode>>>
295 auto currNode = std::make_shared<ttk::cta::AlignmentNode>();
296 std::shared_ptr<ttk::cta::BinaryTree> currTree;
299 currNode->type = t->type;
300 currNode->branchID = -1;
301 currNode->scalarValue = t->scalarValue;
303 currNode->nodeRefs = std::vector<std::pair<int, int>>();
304 currNode->nodeRefs.emplace_back(0, t->nodeRefs[0].second);
306 nodes.push_back(currNode);
308 q.emplace(t, currNode);
312 currTree = q.front().first;
313 currNode = q.front().second;
316 if(currTree->child1 !=
nullptr) {
318 auto childNode = std::make_shared<ttk::cta::AlignmentNode>();
320 childNode->type = currTree->child1->type;
321 childNode->branchID = -1;
322 childNode->scalarValue = currTree->child1->scalarValue;
324 childNode->nodeRefs = std::vector<std::pair<int, int>>();
325 childNode->nodeRefs.emplace_back(0, currTree->child1->nodeRefs[0].second);
327 auto childEdge = std::make_shared<ttk::cta::AlignmentEdge>();
328 childEdge->area = currTree->child1->area;
329 childEdge->scalardistance = currTree->child1->scalardistanceParent;
330 childEdge->volume = currTree->child1->volume;
331 childEdge->region = currTree->child1->region;
332 childEdge->node1 = currNode;
333 childEdge->node2 = childNode;
335 childEdge->arcRefs = std::vector<std::pair<int, int>>();
336 childEdge->arcRefs.emplace_back(0, currTree->child1->arcRefs[0].second);
338 childNode->edgeList.push_back(childEdge);
339 currNode->edgeList.push_back(childEdge);
341 nodes.push_back(childNode);
342 arcs.push_back(childEdge);
344 q.emplace(currTree->child1, childNode);
347 if(currTree->child2 !=
nullptr) {
349 auto childNode = std::make_shared<ttk::cta::AlignmentNode>();
351 childNode->type = currTree->child2->type;
352 childNode->branchID = -1;
353 childNode->scalarValue = currTree->child2->scalarValue;
355 childNode->nodeRefs = std::vector<std::pair<int, int>>();
356 childNode->nodeRefs.emplace_back(0, currTree->child2->nodeRefs[0].second);
358 auto childEdge = std::make_shared<ttk::cta::AlignmentEdge>();
359 childEdge->area = currTree->child2->area;
360 childEdge->scalardistance = currTree->child2->scalardistanceParent;
361 childEdge->volume = currTree->child2->volume;
362 childEdge->region = currTree->child2->region;
363 childEdge->node1 = currNode;
364 childEdge->node2 = childNode;
366 childEdge->arcRefs = std::vector<std::pair<int, int>>();
367 childEdge->arcRefs.emplace_back(0, currTree->child2->arcRefs[0].second);
369 childNode->edgeList.push_back(childEdge);
370 currNode->edgeList.push_back(childEdge);
372 nodes.push_back(childNode);
373 arcs.push_back(childEdge);
375 q.emplace(currTree->child2, childNode);
379 if(nodes.size() != ct->getGraph().first.size()) {
383 alignmentRoot = nodes[rootIdx];
384 alignmentRootIdx = rootIdx;
501 const std::shared_ptr<ttk::cta::AlignmentTree> &res) {
506 std::queue<std::tuple<std::shared_ptr<ttk::cta::AlignmentTree>,
507 std::shared_ptr<ttk::cta::AlignmentNode>,
508 std::vector<std::shared_ptr<ttk::cta::AlignmentEdge>>,
509 std::vector<std::shared_ptr<ttk::cta::AlignmentEdge>>>>
512 std::shared_ptr<ttk::cta::AlignmentNode> currNode;
513 std::shared_ptr<ttk::cta::AlignmentTree> currTree;
515 currNode = std::make_shared<ttk::cta::AlignmentNode>();
517 if(res->node1 ==
nullptr && res->node2 ==
nullptr) {
521 currNode->freq = (res->node1 ==
nullptr ? 0 : res->node1->freq)
522 + (res->node2 ==
nullptr ? 0 : res->node2->freq);
523 currNode->type = res->node1 ==
nullptr ? res->node2->type : res->node1->type;
524 currNode->branchID = -1;
528 currNode->scalarValue = res->node2 ==
nullptr ? res->node1->scalarValue
529 : res->node2->scalarValue;
531 currNode->nodeRefs = std::vector<std::pair<int, int>>();
532 if(res->node1 !=
nullptr)
533 currNode->nodeRefs.insert(currNode->nodeRefs.end(),
534 res->node1->nodeRefs.begin(),
535 res->node1->nodeRefs.end());
536 if(res->node2 !=
nullptr)
537 currNode->nodeRefs.emplace_back(
538 (
int)contourtrees.size() - 1, res->node2->nodeRefs[0].second);
542 currNode->scalarValue = res->node1 ==
nullptr ? res->node2->scalarValue
543 : res->node2 ==
nullptr
544 ? res->node1->scalarValue
545 : (res->node1->scalarValue * res->node1->freq
546 + res->node2->scalarValue)
551 if(res->node1 ==
nullptr)
552 currNode->scalarValue = res->node2->scalarValue;
553 else if(res->node2 ==
nullptr)
554 currNode->scalarValue = res->node1->scalarValue;
556 std::vector<float> values;
557 for(
auto p : res->node1->nodeRefs) {
559 contourtrees[p.first]->getGraph().first[p.second]->scalarValue);
561 values.push_back(res->node2->scalarValue);
562 std::sort(values.begin(), values.end());
563 const float newMedian = values[values.size() / 2];
564 currNode->scalarValue = newMedian;
568 currNode->nodeRefs = std::vector<std::pair<int, int>>();
569 if(res->node1 !=
nullptr)
570 currNode->nodeRefs.insert(currNode->nodeRefs.end(),
571 res->node1->nodeRefs.begin(),
572 res->node1->nodeRefs.end());
573 if(res->node2 !=
nullptr)
574 currNode->nodeRefs.emplace_back(
575 (
int)contourtrees.size() - 1, res->node2->nodeRefs[0].second);
577 nodes.push_back(currNode);
579 q.emplace(res, currNode,
580 std::vector<std::shared_ptr<ttk::cta::AlignmentEdge>>(),
581 std::vector<std::shared_ptr<ttk::cta::AlignmentEdge>>());
585 currTree = std::get<0>(q.front());
586 currNode = std::get<1>(q.front());
587 auto openEdgesOld1 = std::get<2>(q.front());
588 auto openEdgesNew1 = std::get<3>(q.front());
589 auto openEdgesOld2 = std::get<2>(q.front());
590 auto openEdgesNew2 = std::get<3>(q.front());
595 if(currTree->child1 !=
nullptr) {
597 if(currTree->child1->node1 ==
nullptr
598 && currTree->child1->node2 ==
nullptr) {
602 auto childNode = std::make_shared<ttk::cta::AlignmentNode>();
605 = (currTree->child1->node1 ==
nullptr ? 0
606 : currTree->child1->node1->freq)
607 + (currTree->child1->node2 ==
nullptr
609 : currTree->child1->node2->freq);
610 childNode->type = currTree->child1->node1 ==
nullptr
611 ? currTree->child1->node2->type
612 : currTree->child1->node1->type;
614 childNode->branchID = -1;
618 childNode->scalarValue = currTree->child1->node2 ==
nullptr
619 ? currTree->child1->node1->scalarValue
620 : currTree->child1->node2->scalarValue;
624 childNode->scalarValue = currTree->child1->node1 ==
nullptr
625 ? currTree->child1->node2->scalarValue
626 : currTree->child1->node2 ==
nullptr
627 ? currTree->child1->node1->scalarValue
628 : (currTree->child1->node1->scalarValue
629 * currTree->child1->node1->freq
630 + currTree->child1->node2->scalarValue)
635 if(currTree->child1->node1 ==
nullptr)
636 childNode->scalarValue = currTree->child1->node2->scalarValue;
637 else if(currTree->child1->node2 ==
nullptr)
638 childNode->scalarValue = currTree->child1->node1->scalarValue;
640 std::vector<float> values;
641 for(
auto p : currTree->child1->node1->nodeRefs) {
643 contourtrees[p.first]->getGraph().first[p.second]->scalarValue);
645 values.push_back(res->node2->scalarValue);
646 std::sort(values.begin(), values.end());
647 const float newMedian = values[values.size() / 2];
648 childNode->scalarValue = newMedian;
652 childNode->nodeRefs = std::vector<std::pair<int, int>>();
653 if(currTree->child1->node1 !=
nullptr)
654 childNode->nodeRefs.insert(childNode->nodeRefs.end(),
655 currTree->child1->node1->nodeRefs.begin(),
656 currTree->child1->node1->nodeRefs.end());
657 if(currTree->child1->node2 !=
nullptr)
658 childNode->nodeRefs.emplace_back(
659 (
int)contourtrees.size() - 1,
660 currTree->child1->node2->nodeRefs[0].second);
662 auto childEdge = std::make_shared<ttk::cta::AlignmentEdge>();
666 childEdge->area = currTree->child1->node2 ==
nullptr
667 ? currTree->child1->node1->area
668 : currTree->child1->node2->area;
670 childEdge->scalardistance
671 = currTree->child1->node2 ==
nullptr
672 ? currTree->child1->node1->scalardistanceParent
673 : currTree->child1->node2->scalardistanceParent;
678 = currTree->child1->node1 ==
nullptr ? currTree->child1->node2->area
679 : currTree->child1->node2 ==
nullptr
680 ? currTree->child1->node1->area
681 : (currTree->child1->node1->area * currTree->child1->node1->freq
682 + currTree->child1->node2->area)
685 childEdge->scalardistance
686 = currTree->child1->node1 ==
nullptr
687 ? currTree->child1->node2->scalardistanceParent
688 : currTree->child1->node2 ==
nullptr
689 ? currTree->child1->node1->scalardistanceParent
690 : (currTree->child1->node1->scalardistanceParent
691 * currTree->child1->node1->freq
692 + currTree->child1->node2->scalardistanceParent)
697 if(currTree->child1->node1 ==
nullptr) {
698 childEdge->area = currTree->child1->node2->area;
699 childEdge->scalardistance
700 = currTree->child1->node2->scalardistanceParent;
701 }
else if(currTree->child1->node2 ==
nullptr) {
702 childEdge->area = currTree->child1->node1->scalarValue;
703 childEdge->scalardistance
704 = currTree->child1->node1->scalardistanceParent;
706 std::vector<float> values;
707 for(
auto p : currTree->child1->node1->arcRefs) {
709 contourtrees[p.first]->getGraph().second[p.second]->area);
711 values.push_back(currTree->child1->node2->area);
712 std::sort(values.begin(), values.end());
713 float newMedian = values[values.size() / 2];
714 childEdge->area = newMedian;
716 for(
auto p : currTree->child1->node1->arcRefs) {
717 values.push_back(contourtrees[p.first]
722 values.push_back(currTree->child1->node2->scalardistanceParent);
723 std::sort(values.begin(), values.end());
724 newMedian = values[values.size() / 2];
725 childEdge->scalardistance = newMedian;
729 childEdge->region = currTree->child1->node2 ==
nullptr
730 ? currTree->child1->node1->region
731 : currTree->child1->node2->region;
733 childEdge->arcRefs = std::vector<std::pair<int, int>>();
734 if(currTree->child1->node1 !=
nullptr) {
735 for(
const auto &e : openEdgesOld1) {
736 e->arcRefs.insert(e->arcRefs.end(),
737 currTree->child1->node1->arcRefs.begin(),
738 currTree->child1->node1->arcRefs.end());
740 openEdgesOld1.clear();
741 childEdge->arcRefs.insert(childEdge->arcRefs.end(),
742 currTree->child1->node1->arcRefs.begin(),
743 currTree->child1->node1->arcRefs.end());
745 openEdgesOld1.push_back(childEdge);
746 if(currTree->child1->node2 !=
nullptr) {
747 for(
const auto &e : openEdgesNew1) {
748 e->arcRefs.emplace_back((
int)contourtrees.size() - 1,
749 currTree->child1->node2->arcRefs[0].second);
751 openEdgesNew1.clear();
752 childEdge->arcRefs.emplace_back(
753 (
int)contourtrees.size() - 1,
754 currTree->child1->node2->arcRefs[0].second);
756 openEdgesNew1.push_back(childEdge);
758 childEdge->volume = childEdge->area * childEdge->scalardistance;
760 childEdge->node1 = currNode;
761 childEdge->node2 = childNode;
763 childNode->edgeList.push_back(childEdge);
764 currNode->edgeList.push_back(childEdge);
766 nodes.push_back(childNode);
767 arcs.push_back(childEdge);
769 q.emplace(currTree->child1, childNode, openEdgesOld1, openEdgesNew1);
772 if(currTree->child2 !=
nullptr) {
774 if(currTree->child2->node1 ==
nullptr
775 && currTree->child2->node2 ==
nullptr) {
779 auto childNode = std::make_shared<ttk::cta::AlignmentNode>();
782 = (currTree->child2->node1 ==
nullptr ? 0
783 : currTree->child2->node1->freq)
784 + (currTree->child2->node2 ==
nullptr
786 : currTree->child2->node2->freq);
787 childNode->type = currTree->child2->node1 ==
nullptr
788 ? currTree->child2->node2->type
789 : currTree->child2->node1->type;
791 childNode->branchID = -1;
795 childNode->scalarValue = currTree->child2->node2 ==
nullptr
796 ? currTree->child2->node1->scalarValue
797 : currTree->child2->node2->scalarValue;
801 childNode->scalarValue = currTree->child2->node1 ==
nullptr
802 ? currTree->child2->node2->scalarValue
803 : currTree->child2->node2 ==
nullptr
804 ? currTree->child2->node1->scalarValue
805 : (currTree->child2->node1->scalarValue
806 * currTree->child2->node1->freq
807 + currTree->child2->node2->scalarValue)
812 if(currTree->child2->node1 ==
nullptr)
813 childNode->scalarValue = currTree->child2->node2->scalarValue;
814 else if(currTree->child2->node2 ==
nullptr)
815 childNode->scalarValue = currTree->child2->node1->scalarValue;
817 std::vector<float> values;
818 for(
auto p : currTree->child2->node1->nodeRefs) {
820 contourtrees[p.first]->getGraph().first[p.second]->scalarValue);
822 values.push_back(res->node2->scalarValue);
823 std::sort(values.begin(), values.end());
824 const float newMedian = values[values.size() / 2];
825 childNode->scalarValue = newMedian;
829 childNode->nodeRefs = std::vector<std::pair<int, int>>();
830 if(currTree->child2->node1 !=
nullptr)
831 childNode->nodeRefs.insert(childNode->nodeRefs.end(),
832 currTree->child2->node1->nodeRefs.begin(),
833 currTree->child2->node1->nodeRefs.end());
834 if(currTree->child2->node2 !=
nullptr)
835 childNode->nodeRefs.emplace_back(
836 (
int)contourtrees.size() - 1,
837 currTree->child2->node2->nodeRefs[0].second);
839 auto childEdge = std::make_shared<ttk::cta::AlignmentEdge>();
843 childEdge->area = currTree->child2->node2 ==
nullptr
844 ? currTree->child2->node1->area
845 : currTree->child2->node2->area;
847 childEdge->scalardistance
848 = currTree->child2->node2 ==
nullptr
849 ? currTree->child2->node1->scalardistanceParent
850 : currTree->child2->node2->scalardistanceParent;
855 = currTree->child2->node1 ==
nullptr ? currTree->child2->node2->area
856 : currTree->child2->node2 ==
nullptr
857 ? currTree->child2->node1->area
858 : (currTree->child2->node1->area * currTree->child2->node1->freq
859 + currTree->child2->node2->area)
862 childEdge->scalardistance
863 = currTree->child2->node1 ==
nullptr
864 ? currTree->child2->node2->scalardistanceParent
865 : currTree->child2->node2 ==
nullptr
866 ? currTree->child2->node1->scalardistanceParent
867 : (currTree->child2->node1->scalardistanceParent
868 * currTree->child2->node1->freq
869 + currTree->child2->node2->scalardistanceParent)
874 if(currTree->child2->node1 ==
nullptr) {
875 childEdge->area = currTree->child2->node2->area;
876 childEdge->scalardistance
877 = currTree->child2->node2->scalardistanceParent;
878 }
else if(currTree->child2->node2 ==
nullptr) {
879 childEdge->area = currTree->child2->node1->scalarValue;
880 childEdge->scalardistance
881 = currTree->child2->node1->scalardistanceParent;
883 std::vector<float> values;
884 for(
auto p : currTree->child2->node1->arcRefs) {
886 contourtrees[p.first]->getGraph().second[p.second]->area);
888 values.push_back(currTree->child2->node2->area);
889 std::sort(values.begin(), values.end());
890 float newMedian = values[values.size() / 2];
891 childEdge->area = newMedian;
893 for(
auto p : currTree->child2->node1->arcRefs) {
894 values.push_back(contourtrees[p.first]
899 values.push_back(currTree->child2->node2->scalardistanceParent);
900 std::sort(values.begin(), values.end());
901 newMedian = values[values.size() / 2];
902 childEdge->scalardistance = newMedian;
906 childEdge->region = currTree->child2->node2 ==
nullptr
907 ? currTree->child2->node1->region
908 : currTree->child2->node2->region;
910 childEdge->arcRefs = std::vector<std::pair<int, int>>();
911 if(currTree->child2->node1 !=
nullptr) {
912 for(
const auto &e : openEdgesOld2) {
913 e->arcRefs.insert(e->arcRefs.end(),
914 currTree->child2->node1->arcRefs.begin(),
915 currTree->child2->node1->arcRefs.end());
917 openEdgesOld2.clear();
918 childEdge->arcRefs.insert(childEdge->arcRefs.end(),
919 currTree->child2->node1->arcRefs.begin(),
920 currTree->child2->node1->arcRefs.end());
922 openEdgesOld2.push_back(childEdge);
923 if(currTree->child2->node2 !=
nullptr) {
924 for(
const auto &e : openEdgesNew1) {
925 e->arcRefs.emplace_back((
int)contourtrees.size() - 1,
926 currTree->child2->node2->arcRefs[0].second);
928 openEdgesNew2.clear();
929 childEdge->arcRefs.emplace_back(
930 (
int)contourtrees.size() - 1,
931 currTree->child2->node2->arcRefs[0].second);
933 openEdgesNew2.push_back(childEdge);
935 childEdge->volume = childEdge->area * childEdge->scalardistance;
937 childEdge->node1 = currNode;
938 childEdge->node2 = childNode;
940 childNode->edgeList.push_back(childEdge);
941 currNode->edgeList.push_back(childEdge);
943 nodes.push_back(childNode);
944 arcs.push_back(childEdge);
947 q.emplace(currTree->child2, childNode, openEdgesOld2, openEdgesNew2);
1281 const std::shared_ptr<ttk::cta::BinaryTree> &t1,
1282 const std::shared_ptr<ttk::cta::BinaryTree> &t2,
1283 std::vector<std::vector<float>> &memT,
1284 std::vector<std::vector<float>> &memF) {
1287 return traceNullAlignment(t2,
false);
1289 return traceNullAlignment(t1,
true);
1291 auto id = [](std::shared_ptr<ttk::cta::BinaryTree> &t) {
1292 return t ==
nullptr ? 0 : t->id;
1295 if(memT[t1->id][t2->id] == editCost(t1, t2) + memF[t1->id][t2->id]) {
1297 auto resNode = std::make_shared<ttk::cta::AlignmentTree>();
1299 resNode->node1 = t1;
1300 resNode->node2 = t2;
1301 resNode->child1 =
nullptr;
1302 resNode->child2 =
nullptr;
1303 resNode->height = 0;
1306 std::vector<std::shared_ptr<ttk::cta::AlignmentTree>> resChildren
1307 = traceAlignmentForest(t1, t2, memT, memF);
1309 if(resChildren.size() > 0)
1310 resNode->child1 = resChildren[0];
1311 if(resChildren.size() > 1)
1312 resNode->child2 = resChildren[1];
1314 for(
const auto &child : resChildren) {
1316 if(child !=
nullptr) {
1317 resNode->height = std::max(resNode->height, child->height + 1);
1318 resNode->size += child->size;
1325 if(memT[t1->id][t2->id]
1326 == editCost(t1,
nullptr) + memT[
id(t1->child2)][0]
1327 + memT[
id(t1->child1)]
1330 const std::shared_ptr<ttk::cta::AlignmentTree> resChild1
1331 = traceAlignmentTree(t1->child1, t2, memT, memF);
1332 const std::shared_ptr<ttk::cta::AlignmentTree> resChild2
1333 = traceNullAlignment(t1->child2,
true);
1334 auto res = std::make_shared<ttk::cta::AlignmentTree>();
1336 res->node2 =
nullptr;
1339 res->child1 = resChild1;
1340 res->child2 = resChild2;
1341 res->size += resChild1 ==
nullptr ? 0 : resChild1->size;
1342 res->size += resChild2 ==
nullptr ? 1 : resChild2->size;
1344 = std::max(res->height, resChild1 ==
nullptr ? 0 : resChild1->height + 1);
1346 = std::max(res->height, resChild2 ==
nullptr ? 0 : resChild2->height + 1);
1350 if(memT[t1->id][t2->id]
1351 == editCost(t1,
nullptr) + memT[id(t1->child1)][0]
1352 + memT[id(t1->child2)]
1355 const std::shared_ptr<ttk::cta::AlignmentTree> resChild1
1356 = traceAlignmentTree(t1->child2, t2, memT, memF);
1357 const std::shared_ptr<ttk::cta::AlignmentTree> resChild2
1358 = traceNullAlignment(t1->child1,
true);
1359 auto res = std::make_shared<ttk::cta::AlignmentTree>();
1361 res->node2 =
nullptr;
1364 res->child1 = resChild1;
1365 res->child2 = resChild2;
1366 res->size += resChild1 ==
nullptr ? 0 : resChild1->size;
1367 res->size += resChild2 ==
nullptr ? 0 : resChild2->size;
1369 = std::max(res->height, resChild1 ==
nullptr ? 0 : resChild1->height + 1);
1371 = std::max(res->height, resChild2 ==
nullptr ? 0 : resChild2->height + 1);
1375 if(memT[t1->id][t2->id]
1376 == editCost(
nullptr, t2) + memT[0][id(t2->child2)]
1380 const std::shared_ptr<ttk::cta::AlignmentTree> resChild1
1381 = traceAlignmentTree(t1, t2->child1, memT, memF);
1382 const std::shared_ptr<ttk::cta::AlignmentTree> resChild2
1383 = traceNullAlignment(t2->child2,
false);
1384 auto res = std::make_shared<ttk::cta::AlignmentTree>();
1385 res->node1 =
nullptr;
1389 res->child1 = resChild1;
1390 res->child2 = resChild2;
1391 res->size += resChild1 ==
nullptr ? 0 : resChild1->size;
1392 res->size += resChild2 ==
nullptr ? 0 : resChild2->size;
1394 = std::max(res->height, resChild1 ==
nullptr ? 0 : resChild1->height + 1);
1396 = std::max(res->height, resChild2 ==
nullptr ? 0 : resChild2->height + 1);
1400 if(memT[t1->id][t2->id]
1401 == editCost(
nullptr, t2) + memT[0][id(t2->child1)]
1405 const std::shared_ptr<ttk::cta::AlignmentTree> resChild1
1406 = traceAlignmentTree(t1, t2->child2, memT, memF);
1407 const std::shared_ptr<ttk::cta::AlignmentTree> resChild2
1408 = traceNullAlignment(t2->child1,
false);
1409 auto res = std::make_shared<ttk::cta::AlignmentTree>();
1410 res->node1 =
nullptr;
1414 res->child1 = resChild1;
1415 res->child2 = resChild2;
1416 res->size += resChild1 ==
nullptr ? 0 : resChild1->size;
1417 res->size += resChild2 ==
nullptr ? 0 : resChild2->size;
1419 = std::max(res->height, resChild1 ==
nullptr ? 0 : resChild1->height + 1);
1421 = std::max(res->height, resChild2 ==
nullptr ? 0 : resChild2->height + 1);
1425 printErr(
"Alignment computation failed. Traceback of memoization table not "
1427 return std::make_shared<ttk::cta::AlignmentTree>();
1432 const std::shared_ptr<ttk::cta::BinaryTree> &t1,
1433 const std::shared_ptr<ttk::cta::BinaryTree> &t2,
1434 std::vector<std::vector<float>> &memT,
1435 std::vector<std::vector<float>> &memF) {
1437 if(t1 ==
nullptr && t2 ==
nullptr)
1438 return std::vector<std::shared_ptr<ttk::cta::AlignmentTree>>();
1440 std::vector<std::shared_ptr<ttk::cta::AlignmentTree>> res;
1441 if(t2->child1 !=
nullptr)
1442 res.push_back(traceNullAlignment(t2->child1,
false));
1443 if(t2->child2 !=
nullptr)
1444 res.push_back(traceNullAlignment(t2->child2,
false));
1447 std::vector<std::shared_ptr<ttk::cta::AlignmentTree>> res;
1448 if(t1->child1 !=
nullptr)
1449 res.push_back(traceNullAlignment(t1->child1,
true));
1450 if(t1->child2 !=
nullptr)
1451 res.push_back(traceNullAlignment(t1->child2,
true));
1454 auto id = [](
const std::shared_ptr<ttk::cta::BinaryTree> &t) {
1455 return t ==
nullptr ? 0 : t->id;
1458 if(memF[t1->id][t2->id]
1459 == memT[
id(t1->child1)][id(t2->child1)]
1460 + memT[id(t1->child2)][id(t2->child2)]) {
1462 std::vector<std::shared_ptr<ttk::cta::AlignmentTree>> res;
1463 const std::shared_ptr<ttk::cta::AlignmentTree> res1
1464 = traceAlignmentTree(t1->child1, t2->child1, memT, memF);
1466 res.push_back(res1);
1467 const std::shared_ptr<ttk::cta::AlignmentTree> res2
1468 = traceAlignmentTree(t1->child2, t2->child2, memT, memF);
1470 res.push_back(res2);
1475 if(memF[t1->id][t2->id]
1476 == memT[
id(t1->child1)][
id(t2->child2)]
1477 + memT[
id(t1->child2)][
id(t2->child1)]) {
1479 std::vector<std::shared_ptr<ttk::cta::AlignmentTree>> res;
1480 const std::shared_ptr<ttk::cta::AlignmentTree> res1
1481 = traceAlignmentTree(t1->child1, t2->child2, memT, memF);
1483 res.push_back(res1);
1484 const std::shared_ptr<ttk::cta::AlignmentTree> res2
1485 = traceAlignmentTree(t1->child2, t2->child1, memT, memF);
1487 res.push_back(res2);
1492 if(memF[t1->id][t2->id]
1493 == editCost(t1->child1,
nullptr) + memF[
id(t1->child1)][t2->id]
1494 + memT[
id(t1->child2)][0]) {
1496 if(t1->child1 !=
nullptr) {
1498 std::vector<std::shared_ptr<ttk::cta::AlignmentTree>> res;
1500 auto t = std::make_shared<ttk::cta::AlignmentTree>();
1501 t->node1 = t1->child1;
1504 t->child1 =
nullptr;
1505 t->child2 =
nullptr;
1510 std::vector<std::shared_ptr<ttk::cta::AlignmentTree>> resChildren
1511 = traceAlignmentForest(t1->child1, t2, memT, memF);
1512 if(resChildren.size() > 0)
1513 t->child1 = resChildren[0];
1514 if(resChildren.size() > 1)
1515 t->child2 = resChildren[1];
1517 for(
const auto &c : resChildren) {
1519 t->height = std::max(t->height, c->height + 1);
1525 if(t1->child2 !=
nullptr)
1526 res.push_back(traceNullAlignment(t1->child2,
true));
1532 if(memF[t1->id][t2->id]
1533 == editCost(t1->child2,
nullptr) + memF[
id(t1->child2)][t2->id]
1534 + memT[
id(t1->child1)][0]) {
1536 if(t1->child2 !=
nullptr) {
1538 std::vector<std::shared_ptr<ttk::cta::AlignmentTree>> res;
1540 auto t = std::make_shared<ttk::cta::AlignmentTree>();
1541 t->node1 = t1->child2;
1544 t->child1 =
nullptr;
1545 t->child2 =
nullptr;
1550 std::vector<std::shared_ptr<ttk::cta::AlignmentTree>> resChildren
1551 = traceAlignmentForest(t1->child2, t2, memT, memF);
1552 if(resChildren.size() > 0)
1553 t->child1 = resChildren[0];
1554 if(resChildren.size() > 1)
1555 t->child2 = resChildren[1];
1557 for(
const auto &c : resChildren) {
1559 t->height = std::max(t->height, c->height + 1);
1565 if(t1->child1 !=
nullptr)
1566 res.push_back(traceNullAlignment(t1->child1,
true));
1572 if(memF[t1->id][t2->id]
1573 == editCost(
nullptr, t2->child1) + memF[t1->id][
id(t2->child1)]
1574 + memT[0][
id(t2->child2)]) {
1576 if(t2->child1 !=
nullptr) {
1578 std::vector<std::shared_ptr<ttk::cta::AlignmentTree>> res;
1580 auto t = std::make_shared<ttk::cta::AlignmentTree>();
1582 t->node2 = t2->child1;
1584 t->child1 =
nullptr;
1585 t->child2 =
nullptr;
1590 std::vector<std::shared_ptr<ttk::cta::AlignmentTree>> resChildren
1591 = traceAlignmentForest(t1, t2->child1, memT, memF);
1592 if(resChildren.size() > 0)
1593 t->child1 = resChildren[0];
1594 if(resChildren.size() > 1)
1595 t->child2 = resChildren[1];
1597 for(
const auto &c : resChildren) {
1599 t->height = std::max(t->height, c->height + 1);
1605 if(t2->child2 !=
nullptr)
1606 res.push_back(traceNullAlignment(t2->child2,
false));
1612 if(memF[t1->id][t2->id]
1613 == editCost(
nullptr, t2->child2) + memF[t1->id][
id(t2->child2)]
1614 + memT[0][
id(t2->child1)]) {
1616 if(t2->child2 !=
nullptr) {
1618 std::vector<std::shared_ptr<ttk::cta::AlignmentTree>> res;
1620 auto t = std::make_shared<ttk::cta::AlignmentTree>();
1622 t->node2 = t2->child2;
1624 t->child1 =
nullptr;
1625 t->child2 =
nullptr;
1630 std::vector<std::shared_ptr<ttk::cta::AlignmentTree>> resChildren
1631 = traceAlignmentForest(t1, t2->child2, memT, memF);
1632 if(resChildren.size() > 0)
1633 t->child1 = resChildren[0];
1634 if(resChildren.size() > 1)
1635 t->child2 = resChildren[1];
1637 for(
const auto &c : resChildren) {
1639 t->height = std::max(t->height, c->height + 1);
1645 if(t2->child1 !=
nullptr)
1646 res.push_back(traceNullAlignment(t2->child1,
false));
1652 printErr(
"Alignment computation failed. Traceback of memoization table not "
1654 return std::vector<std::shared_ptr<ttk::cta::AlignmentTree>>();