Library for the Development and Use of Phylogenetic Network Methods
Network topology move operations for MCMC search (add/remove/flip reticulation, SPR).
This exception is raised whenever there is a fatal error in executing a network move.
Abstract base class for every network proposal move. A :class:`Move` is a stateful object whose ``execute`` method mutates the ``Network`` held by a :class:`Model` and whose ``undo`` method restores the pre-execute state. The contract is: * ``execute(model)`` performs the proposal and records just enough information (either compact deltas in ``same_move_info`` or a full ``copy.deepcopy`` snapshot in ``undo_info``) to later roll back or replay the move. * ``undo(model)`` returns the network to its pre-execute state. Must be cheap and side-effect-free on anything else. * ``same_move(model)`` re-plays the proposal on a clone of the model, used by the parallel MCMC driver. * ``hastings_ratio()`` returns ``q(x | x') / q(x' | x)`` for proper MCMC; see the method-level docstring below for why eve...
Initialise per-instance bookkeeping fields.
Apply the proposal to ``model.network`` in place.
| Parameter | Type | Description |
|---|---|---|
| model | Model whose ``network`` will be mutated. The move uses ``model.rng`` (a seeded ``numpy.random.Generator``) for every random decision. |
Undo the most recent call to :meth:`execute`.
| Parameter | Type | Description |
|---|---|---|
| model | The same model that was passed to :meth:`execute`. After this call, the network is restored to its pre-execute state. |
Replay the last proposal on an identical (cloned) model. Used by the parallel MCMC driver, which runs multiple chains with shared move sequences. Concrete moves that use deep-copy ``undo_info`` typically implement this as a no-op, since replay is not meaningful without the exact random draws.
| Parameter | Type | Description |
|---|---|---|
| model | A topologically-equivalent clone of the model passed to :meth:`execute`. |
Network nodes whose incident branches or gammas this move modified. Consumed by scorers that maintain per-network-edge likelihood caches (see :class:`phynetpy._mcmc_gt._GTLikelihoodEngine`): any node returned here -- plus its ancestor path to the root -- will have its cached partials invalidated, everything else is reused across iterations. The default implementation returns ``None`` (fully dirty), which is the safe fallback for moves whose impact on the network structure is hard to localise. Topology-preserving moves (``ChangeNodeHeight``, ``ChangeInheritanceProb``) should override and return the single node whose incident edges changed. Topology-changing moves (``SPR``, ``AddReticulation``, ``RemoveReticulation``, ``RelocateReticulation``, ``ChangeReticSource``, ``ChangeReticDest``, ``FlipReticulation``) generally keep the default ``None``: they replace edges entirely, which the engine's per-edge cache has to rebuild anyway.
| Parameter | Type | Description |
|---|---|---|
| net | Current network (i.e. the network after :meth:`execute`). Overrides may use it to resolve stored labels to live :class:`Node` references. |
Proposal asymmetry correction ``q(x|x') / q(x'|x)``. A proper MCMC sampler uses the Hastings ratio to correct for asymmetric proposal distributions so that the chain converges to the target distribution. **Every concrete move in this module currently returns 1.0**, which would be exact only for strictly symmetric proposals. Three are not: * :class:`SPR` weights candidate regraft edges by ``1 / d ** distance_decay`` of their topological distance from the prune point. The reverse regraft probability depends on the hop-distance distribution *after* the move, which is not cheap to compute on a network. * :class:`ChangeNodeHeight` draws a Gaussian delta whose sigma is a fraction of the per-node *feasible* half-range; the half-range changes after the move, so proposals are mildly asymmetric even though the draw itself is symmetric. * :class:`ChangeInheritanceProb` clamps its Gaussian draw to the open interval ``(eps, 1 - eps)`` (rather than renormalising a truncated Gaussian). This piles proposal mass on the boundaries. For the MPL search this module is driving, the Metropolis-Hastings criterion is applied to a *log-likelihood surface* being maximised under simulated annealing -- not to a stationary distribution we care about matching. The un-corrected acceptance rule is still monotone in the score, so the search is still guaranteed to climb in expectation; the bias affects dwell-time distribution, which matters for Bayesian posteriors but not for finding the optimum. Returning 1.0 is therefore a deliberate SA-scoped shortcut, not an oversight. Bayesian callers should override these ratios before using the moves in an MCMC sampler.
A move that adds a reticulation to a network. Host edges are split at a random point so their original branch length is preserved across the two halves. The new reticulation edge is given a short length drawn from Exp(mean=0.1*min_host_len) and both parent edges of the new reticulation node receive gamma = 0.5. Uses deep-copy for undo/same_move to guarantee correctness.
Create a new ``AddReticulation`` proposal.
| Parameter | Type | Description |
|---|---|---|
| max_reticulations | Optional hard cap on the number of reticulations. If the current network already has ``max_reticulations`` reticulation nodes, the proposal silently returns without modifying the network. ``None`` disables the cap. |
Insert a new reticulation into ``model.network``.
| Parameter | Type | Description |
|---|---|---|
| model | Model whose ``network`` will be mutated in place. |
Undo the most recent call to :meth:`execute`.
| Parameter | Type | Description |
|---|---|---|
| model | The same model that was passed to :meth:`execute`. After this call, the network is restored to its pre-execute state. |
Replay the last proposal on an identical (cloned) model. Used by the parallel MCMC driver, which runs multiple chains with shared move sequences. Concrete moves that use deep-copy ``undo_info`` typically implement this as a no-op, since replay is not meaningful without the exact random draws.
| Parameter | Type | Description |
|---|---|---|
| model | A topologically-equivalent clone of the model passed to :meth:`execute`. |
Proposal asymmetry correction ``q(x|x') / q(x'|x)``. A proper MCMC sampler uses the Hastings ratio to correct for asymmetric proposal distributions so that the chain converges to the target distribution. **Every concrete move in this module currently returns 1.0**, which would be exact only for strictly symmetric proposals. Three are not: * :class:`SPR` weights candidate regraft edges by ``1 / d ** distance_decay`` of their topological distance from the prune point. The reverse regraft probability depends on the hop-distance distribution *after* the move, which is not cheap to compute on a network. * :class:`ChangeNodeHeight` draws a Gaussian delta whose sigma is a fraction of the per-node *feasible* half-range; the half-range changes after the move, so proposals are mildly asymmetric even though the draw itself is symmetric. * :class:`ChangeInheritanceProb` clamps its Gaussian draw to the open interval ``(eps, 1 - eps)`` (rather than renormalising a truncated Gaussian). This piles proposal mass on the boundaries. For the MPL search this module is driving, the Metropolis-Hastings criterion is applied to a *log-likelihood surface* being maximised under simulated annealing -- not to a stationary distribution we care about matching. The un-corrected acceptance rule is still monotone in the score, so the search is still guaranteed to climb in expectation; the bias affects dwell-time distribution, which matters for Bayesian posteriors but not for finding the optimum. Returning 1.0 is therefore a deliberate SA-scoped shortcut, not an oversight. Bayesian callers should override these ratios before using the moves in an MCMC sampler.
Remove a reticulation node from the network. Algorithm: 1. Pick a random reticulation node c (in=2, out=1). 2. Randomly choose one of its two parent edges to delete. 3. Remove that parent edge. c now has (in=1, out=1) -- suppress c. 4. The source of the deleted edge may now be degree-2 -- suppress it. Uses deep-copy for undo/same_move to guarantee correctness.
Initialise per-instance bookkeeping fields.
Apply the proposal to ``model.network`` in place.
| Parameter | Type | Description |
|---|---|---|
| model | Model whose ``network`` will be mutated. The move uses ``model.rng`` (a seeded ``numpy.random.Generator``) for every random decision. |
Undo the most recent call to :meth:`execute`.
| Parameter | Type | Description |
|---|---|---|
| model | The same model that was passed to :meth:`execute`. After this call, the network is restored to its pre-execute state. |
Replay the last proposal on an identical (cloned) model. Used by the parallel MCMC driver, which runs multiple chains with shared move sequences. Concrete moves that use deep-copy ``undo_info`` typically implement this as a no-op, since replay is not meaningful without the exact random draws.
| Parameter | Type | Description |
|---|---|---|
| model | A topologically-equivalent clone of the model passed to :meth:`execute`. |
Proposal asymmetry correction ``q(x|x') / q(x'|x)``. A proper MCMC sampler uses the Hastings ratio to correct for asymmetric proposal distributions so that the chain converges to the target distribution. **Every concrete move in this module currently returns 1.0**, which would be exact only for strictly symmetric proposals. Three are not: * :class:`SPR` weights candidate regraft edges by ``1 / d ** distance_decay`` of their topological distance from the prune point. The reverse regraft probability depends on the hop-distance distribution *after* the move, which is not cheap to compute on a network. * :class:`ChangeNodeHeight` draws a Gaussian delta whose sigma is a fraction of the per-node *feasible* half-range; the half-range changes after the move, so proposals are mildly asymmetric even though the draw itself is symmetric. * :class:`ChangeInheritanceProb` clamps its Gaussian draw to the open interval ``(eps, 1 - eps)`` (rather than renormalising a truncated Gaussian). This piles proposal mass on the boundaries. For the MPL search this module is driving, the Metropolis-Hastings criterion is applied to a *log-likelihood surface* being maximised under simulated annealing -- not to a stationary distribution we care about matching. The un-corrected acceptance rule is still monotone in the score, so the search is still guaranteed to climb in expectation; the bias affects dwell-time distribution, which matters for Bayesian posteriors but not for finding the optimum. Returning 1.0 is therefore a deliberate SA-scoped shortcut, not an oversight. Bayesian callers should override these ratios before using the moves in an MCMC sampler.
Flip the direction of one reticulation edge. Picks a random reticulation edge ``z -> c`` and reverses it to ``c -> z``, provided the result is still a valid DAG. After the flip, ``z`` becomes a reticulation (in-degree 2) and ``c`` may lose its reticulation status. Invariants enforced on the candidate edge before the flip: * ``c`` must be a reticulation (so it currently has in-degree 2 -- otherwise the flip wouldn't produce a well-defined reticulation swap). * ``z`` must not be the root (the root cannot become a reticulation). * ``z`` must not already be a reticulation and must have in-degree <= 1 (otherwise the flip would push ``z``'s in-degree to 3, an invalid structure that the acyclicity check does not catch). If the post-flip network is cyclic (rare but possible through other ...
Initialise with no per-instance parameters (see :class:`Move`).
Propose a single reticulation-edge flip on ``model.network``.
| Parameter | Type | Description |
|---|---|---|
| model | Model whose ``network`` will be mutated in place. |
Undo the most recent call to :meth:`execute`.
| Parameter | Type | Description |
|---|---|---|
| model | The same model that was passed to :meth:`execute`. After this call, the network is restored to its pre-execute state. |
Replay the last proposal on an identical (cloned) model. Used by the parallel MCMC driver, which runs multiple chains with shared move sequences. Concrete moves that use deep-copy ``undo_info`` typically implement this as a no-op, since replay is not meaningful without the exact random draws.
| Parameter | Type | Description |
|---|---|---|
| model | A topologically-equivalent clone of the model passed to :meth:`execute`. |
Proposal asymmetry correction ``q(x|x') / q(x'|x)``. A proper MCMC sampler uses the Hastings ratio to correct for asymmetric proposal distributions so that the chain converges to the target distribution. **Every concrete move in this module currently returns 1.0**, which would be exact only for strictly symmetric proposals. Three are not: * :class:`SPR` weights candidate regraft edges by ``1 / d ** distance_decay`` of their topological distance from the prune point. The reverse regraft probability depends on the hop-distance distribution *after* the move, which is not cheap to compute on a network. * :class:`ChangeNodeHeight` draws a Gaussian delta whose sigma is a fraction of the per-node *feasible* half-range; the half-range changes after the move, so proposals are mildly asymmetric even though the draw itself is symmetric. * :class:`ChangeInheritanceProb` clamps its Gaussian draw to the open interval ``(eps, 1 - eps)`` (rather than renormalising a truncated Gaussian). This piles proposal mass on the boundaries. For the MPL search this module is driving, the Metropolis-Hastings criterion is applied to a *log-likelihood surface* being maximised under simulated annealing -- not to a stationary distribution we care about matching. The un-corrected acceptance rule is still monotone in the score, so the search is still guaranteed to climb in expectation; the bias affects dwell-time distribution, which matters for Bayesian posteriors but not for finding the optimum. Returning 1.0 is therefore a deliberate SA-scoped shortcut, not an oversight. Bayesian callers should override these ratios before using the moves in an MCMC sampler.
PSPP (Parentage-Switching for Polyploid Phylogenetics) move for Infer_MP_Allop. Alters the genetic parentage of a subnetwork while maintaining the same ploidy values for each leaf. Uses deep-copy for undo/same_move to guarantee correctness.
Initialise per-instance bookkeeping fields.
Executes the PSPP (Switch-Parentage) move.
| Parameter | Type | Description |
|---|---|---|
| model | Model | A model object with a populated network field. |
Restores the network to its pre-move state.
Replays the same topology change on a different model instance.
Proposal asymmetry correction ``q(x|x') / q(x'|x)``. A proper MCMC sampler uses the Hastings ratio to correct for asymmetric proposal distributions so that the chain converges to the target distribution. **Every concrete move in this module currently returns 1.0**, which would be exact only for strictly symmetric proposals. Three are not: * :class:`SPR` weights candidate regraft edges by ``1 / d ** distance_decay`` of their topological distance from the prune point. The reverse regraft probability depends on the hop-distance distribution *after* the move, which is not cheap to compute on a network. * :class:`ChangeNodeHeight` draws a Gaussian delta whose sigma is a fraction of the per-node *feasible* half-range; the half-range changes after the move, so proposals are mildly asymmetric even though the draw itself is symmetric. * :class:`ChangeInheritanceProb` clamps its Gaussian draw to the open interval ``(eps, 1 - eps)`` (rather than renormalising a truncated Gaussian). This piles proposal mass on the boundaries. For the MPL search this module is driving, the Metropolis-Hastings criterion is applied to a *log-likelihood surface* being maximised under simulated annealing -- not to a stationary distribution we care about matching. The un-corrected acceptance rule is still monotone in the score, so the search is still guaranteed to climb in expectation; the bias affects dwell-time distribution, which matters for Bayesian posteriors but not for finding the optimum. Returning 1.0 is therefore a deliberate SA-scoped shortcut, not an oversight. Bayesian callers should override these ratios before using the moves in an MCMC sampler.
Subtree Prune and Regraft on a phylogenetic network. Network-safe algorithm: 1. Select a random edge (u -> v) to prune, subject to: - v is not a leaf - v is not a reticulation (we don't detach reticulation children) - u is not a reticulation with out-degree 1 (would leave it (2,0)) - u is not root with out-degree 2 (would leave root with 1 child) 2. Remove the edge (u -> v). 3. Repair u: if u becomes (1,1), suppress u (merge incident edges). 4. Collect subtree nodes rooted at v (used to prevent cycles). 5. Select a target edge (a -> b) where neither endpoint is in the subtree (prevents cycles). Edges are weighted by inverse topological distance from the prune point so that nearby regraft locations are strongly preferred. 6. Subdivide (a -> b) by inserting a new node w: a -> ...
Initialise per-instance bookkeeping fields.
Apply the proposal to ``model.network`` in place.
| Parameter | Type | Description |
|---|---|---|
| model | Model whose ``network`` will be mutated. The move uses ``model.rng`` (a seeded ``numpy.random.Generator``) for every random decision. |
Undo the most recent call to :meth:`execute`.
| Parameter | Type | Description |
|---|---|---|
| model | The same model that was passed to :meth:`execute`. After this call, the network is restored to its pre-execute state. |
Replay the last proposal on an identical (cloned) model. Used by the parallel MCMC driver, which runs multiple chains with shared move sequences. Concrete moves that use deep-copy ``undo_info`` typically implement this as a no-op, since replay is not meaningful without the exact random draws.
| Parameter | Type | Description |
|---|---|---|
| model | A topologically-equivalent clone of the model passed to :meth:`execute`. |
Proposal asymmetry correction ``q(x|x') / q(x'|x)``. A proper MCMC sampler uses the Hastings ratio to correct for asymmetric proposal distributions so that the chain converges to the target distribution. **Every concrete move in this module currently returns 1.0**, which would be exact only for strictly symmetric proposals. Three are not: * :class:`SPR` weights candidate regraft edges by ``1 / d ** distance_decay`` of their topological distance from the prune point. The reverse regraft probability depends on the hop-distance distribution *after* the move, which is not cheap to compute on a network. * :class:`ChangeNodeHeight` draws a Gaussian delta whose sigma is a fraction of the per-node *feasible* half-range; the half-range changes after the move, so proposals are mildly asymmetric even though the draw itself is symmetric. * :class:`ChangeInheritanceProb` clamps its Gaussian draw to the open interval ``(eps, 1 - eps)`` (rather than renormalising a truncated Gaussian). This piles proposal mass on the boundaries. For the MPL search this module is driving, the Metropolis-Hastings criterion is applied to a *log-likelihood surface* being maximised under simulated annealing -- not to a stationary distribution we care about matching. The un-corrected acceptance rule is still monotone in the score, so the search is still guaranteed to climb in expectation; the bias affects dwell-time distribution, which matters for Bayesian posteriors but not for finding the optimum. Returning 1.0 is therefore a deliberate SA-scoped shortcut, not an oversight. Bayesian callers should override these ratios before using the moves in an MCMC sampler.
Slide an internal node up or down by adjusting incident branch lengths. A random internal (non-root, non-leaf) node is chosen and shifted by a Gaussian delta. The step standard deviation is ``sigma_frac`` times the feasible half-range (the maximum shift that doesn't push any incident branch below ``_EPSILON``), so proposals stay in bounds naturally while still concentrating mass around the current height. ``sigma_frac`` is meant to be tuned by ``MPLKernel``'s adaptive scheduler so the acceptance rate tracks a target. The uniform proposal it replaced was equivalent to ``sigma_frac ≈ 0.58`` (sd of a uniform is ``half_range/sqrt(3)``) and always ignored acceptance feedback. Starting at ``0.4`` gives a tighter, higher-acceptance default that the adaptive layer can still crank back up when usef...
Initialise per-instance bookkeeping fields.
Apply the proposal to ``model.network`` in place.
| Parameter | Type | Description |
|---|---|---|
| model | Model whose ``network`` will be mutated. The move uses ``model.rng`` (a seeded ``numpy.random.Generator``) for every random decision. |
Undo the most recent call to :meth:`execute`.
| Parameter | Type | Description |
|---|---|---|
| model | The same model that was passed to :meth:`execute`. After this call, the network is restored to its pre-execute state. |
Replay the last proposal on an identical (cloned) model. Used by the parallel MCMC driver, which runs multiple chains with shared move sequences. Concrete moves that use deep-copy ``undo_info`` typically implement this as a no-op, since replay is not meaningful without the exact random draws.
| Parameter | Type | Description |
|---|---|---|
| model | A topologically-equivalent clone of the model passed to :meth:`execute`. |
Return the single node whose height changed. Sliding one internal node by a Gaussian delta only modifies its incident parent / child branch lengths. For the MCMC_GT engine this means only the DP partials on the touched node's ancestor-to-root path need recomputation.
Proposal asymmetry correction ``q(x|x') / q(x'|x)``. A proper MCMC sampler uses the Hastings ratio to correct for asymmetric proposal distributions so that the chain converges to the target distribution. **Every concrete move in this module currently returns 1.0**, which would be exact only for strictly symmetric proposals. Three are not: * :class:`SPR` weights candidate regraft edges by ``1 / d ** distance_decay`` of their topological distance from the prune point. The reverse regraft probability depends on the hop-distance distribution *after* the move, which is not cheap to compute on a network. * :class:`ChangeNodeHeight` draws a Gaussian delta whose sigma is a fraction of the per-node *feasible* half-range; the half-range changes after the move, so proposals are mildly asymmetric even though the draw itself is symmetric. * :class:`ChangeInheritanceProb` clamps its Gaussian draw to the open interval ``(eps, 1 - eps)`` (rather than renormalising a truncated Gaussian). This piles proposal mass on the boundaries. For the MPL search this module is driving, the Metropolis-Hastings criterion is applied to a *log-likelihood surface* being maximised under simulated annealing -- not to a stationary distribution we care about matching. The un-corrected acceptance rule is still monotone in the score, so the search is still guaranteed to climb in expectation; the bias affects dwell-time distribution, which matters for Bayesian posteriors but not for finding the optimum. Returning 1.0 is therefore a deliberate SA-scoped shortcut, not an oversight. Bayesian callers should override these ratios before using the moves in an MCMC sampler.
Propose a new inheritance probability for a random reticulation node. The two parent edges of a reticulation always carry complementary gammas (gamma and 1-gamma). The new value is drawn from a Gaussian centered on the current gamma, truncated to (epsilon, 1-epsilon), so proposals stay close to the current value and accept more often than a flat Uniform(0, 1) draw.
Initialise per-instance bookkeeping fields.
Apply the proposal to ``model.network`` in place.
| Parameter | Type | Description |
|---|---|---|
| model | Model whose ``network`` will be mutated. The move uses ``model.rng`` (a seeded ``numpy.random.Generator``) for every random decision. |
Undo the most recent call to :meth:`execute`.
| Parameter | Type | Description |
|---|---|---|
| model | The same model that was passed to :meth:`execute`. After this call, the network is restored to its pre-execute state. |
Replay the last proposal on an identical (cloned) model. Used by the parallel MCMC driver, which runs multiple chains with shared move sequences. Concrete moves that use deep-copy ``undo_info`` typically implement this as a no-op, since replay is not meaningful without the exact random draws.
| Parameter | Type | Description |
|---|---|---|
| model | A topologically-equivalent clone of the model passed to :meth:`execute`. |
Return the single reticulation whose inheritance prob changed. Updating the gamma on one reticulation's two parent edges only affects that node's incident branch weights -- the rest of the per-network-edge partial cache can be reused.
Proposal asymmetry correction ``q(x|x') / q(x'|x)``. A proper MCMC sampler uses the Hastings ratio to correct for asymmetric proposal distributions so that the chain converges to the target distribution. **Every concrete move in this module currently returns 1.0**, which would be exact only for strictly symmetric proposals. Three are not: * :class:`SPR` weights candidate regraft edges by ``1 / d ** distance_decay`` of their topological distance from the prune point. The reverse regraft probability depends on the hop-distance distribution *after* the move, which is not cheap to compute on a network. * :class:`ChangeNodeHeight` draws a Gaussian delta whose sigma is a fraction of the per-node *feasible* half-range; the half-range changes after the move, so proposals are mildly asymmetric even though the draw itself is symmetric. * :class:`ChangeInheritanceProb` clamps its Gaussian draw to the open interval ``(eps, 1 - eps)`` (rather than renormalising a truncated Gaussian). This piles proposal mass on the boundaries. For the MPL search this module is driving, the Metropolis-Hastings criterion is applied to a *log-likelihood surface* being maximised under simulated annealing -- not to a stationary distribution we care about matching. The un-corrected acceptance rule is still monotone in the score, so the search is still guaranteed to climb in expectation; the bias affects dwell-time distribution, which matters for Bayesian posteriors but not for finding the optimum. Returning 1.0 is therefore a deliberate SA-scoped shortcut, not an oversight. Bayesian callers should override these ratios before using the moves in an MCMC sampler.
Move the source (tail / parent) end of a reticulation edge. Picks a random reticulation edge ``z -> c``, detaches the source end, cleans up anything ``z`` leaves behind (deg-2 collapse or orphan-chain pruning), then reattaches ``c``'s parent from a freshly-inserted node split into a randomly chosen host edge. Cycle-safe: host edges downstream of ``c`` are filtered out. Uses deep-copy for undo/same_move to guarantee correctness.
Initialise with no per-instance parameters (see :class:`Move`).
Propose a source-relocation for one reticulation edge.
| Parameter | Type | Description |
|---|---|---|
| model | Model whose ``network`` will be mutated in place. |
Undo the most recent call to :meth:`execute`.
| Parameter | Type | Description |
|---|---|---|
| model | The same model that was passed to :meth:`execute`. After this call, the network is restored to its pre-execute state. |
Replay the last proposal on an identical (cloned) model. Used by the parallel MCMC driver, which runs multiple chains with shared move sequences. Concrete moves that use deep-copy ``undo_info`` typically implement this as a no-op, since replay is not meaningful without the exact random draws.
| Parameter | Type | Description |
|---|---|---|
| model | A topologically-equivalent clone of the model passed to :meth:`execute`. |
Proposal asymmetry correction ``q(x|x') / q(x'|x)``. A proper MCMC sampler uses the Hastings ratio to correct for asymmetric proposal distributions so that the chain converges to the target distribution. **Every concrete move in this module currently returns 1.0**, which would be exact only for strictly symmetric proposals. Three are not: * :class:`SPR` weights candidate regraft edges by ``1 / d ** distance_decay`` of their topological distance from the prune point. The reverse regraft probability depends on the hop-distance distribution *after* the move, which is not cheap to compute on a network. * :class:`ChangeNodeHeight` draws a Gaussian delta whose sigma is a fraction of the per-node *feasible* half-range; the half-range changes after the move, so proposals are mildly asymmetric even though the draw itself is symmetric. * :class:`ChangeInheritanceProb` clamps its Gaussian draw to the open interval ``(eps, 1 - eps)`` (rather than renormalising a truncated Gaussian). This piles proposal mass on the boundaries. For the MPL search this module is driving, the Metropolis-Hastings criterion is applied to a *log-likelihood surface* being maximised under simulated annealing -- not to a stationary distribution we care about matching. The un-corrected acceptance rule is still monotone in the score, so the search is still guaranteed to climb in expectation; the bias affects dwell-time distribution, which matters for Bayesian posteriors but not for finding the optimum. Returning 1.0 is therefore a deliberate SA-scoped shortcut, not an oversight. Bayesian callers should override these ratios before using the moves in an MCMC sampler.
Atomically relocate a reticulation node end-to-end. Picks a random reticulation node, detaches both incoming edges and the single outgoing edge, cleans up any passthroughs or orphan chains left behind, and then reattaches a fresh reticulation on two newly split host edges. This is equivalent to ``ChangeReticSource + ChangeReticDest`` in a single atomic step, avoiding the deep likelihood valley that would arise from the intermediate partially-detached state. Cycle-safe via a ``descendants_of_child`` filter on host edges. Uses deep-copy for undo to guarantee correctness.
Initialise with no per-instance parameters (see :class:`Move`).
Propose a whole-reticulation relocation.
| Parameter | Type | Description |
|---|---|---|
| model | Model whose ``network`` will be mutated in place. |
Undo the most recent call to :meth:`execute`.
| Parameter | Type | Description |
|---|---|---|
| model | The same model that was passed to :meth:`execute`. After this call, the network is restored to its pre-execute state. |
Replay the last proposal on an identical (cloned) model. Used by the parallel MCMC driver, which runs multiple chains with shared move sequences. Concrete moves that use deep-copy ``undo_info`` typically implement this as a no-op, since replay is not meaningful without the exact random draws.
| Parameter | Type | Description |
|---|---|---|
| model | A topologically-equivalent clone of the model passed to :meth:`execute`. |
Proposal asymmetry correction ``q(x|x') / q(x'|x)``. A proper MCMC sampler uses the Hastings ratio to correct for asymmetric proposal distributions so that the chain converges to the target distribution. **Every concrete move in this module currently returns 1.0**, which would be exact only for strictly symmetric proposals. Three are not: * :class:`SPR` weights candidate regraft edges by ``1 / d ** distance_decay`` of their topological distance from the prune point. The reverse regraft probability depends on the hop-distance distribution *after* the move, which is not cheap to compute on a network. * :class:`ChangeNodeHeight` draws a Gaussian delta whose sigma is a fraction of the per-node *feasible* half-range; the half-range changes after the move, so proposals are mildly asymmetric even though the draw itself is symmetric. * :class:`ChangeInheritanceProb` clamps its Gaussian draw to the open interval ``(eps, 1 - eps)`` (rather than renormalising a truncated Gaussian). This piles proposal mass on the boundaries. For the MPL search this module is driving, the Metropolis-Hastings criterion is applied to a *log-likelihood surface* being maximised under simulated annealing -- not to a stationary distribution we care about matching. The un-corrected acceptance rule is still monotone in the score, so the search is still guaranteed to climb in expectation; the bias affects dwell-time distribution, which matters for Bayesian posteriors but not for finding the optimum. Returning 1.0 is therefore a deliberate SA-scoped shortcut, not an oversight. Bayesian callers should override these ratios before using the moves in an MCMC sampler.
Move the destination (head) end of a reticulation edge. Picks a random reticulation edge ``z -> c``, detaches the destination end, clears ``c``'s reticulation flag and collapses it if it became a deg-2 passthrough, then reattaches into a freshly-inserted reticulation node split onto a randomly chosen host edge. Cycle-safe: edges upstream of ``z`` are filtered out. Uses deep-copy for undo/same_move to guarantee correctness.
Initialise with no per-instance parameters (see :class:`Move`).
Propose a destination-relocation for one reticulation edge.
| Parameter | Type | Description |
|---|---|---|
| model | Model whose ``network`` will be mutated in place. |
Undo the most recent call to :meth:`execute`.
| Parameter | Type | Description |
|---|---|---|
| model | The same model that was passed to :meth:`execute`. After this call, the network is restored to its pre-execute state. |
Replay the last proposal on an identical (cloned) model. Used by the parallel MCMC driver, which runs multiple chains with shared move sequences. Concrete moves that use deep-copy ``undo_info`` typically implement this as a no-op, since replay is not meaningful without the exact random draws.
| Parameter | Type | Description |
|---|---|---|
| model | A topologically-equivalent clone of the model passed to :meth:`execute`. |
Proposal asymmetry correction ``q(x|x') / q(x'|x)``. A proper MCMC sampler uses the Hastings ratio to correct for asymmetric proposal distributions so that the chain converges to the target distribution. **Every concrete move in this module currently returns 1.0**, which would be exact only for strictly symmetric proposals. Three are not: * :class:`SPR` weights candidate regraft edges by ``1 / d ** distance_decay`` of their topological distance from the prune point. The reverse regraft probability depends on the hop-distance distribution *after* the move, which is not cheap to compute on a network. * :class:`ChangeNodeHeight` draws a Gaussian delta whose sigma is a fraction of the per-node *feasible* half-range; the half-range changes after the move, so proposals are mildly asymmetric even though the draw itself is symmetric. * :class:`ChangeInheritanceProb` clamps its Gaussian draw to the open interval ``(eps, 1 - eps)`` (rather than renormalising a truncated Gaussian). This piles proposal mass on the boundaries. For the MPL search this module is driving, the Metropolis-Hastings criterion is applied to a *log-likelihood surface* being maximised under simulated annealing -- not to a stationary distribution we care about matching. The un-corrected acceptance rule is still monotone in the score, so the search is still guaranteed to climb in expectation; the bias affects dwell-time distribution, which matters for Bayesian posteriors but not for finding the optimum. Returning 1.0 is therefore a deliberate SA-scoped shortcut, not an oversight. Bayesian callers should override these ratios before using the moves in an MCMC sampler.
Given an edge, a -> b, place a node c, such that a -> c -> b. This requires the deletion of edge a -> b, then the addition of edges a -> c and c -> b. Gamma preservation. When ``b`` is a reticulation, the original edge ``a -> b`` carries an inheritance probability ``gamma`` that represents one component of ``b``'s parental-mass split. After the insertion the new in-edge to ``b`` is ``c -> b`` (``a -> c`` is just a fresh tree edge feeding the new internal node), so we propagate the original gamma to ``c -> b``. Without this, every ``insert_node_in_edge`` call on a retic in-edge silently breaks the retic gamma sum invariant -- which is the root cause of the historical 14% bad-gamma rate in ``AddReticulation``. The new ``a -> c`` edge has no gamma (its retic-ness, if any, is the caller's responsibility to set explicitly).
| Parameter | Type | Description |
|---|---|---|
| edge | Edge | An edge, a -> b |
| node | Node | A node, c. |
| net | Network | The network that contains nodes a, b, and c |
Given two nodes in a network, connect them and check whether or not a reticulation is created.
| Parameter | Type | Description |
|---|---|---|
| src | Node | The parent of the new edge |
| dest | Node | The child of the new edge |
| net | Network | Network for which to add the edge |