Repository navigation
Add BactrianSubtreeScale, a scale-invariant subtree slide, and use it in BEAUti - #214
Merged
Merged
Conversation
Port BactrianSubtreeScale from beast-phylonco (commit 718de3a). It proposes the slid node's height by scaling, in log space, the branch between the node and the subtree it carries: gap' = gap * exp(size * Z), height' = floor + gap'. The new height can never fall below the carried subtree, so that flat rejection is gone, and the move is relative to the branch length, so one size suits any tree height or time unit. The Hastings ratio is log(gap'/gap) plus the same topology terms as BactrianSubtreeSlide. The one change from the phylonco version: it overrides getDefaultTargetAcceptanceProbability, so the target can be set from XML as for other operators. BactrianSubtreeSlide's additive step has to be sized to the tree: tuned sizes in the example XMLs range from 0.008 (height 0.06) to 2.5 (height 70), and auto-tuning can't recover from a start that is far too large (#200) or climbs slowly from one far too small. With this operator, the tuned size on testCoalescent, testYuleCalibrated and testBSP was 0.46-0.66 for all three, and ESS per step of the posterior and root height was within about 10% of BactrianSubtreeSlide started at its converged size. BactrianSubtreeScaleTest: - the floor is never violated and no proposal is rejected on an ultrametric tree (from beast-phylonco); - run alone on a 4-taxon tree under a constant-population coalescent, it reproduces the exact distribution: interval means theta/6, theta/3, theta and the balanced shape at 1/3 (BactrianSubtreeSlide is run the same way as a control); - with tuning off, theta = 1e-3 and 1e3 give the same acceptance rate (0.827) and the same rescaled distribution; an additive slide with a fixed size accepts 0.01% and 99.6% of moves. Registered in module-info.java and version.xml. Templates are unchanged.
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.
Switch the 28 examples (27 XML, testHKY.json) that used BactrianSubtreeSlide to BactrianSubtreeScale, as the BEAUti templates now do. Their size values were tuned for the additive slide, in tree-height units, and mean something different for the unitless scale move, so they are dropped and the operator's default is used. The examples/legacy/ copies do not use the slide and are unchanged.
Member
|
Minor issues (non-blocking)
|
#204 added 8 examples that use BactrianSubtreeSlide with tuned sizes (testMultipleAlignments_randomTaxaOrder, testRandomLocalClock, testRelaxedClock, testSRD06, testTipDates, testTipDates2, testUCLNclock.json and beast-fx testSimulatedAlignment). Switch them to BactrianSubtreeScale with no size, and rewrite their conversion comments to match. Note the switch in MIGRATION-REPORT-batch2.md, keeping the tuned slide sizes as a record. CHANGELOG: list BactrianSubtreeScale as a new operator and as part of BEAUti's default tree operator set. migration-guide: the recommended new operator set uses it without a size.
From Walter's review of #214: - markclades is now honoured, with the same makeDirty(IS_FILTHY) calls as BactrianSubtreeSlide. - Reject a downward proposal whose height rounds to exactly the floor (a tiny gap relative to the floor), instead of making a zero-length branch. - Javadoc: not for sampled-ancestor trees, as for BactrianSubtreeSlide. - scaledSlideIsUnitFree now asserts the additive contrast it runs (acceptance < 0.05 at theta 1e-3, > 0.9 at theta 1e3).
BactrianSubtreeScale duplicated about 150 lines of BactrianSubtreeSlide (Walter's review of #214). Move the shared move into an abstract AbstractSubtreeSlide: node choice, reattachment up and down, intersectingEdges, markclades, and the source/destination counts. One hook, proposeHeight(i, p), returns the new height and its log-Jacobian, or null to reject. A base class rather than a hook in BactrianSubtreeSlide, so the scale move does not inherit the slide's size (tree-height units) and limit inputs, which it would accept and ignore. Each operator keeps its own inputs and tuning; BactrianSubtreeSlide.getDelta() stays for packages that override it. The random-number calls are unchanged, so the refactor is exact: 16 fixed-seed runs (testCoalescent, testYuleCalibrated, testTipDates, testBSP; scale, scale+markclades, slide, slide+limit+markclades) give byte-identical logs and trees before and after.
Member
Author
|
Thanks Walter, all useful. Addressed in 6e62d24 and 1d7e680:
Also since your review: master is merged in, the full default test suite passes, and #204's 8 new examples are switched to |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds
BactrianSubtreeScale, ported from beast-phylonco (commit 718de3a), where Yao has been using it for months, and makes it BEAUti's subtree slide. It's a subtree slide that's scale-invariant. Instead of adding a step to the slid node's height, it scales, in log space, the branch between the node and the subtree it carries:sizesuits any tree height or time unit.BactrianSubtreeSlide.getDefaultTargetAcceptanceProbability(), so the target can be set from XML like other operators.Why
BactrianSubtreeSlide's additive step has to be sized to the tree. In the example XMLs its tuned size ranges from 0.008 (testCoalescent, height 0.06) to 2.5 (testBSP, height 70). Auto-tuning can't recover from a start that is far too large (#200), and it climbs slowly from one far too small (see the table in #201's comments). A fixed default, 1.0 or 0.01, fails one end or the other. This operator removes the problem at the source, which also makes #213 (predicting the tree height to size the slide) largely unnecessary.BEAUti templates
The Standard (Yule) and TreePriors templates now use
BactrianSubtreeScaleinstead ofBactrianSubtreeSlide. The operator IDs and weights are unchanged, and there's nosize, so the default of 0.3 applies to every tree. This replaces #201's fixed 0.01 start, which suits substitution-scale trees but takes millions of steps to tune up on dated trees in years, and still fails on very shallow ones (#201 comments). The proposal kernel affects only mixing, not the posterior, so comparisons with BEAST 2.7.9 stay like-for-like.The core templates never build sampled-ancestor trees, whose zero-length branches this operator rejects. The sampled-ancestor package has its own templates and operators.
Tests:
BactrianSubtreeScaleTestBactrianSubtreeSlideis run the same way as a control.SimpleTreePriorTestnow also checks, for each of its six tree priors, that the subtree slide BEAUti builds is aBactrianSubtreeScaleat its default size. It fails on the previous templates.Fast
beast-basesuite: 572 tests, 0 failures.beast-fxtests pass: 52 run, 0 failures, plus the slow ones.Benchmark
Each operator replaced the slide in three examples (2M steps, 2 replicates, both auto-tuned). The additive slide started at its converged size, its best case; the scaled one at 0.5 everywhere.
Mixing is within about ±10% of the best-case additive slide. The scaled slide gets there from one default: its tuned size stays at 0.46–0.66 across tree heights spanning three orders of magnitude.
Shared code with BactrianSubtreeSlide
The slide and the scale move share everything but the height proposal, now in an abstract
AbstractSubtreeSlide(node choice, reattachment up and down,intersectingEdges, markclades, source/destination counts) with one hook,proposeHeight(i, p). Each operator keeps its own inputs and tuning. The refactor leaves the random-number calls unchanged and is exact: 16 fixed-seed runs (4 examples × scale, scale+markclades, slide, slide+limit+markclades) give byte-identical logs and trees before and after.Examples
The 28 examples that used
BactrianSubtreeSlide(27 XML,testHKY.json) now useBactrianSubtreeScale, withsizedropped: their sizes were tuned for the additive slide in tree-height units and mean something else for the unitless scale move. Theexamples/legacy/copies don't use the slide and are unchanged.All 28 run cleanly;
Example*tests pass. Posterior against the existing slide logs in beast3-test (same chain length and sampling, 2 replicates each):testTwoCalibrationsPrior was borderline with 2 replicates (
yulez = 3.77, a 0.05 difference in log density); with 4 fresh seeds it matches, so that was noise. ESS is within about ±10% of the slide's across these, as in the benchmark above.Interaction with #204: #204 adds 8 more examples that use the slide (testMultipleAlignments_randomTaxaOrder, testRandomLocalClock, testRelaxedClock, testSRD06, testTipDates, testTipDates2, testUCLNclock.json, beast-fx testSimulatedAlignment). #204 merged first; they are switched here too.
Not in this PR