Skip to content

Start the BEAUti subtree slide at size 0.01 - #201

Merged
walterxie merged 1 commit into
masterfrom
fix/template-subtreeslide-size
Nov 6, 2026
Merged

walterxie merged 1 commit into
masterfrom
fix/template-subtreeslide-size

Conversation

@alexeid

@alexeid alexeid commented Nov 5, 2026 •

Copy link
Copy Markdown
Member

Stopgap for #200 before the release: the BEAUti templates (Standard.xml for the Yule prior, TreePriors.xml for the other tree priors) start BactrianSubtreeSlide at size="0.01" instead of "1.0".

Why

The size is measured in tree-height units. In example runs it tunes to:

  • about 0.006–0.008 on substitution-scale trees (root height ≈ 0.06);
  • 0.4–2.5 on time-scaled trees (root height 6–100).

So 1.0 is about 100× too big for a typical clock-rate-1 analysis, and tuning can't recover from that (#200). From 1.0, testCoalescent's slide sticks at 0.029 with 1.4% acceptance, against an optimum of 0.0083 at the 0.3 target.

Starting too small costs much less, because tuning grows the size far faster than it shrinks it. On testYuleCalibrated (optimum ≈ 2.0), a start of 0.01 reaches 1.6 within 1M steps.

Starting from the tree's own scale (about 0.5 · H/√nodeCount) is the better fix. It's in #200 for after the release.

Testing

BeautiSimpleTest and SimpleTreePriorTest pass. They build analyses from these templates, but they check operator IDs, not sizes.

The Standard and TreePriors templates started BactrianSubtreeSlide at
size 1.0. The size is in tree-height units: in example runs it tunes to
about 0.006-0.008 on substitution-scale trees (height ~0.06) and to
0.4-2.5 on time-scaled trees (height 6-100). Tuning cannot recover from
a start that is much too large: when proposals are rejected the gain of
1/n lets log(size) fall by only about 0.3 ln n over a run. Started at 1.0,
the slide on testCoalescent stuck at 0.029 with 1.4% acceptance, against
an optimum of 0.0083 at the 0.3 target. A start that is too small
recovers quickly: on testYuleCalibrated a start of 0.01 reached 1.6 of
the optimal ~2.0 within 1M steps.

0.01 suits clock-rate-1 analyses and costs little on time-scaled trees.
Starting from the tree's own scale is the better fix and is left for
after the release.
@walterxie

walterxie commented Nov 6, 2026 •

Copy link
Copy Markdown
Member

PR #201 doesn't break anything in BEAUti, and for the most common case it's a clear improvement. Its effect is to move the range of tree sizes where tuning fails, not to remove it. These are the problems it causes or leaves:

  1. Trees with large height values now tune very slowly. This is the main new problem. Tuning grows the size by at most a factor of about e^(0.7·ln n) after n operator calls, so reaching a large optimum from 0.01 takes a long time. These are best-case numbers:
Tree (root height) Optimum size Slide calls needed Roughly MCMC steps
~10 (testYuleCalibrated, Myr scale) ~2 ~1,100 ~10⁴, fine
~10³ (for example days) ~20 ~3×10⁴ ~3×10⁵
~10⁴ (for example years) ~200 ~8×10⁵ ~8×10⁶
~10⁵ years ~2000 ~2×10⁷ ~2×10⁸: in practice it never gets there
Dated analyses in years (ancient DNA, phylogeography) are where a user would hit this. The results aren't wrong; the slide just makes tiny moves, so the tree mixes more slowly and relies on the other tree operators.
  1. Very shallow trees fail the old way. On a substitution-scale tree with root ~10⁻³ (low-diversity data, clock rate 1), the optimum is about 10⁻⁴. That's 100× below 0.01, and shrinking is slow: at least 2.6×10⁶ calls. This is the same "can't recover" failure as Auto-tuning can't recover from a step size that starts too large (1/n gain) #200, now at a smaller scale.
  2. No tuning means the slide stays at 0.01. If the user turns off optimise on the operator, or autoOptimize on the run, the size never changes. 0.01 is far too small for any time-scaled tree.
  3. The defaults now disagree. BactrianSubtreeSlide's own default (and its input description) is still size = 1.0. Hand-written XML and converted examples, including Convert 12 BEAST2 examples to BEAST3 (batch 2); ship SeqGen examples in beast-fx #204's, get 1.0, while BEAUti-made analyses get 0.01.
  4. No test checks the new value. As the PR says, BeautiSimpleTest and SimpleTreePriorTest check operator IDs, not sizes, so nothing would catch a regression.

@walterxie
walterxie merged commit 9fba433 into master Nov 6, 2026
1 check passed
@walterxie
walterxie deleted the fix/template-subtreeslide-size branch November 6, 2026 01:56
walterxie added a commit that referenced this pull request Nov 6, 2026
…odel input

Review requests from alexeid on #204:

1. Proper priors, in both versions (BEAST 3 examples and the BEAST 2 files
   in legacy/), as in #199 and BEAUti's defaults (#208): LogNormal(0, 8) for
   rates and sizes, LogNormal(1, 1.25) for kappa. Replaces the improper flat,
   OneOnX and Uniform(0, Infinity) priors, and the LogUniform stand-ins.
2. BactrianSubtreeSlide starts at its tuned size (BEAST 3 runs, acceptance
   about 0.3) instead of 1.0. The sizes are kept rather than BEAUti's new
   0.01 (#201); each file's comment says why.
4. SequenceSimulator / SimulatedAlignment: branchRateModel takes the
   BranchRateModel interface, so legacy clocks are accepted too.

Also:
- Move the BEAST 2 seqgen files to beast.fx/examples/legacy/, next to their
  BEAST 3 conversions (they need beast-fx classes).
- legacy/README.md: the legacy/ files are BEAST 2 XML, not converted, and
  must still run in BEAST 2.8.x with the old (deprecated) classes.
- Test that the legacy examples still parse: a new method in beast-base's
  ExampleXmlParsingTest, and a beast-fx ExampleXmlParsingTest for the
  beast-fx examples and their legacy sources.
- Update MIGRATION-REPORT-batch2.md; add TODO-migrate-legacy-xmls-batch2.md
  for the open requests (3: posterior comparison with 2.7.9; 5: release
  scripts end to end).
alexeid added a commit that referenced this pull request Nov 6, 2026
The Standard (Yule) and TreePriors templates used BactrianSubtreeSlide,
whose additive step has to be sized to the tree. #201 started it at
0.01, which suits substitution-scale trees but takes millions of steps
to tune up on dated trees in years, and still fails for very shallow
trees (#201 comments). Use BactrianSubtreeScale instead, with the same
operator IDs and weights and no size, so its unitless default of 0.3
applies to every tree. The proposal kernel affects mixing, not the
posterior.

The core templates never build sampled-ancestor trees, whose
zero-length branches BactrianSubtreeScale rejects; the sampled-ancestor
package has its own templates and operators.

SimpleTreePriorTest now checks, for each of its six tree priors, that
the subtree slide BEAUti builds is a BactrianSubtreeScale at its default
size. It fails on the previous templates. beast-fx tests pass, slow ones
included.
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