Skip to content

NNIDist(): score all pairs in one C++ call - #228

Open
ms609-agent wants to merge 1 commit into
mainfrom
claude/nni-all-pairs
Open

ms609-agent wants to merge 1 commit into
mainfrom
claude/nni-all-pairs

Conversation

@ms609-agent

Copy link
Copy Markdown
Collaborator

NNIDist(trees) (one list, all pairs) now renumbers and postorders each tree once and scores every pair in a single C++ call (cpp_nni_distance_all_pairs()), instead of CompareAll() → .NNIDistSingle() per pair. Each tree's splits are computed once; per pair only the split matching and scoring run. cpp_nni_distance() shares the same core (nni_tree(), nni_edge_to_splits(), nni_rf_matching(), nni_score()). Two-argument NNIDist(tree1, tree2) is unchanged.

Identity. Output is identical() to CompareAll(trees, NNIDist) (old path) on all 945 7-leaf trees, unrooted 7-leaf trees, random 60–200-leaf trees with shuffled labels, 3-leaf trees, polytomies, and lists that mix rooted and unrooted trees with equal edge counts (a pair is scored under the first tree's rootedness, as before; the second tree's splits are recomputed in that case).

Benchmark (release installs, min of N, single thread, local R-devel, same session):

Workload main PR
945 × 7 leaves 136.7 s 0.23 s
100 × 50 leaves 1.80 s 0.040 s
40 × 200 leaves 0.86 s 0.110 s

Main's 945-tree time includes the multiPhylo indexing cost fixed in #227; this PR bypasses CompareAll() so doesn't conflict with it. Recorded in .AGENTS/memory/Optimizations.md. At 200 leaves the O(s²) split matching now dominates; sorting canonical splits would allow a linear merge (follow-up).

New R and C++ lines covered by test-tree_distance_nni.R; NEWS entry added.

🤖 Generated with Claude Code

Renumber and postorder each tree once, compute each tree's splits once,
and score every pair in cpp_nni_distance_all_pairs(). Output identical
to CompareAll(trees, NNIDist).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ms609-agent
ms609-agent requested a review from ms609 October 31, 2026 08:50
Comment thread src/nni_distance.cpp
for (int32_t i = 0; i < n_edge - 1; ++i) { /* final edge is second root edge */
const ptrdiff_t parent_row_i = (edge(i, 0) - 1) * n_bin;
const ptrdiff_t child_row_i = (edge(i, 1) - 1) * n_bin;
const ptrdiff_t parent_row_i = (tree.parent[i] - 1) * n_bin;
Comment thread src/nni_distance.cpp
const ptrdiff_t parent_row_i = (edge(i, 0) - 1) * n_bin;
const ptrdiff_t child_row_i = (edge(i, 1) - 1) * n_bin;
const ptrdiff_t parent_row_i = (tree.parent[i] - 1) * n_bin;
const ptrdiff_t child_row_i = (tree.child[i] - 1) * n_bin;
@github-actions

Copy link
Copy Markdown

Performance benchmark results

Call Status Change Time (ms)
ClusteringInfoDistance(tr280) ⚪ NSD 0.15% 5.28, 5.51 →
5.18, 5.51
ClusteringInfoDistance(tr50) ⚪ NSD 0.99% 3.66, 3.84 →
3.51, 3.84
LAPJV(test2000) ⚪ NSD -2.18% 82.5, 84.3 →
85, 84.3
LAPJV(test40) ⚪ NSD 1.95% 0.0108, 0.0108 →
0.0107, 0.0106
LAPJV(test400) ⚪ NSD 5.08% 1.96, 1.96 →
1.91, 1.86
MutualClusteringInfo(tr280) ⚪ NSD -0.92% 9.25, 9.08 →
9.33, 9.18
MutualClusteringInfo(tr50) ⚪ NSD -0.26% 6.99, 6.76 →
6.94, 6.81
NNIMaxStep(2000, normalize = TRUE) ⚪ NSD -1.56% 0.0943, 0.0984 →
0.0955, 0.099
NNIMaxStep(300, normalize = TRUE) ⚪ NSD -2.68% 0.0155, 0.0159 →
0.0161, 0.0161
NNIMaxStep(300) ⚪ NSD -0.63% 0.00477, 0.00473 →
0.00474, 0.00482
PathDist(postTrees) ⚪ NSD 1.72% 1.06, 1.03 →
1.03, 1.03
PhylogeneticInfoDistance(tr180) ⚪ NSD 2.96% 32.4, 34.3 →
32.5, 34.5
PhylogeneticInfoDistance(tr50) ⚪ NSD -1.82% 21.3, 22.3 →
21.6, 22.5
RobinsonFoulds(tr280) ⚪ NSD 3.02% 2.98, 3.22 →
2.96, 3.06
RobinsonFoulds(tr280) ⚪ NSD 0.57% 2.55, 2.6 →
2.52, 2.59
RobinsonFoulds(tr50) ⚪ NSD -0.73% 2.51, 2.55 →
2.49, 2.62

@codecov

codecov Bot commented Oct 31, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.77%. Comparing base (2f6776d) to head (c566b61).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #228      +/-   ##
==========================================
+ Coverage   97.74%   97.77%   +0.02%     
==========================================
  Files          60       60              
  Lines        6575     6648      +73     
==========================================
+ Hits         6427     6500      +73     
  Misses        148      148              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants