aspartik.b3

class Stateful:

@runtime_checkable
class Stateful(Protocol):
    """
    Epoch-versioned objects for use with MCMC

    All stateful objects handled by `MCMC` must conform to this protocol.
    During each step operators can edit objects using whatever APIs provided.
    Then, at the end of the step, `MCMC` calls `accept` if the move has been
    accepted, or `reject` otherwise.
    """

    def accept(self) -> None:
        """Accept changes made during the current step"""

    def reject(self) -> None:
        """Reject changes made during the current step

        This method must roll the state of the object back to how it was at the
        beginning of the MCMC step.
        """
#

Epoch-versioned objects for use with MCMC

All stateful objects handled by MCMC must conform to this protocol. During each step operators can edit objects using whatever APIs provided. Then, at the end of the step, MCMC calls accept if the move has been accepted, or reject otherwise.

def accept(self) -> None

    def accept(self) -> None:
        """Accept changes made during the current step"""
#

Accept changes made during the current step

def reject(self) -> None

    def reject(self) -> None:
        """Reject changes made during the current step

        This method must roll the state of the object back to how it was at the
        beginning of the MCMC step.
        """
#

Reject changes made during the current step

This method must roll the state of the object back to how it was at the beginning of the MCMC step.

class Prior:

@runtime_checkable
class Prior(Protocol):
    """
    Interface which describes all prior distributions

    A `Prior` object will be queried by `MCMC` on each step after the operator
    edits the state to get the prior probability of the new state.  It's the
    responsibility of the prior to track the stateful objects it's interested
    in, so they will typically be passed in the constructor.

    Variable priors, coalescents, birth-death models, and all other
    non-likelihood models implement this protocol.
    """

    def probability(self) -> float:
        """Calculates the log prior probability of the model state

        The return value must be a **natural logarithm** of the probability.

        `MCMC` will short-circuit and abort the move if `probability` returns a
        negative infinity.  This can be used to avoid expensive likelihood
        calculations for obviously invalid moves, like going out of variable
        bounds.
        """
        ...
#

Interface which describes all prior distributions

A Prior object will be queried by MCMC on each step after the operator edits the state to get the prior probability of the new state. It's the responsibility of the prior to track the stateful objects it's interested in, so they will typically be passed in the constructor.

Variable priors, coalescents, birth-death models, and all other non-likelihood models implement this protocol.

def probability(self) -> float

    def probability(self) -> float:
        """Calculates the log prior probability of the model state

        The return value must be a **natural logarithm** of the probability.

        `MCMC` will short-circuit and abort the move if `probability` returns a
        negative infinity.  This can be used to avoid expensive likelihood
        calculations for obviously invalid moves, like going out of variable
        bounds.
        """
        ...
#

Calculates the log prior probability of the model state

The return value must be a natural logarithm of the probability.

MCMC will short-circuit and abort the move if probability returns a negative infinity. This can be used to avoid expensive likelihood calculations for obviously invalid moves, like going out of variable bounds.

class Operator:

class Operator(Protocol):
    """
    Objects which propose moves by editing state

    It is the responsibility of the objects to track the parts of the state it
    might want to edit.  Typically these objects will be passed in the
    constructor.
    """

    weight: float
    """Influences the probability of the operator being picked

    On each step `MCMC` picks a random operator from the list passed to it.
    It uses this value to weight them.  So, the larger it is, the more
    often the operator will be picked, and visa versa.  This value is read
    once on startup.  Therefore, if it's changed mid-execution the old
    cached value will still be used.
    """

    def propose(self) -> Proposal:
        """Proposes a new MCMC step

        It is presumed that the operator will store all the references to
        parameters and trees it wants to edit and will change them accordingly.
        If a move cannot be proposed for any reason `Proposal.Abort` should be
        returned.  `MCMC` will deal with rolling back the state.
        """
        ...
#

Objects which propose moves by editing state

It is the responsibility of the objects to track the parts of the state it might want to edit. Typically these objects will be passed in the constructor.

weight: float

#

Influences the probability of the operator being picked

On each step MCMC picks a random operator from the list passed to it. It uses this value to weight them. So, the larger it is, the more often the operator will be picked, and visa versa. This value is read once on startup. Therefore, if it's changed mid-execution the old cached value will still be used.

def propose(self) -> aspartik.b3.Proposal

    def propose(self) -> Proposal:
        """Proposes a new MCMC step

        It is presumed that the operator will store all the references to
        parameters and trees it wants to edit and will change them accordingly.
        If a move cannot be proposed for any reason `Proposal.Abort` should be
        returned.  `MCMC` will deal with rolling back the state.
        """
        ...
#

Proposes a new MCMC step

It is presumed that the operator will store all the references to parameters and trees it wants to edit and will change them accordingly. If a move cannot be proposed for any reason Proposal.Abort should be returned. MCMC will deal with rolling back the state.

class Callback:

class Callback(Protocol):
    """
    Custom callbacks

    `b3` supports arbitrary logging and checks via this protocol.  The `call`
    function is passed a reference to the main `MCMC` object, so the callback
    can either take state variables in the constructor of fetch them via the
    `MCMC` attributes.

    The `call` function won't be called after each step for efficiency.  See
    [`every`](#Callback.every) for configuring how often the callback will be
    invoked.
    """

    every: int
    """How often this callback should be called

    The `MCMC` will call each callback object when `index % every` is 0.  This
    value is read once when MCMC is created, so if it's changed during
    execution, the old `every` value will continue to be used.
    """

    def call(self, mcmc: MCMC) -> None:
        """
        A custom operation

        Used by loggers and other periodic actions.
        """
        ...

    def finish(self, mcmc: MCMC) -> None:
        """
        A method which will be called after a run ends

        It's useful for finalizing logger actions, including flushing to files.
        This method has a default no-op implementation, so it's not necessary
        to implement it on a custom logger.
        """
        pass
#

Custom callbacks

b3 supports arbitrary logging and checks via this protocol. The call function is passed a reference to the main MCMC object, so the callback can either take state variables in the constructor of fetch them via the MCMC attributes.

The call function won't be called after each step for efficiency. See every for configuring how often the callback will be invoked.

every: int

#

How often this callback should be called

The MCMC will call each callback object when index % every is 0. This value is read once when MCMC is created, so if it's changed during execution, the old every value will continue to be used.

def call(self, mcmc: aspartik.b3.MCMC) -> None

    def call(self, mcmc: MCMC) -> None:
        """
        A custom operation

        Used by loggers and other periodic actions.
        """
        ...
#

A custom operation

Used by loggers and other periodic actions.

def finish(self, mcmc: aspartik.b3.MCMC) -> None

    def finish(self, mcmc: MCMC) -> None:
        """
        A method which will be called after a run ends

        It's useful for finalizing logger actions, including flushing to files.
        This method has a default no-op implementation, so it's not necessary
        to implement it on a custom logger.
        """
        pass
#

A method which will be called after a run ends

It's useful for finalizing logger actions, including flushing to files. This method has a default no-op implementation, so it's not necessary to implement it on a custom logger.

class MCMC:

#

The main object which runs the analysis

rng

#

callbacks

#

A list of callbacks

posterior

#

Posterior probability for the last accepted step

operator_statistics

#

Operator statistics for this run

Returns a list of (operator, results, propose, likelihood) tuples for each operator. propose and likelihood records the total time the MCMC spent waiting for the operator to generate a proposal and calculate it respectively. operator is the reference to the original operator object. And results is a list of step results.

current_step

#

Index of the current MCMC step

Starts from 0, includes burn-in.

parameters

#

priors

#

All priors

operators

#

A list of active operators

likelihood

#

likelihood_value

#

prior

#

Prior likelihood for the current step

Note that unlike posterior and Likelihood, this property isn't cached. It will trigger a recalculation on all priors on each access.

def run(self, /, n)

#

Execute n steps of the Markov chain

This yields flow control to the Rust core until the simulation is done. Press Ctrl+C to interrupt and stop the execution.

def dump_state(self, /)

#

The type of the None singleton.

def load_state(self, /, bytes)

#

The type of the None singleton.

class Clock:

#

def Strict(cls, /, rate)

#

The type of the None singleton.

class Proposal:

#

A result of the move proposed by an operator

While the operators edit the tree directly, they need to communicate the status of their move to MCMC. This is the class used for that.

def Abort(cls, /)

#

Aborts the move unconditionally

All of the trees and parameters are rolled back. This is relatively fast, as it typically skips recalculating the likelihoods.

def Hastings(cls, /, ratio)

#

Proposes the move with the ratio

This is the ratio from the Metropolis–Hastings algorithm.