From 3b50b0e0f0e2ebdf82c2c9fb050dd87898864dc6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 5 Jan 2026 16:14:21 +0000 Subject: [PATCH 1/3] Initial plan From a66f2ce94b56437f238cb4f8ada08a8ef9399a2d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 5 Jan 2026 16:49:58 +0000 Subject: [PATCH 2/3] Implement heap allocation for large trees in splits_to_edge Co-authored-by: ms609 <1695515+ms609@users.noreply.github.com> --- src/splits_to_tree.cpp | 45 +++++++++++++++++++++++++++--------- tests/testthat/test-Splits.R | 14 +++++++---- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/splits_to_tree.cpp b/src/splits_to_tree.cpp index 9984170e3..cbd3e5aba 100644 --- a/src/splits_to_tree.cpp +++ b/src/splits_to_tree.cpp @@ -7,8 +7,8 @@ using namespace Rcpp; using namespace TreeTools; inline void insert_ancestor(const int16 tip, const int16 *next_node, - std::array& parent, - std::array& patriarch) { + int16* parent, + int16* patriarch) { if (patriarch[tip]) { parent[patriarch[tip]] = *next_node; } else { @@ -19,9 +19,6 @@ inline void insert_ancestor(const int16 tip, const int16 *next_node, // [[Rcpp::export]] IntegerMatrix splits_to_edge(const RawMatrix splits, const IntegerVector nTip) { - if (double(nTip[0]) > 2048) { - Rcpp::stop("This many leaves are not (yet) supported."); - } const int16 n_tip = int16(nTip[0]); if (splits.nrow() == 0) { IntegerMatrix ret(n_tip, 2); @@ -32,12 +29,38 @@ IntegerMatrix splits_to_edge(const RawMatrix splits, const IntegerVector nTip) { return ret; } const SplitList x(splits); - alignas(64) std::array parent{}; - alignas(64) std::array patriarch{}; - - std::array split_order; - std::iota(split_order.begin(), split_order.begin() + x.n_splits, 0); - std::sort(split_order.begin(), split_order.begin() + x.n_splits, + + // Decide whether to use stack or heap allocation based on tree size + const bool use_heap = (n_tip > SL_MAX_TIPS) || (x.n_splits > SL_MAX_SPLITS); + + // Stack allocation for small trees (fast path) + alignas(64) std::array stack_parent{}; + alignas(64) std::array stack_patriarch{}; + + // Heap allocation for large trees + std::vector heap_parent; + std::vector heap_patriarch; + + // Pointers to active storage + int16* parent; + int16* patriarch; + + if (use_heap) { + const size_t parent_size = static_cast(n_tip) + + static_cast(x.n_splits); + heap_parent.resize(parent_size, 0); + heap_patriarch.resize(n_tip, 0); + parent = heap_parent.data(); + patriarch = heap_patriarch.data(); + } else { + parent = stack_parent.data(); + patriarch = stack_patriarch.data(); + } + + // Allocate split_order appropriately + std::vector split_order(x.n_splits); + std::iota(split_order.begin(), split_order.end(), 0); + std::sort(split_order.begin(), split_order.end(), [&in_split = x.in_split](int16 a, int16 b) { return in_split[a] > in_split[b]; }); diff --git a/tests/testthat/test-Splits.R b/tests/testthat/test-Splits.R index 6f3201116..637751a33 100644 --- a/tests/testthat/test-Splits.R +++ b/tests/testthat/test-Splits.R @@ -512,11 +512,15 @@ test_that("Split combination", { #TODO: Fully test splits with large (> 8 tip) trees }) -test_that("as.phylo.Splits() fails gracefully", { - expect_error( - as.phylo(as.Splits(BalancedTree(3000))), - "many leaves are not .*supported" - ) +test_that("as.phylo.Splits() supports large trees", { + tree3000 <- BalancedTree(3000) + splits3000 <- as.Splits(tree3000) + result <- as.phylo(splits3000) + + # Verify it's a valid phylo object + expect_s3_class(result, "phylo") + expect_equal(length(result$tip.label), 3000) + expect_equal(NTip(result), 3000) }) test_that("as.phylo.Splits()", { From 5ad65570e953b34ab9dae6803848cc351b755cf4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 5 Jan 2026 16:55:20 +0000 Subject: [PATCH 3/3] Successfully tested large tree support - all sizes working Co-authored-by: ms609 <1695515+ms609@users.noreply.github.com> --- man/figures/Stemwardness.png | Bin 3703 -> 7709 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/man/figures/Stemwardness.png b/man/figures/Stemwardness.png index 3b49ff71773cc0ccee27dd6af5abadb16506ad46..d2954f60831828860909c98b887e466f0e2c86a1 100644 GIT binary patch literal 7709 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