@@ -6,24 +6,23 @@ using namespace Rcpp;
66
77#include < algorithm> /* for fill */
88#include < array> /* for array */
9- #include < vector> /* for vector */
109
11- using TreeTools::ct_stack_size;
1210using TreeTools::ct_stack_threshold;
1311using TreeTools::ct_max_leaves_heap;
1412
13+ struct StackEntry { int32 L, R, N, W; };
14+
1515// Helper template function to perform consensus computation
1616// Uses StackContainer for the S array (either std::array or std::vector)
1717template <typename StackContainer>
18- RawMatrix consensus_tree_impl (
18+ RawMatrix calc_consensus_tree (
1919 const List& trees,
2020 const NumericVector& p,
2121 StackContainer& S
2222) {
2323 int32 v = 0 ;
2424 int32 w = 0 ;
2525 int32 L, R, N, W;
26- int32 L_j, R_j, N_j, W_j;
2726
2827 const int32 n_trees = trees.length ();
2928 const int32 frac_thresh = int32 (n_trees * p[0 ]) + 1 ;
@@ -39,11 +38,21 @@ RawMatrix consensus_tree_impl(
3938 const int32 ntip_3 = n_tip - 3 ;
4039 const int32 nbin = (n_tip + 7 ) / 8 ; // bytes per row in packed output
4140
42- std::vector<int32> split_count (n_tip, 1 );
41+ int32* split_count;
42+ std::array<int32, ct_stack_threshold> split_stack;
43+ std::vector<int32> split_heap;
44+ if (n_tip <= ct_stack_threshold) {
45+ split_count = split_stack.data ();
46+ } else {
47+ split_heap.resize (n_tip);
48+ split_count = split_heap.data ();
49+ }
50+
51+ StackEntry *const S_start = S.data ();
4352
4453 // Packed output: each row has nbin bytes
4554 RawMatrix ret (ntip_3, nbin);
46-
55+
4756 int32 i = 0 ;
4857 int32 splits_found = 0 ;
4958
@@ -52,42 +61,38 @@ RawMatrix consensus_tree_impl(
5261 continue ;
5362 }
5463
55- std::fill (split_count. begin () , split_count. end () , 1 );
56-
64+ std::fill (split_count, split_count + n_tip , 1 );
65+
5766 for (int32 j = i + 1 ; j < n_trees; ++j) {
5867 ASSERT (tables[i].N () == tables[j].N ());
59-
68+
6069 tables[i].CLEAR ();
61-
70+
6271 tables[j].TRESET ();
6372 tables[j].READT (&v, &w);
6473
6574 int32 j_pos = 0 ;
66- int32 Spos = 0 ; // Empty the stack S. Used in CT_PUSH / CT_POP macros.
75+ StackEntry* S_top = S_start ; // Empty the stack S
6776
6877 do {
6978 if (CT_IS_LEAF (v)) {
70- CT_ASSERT_CAN_PUSH ( );
71- CT_PUSH (tables[i]. ENCODE (v), tables[i]. ENCODE (v) , 1 , 1 ) ;
79+ const auto enc_v = tables[i]. ENCODE (v );
80+ *S_top++ = {enc_v, enc_v , 1 , 1 } ;
7281 } else {
73- CT_ASSERT_CAN_POP ();
74- CT_POP (L, R, N, W_j);
75-
76- W = 1 + W_j;
77- w = w - W_j;
78-
82+ const StackEntry& entry = *--S_top;
83+ L = entry.L ; R = entry.R ; N = entry.N ;
84+ W = 1 + entry.W ;
85+ w -= entry.W ;
7986 while (w) {
80- CT_ASSERT_CAN_POP ();
81- CT_POP (L_j, R_j, N_j, W_j);
82- if (L_j < L) L = L_j;
83- if (R_j > R) R = R_j;
84- N = N + N_j;
85- W = W + W_j;
86- w = w - W_j;
87+ const StackEntry& next = *--S_top;
88+ L = std::min (L, next.L ); // Faster than ternary operator
89+ R = std::max (R, next.R );
90+ N += next.N ;
91+ W += next.W ;
92+ w -= next.W ;
8793 }
8894
89- CT_ASSERT_CAN_PUSH ();
90- CT_PUSH (L, R, N, W);
95+ *S_top++ = {L, R, N, W};
9196
9297 ++j_pos;
9398
@@ -133,14 +138,8 @@ RawMatrix consensus_tree_impl(
133138 }
134139 } while (i++ != n_trees - thresh); // All clades in p% consensus must occur in first q% of trees.
135140
136- if (splits_found == 0 ) {
137- return RawMatrix (0 , nbin);
138- } else if (splits_found < ntip_3) {
139- // Return only the rows we filled
140- return ret (Range (0 , splits_found - 1 ), _);
141- } else {
142- return ret;
143- }
141+ return (splits_found == 0 ) ? RawMatrix (0 , nbin) :
142+ (splits_found < ntip_3) ? ret (Range (0 , splits_found - 1 ), _) : ret;
144143}
145144
146145// trees is a list of objects of class phylo, all with the same tip labels
@@ -158,12 +157,12 @@ RawMatrix consensus_tree(const List trees, const NumericVector p) {
158157
159158 if (n_tip <= ct_stack_threshold) {
160159 // Small tree: use stack-allocated array
161- std::array<int32, ct_stack_size * ct_stack_threshold> S;
162- return consensus_tree_impl (trees, p, S);
160+ std::array<StackEntry, ct_stack_threshold> S;
161+ return calc_consensus_tree (trees, p, S);
163162 } else {
164163 // Large tree: use heap-allocated vector
165- std::vector<int32 > S (ct_stack_size * n_tip);
166- return consensus_tree_impl (trees, p, S);
164+ std::vector<StackEntry > S (n_tip);
165+ return calc_consensus_tree (trees, p, S);
167166 }
168167 } catch (const std::exception& e) {
169168 Rcpp::stop (e.what ());
0 commit comments